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