Chromium Code Reviews| Index: src/objects.cc |
| diff --git a/src/objects.cc b/src/objects.cc |
| index 724a734a2145d6b682725a6b9b7e9d5b7c2f26af..cde727df9d7009de7efadb214c66f48cb663c1eb 100644 |
| --- a/src/objects.cc |
| +++ b/src/objects.cc |
| @@ -134,24 +134,22 @@ Object* Object::ToBoolean() { |
| void Object::Lookup(String* name, LookupResult* result) { |
| Object* holder = NULL; |
| if (IsSmi()) { |
| - Heap* heap = Isolate::Current()->heap(); |
| - Context* global_context = heap->isolate()->context()->global_context(); |
| + Context* global_context = Isolate::Current()->context()->global_context(); |
| holder = global_context->number_function()->instance_prototype(); |
| } else { |
| HeapObject* heap_object = HeapObject::cast(this); |
| if (heap_object->IsJSObject()) { |
| return JSObject::cast(this)->Lookup(name, result); |
| } |
| - Heap* heap = heap_object->GetHeap(); |
| + Context* global_context = Isolate::Current()->context()->global_context(); |
| if (heap_object->IsString()) { |
| - Context* global_context = heap->isolate()->context()->global_context(); |
| holder = global_context->string_function()->instance_prototype(); |
| } else if (heap_object->IsHeapNumber()) { |
| - Context* global_context = heap->isolate()->context()->global_context(); |
| holder = global_context->number_function()->instance_prototype(); |
| } else if (heap_object->IsBoolean()) { |
| - Context* global_context = heap->isolate()->context()->global_context(); |
| holder = global_context->boolean_function()->instance_prototype(); |
| + } else if (heap_object->IsJSProxy()) { |
| + return result->HandlerResult(); |
| } |
| } |
| ASSERT(holder != NULL); // Cannot handle null or undefined. |
| @@ -227,6 +225,46 @@ 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)); |
| +// Handle<String> method = isolate->factory()->LookupAsciiSymbol("get"); |
|
Kevin Millikin (Chromium)
2011/05/16 15:21:41
Is the commented-out code still needed?
rossberg
2011/05/16 15:54:37
Done.
|
| +// Handle<Object> args[] = { handler, method }; |
| +// Handle<Object> error = isolate->factory()->NewTypeError( |
| +// "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args))); |
| +// return isolate->Throw(*error); |
| + } |
| + |
| + // to install JS objects: |
| + // - add to builtins.h BUILTINS_LIST_JS |
| + // - implement builtin in runtime.js |
| + // - get it through isolate()->global_context()->builtins()->javascript_builtin(id) |
| + |
| + // 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; |
| @@ -494,30 +532,34 @@ MaybeObject* Object::GetProperty(Object* receiver, |
| Heap* heap = name->GetHeap(); |
| // Traverse the prototype chain from the current object (this) to |
| - // the holder and check for access rights. This avoid traversing the |
| + // the holder and check for access rights. This avoids traversing the |
| // objects more than once in case of interceptors, because the |
| // 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(); |
| - 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()) { |
| @@ -543,14 +585,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; |
| } |
| @@ -575,6 +625,8 @@ MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) { |
| holder = global_context->number_function()->instance_prototype(); |
| } else if (heap_object->IsBoolean()) { |
| holder = global_context->boolean_function()->instance_prototype(); |
| + } else if (heap_object->IsJSProxy()) { |
| + return heap->undefined_value(); // For now... |
| } else { |
| // Undefined and null have no indexed properties. |
| ASSERT(heap_object->IsUndefined() || heap_object->IsNull()); |
| @@ -595,9 +647,10 @@ Object* Object::GetPrototype() { |
| HeapObject* heap_object = HeapObject::cast(this); |
| - // The object is either a number, a string, a boolean, or a real JS object. |
| - if (heap_object->IsJSObject()) { |
| - return JSObject::cast(this)->map()->prototype(); |
| + // The object is either a number, a string, a boolean, |
| + // a real JS object, or a Harmony proxy. |
| + if (heap_object->IsJSObject() || heap_object->IsJSProxy()) { |
| + return heap_object->map()->prototype(); |
| } |
| Heap* heap = heap_object->GetHeap(); |
| Context* context = heap->isolate()->context()->global_context(); |
| @@ -1154,6 +1207,9 @@ void HeapObject::IterateBody(InstanceType type, int object_size, |
| case ODDBALL_TYPE: |
| Oddball::BodyDescriptor::IterateBody(this, v); |
| break; |
| + case JS_PROXY_TYPE: |
| + JSProxy::BodyDescriptor::IterateBody(this, v); |
| + break; |
| case PROXY_TYPE: |
| reinterpret_cast<Proxy*>(this)->ProxyIterateBody(v); |
| break; |
| @@ -6544,6 +6600,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"; |