Commit f7ff89ea authored by rossberg@chromium.org's avatar rossberg@chromium.org

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
parent 85f5afb7
......@@ -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);
}
......
......@@ -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,
......
......@@ -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);
}
......
......@@ -2196,6 +2196,31 @@ MaybeObject* JSReceiver::SetProperty(LookupResult* result,
}
bool JSProxy::HasPropertyWithHandler(String* name_raw) {
Isolate* isolate = GetIsolate();
HandleScope scope(isolate);
Handle<Object> receiver(this);
Handle<Object> name(name_raw);
Handle<Object> handler(this->handler());
// Extract trap function.
Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("has");
Handle<Object> 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<Object> 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,
......
......@@ -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,
......
......@@ -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();
}
......
......@@ -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));
}
......
......@@ -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() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment