Treat ExecutableAccessorInfo as regular data properties.
BUG= R=dcarney@chromium.org, mvstanton@chromium.org Review URL: https://codereview.chromium.org/368783006 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22236 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
9230c1f3ca
commit
251ae22156
@ -191,16 +191,7 @@ void Accessors::ArrayLengthSetter(
|
||||
Handle<JSObject> object = Handle<JSObject>::cast(
|
||||
Utils::OpenHandle(*info.This()));
|
||||
Handle<Object> value = Utils::OpenHandle(*val);
|
||||
// This means one of the object's prototypes is a JSArray and the
|
||||
// object does not have a 'length' property. Calling SetProperty
|
||||
// causes an infinite loop.
|
||||
if (!object->IsJSArray()) {
|
||||
MaybeHandle<Object> maybe_result =
|
||||
JSObject::SetOwnPropertyIgnoreAttributes(
|
||||
object, isolate->factory()->length_string(), value, NONE);
|
||||
maybe_result.Check();
|
||||
return;
|
||||
}
|
||||
ASSERT(object->IsJSArray());
|
||||
|
||||
value = FlattenNumber(isolate, value);
|
||||
|
||||
@ -871,13 +862,7 @@ static Handle<Object> SetFunctionPrototype(Isolate* isolate,
|
||||
function = Handle<JSFunction>(function_raw, isolate);
|
||||
}
|
||||
|
||||
if (!function->should_have_prototype()) {
|
||||
// Since we hit this accessor, object will have no prototype property.
|
||||
MaybeHandle<Object> maybe_result =
|
||||
JSObject::SetOwnPropertyIgnoreAttributes(
|
||||
receiver, isolate->factory()->prototype_string(), value, NONE);
|
||||
return maybe_result.ToHandleChecked();
|
||||
}
|
||||
ASSERT(function->should_have_prototype());
|
||||
|
||||
Handle<Object> old_value;
|
||||
bool is_observed = *function == *receiver && function->map()->is_observed();
|
||||
|
@ -1206,7 +1206,9 @@ static bool LookupForWrite(Handle<JSObject> receiver,
|
||||
|
||||
if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false;
|
||||
if (lookup->holder() == *receiver) return lookup->CanHoldValue(value);
|
||||
if (lookup->IsPropertyCallbacks()) return true;
|
||||
if (lookup->IsPropertyCallbacks() &&
|
||||
!lookup->GetCallbackObject()->IsExecutableAccessorInfo())
|
||||
return true;
|
||||
// JSGlobalProxy either stores on the global object in the prototype, or
|
||||
// goes into the runtime if access checks are needed, so this is always
|
||||
// safe.
|
||||
|
@ -3096,6 +3096,25 @@ MaybeHandle<Object> JSObject::SetPropertyViaPrototypes(
|
||||
*done = true;
|
||||
if (!result.IsReadOnly()) {
|
||||
Handle<Object> callback_object(result.GetCallbackObject(), isolate);
|
||||
// Only store via executable access info setters if the holder is the
|
||||
// receiver or on its hidden prototype chain.
|
||||
if (callback_object->IsExecutableAccessorInfo()) {
|
||||
Handle<JSObject> current = object;
|
||||
while (*current != result.holder()) {
|
||||
// There is a callbacks holder, so we are guaranteed that all
|
||||
// objects in between are JSObjects.
|
||||
Handle<JSObject> prototype(
|
||||
JSObject::cast(current->GetPrototype()));
|
||||
if (!current->IsJSGlobalProxy() &&
|
||||
!prototype->map()->is_hidden_prototype()) {
|
||||
*done = false;
|
||||
break;
|
||||
}
|
||||
current = prototype;
|
||||
}
|
||||
// Break out of the switch after breaking out of the loop above.
|
||||
if (*current != result.holder()) break;
|
||||
}
|
||||
return SetPropertyWithCallback(object, name, value,
|
||||
handle(result.holder()),
|
||||
callback_object, strict_mode);
|
||||
|
@ -1924,7 +1924,7 @@ void AddAccessor(Handle<FunctionTemplate> templ,
|
||||
Handle<String> name,
|
||||
v8::AccessorGetterCallback getter,
|
||||
v8::AccessorSetterCallback setter) {
|
||||
templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
|
||||
templ->InstanceTemplate()->SetAccessor(name, getter, setter);
|
||||
}
|
||||
|
||||
void AddInterceptor(Handle<FunctionTemplate> templ,
|
||||
@ -1937,6 +1937,7 @@ void AddInterceptor(Handle<FunctionTemplate> templ,
|
||||
THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
|
||||
parent->SetHiddenPrototype(true);
|
||||
Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
|
||||
child->Inherit(parent);
|
||||
AddAccessor(parent, v8_str("age"),
|
||||
@ -1946,7 +1947,7 @@ THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
|
||||
env->Global()->Set(v8_str("Child"), child->GetFunction());
|
||||
CompileRun("var child = new Child;"
|
||||
"child.age = 10;");
|
||||
ExpectBoolean("child.hasOwnProperty('age')", false);
|
||||
ExpectBoolean("child.hasOwnProperty('age')", true);
|
||||
ExpectInt32("child.age", 10);
|
||||
ExpectInt32("child.accessor_age", 10);
|
||||
}
|
||||
@ -9985,10 +9986,13 @@ THREADED_TEST(ShadowObject) {
|
||||
LocalContext context(NULL, global_template);
|
||||
|
||||
Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
|
||||
t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
|
||||
t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
|
||||
Local<ObjectTemplate> proto = t->PrototypeTemplate();
|
||||
t->SetHiddenPrototype(true);
|
||||
Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
|
||||
t->Inherit(pt);
|
||||
Local<ObjectTemplate> proto = pt->PrototypeTemplate();
|
||||
Local<ObjectTemplate> instance = t->InstanceTemplate();
|
||||
instance->SetNamedPropertyHandler(ShadowNamedGet);
|
||||
instance->SetIndexedPropertyHandler(ShadowIndexedGet);
|
||||
|
||||
proto->Set(v8_str("f"),
|
||||
v8::FunctionTemplate::New(isolate,
|
||||
@ -18535,12 +18539,12 @@ void FooSetInterceptor(Local<String> name,
|
||||
TEST(SetterOnConstructorPrototype) {
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
|
||||
templ->SetAccessor(v8_str("x"),
|
||||
GetterWhichReturns42,
|
||||
SetterWhichSetsYOnThisTo23);
|
||||
Local<FunctionTemplate> templ = FunctionTemplate::New(isolate);
|
||||
templ->SetHiddenPrototype(true);
|
||||
templ->InstanceTemplate()->SetAccessor(v8_str("x"), GetterWhichReturns42,
|
||||
SetterWhichSetsYOnThisTo23);
|
||||
LocalContext context;
|
||||
context->Global()->Set(v8_str("P"), templ->NewInstance());
|
||||
context->Global()->Set(v8_str("P"), templ->InstanceTemplate()->NewInstance());
|
||||
CompileRun("function C1() {"
|
||||
" this.x = 23;"
|
||||
"};"
|
||||
@ -18562,8 +18566,7 @@ TEST(SetterOnConstructorPrototype) {
|
||||
script = v8_compile("new C2();");
|
||||
for (int i = 0; i < 10; i++) {
|
||||
v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
|
||||
CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
|
||||
CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
|
||||
CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
|
||||
}
|
||||
}
|
||||
|
||||
@ -18649,11 +18652,11 @@ TEST(Regress618) {
|
||||
}
|
||||
|
||||
// Use an API object with accessors as prototype.
|
||||
Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
|
||||
templ->SetAccessor(v8_str("x"),
|
||||
GetterWhichReturns42,
|
||||
SetterWhichSetsYOnThisTo23);
|
||||
context->Global()->Set(v8_str("P"), templ->NewInstance());
|
||||
Local<FunctionTemplate> templ = FunctionTemplate::New(isolate);
|
||||
templ->SetHiddenPrototype(true);
|
||||
templ->InstanceTemplate()->SetAccessor(v8_str("x"), GetterWhichReturns42,
|
||||
SetterWhichSetsYOnThisTo23);
|
||||
context->Global()->Set(v8_str("P"), templ->InstanceTemplate()->NewInstance());
|
||||
|
||||
// This compile will get the code from the compilation cache.
|
||||
CompileRun(source);
|
||||
@ -21067,16 +21070,16 @@ static void InstanceCheckedSetter(Local<String> name,
|
||||
}
|
||||
|
||||
|
||||
static void CheckInstanceCheckedResult(int getters,
|
||||
int setters,
|
||||
bool expects_callbacks,
|
||||
static void CheckInstanceCheckedResult(int getters, int setters,
|
||||
bool expects_callbacks, bool is_setter,
|
||||
TryCatch* try_catch) {
|
||||
if (expects_callbacks) {
|
||||
CHECK(!try_catch->HasCaught());
|
||||
CHECK_EQ(getters, instance_checked_getter_count);
|
||||
CHECK_EQ(setters, instance_checked_setter_count);
|
||||
} else {
|
||||
CHECK(try_catch->HasCaught());
|
||||
CHECK((is_setter && !try_catch->HasCaught()) ||
|
||||
(!is_setter && try_catch->HasCaught()));
|
||||
CHECK_EQ(0, instance_checked_getter_count);
|
||||
CHECK_EQ(0, instance_checked_setter_count);
|
||||
}
|
||||
@ -21091,33 +21094,38 @@ static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
|
||||
|
||||
// Test path through generic runtime code.
|
||||
CompileRun("obj.foo");
|
||||
CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
|
||||
CheckInstanceCheckedResult(1, 0, expects_callbacks, false, &try_catch);
|
||||
CompileRun("obj.foo = 23");
|
||||
CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
|
||||
CheckInstanceCheckedResult(1, 1, expects_callbacks, true, &try_catch);
|
||||
if (!expects_callbacks) CompileRun("delete obj.foo");
|
||||
|
||||
// Test path through generated LoadIC and StoredIC.
|
||||
CompileRun("function test_get(o) { o.foo; }"
|
||||
"test_get(obj);");
|
||||
CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
|
||||
CheckInstanceCheckedResult(2, 1, expects_callbacks, false, &try_catch);
|
||||
CompileRun("test_get(obj);");
|
||||
CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
|
||||
CheckInstanceCheckedResult(3, 1, expects_callbacks, false, &try_catch);
|
||||
CompileRun("test_get(obj);");
|
||||
CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
|
||||
CheckInstanceCheckedResult(4, 1, expects_callbacks, false, &try_catch);
|
||||
CompileRun("function test_set(o) { o.foo = 23; }"
|
||||
"test_set(obj);");
|
||||
CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
|
||||
CheckInstanceCheckedResult(4, 2, expects_callbacks, true, &try_catch);
|
||||
if (!expects_callbacks) CompileRun("delete obj.foo");
|
||||
CompileRun("test_set(obj);");
|
||||
CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
|
||||
CheckInstanceCheckedResult(4, 3, expects_callbacks, true, &try_catch);
|
||||
if (!expects_callbacks) CompileRun("delete obj.foo");
|
||||
CompileRun("test_set(obj);");
|
||||
CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
|
||||
CheckInstanceCheckedResult(4, 4, expects_callbacks, true, &try_catch);
|
||||
if (!expects_callbacks) CompileRun("delete obj.foo");
|
||||
|
||||
// Test path through optimized code.
|
||||
CompileRun("%OptimizeFunctionOnNextCall(test_get);"
|
||||
"test_get(obj);");
|
||||
CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
|
||||
CheckInstanceCheckedResult(5, 4, expects_callbacks, false, &try_catch);
|
||||
CompileRun("%OptimizeFunctionOnNextCall(test_set);"
|
||||
"test_set(obj);");
|
||||
CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
|
||||
if (!expects_callbacks) CompileRun("delete obj.foo");
|
||||
CheckInstanceCheckedResult(5, 5, expects_callbacks, true, &try_catch);
|
||||
|
||||
// Cleanup so that closures start out fresh in next check.
|
||||
CompileRun("%DeoptimizeFunction(test_get);"
|
||||
@ -21189,14 +21197,16 @@ THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
|
||||
LocalContext context;
|
||||
v8::HandleScope scope(context->GetIsolate());
|
||||
|
||||
Local<FunctionTemplate> proto_templ =
|
||||
FunctionTemplate::New(context->GetIsolate());
|
||||
proto_templ->SetHiddenPrototype(true);
|
||||
Local<ObjectTemplate> proto = proto_templ->InstanceTemplate();
|
||||
proto->SetAccessor(
|
||||
v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter,
|
||||
Handle<Value>(), v8::DEFAULT, v8::None,
|
||||
v8::AccessorSignature::New(context->GetIsolate(), proto_templ));
|
||||
Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
|
||||
Local<ObjectTemplate> proto = templ->PrototypeTemplate();
|
||||
proto->SetAccessor(v8_str("foo"),
|
||||
InstanceCheckedGetter, InstanceCheckedSetter,
|
||||
Handle<Value>(),
|
||||
v8::DEFAULT,
|
||||
v8::None,
|
||||
v8::AccessorSignature::New(context->GetIsolate(), templ));
|
||||
templ->Inherit(proto_templ);
|
||||
context->Global()->Set(v8_str("f"), templ->GetFunction());
|
||||
|
||||
printf("Testing positive ...\n");
|
||||
|
@ -1685,7 +1685,9 @@ var obj = { __proto__: fun };
|
||||
Object.observe(obj, observer.callback);
|
||||
obj.prototype = 7;
|
||||
Object.deliverChangeRecords(observer.callback);
|
||||
observer.assertNotCalled();
|
||||
observer.assertCallbackRecords([
|
||||
{ object: obj, name: 'prototype', type: 'add'},
|
||||
]);
|
||||
|
||||
|
||||
// Check that changes in observation status are detected in all IC states and
|
||||
|
Loading…
Reference in New Issue
Block a user