Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 1821f500051ca75f8cebcd721b5a3a67e095bf28..8c7695db535a1d70162fa635a311a21b55900da9 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -149,7 +149,7 @@ void Object::Lookup(String* name, LookupResult* result) { |
} else if (heap_object->IsBoolean()) { |
holder = global_context->boolean_function()->instance_prototype(); |
} else if (heap_object->IsJSProxy()) { |
- return result->NotFound(); // For now... |
+ return result->HandlerResult(); |
} |
} |
ASSERT(holder != NULL); // Cannot handle null or undefined. |
@@ -225,6 +225,36 @@ MaybeObject* Object::GetPropertyWithCallback(Object* receiver, |
} |
+MaybeObject* Object::GetPropertyWithHandler(Object* receiver_raw, |
+ String* name_raw, |
+ Object* handler_raw) { |
+ Isolate* isolate = name_raw->GetIsolate(); |
+ HandleScope scope; |
+ Handle<Object> receiver(receiver_raw); |
+ Handle<Object> name(name_raw); |
+ Handle<Object> handler(handler_raw); |
+ |
+ // Extract trap function. |
+ LookupResult lookup; |
+ Handle<Object> trap(v8::internal::GetProperty(handler, "get", &lookup)); |
+ if (!lookup.IsFound()) { |
+ // Get the derived `get' property. |
+ Object* derived = isolate->global_context()->builtins()->javascript_builtin( |
+ Builtins::DERIVED_GET_TRAP); |
+ trap = Handle<JSFunction>(JSFunction::cast(derived)); |
+ } |
+ |
+ // Call trap function. |
+ Object** args[] = { receiver.location(), 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; |
+} |
+ |
+ |
MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver, |
JSFunction* getter) { |
HandleScope scope; |
@@ -497,26 +527,29 @@ MaybeObject* Object::GetProperty(Object* receiver, |
// holder will always be the interceptor holder and the search may |
// only continue with a current object just after the interceptor |
// holder in the prototype chain. |
- Object* last = result->IsProperty() ? result->holder() : heap->null_value(); |
- ASSERT(this != this->GetPrototype()); |
- for (Object* current = this; true; current = current->GetPrototype()) { |
- if (current->IsAccessCheckNeeded()) { |
- // Check if we're allowed to read from the current object. Note |
- // that even though we may not actually end up loading the named |
- // property from the current object, we still check that we have |
- // access to it. |
- JSObject* checked = JSObject::cast(current); |
- if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) { |
- return checked->GetPropertyWithFailedAccessCheck(receiver, |
- result, |
- name, |
- attributes); |
- } |
- } |
- // Stop traversing the chain once we reach the last object in the |
- // chain; either the holder of the result or null in case of an |
- // absent property. |
- if (current == last) break; |
+ // Proxy handlers do not use the proxy's prototype, so we can skip this. |
+ if (!result->IsHandler()) { |
+ Object* last = result->IsProperty() ? result->holder() : heap->null_value(); |
+ ASSERT(this != this->GetPrototype()); |
+ for (Object* current = this; true; current = current->GetPrototype()) { |
+ if (current->IsAccessCheckNeeded()) { |
+ // Check if we're allowed to read from the current object. Note |
+ // that even though we may not actually end up loading the named |
+ // property from the current object, we still check that we have |
+ // access to it. |
+ JSObject* checked = JSObject::cast(current); |
+ if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) { |
+ return checked->GetPropertyWithFailedAccessCheck(receiver, |
+ result, |
+ name, |
+ attributes); |
+ } |
+ } |
+ // Stop traversing the chain once we reach the last object in the |
+ // chain; either the holder of the result or null in case of an |
+ // absent property. |
+ if (current == last) break; |
+ } |
} |
if (!result->IsProperty()) { |
@@ -542,14 +575,22 @@ MaybeObject* Object::GetProperty(Object* receiver, |
result->GetCallbackObject(), |
name, |
holder); |
+ case HANDLER: { |
+ JSProxy* proxy = JSProxy::cast(this); |
+ return GetPropertyWithHandler(receiver, name, proxy->handler()); |
+ } |
case INTERCEPTOR: { |
JSObject* recvr = JSObject::cast(receiver); |
return holder->GetPropertyWithInterceptor(recvr, name, attributes); |
} |
- default: |
- UNREACHABLE(); |
- return NULL; |
+ case MAP_TRANSITION: |
+ case EXTERNAL_ARRAY_TRANSITION: |
+ case CONSTANT_TRANSITION: |
+ case NULL_DESCRIPTOR: |
+ break; |
} |
+ UNREACHABLE(); |
+ return NULL; |
} |
@@ -6550,6 +6591,7 @@ const char* Code::PropertyType2String(PropertyType type) { |
case FIELD: return "FIELD"; |
case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION"; |
case CALLBACKS: return "CALLBACKS"; |
+ case HANDLER: return "HANDLER"; |
case INTERCEPTOR: return "INTERCEPTOR"; |
case MAP_TRANSITION: return "MAP_TRANSITION"; |
case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION"; |