| Index: src/objects.cc
|
| ===================================================================
|
| --- src/objects.cc (revision 7948)
|
| +++ src/objects.cc (working copy)
|
| @@ -135,24 +135,22 @@
|
| 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.
|
| @@ -228,6 +226,34 @@
|
| }
|
|
|
|
|
| +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.
|
| + trap = isolate->derived_get_trap();
|
| + }
|
| +
|
| + // 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;
|
| @@ -495,30 +521,34 @@
|
| 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);
|
| + // 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;
|
| }
|
| - // 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()) {
|
| @@ -544,14 +574,22 @@
|
| 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;
|
| }
|
|
|
|
|
| @@ -576,6 +614,8 @@
|
| 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());
|
| @@ -596,9 +636,10 @@
|
|
|
| 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();
|
| @@ -1158,6 +1199,9 @@
|
| 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;
|
| @@ -2586,6 +2630,7 @@
|
| case CONSTANT_TRANSITION:
|
| case NULL_DESCRIPTOR:
|
| case INTERCEPTOR:
|
| + case EXTERNAL_ARRAY_TRANSITION:
|
| break;
|
| default:
|
| UNREACHABLE();
|
| @@ -2872,8 +2917,9 @@
|
| // exception. dictionary->DeleteProperty will return false_value()
|
| // if a non-configurable property is being deleted.
|
| HandleScope scope;
|
| + Handle<Object> self(this);
|
| Handle<Object> i = isolate->factory()->NewNumberFromUint(index);
|
| - Handle<Object> args[2] = { i, Handle<Object>(this) };
|
| + Handle<Object> args[2] = { i, self };
|
| return isolate->Throw(*isolate->factory()->NewTypeError(
|
| "strict_delete_property", HandleVector(args, 2)));
|
| }
|
| @@ -3768,8 +3814,6 @@
|
|
|
|
|
| MaybeObject* CodeCache::Update(String* name, Code* code) {
|
| - ASSERT(code->ic_state() == MONOMORPHIC);
|
| -
|
| // The number of monomorphic stubs for normal load/store/call IC's can grow to
|
| // a large number and therefore they need to go into a hash table. They are
|
| // used to load global properties from cells.
|
| @@ -4962,8 +5006,7 @@
|
|
|
|
|
| // Archive statics that are thread local.
|
| -char* Relocatable::ArchiveState(char* to) {
|
| - Isolate* isolate = Isolate::Current();
|
| +char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
|
| *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
|
| isolate->set_relocatable_top(NULL);
|
| return to + ArchiveSpacePerThread();
|
| @@ -4971,8 +5014,7 @@
|
|
|
|
|
| // Restore statics that are thread local.
|
| -char* Relocatable::RestoreState(char* from) {
|
| - Isolate* isolate = Isolate::Current();
|
| +char* Relocatable::RestoreState(Isolate* isolate, char* from) {
|
| isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
|
| return from + ArchiveSpacePerThread();
|
| }
|
| @@ -6516,10 +6558,8 @@
|
| case BUILTIN: return "BUILTIN";
|
| case LOAD_IC: return "LOAD_IC";
|
| case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
|
| - case KEYED_EXTERNAL_ARRAY_LOAD_IC: return "KEYED_EXTERNAL_ARRAY_LOAD_IC";
|
| case STORE_IC: return "STORE_IC";
|
| case KEYED_STORE_IC: return "KEYED_STORE_IC";
|
| - case KEYED_EXTERNAL_ARRAY_STORE_IC: return "KEYED_EXTERNAL_ARRAY_STORE_IC";
|
| case CALL_IC: return "CALL_IC";
|
| case KEYED_CALL_IC: return "KEYED_CALL_IC";
|
| case TYPE_RECORDING_UNARY_OP_IC: return "TYPE_RECORDING_UNARY_OP_IC";
|
| @@ -6552,6 +6592,7 @@
|
| 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";
|
| @@ -7295,7 +7336,7 @@
|
|
|
| // api style callbacks.
|
| if (structure->IsAccessorInfo()) {
|
| - AccessorInfo* data = AccessorInfo::cast(structure);
|
| + Handle<AccessorInfo> data(AccessorInfo::cast(structure));
|
| Object* fun_obj = data->getter();
|
| v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
|
| HandleScope scope(isolate);
|
| @@ -7352,14 +7393,16 @@
|
|
|
| if (structure->IsAccessorInfo()) {
|
| // api style callbacks
|
| - AccessorInfo* data = AccessorInfo::cast(structure);
|
| + Handle<JSObject> self(this);
|
| + Handle<JSObject> holder_handle(JSObject::cast(holder));
|
| + Handle<AccessorInfo> data(AccessorInfo::cast(structure));
|
| Object* call_obj = data->setter();
|
| v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
|
| if (call_fun == NULL) return value;
|
| Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
|
| Handle<String> key(isolate->factory()->NumberToString(number));
|
| - LOG(isolate, ApiNamedPropertyAccess("store", this, *key));
|
| - CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
|
| + LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
|
| + CustomArguments args(isolate, data->data(), *self, *holder_handle);
|
| v8::AccessorInfo info(args.end());
|
| {
|
| // Leaving JavaScript.
|
| @@ -7561,8 +7604,8 @@
|
| // If put fails instrict mode, throw exception.
|
| if (!dictionary->ValueAtPut(entry, value) &&
|
| strict_mode == kStrictMode) {
|
| + Handle<Object> holder(this);
|
| Handle<Object> number(isolate->factory()->NewNumberFromUint(index));
|
| - Handle<Object> holder(this);
|
| Handle<Object> args[2] = { number, holder };
|
| return isolate->Throw(
|
| *isolate->factory()->NewTypeError("strict_read_only_property",
|
|
|