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