Index: test/cctest/test-api.cc |
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc |
index 8a1e9147369fbde7d20e996c91e45089c0545e67..5cd9dd45d5adfd36e76a7feea44351dfe18b3f32 100644 |
--- a/test/cctest/test-api.cc |
+++ b/test/cctest/test-api.cc |
@@ -16593,3 +16593,175 @@ TEST(StringEmpty) { |
CHECK(v8::String::Empty(isolate).IsEmpty()); |
CHECK_EQ(3, fatal_error_callback_counter); |
} |
+ |
+ |
+static int instance_checked_getter_count = 0; |
+static Handle<Value> InstanceCheckedGetter(Local<String> name, |
+ const AccessorInfo& info) { |
+ CHECK_EQ(name, v8_str("foo")); |
+ instance_checked_getter_count++; |
+ return v8_num(11); |
+} |
+ |
+ |
+static int instance_checked_setter_count = 0; |
+static void InstanceCheckedSetter(Local<String> name, |
+ Local<Value> value, |
+ const AccessorInfo& info) { |
+ CHECK_EQ(name, v8_str("foo")); |
+ CHECK_EQ(value, v8_num(23)); |
+ instance_checked_setter_count++; |
+} |
+ |
+ |
+static void CheckInstanceCheckedResult(int getters, |
+ int setters, |
+ bool expects_callbacks, |
+ 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_EQ(0, instance_checked_getter_count); |
+ CHECK_EQ(0, instance_checked_setter_count); |
+ } |
+ try_catch->Reset(); |
+} |
+ |
+ |
+static void CheckInstanceCheckedAccessors(bool expects_callbacks) { |
+ instance_checked_getter_count = 0; |
+ instance_checked_setter_count = 0; |
+ TryCatch try_catch; |
+ |
+ // Test path through generic runtime code. |
+ CompileRun("obj.foo"); |
+ CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch); |
+ CompileRun("obj.foo = 23"); |
+ CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch); |
+ |
+ // Test path through generated LoadIC and StoredIC. |
+ CompileRun("function test_get(o) { o.foo; }" |
+ "test_get(obj);"); |
+ CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch); |
+ CompileRun("test_get(obj);"); |
+ CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch); |
+ CompileRun("test_get(obj);"); |
+ CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch); |
+ CompileRun("function test_set(o) { o.foo = 23; }" |
+ "test_set(obj);"); |
+ CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch); |
+ CompileRun("test_set(obj);"); |
+ CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch); |
+ CompileRun("test_set(obj);"); |
+ CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch); |
+ |
+ // Test path through optimized code. |
+ CompileRun("%OptimizeFunctionOnNextCall(test_get);" |
+ "test_get(obj);"); |
+ CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch); |
+ CompileRun("%OptimizeFunctionOnNextCall(test_set);" |
+ "test_set(obj);"); |
+ CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch); |
+ |
+ // Cleanup so that closures start out fresh in next check. |
+ CompileRun("%DeoptimizeFunction(test_get);" |
+ "%ClearFunctionTypeFeedback(test_get);" |
+ "%DeoptimizeFunction(test_set);" |
+ "%ClearFunctionTypeFeedback(test_set);"); |
+} |
+ |
+ |
+THREADED_TEST(InstanceCheckOnInstanceAccessor) { |
+ v8::internal::FLAG_allow_natives_syntax = true; |
+ v8::HandleScope scope; |
+ LocalContext context; |
+ |
+ Local<FunctionTemplate> templ = FunctionTemplate::New(); |
+ Local<ObjectTemplate> inst = templ->InstanceTemplate(); |
+ inst->SetAccessor(v8_str("foo"), |
+ InstanceCheckedGetter, InstanceCheckedSetter, |
+ Handle<Value>(), |
+ v8::DEFAULT, |
+ v8::None, |
+ v8::AccessorSignature::New(templ)); |
+ context->Global()->Set(v8_str("f"), templ->GetFunction()); |
+ |
+ printf("Testing positive ...\n"); |
+ CompileRun("var obj = new f();"); |
+ CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); |
+ CheckInstanceCheckedAccessors(true); |
+ |
+ printf("Testing negative ...\n"); |
+ CompileRun("var obj = {};" |
+ "obj.__proto__ = new f();"); |
+ CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj")))); |
+ CheckInstanceCheckedAccessors(false); |
+} |
+ |
+ |
+THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) { |
+ v8::internal::FLAG_allow_natives_syntax = true; |
+ v8::HandleScope scope; |
+ LocalContext context; |
+ |
+ Local<FunctionTemplate> templ = FunctionTemplate::New(); |
+ Local<ObjectTemplate> inst = templ->InstanceTemplate(); |
+ AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter); |
+ inst->SetAccessor(v8_str("foo"), |
+ InstanceCheckedGetter, InstanceCheckedSetter, |
+ Handle<Value>(), |
+ v8::DEFAULT, |
+ v8::None, |
+ v8::AccessorSignature::New(templ)); |
+ context->Global()->Set(v8_str("f"), templ->GetFunction()); |
+ |
+ printf("Testing positive ...\n"); |
+ CompileRun("var obj = new f();"); |
+ CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); |
+ CheckInstanceCheckedAccessors(true); |
+ |
+ printf("Testing negative ...\n"); |
+ CompileRun("var obj = {};" |
+ "obj.__proto__ = new f();"); |
+ CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj")))); |
+ CheckInstanceCheckedAccessors(false); |
+} |
+ |
+ |
+THREADED_TEST(InstanceCheckOnPrototypeAccessor) { |
+ v8::internal::FLAG_allow_natives_syntax = true; |
+ v8::HandleScope scope; |
+ LocalContext context; |
+ |
+ Local<FunctionTemplate> templ = FunctionTemplate::New(); |
+ Local<ObjectTemplate> proto = templ->PrototypeTemplate(); |
+ proto->SetAccessor(v8_str("foo"), |
+ InstanceCheckedGetter, InstanceCheckedSetter, |
+ Handle<Value>(), |
+ v8::DEFAULT, |
+ v8::None, |
+ v8::AccessorSignature::New(templ)); |
+ context->Global()->Set(v8_str("f"), templ->GetFunction()); |
+ |
+ printf("Testing positive ...\n"); |
+ CompileRun("var obj = new f();"); |
+ CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); |
+ CheckInstanceCheckedAccessors(true); |
+ |
+ printf("Testing negative ...\n"); |
+ CompileRun("var obj = {};" |
+ "obj.__proto__ = new f();"); |
+ CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj")))); |
+ CheckInstanceCheckedAccessors(false); |
+ |
+ printf("Testing positive with modified prototype chain ...\n"); |
+ CompileRun("var obj = new f();" |
+ "var pro = {};" |
+ "pro.__proto__ = obj.__proto__;" |
+ "obj.__proto__ = pro;"); |
+ CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); |
+ CheckInstanceCheckedAccessors(true); |
+} |