| 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); | 
| +} | 
|  |