From: rossberg@chromium.org Date: Tue, 19 Jul 2011 09:38:59 +0000 (+0000) Subject: Implement `in' for proxies. X-Git-Tag: upstream/4.7.83~18873 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f7ff89ea02cbad13551ab6c55eacb18c9bb46cc2;p=platform%2Fupstream%2Fv8.git Implement `in' for proxies. R=ager@chromium.org BUG=v8:1543 TEST= Review URL: http://codereview.chromium.org/7390028 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8681 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 8e34b9c..8cca561 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -1309,6 +1309,7 @@ void Genesis::InstallNativeFunctions() { void Genesis::InstallExperimentalNativeFunctions() { if (FLAG_harmony_proxies) { + INSTALL_NATIVE(JSFunction, "DerivedHasTrap", derived_has_trap); INSTALL_NATIVE(JSFunction, "DerivedGetTrap", derived_get_trap); INSTALL_NATIVE(JSFunction, "DerivedSetTrap", derived_set_trap); } diff --git a/src/contexts.h b/src/contexts.h index 0f3d44c..53b40f1 100644 --- a/src/contexts.h +++ b/src/contexts.h @@ -110,6 +110,7 @@ enum ContextLookupFlags { V(MAP_CACHE_INDEX, Object, map_cache) \ V(CONTEXT_DATA_INDEX, Object, data) \ V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \ + V(DERIVED_HAS_TRAP_INDEX, JSFunction, derived_has_trap) \ V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \ V(DERIVED_SET_TRAP_INDEX, JSFunction, derived_set_trap) @@ -227,6 +228,7 @@ class Context: public FixedArray { OUT_OF_MEMORY_INDEX, CONTEXT_DATA_INDEX, ALLOW_CODE_GEN_FROM_STRINGS_INDEX, + DERIVED_HAS_TRAP_INDEX, DERIVED_GET_TRAP_INDEX, DERIVED_SET_TRAP_INDEX, diff --git a/src/objects-inl.h b/src/objects-inl.h index 7fbf6c9..e069b79 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -4157,6 +4157,22 @@ Object* JSReceiver::GetPrototype() { } +bool JSReceiver::HasProperty(String* name) { + if (IsJSProxy()) { + return JSProxy::cast(this)->HasPropertyWithHandler(name); + } + return GetPropertyAttribute(name) != ABSENT; +} + + +bool JSReceiver::HasLocalProperty(String* name) { + if (IsJSProxy()) { + return JSProxy::cast(this)->HasPropertyWithHandler(name); + } + return GetLocalPropertyAttribute(name) != ABSENT; +} + + PropertyAttributes JSReceiver::GetPropertyAttribute(String* key) { return GetPropertyAttributeWithReceiver(this, key); } diff --git a/src/objects.cc b/src/objects.cc index 7b85703..b1d5f14 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -2196,6 +2196,31 @@ MaybeObject* JSReceiver::SetProperty(LookupResult* result, } +bool JSProxy::HasPropertyWithHandler(String* name_raw) { + Isolate* isolate = GetIsolate(); + HandleScope scope(isolate); + Handle receiver(this); + Handle name(name_raw); + Handle handler(this->handler()); + + // Extract trap function. + Handle trap_name = isolate->factory()->LookupAsciiSymbol("has"); + Handle trap(v8::internal::GetProperty(handler, trap_name)); + if (trap->IsUndefined()) { + trap = isolate->derived_has_trap(); + } + + // Call trap function. + Object** args[] = { name.location() }; + bool has_exception; + Handle result = + Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception); + if (has_exception) return Failure::Exception(); + + return result->ToBoolean()->IsTrue(); +} + + MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler( String* name_raw, Object* value_raw, diff --git a/src/objects.h b/src/objects.h index fbb8315..43747cc 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1394,14 +1394,8 @@ class JSReceiver: public HeapObject { PropertyAttributes GetLocalPropertyAttribute(String* name); // Can cause a GC. - bool HasProperty(String* name) { - return GetPropertyAttribute(name) != ABSENT; - } - - // Can cause a GC. - bool HasLocalProperty(String* name) { - return GetLocalPropertyAttribute(name) != ABSENT; - } + inline bool HasProperty(String* name); + inline bool HasLocalProperty(String* name); // Return the object's prototype (might be Heap::null_value()). inline Object* GetPrototype(); @@ -6481,6 +6475,8 @@ class JSProxy: public JSReceiver { // Casting. static inline JSProxy* cast(Object* obj); + bool HasPropertyWithHandler(String* name); + MUST_USE_RESULT MaybeObject* SetPropertyWithHandler( String* name, Object* value, diff --git a/src/runtime.cc b/src/runtime.cc index bba06d9..b4259c4 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -4315,11 +4315,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) { NoHandleAllocation na; ASSERT(args.length() == 2); - // Only JS objects can have properties. - if (args[0]->IsJSObject()) { - JSObject* object = JSObject::cast(args[0]); + // Only JS receivers can have properties. + if (args[0]->IsJSReceiver()) { + JSReceiver* receiver = JSReceiver::cast(args[0]); CONVERT_CHECKED(String, key, args[1]); - if (object->HasProperty(key)) return isolate->heap()->true_value(); + if (receiver->HasProperty(key)) return isolate->heap()->true_value(); } return isolate->heap()->false_value(); } diff --git a/src/runtime.js b/src/runtime.js index 77b97ae..4b600df 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -354,7 +354,8 @@ function IN(x) { if (!IS_SPEC_OBJECT(x)) { throw %MakeTypeError('invalid_in_operator_use', [this, x]); } - return %_IsNonNegativeSmi(this) ? %HasElement(x, this) : %HasProperty(x, %ToString(this)); + return %_IsNonNegativeSmi(this) && !%IsJSProxy(x) ? + %HasElement(x, this) : %HasProperty(x, %ToString(this)); } diff --git a/test/mjsunit/harmony/proxies.js b/test/mjsunit/harmony/proxies.js index 123ab83..84641d5 100644 --- a/test/mjsunit/harmony/proxies.js +++ b/test/mjsunit/harmony/proxies.js @@ -28,6 +28,8 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// TODO(rossberg): test exception cases. + // Getters. @@ -402,6 +404,79 @@ assertTrue("object" == typeof Proxy.create({})) +// Element (in). + +var key +function TestIn(handler) { + var o = Proxy.create(handler) + assertTrue("a" in o) + assertEquals("a", key) + assertTrue(99 in o) + assertEquals("99", key) + assertFalse("z" in o) + assertEquals("z", key) + + if ("b" in o) { + } else { + assertTrue(false) + } + assertEquals("b", key) + + if ("zz" in o) { + assertTrue(false) + } + assertEquals("zz", key) + + if (!("c" in o)) { + assertTrue(false) + } + assertEquals("c", key) + + if (!("zzz" in o)) { + } else { + assertTrue(false) + } + assertEquals("zzz", key) +} + +TestIn({ + has: function(k) { key = k; return k < "z" } +}) +TestIn({ + has: function(k) { return this.has2(k) }, + has2: function(k) { key = k; return k < "z" } +}) +TestIn({ + getPropertyDescriptor: function(k) { + key = k; return k < "z" ? {value: 42} : void 0 + } +}) +TestIn({ + getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) }, + getPropertyDescriptor2: function(k) { + key = k; return k < "z" ? {value: 42} : void 0 + } +}) +TestIn({ + getPropertyDescriptor: function(k) { + key = k; return k < "z" ? {get value() { return 42 }} : void 0 + } +}) +TestIn({ + get: undefined, + getPropertyDescriptor: function(k) { + key = k; return k < "z" ? {value: 42} : void 0 + } +}) + +TestIn(Proxy.create({ + get: function(pr, pk) { + return function(k) { key = k; return k < "z" } + } +})) + + + // Instanceof (instanceof). function TestInstanceof() {