Index: test/cctest/test-api.cc |
=================================================================== |
--- test/cctest/test-api.cc (revision 12347) |
+++ test/cctest/test-api.cc (working copy) |
@@ -14567,6 +14567,8 @@ |
static v8::Handle<Value> GetterWhichReturns42(Local<String> name, |
const AccessorInfo& info) { |
+ CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); |
+ CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); |
return v8_num(42); |
} |
@@ -14574,10 +14576,32 @@ |
static void SetterWhichSetsYOnThisTo23(Local<String> name, |
Local<Value> value, |
const AccessorInfo& info) { |
+ CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); |
+ CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); |
info.This()->Set(v8_str("y"), v8_num(23)); |
} |
+Handle<Value> FooGetInterceptor(Local<String> name, |
+ const AccessorInfo& info) { |
+ CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); |
+ CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); |
+ if (!name->Equals(v8_str("foo"))) return Handle<Value>(); |
+ return v8_num(42); |
+} |
+ |
+ |
+Handle<Value> FooSetInterceptor(Local<String> name, |
+ Local<Value> value, |
+ const AccessorInfo& info) { |
+ CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); |
+ CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); |
+ if (!name->Equals(v8_str("foo"))) return Handle<Value>(); |
+ info.This()->Set(v8_str("y"), v8_num(23)); |
+ return v8_num(23); |
+} |
+ |
+ |
TEST(SetterOnConstructorPrototype) { |
v8::HandleScope scope; |
Local<ObjectTemplate> templ = ObjectTemplate::New(); |
@@ -16813,9 +16837,66 @@ |
} |
+static void Helper137002(bool do_store, |
+ bool polymorphic, |
+ bool remove_accessor, |
+ bool interceptor) { |
+ LocalContext context; |
+ Local<ObjectTemplate> templ = ObjectTemplate::New(); |
+ if (interceptor) { |
+ templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor); |
+ } else { |
+ templ->SetAccessor(v8_str("foo"), |
+ GetterWhichReturns42, |
+ SetterWhichSetsYOnThisTo23); |
+ } |
+ context->Global()->Set(v8_str("obj"), templ->NewInstance()); |
+ |
+ // Turn monomorphic on slow object with native accessor, then turn |
+ // polymorphic, finally optimize to create negative lookup and fail. |
+ CompileRun(do_store ? |
+ "function f(x) { x.foo = void 0; }" : |
+ "function f(x) { return x.foo; }"); |
+ CompileRun("obj.y = void 0;"); |
+ if (!interceptor) { |
+ CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);"); |
+ } |
+ CompileRun("obj.__proto__ = null;" |
+ "f(obj); f(obj); f(obj);"); |
+ if (polymorphic) { |
+ CompileRun("f({});"); |
+ } |
+ CompileRun("obj.y = void 0;" |
+ "%OptimizeFunctionOnNextCall(f);"); |
+ if (remove_accessor) { |
+ CompileRun("delete obj.foo;"); |
+ } |
+ CompileRun("var result = f(obj);"); |
+ if (do_store) { |
+ CompileRun("result = obj.y;"); |
+ } |
+ if (remove_accessor && !interceptor) { |
+ CHECK(context->Global()->Get(v8_str("result"))->IsUndefined()); |
+ } else { |
+ CHECK_EQ(do_store ? 23 : 42, |
+ context->Global()->Get(v8_str("result"))->Int32Value()); |
+ } |
+} |
+ |
+ |
THREADED_TEST(Regress137002a) { |
i::FLAG_allow_natives_syntax = true; |
+ i::FLAG_compilation_cache = false; |
v8::HandleScope scope; |
+ for (int i = 0; i < 16; i++) { |
+ Helper137002(i & 8, i & 4, i & 2, i & 1); |
+ } |
+} |
+ |
+ |
+THREADED_TEST(Regress137002b) { |
+ i::FLAG_allow_natives_syntax = true; |
+ v8::HandleScope scope; |
LocalContext context; |
Local<ObjectTemplate> templ = ObjectTemplate::New(); |
templ->SetAccessor(v8_str("foo"), |
@@ -16823,19 +16904,65 @@ |
SetterWhichSetsYOnThisTo23); |
context->Global()->Set(v8_str("obj"), templ->NewInstance()); |
- // Turn monomorphic on slow object with native accessor, then turn |
- // polymorphic, finally optimize to create negative lookup and fail. |
- CompileRun("function f(x) { return x.foo; }" |
+ // Turn monomorphic on slow object with native accessor, then just |
+ // delete the property and fail. |
+ CompileRun("function load(x) { return x.foo; }" |
+ "function store(x) { x.foo = void 0; }" |
+ "function keyed_load(x, key) { return x[key]; }" |
+ // Second version of function has a different source (add void 0) |
+ // so that it does not share code with the first version. This |
+ // ensures that the ICs are monomorphic. |
+ "function load2(x) { void 0; return x.foo; }" |
+ "function store2(x) { void 0; x.foo = void 0; }" |
+ "function keyed_load2(x, key) { void 0; return x[key]; }" |
+ |
+ "obj.y = void 0;" |
+ "obj.__proto__ = null;" |
+ "var subobj = {};" |
+ "subobj.y = void 0;" |
+ "subobj.__proto__ = obj;" |
"%OptimizeObjectForAddingMultipleProperties(obj, 1);" |
- "obj.__proto__ = null;" |
- "f(obj); f(obj); f({});" |
- "%OptimizeFunctionOnNextCall(f);" |
- "var result = f(obj);"); |
- CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); |
+ |
+ // Make the ICs monomorphic. |
+ "load(obj); load(obj);" |
+ "load2(subobj); load2(subobj);" |
+ "store(obj); store(obj);" |
+ "store2(subobj); store2(subobj);" |
+ "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');" |
+ "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');" |
+ |
+ // Actually test the shiny new ICs and better not crash. This |
+ // serves as a regression test for issue 142088 as well. |
+ "load(obj);" |
+ "load2(subobj);" |
+ "store(obj);" |
+ "store2(subobj);" |
+ "keyed_load(obj, 'foo');" |
+ "keyed_load2(subobj, 'foo');" |
+ |
+ // Delete the accessor. It better not be called any more now. |
+ "delete obj.foo;" |
+ "obj.y = void 0;" |
+ "subobj.y = void 0;" |
+ |
+ "var load_result = load(obj);" |
+ "var load_result2 = load2(subobj);" |
+ "var keyed_load_result = keyed_load(obj, 'foo');" |
+ "var keyed_load_result2 = keyed_load2(subobj, 'foo');" |
+ "store(obj);" |
+ "store2(subobj);" |
+ "var y_from_obj = obj.y;" |
+ "var y_from_subobj = subobj.y;"); |
+ CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined()); |
+ CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined()); |
+ CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined()); |
+ CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined()); |
+ CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined()); |
+ CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined()); |
} |
-THREADED_TEST(Regress137002b) { |
+THREADED_TEST(Regress142088) { |
i::FLAG_allow_natives_syntax = true; |
v8::HandleScope scope; |
LocalContext context; |
@@ -16847,10 +16974,46 @@ |
// Turn monomorphic on slow object with native accessor, then just |
// delete the property and fail. |
- CompileRun("function f(x) { return x.foo; }" |
+ CompileRun("function load(x) { return x.foo; }" |
+ "function store(x) { x.foo = void 0; }" |
+ "function keyed_load(x, key) { return x[key]; }" |
+ // Second version of function has a different source (add void 0) |
+ // so that it does not share code with the first version. This |
+ // ensures that the ICs are monomorphic. |
+ "function load2(x) { void 0; return x.foo; }" |
+ "function store2(x) { void 0; x.foo = void 0; }" |
+ "function keyed_load2(x, key) { void 0; return x[key]; }" |
+ |
+ "obj.__proto__ = null;" |
+ "var subobj = {};" |
+ "subobj.__proto__ = obj;" |
"%OptimizeObjectForAddingMultipleProperties(obj, 1);" |
- "obj.__proto__ = null;" |
- "f(obj); f(obj); delete obj.foo;" |
- "var result = f(obj);"); |
- CHECK(context->Global()->Get(v8_str("result"))->IsUndefined()); |
+ |
+ // Make the ICs monomorphic. |
+ "load(obj); load(obj);" |
+ "load2(subobj); load2(subobj);" |
+ "store(obj);" |
+ "store2(subobj);" |
+ "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');" |
+ "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');" |
+ |
+ // Delete the accessor. It better not be called any more now. |
+ "delete obj.foo;" |
+ "obj.y = void 0;" |
+ "subobj.y = void 0;" |
+ |
+ "var load_result = load(obj);" |
+ "var load_result2 = load2(subobj);" |
+ "var keyed_load_result = keyed_load(obj, 'foo');" |
+ "var keyed_load_result2 = keyed_load2(subobj, 'foo');" |
+ "store(obj);" |
+ "store2(subobj);" |
+ "var y_from_obj = obj.y;" |
+ "var y_from_subobj = subobj.y;"); |
+ CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined()); |
+ CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined()); |
+ CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined()); |
+ CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined()); |
+ CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined()); |
+ CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined()); |
} |