diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index da12179b08..c4621c5749 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -1892,12 +1892,16 @@ void Genesis::InitializeGlobal_harmony_tolength() { } -static void SimpleInstallFunction( - Handle& base, const char* name, Builtins::Name call, int len) { +static void SimpleInstallFunction(Handle& base, const char* name, + Builtins::Name call, int len, bool adapt) { Handle fun = InstallFunction(base, name, JS_OBJECT_TYPE, JSObject::kHeaderSize, MaybeHandle(), call); - fun->shared()->set_internal_formal_parameter_count(len); + if (adapt) { + fun->shared()->set_internal_formal_parameter_count(len); + } else { + fun->shared()->DontAdaptArguments(); + } fun->shared()->set_length(len); } @@ -1914,13 +1918,13 @@ void Genesis::InitializeGlobal_harmony_reflect() { JSObject::AddProperty(global, reflect_string, reflect, DONT_ENUM); SimpleInstallFunction(reflect, "deleteProperty", - Builtins::kReflectDeleteProperty, 2); + Builtins::kReflectDeleteProperty, 2, true); SimpleInstallFunction(reflect, "get", - Builtins::kReflectGet, 3); + Builtins::kReflectGet, 3, false); SimpleInstallFunction(reflect, "has", - Builtins::kReflectHas, 2); + Builtins::kReflectHas, 2, true); SimpleInstallFunction(reflect, "isExtensible", - Builtins::kReflectIsExtensible, 1); + Builtins::kReflectIsExtensible, 1, true); } diff --git a/src/builtins.cc b/src/builtins.cc index 54d1901691..c97cb584f3 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -1474,14 +1474,10 @@ BUILTIN(ReflectDeleteProperty) { // ES6 section 26.1.6 Reflect.get BUILTIN(ReflectGet) { HandleScope scope(isolate); - DCHECK_LE(3, args.length()); - DCHECK_LE(args.length(), 4); - Handle target = args.at(1); - Handle key = args.at(2); - // Handle receiver = args.length() == 4 ? args.at(3) : target; - // - // TODO(neis): We ignore the receiver argument for now because - // GetPropertyOrElement doesn't support it yet. + Handle undef = isolate->factory()->undefined_value(); + Handle target = args.length() > 1 ? args.at(1) : undef; + Handle key = args.length() > 2 ? args.at(2) : undef; + Handle receiver = args.length() > 3 ? args.at(3) : target; if (!target->IsJSReceiver()) { THROW_NEW_ERROR_RETURN_FAILURE( @@ -1496,7 +1492,8 @@ BUILTIN(ReflectGet) { Handle result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, result, Object::GetPropertyOrElement(target, name)); + isolate, result, Object::GetPropertyOrElement( + Handle::cast(target), name, receiver)); return *result; } diff --git a/src/objects-inl.h b/src/objects-inl.h index 68591ec941..4f2bd7a29c 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -7259,6 +7259,16 @@ MaybeHandle Object::GetPropertyOrElement(Handle object, } +MaybeHandle Object::GetPropertyOrElement(Handle holder, + Handle name, + Handle receiver, + LanguageMode language_mode) { + LookupIterator it = LookupIterator::PropertyOrElement( + name->GetIsolate(), receiver, name, holder); + return GetProperty(&it, language_mode); +} + + Maybe JSReceiver::HasProperty(Handle object, Handle name) { // Call the "has" trap on proxies. diff --git a/src/objects.h b/src/objects.h index 47c9ee929a..8fd25b4ce6 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1250,6 +1250,9 @@ class Object { MUST_USE_RESULT static inline MaybeHandle GetPropertyOrElement( Handle object, Handle name, LanguageMode language_mode = SLOPPY); + MUST_USE_RESULT static inline MaybeHandle GetPropertyOrElement( + Handle holder, Handle name, Handle receiver, + LanguageMode language_mode = SLOPPY); MUST_USE_RESULT static inline MaybeHandle GetProperty( Isolate* isolate, Handle object, const char* key, LanguageMode language_mode = SLOPPY); diff --git a/test/mjsunit/harmony/reflect.js b/test/mjsunit/harmony/reflect.js index d9cd51f649..fc52c93d19 100644 --- a/test/mjsunit/harmony/reflect.js +++ b/test/mjsunit/harmony/reflect.js @@ -53,6 +53,10 @@ function prepare(tgt) { tgt[sym] = "foo"; tgt["noconf"] = 43; Object.defineProperty(tgt, "noconf", {configurable: false}); + Object.defineProperty(tgt, "getter", + { get: function () {return this.bla}, configurable: true }); + Object.defineProperty(tgt, "setter", + { set: function () {}, configurable: true }); } @@ -83,14 +87,43 @@ function prepare(tgt) { (function testReflectGetOnObject() { + var receiver = {bla: false}; for (let tgt of objects) { prepare(tgt); assertEquals(true, Reflect.get(tgt, "bla")); + assertEquals(true, Reflect.get(tgt, "bla", tgt)); + assertEquals(true, Reflect.get(tgt, "bla", receiver)); assertEquals(42, Reflect.get(tgt, 4)); + assertEquals(42, Reflect.get(tgt, 4, tgt)); + assertEquals(42, Reflect.get(tgt, 4, receiver)); assertEquals(42, Reflect.get(tgt, "4")); + assertEquals(42, Reflect.get(tgt, "4", tgt)); + assertEquals(42, Reflect.get(tgt, "4", receiver)); assertEquals("foo", Reflect.get(tgt, sym)); - assertEquals(undefined, Reflect.get(tgt, "doesnotexist")); + assertEquals("foo", Reflect.get(tgt, sym, tgt)); + assertEquals("foo", Reflect.get(tgt, sym, receiver)); + assertEquals(43, Reflect.get(tgt, "noconf")); + assertEquals(43, Reflect.get(tgt, "noconf", tgt)); + assertEquals(43, Reflect.get(tgt, "noconf", receiver)); + assertEquals(true, Reflect.get(tgt, "getter")); + assertEquals(true, Reflect.get(tgt, "getter", tgt)); + assertEquals(false, Reflect.get(tgt, "getter", receiver)); + assertEquals(undefined, Reflect.get(tgt, "setter")); + assertEquals(undefined, Reflect.get(tgt, "setter", tgt)); + assertEquals(undefined, Reflect.get(tgt, "setter", receiver)); + assertEquals(undefined, Reflect.get(tgt, "foo")); + assertEquals(undefined, Reflect.get(tgt, "foo", tgt)); + assertEquals(undefined, Reflect.get(tgt, "foo", receiver)); assertEquals(undefined, Reflect.get(tgt, 666)); + assertEquals(undefined, Reflect.get(tgt, 666, tgt)); + assertEquals(undefined, Reflect.get(tgt, 666, receiver)); + + let proto = tgt.__proto__; + tgt.__proto__ = { get foo() {return this.bla} }; + assertEquals(true, Reflect.get(tgt, "foo")); + assertEquals(true, Reflect.get(tgt, "foo", tgt)); + assertEquals(false, Reflect.get(tgt, "foo", receiver)); + tgt.__proto__ = proto; } })(); @@ -128,8 +161,16 @@ function prepare(tgt) { assertTrue(Reflect.has(tgt, 4)); assertTrue(Reflect.has(tgt, "4")); assertTrue(Reflect.has(tgt, sym)); - assertFalse(Reflect.has(tgt, "doesnotexist")); + assertTrue(Reflect.has(tgt, "noconf")); + assertTrue(Reflect.has(tgt, "getter")); + assertTrue(Reflect.has(tgt, "setter")); + assertFalse(Reflect.has(tgt, "foo")); assertFalse(Reflect.has(tgt, 666)); + + let proto = tgt.__proto__; + tgt.__proto__ = { get foo() {return this.bla} }; + assertEquals(true, Reflect.has(tgt, "foo")); + tgt.__proto__ = proto; } })(); @@ -173,10 +214,17 @@ function prepare(tgt) { } assertTrue(Reflect.deleteProperty(tgt, sym)); assertEquals(undefined, Object.getOwnPropertyDescriptor(tgt, sym)); - assertTrue(Reflect.deleteProperty(tgt, "doesnotexist")); - assertTrue(Reflect.deleteProperty(tgt, 666)); assertFalse(Reflect.deleteProperty(tgt, "noconf")); assertEquals(43, tgt.noconf); + assertTrue(Reflect.deleteProperty(tgt, "getter")); + assertTrue(Reflect.deleteProperty(tgt, "setter")); + assertTrue(Reflect.deleteProperty(tgt, "foo")); + assertTrue(Reflect.deleteProperty(tgt, 666)); + + let proto = tgt.__proto__; + tgt.__proto__ = { get foo() {return this.bla} }; + assertEquals(true, Reflect.deleteProperty(tgt, "foo")); + tgt.__proto__ = proto; } })();