Index: test/cctest/test-api.cc |
=================================================================== |
--- test/cctest/test-api.cc (revision 12276) |
+++ test/cctest/test-api.cc (working copy) |
@@ -14733,6 +14733,22 @@ |
} |
+Handle<Value> FooGetInterceptor(Local<String> name, |
+ const AccessorInfo& info) { |
+ 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) { |
+ 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(); |
@@ -16969,28 +16985,63 @@ |
} |
-THREADED_TEST(Regress137002a) { |
- i::FLAG_allow_natives_syntax = true; |
- v8::HandleScope scope; |
+static void Helper137002(bool do_store, |
+ bool polymorphic, |
+ bool remove_accessor, |
+ bool interceptor) { |
LocalContext context; |
Local<ObjectTemplate> templ = ObjectTemplate::New(); |
- templ->SetAccessor(v8_str("foo"), |
- GetterWhichReturns42, |
- SetterWhichSetsYOnThisTo23); |
+ 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("function f(x) { return x.foo; }" |
- "%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()); |
+ 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; |
@@ -17003,12 +17054,48 @@ |
// 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()); |
} |