| Index: test/cctest/test-api.cc
|
| diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
|
| index d1f25def57ad3eedf0906bbae0c3c7e7401ccd64..fb9bb5d3b366d78008ca314e807f7aafceda46cd 100644
|
| --- a/test/cctest/test-api.cc
|
| +++ b/test/cctest/test-api.cc
|
| @@ -63,6 +63,7 @@ using ::v8::FunctionTemplate;
|
| using ::v8::Handle;
|
| using ::v8::HandleScope;
|
| using ::v8::Local;
|
| +using ::v8::Name;
|
| using ::v8::Message;
|
| using ::v8::MessageCallback;
|
| using ::v8::Object;
|
| @@ -71,6 +72,7 @@ using ::v8::Persistent;
|
| using ::v8::Script;
|
| using ::v8::StackTrace;
|
| using ::v8::String;
|
| +using ::v8::Symbol;
|
| using ::v8::TryCatch;
|
| using ::v8::Undefined;
|
| using ::v8::UniqueId;
|
| @@ -1876,6 +1878,20 @@ void SimpleAccessorSetter(Local<String> name, Local<Value> value,
|
| self->Set(String::Concat(v8_str("accessor_"), name), value);
|
| }
|
|
|
| +void SymbolAccessorGetter(Local<Symbol> name,
|
| + const v8::PropertyCallbackInfo<v8::Value>& info) {
|
| + if (name->Name()->IsUndefined())
|
| + return;
|
| + SimpleAccessorGetter(Local<String>::Cast(name->Name()), info);
|
| +}
|
| +
|
| +void SymbolAccessorSetter(Local<Symbol> name, Local<Value> value,
|
| + const v8::PropertyCallbackInfo<void>& info) {
|
| + if (name->Name()->IsUndefined())
|
| + return;
|
| + SimpleAccessorSetter(Local<String>::Cast(name->Name()), value, info);
|
| +}
|
| +
|
| void EmptyInterceptorGetter(Local<String> name,
|
| const v8::PropertyCallbackInfo<v8::Value>& info) {
|
| }
|
| @@ -1885,6 +1901,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_'.
|
| @@ -1920,6 +1945,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,
|
| @@ -1934,6 +1999,20 @@ void AddInterceptor(Handle<FunctionTemplate> templ,
|
| }
|
|
|
|
|
| +void AddAccessor(Handle<FunctionTemplate> templ,
|
| + Handle<Symbol> name,
|
| + v8::AccessorSymbolGetterCallback getter,
|
| + v8::AccessorSymbolSetterCallback setter) {
|
| + 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());
|
| Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
|
| @@ -1952,6 +2031,65 @@ THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
|
| }
|
|
|
|
|
| +THREADED_TEST(LegacyInterceptorDoesNotSeeSymbols) {
|
| + i::FLAG_harmony_symbols = true;
|
| +
|
| + 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) {
|
| + i::FLAG_harmony_symbols = true;
|
| +
|
| + 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);
|
| @@ -2747,6 +2885,8 @@ THREADED_TEST(SymbolProperties) {
|
| v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
|
| v8::Local<v8::Symbol> sym2 =
|
| v8::Symbol::New(isolate, v8_str("my-symbol"));
|
| + v8::Local<v8::Symbol> sym3 =
|
| + v8::Symbol::New(isolate, v8_str("sym3"));
|
|
|
| CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
|
|
|
| @@ -2802,27 +2942,44 @@ THREADED_TEST(SymbolProperties) {
|
|
|
| CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
|
|
|
| + CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter));
|
| + CHECK(obj->Get(sym3)->IsUndefined());
|
| + CHECK(obj->Set(sym3, v8::Integer::New(isolate, 42)));
|
| + CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
|
| + CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
|
| + v8::Integer::New(isolate, 42)));
|
| +
|
| // Add another property and delete it afterwards to force the object in
|
| // slow case.
|
| CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
|
| CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
|
| CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
|
| CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
|
| - CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
|
| + CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
|
|
|
| CHECK(obj->Has(sym1));
|
| CHECK(obj->Has(sym2));
|
| + CHECK(obj->Has(sym3));
|
| + CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
|
| CHECK(obj->Delete(sym2));
|
| CHECK(obj->Has(sym1));
|
| CHECK(!obj->Has(sym2));
|
| + CHECK(obj->Has(sym3));
|
| + CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
|
| CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
|
| - CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
|
| + CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
|
| + CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
|
| + v8::Integer::New(isolate, 42)));
|
| + CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
|
|
|
| // Symbol properties are inherited.
|
| v8::Local<v8::Object> child = v8::Object::New(isolate);
|
| child->SetPrototype(obj);
|
| CHECK(child->Has(sym1));
|
| CHECK_EQ(2002, child->Get(sym1)->Int32Value());
|
| + CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
|
| + CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
|
| + v8::Integer::New(isolate, 42)));
|
| CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
|
| }
|
|
|
|
|