| Index: test/cctest/test-api.cc
|
| diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
|
| index 01c2ea8404ae5bac4c5b0d6a4b2440d3fbe2895f..3b02fcd3145e9a3d948f95f5b736f47e0005fa60 100644
|
| --- a/test/cctest/test-api.cc
|
| +++ b/test/cctest/test-api.cc
|
| @@ -1907,6 +1907,15 @@ void EmptyInterceptorSetter(Local<String> name,
|
| const v8::PropertyCallbackInfo<v8::Value>& info) {
|
| }
|
|
|
| +void EmptyGenericInterceptorGetter(Local<Name> name,
|
| + const v8::PropertyCallbackInfo<v8::Value>& info) {
|
| +}
|
| +
|
| +void EmptyGenericInterceptorSetter(Local<Name> name,
|
| + Local<Value> value,
|
| + const v8::PropertyCallbackInfo<v8::Value>& info) {
|
| +}
|
| +
|
| void InterceptorGetter(Local<String> name,
|
| const v8::PropertyCallbackInfo<v8::Value>& info) {
|
| // Intercept names that start with 'interceptor_'.
|
| @@ -1942,6 +1951,46 @@ void InterceptorSetter(Local<String> name,
|
| }
|
| }
|
|
|
| +void GenericInterceptorGetter(Local<Name> generic_name,
|
| + const v8::PropertyCallbackInfo<v8::Value>& info) {
|
| + Local<String> str;
|
| + if (generic_name->IsSymbol()) {
|
| + Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
|
| + if (name->IsUndefined()) return;
|
| + str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
|
| + } else {
|
| + Local<String> name = Local<String>::Cast(generic_name);
|
| + String::Utf8Value utf8(name);
|
| + char* name_str = *utf8;
|
| + if (*name_str == '_') return;
|
| + str = String::Concat(v8_str("_str_"), name);
|
| + }
|
| +
|
| + Handle<Object> self = Handle<Object>::Cast(info.This());
|
| + info.GetReturnValue().Set(self->Get(str));
|
| +}
|
| +
|
| +void GenericInterceptorSetter(Local<Name> generic_name,
|
| + Local<Value> value,
|
| + const v8::PropertyCallbackInfo<v8::Value>& info) {
|
| + Local<String> str;
|
| + if (generic_name->IsSymbol()) {
|
| + Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
|
| + if (name->IsUndefined()) return;
|
| + str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
|
| + } else {
|
| + Local<String> name = Local<String>::Cast(generic_name);
|
| + String::Utf8Value utf8(name);
|
| + char* name_str = *utf8;
|
| + if (*name_str == '_') return;
|
| + str = String::Concat(v8_str("_str_"), name);
|
| + }
|
| +
|
| + Handle<Object> self = Handle<Object>::Cast(info.This());
|
| + self->Set(str, value);
|
| + info.GetReturnValue().Set(value);
|
| +}
|
| +
|
| void AddAccessor(Handle<FunctionTemplate> templ,
|
| Handle<String> name,
|
| v8::AccessorGetterCallback getter,
|
| @@ -1963,6 +2012,12 @@ void AddAccessor(Handle<FunctionTemplate> templ,
|
| templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
|
| }
|
|
|
| +void AddGenericInterceptor(Handle<FunctionTemplate> templ,
|
| + v8::GenericNamedPropertyGetterCallback getter,
|
| + v8::GenericNamedPropertySetterCallback setter) {
|
| + templ->InstanceTemplate()->SetGenericNamedPropertyHandler(getter, setter);
|
| +}
|
| +
|
|
|
| THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
|
| v8::HandleScope scope(CcTest::isolate());
|
| @@ -1982,6 +2037,61 @@ THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
|
| }
|
|
|
|
|
| +THREADED_TEST(LegacyInterceptorDoesNotSeeSymbols) {
|
| + LocalContext env;
|
| + v8::Isolate* isolate = CcTest::isolate();
|
| + v8::HandleScope scope(isolate);
|
| + Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
|
| + Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
|
| + v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
|
| +
|
| + child->Inherit(parent);
|
| + AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
|
| + AddInterceptor(child, InterceptorGetter, InterceptorSetter);
|
| +
|
| + env->Global()->Set(v8_str("Child"), child->GetFunction());
|
| + env->Global()->Set(v8_str("age"), age);
|
| + CompileRun("var child = new Child;"
|
| + "child[age] = 10;");
|
| + ExpectInt32("child[age]", 10);
|
| + ExpectBoolean("child.hasOwnProperty('age')", false);
|
| + ExpectBoolean("child.hasOwnProperty('accessor_age')", true);
|
| +}
|
| +
|
| +
|
| +THREADED_TEST(GenericInterceptorDoesSeeSymbols) {
|
| + LocalContext env;
|
| + v8::Isolate* isolate = CcTest::isolate();
|
| + v8::HandleScope scope(isolate);
|
| + Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
|
| + Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
|
| + v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
|
| + v8::Local<v8::Symbol> anon = v8::Symbol::New(isolate);
|
| +
|
| + child->Inherit(parent);
|
| + AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
|
| + AddGenericInterceptor(
|
| + child, GenericInterceptorGetter, GenericInterceptorSetter);
|
| +
|
| + env->Global()->Set(v8_str("Child"), child->GetFunction());
|
| + env->Global()->Set(v8_str("age"), age);
|
| + env->Global()->Set(v8_str("anon"), anon);
|
| + CompileRun("var child = new Child;"
|
| + "child[age] = 10;");
|
| + ExpectInt32("child[age]", 10);
|
| + ExpectInt32("child._sym_age", 10);
|
| +
|
| + // Check that it also sees strings.
|
| + CompileRun("child.foo = 47");
|
| + ExpectInt32("child.foo", 47);
|
| + ExpectInt32("child._str_foo", 47);
|
| +
|
| + // Check that the interceptor can punt (in this case, on anonymous symbols).
|
| + CompileRun("child[anon] = 31337");
|
| + ExpectInt32("child[anon]", 31337);
|
| +}
|
| +
|
| +
|
| THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
|
| v8::Isolate* isolate = CcTest::isolate();
|
| v8::HandleScope scope(isolate);
|
|
|