| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 609f66ae1d5291f3bccb020428497467aa21bca9..1cff8601ff0d573d68b8fd00578f5bb677eb2320 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -234,17 +234,31 @@ MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw,
|
|
|
| MaybeObject* JSProxy::GetElementWithHandler(Object* receiver,
|
| uint32_t index) {
|
| - Heap* heap = GetHeap();
|
| - Object* number;
|
| - MaybeObject* maybe = heap->NumberFromUint32(index);
|
| - if (!maybe->To<Object>(&number)) return maybe;
|
| - maybe = heap->NumberToString(number);
|
| String* name;
|
| + MaybeObject* maybe = GetHeap()->Uint32ToString(index);
|
| if (!maybe->To<String>(&name)) return maybe;
|
| return GetPropertyWithHandler(receiver, name);
|
| }
|
|
|
|
|
| +MaybeObject* JSProxy::SetElementWithHandler(uint32_t index,
|
| + Object* value,
|
| + StrictModeFlag strict_mode) {
|
| + String* name;
|
| + MaybeObject* maybe = GetHeap()->Uint32ToString(index);
|
| + if (!maybe->To<String>(&name)) return maybe;
|
| + return SetPropertyWithHandler(name, value, NONE, strict_mode);
|
| +}
|
| +
|
| +
|
| +bool JSProxy::HasElementWithHandler(uint32_t index) {
|
| + String* name;
|
| + MaybeObject* maybe = GetHeap()->Uint32ToString(index);
|
| + if (!maybe->To<String>(&name)) return maybe;
|
| + return HasPropertyWithHandler(name);
|
| +}
|
| +
|
| +
|
| MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
|
| JSFunction* getter) {
|
| HandleScope scope;
|
| @@ -1926,6 +1940,16 @@ MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
|
| for (Object* pt = GetPrototype();
|
| pt != heap->null_value();
|
| pt = pt->GetPrototype()) {
|
| + if (pt->IsJSProxy()) {
|
| + String* name;
|
| + MaybeObject* maybe = GetHeap()->Uint32ToString(index);
|
| + if (!maybe->To<String>(&name)) {
|
| + *found = true; // Force abort
|
| + return maybe;
|
| + }
|
| + return JSProxy::cast(pt)->SetPropertyWithHandlerIfDefiningSetter(
|
| + name, value, NONE, strict_mode, found);
|
| + }
|
| if (!JSObject::cast(pt)->HasDictionaryElements()) {
|
| continue;
|
| }
|
| @@ -2261,6 +2285,76 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
|
| }
|
|
|
|
|
| +MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
|
| + String* name_raw,
|
| + Object* value_raw,
|
| + PropertyAttributes attributes,
|
| + StrictModeFlag strict_mode,
|
| + bool* found) {
|
| + *found = true; // except where defined otherwise...
|
| + Isolate* isolate = GetHeap()->isolate();
|
| + Handle<JSProxy> proxy(this);
|
| + Handle<String> name(name_raw);
|
| + Handle<Object> value(value_raw);
|
| + Handle<Object> args[] = { name };
|
| + Handle<Object> result = proxy->CallTrap(
|
| + "getOwnPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
|
| + if (isolate->has_pending_exception()) return Failure::Exception();
|
| +
|
| + if (!result->IsUndefined()) {
|
| + // The proxy handler cares about this property.
|
| + // Check whether it is virtualized as an accessor.
|
| + // Emulate [[GetProperty]] semantics for proxies.
|
| + bool has_pending_exception;
|
| + Object** argv[] = { result.location() };
|
| + Handle<Object> desc =
|
| + Execution::Call(isolate->to_complete_property_descriptor(), result,
|
| + ARRAY_SIZE(argv), argv, &has_pending_exception);
|
| + if (has_pending_exception) return Failure::Exception();
|
| +
|
| + Handle<String> conf_name =
|
| + isolate->factory()->LookupAsciiSymbol("configurable_");
|
| + Handle<Object> configurable(v8::internal::GetProperty(desc, conf_name));
|
| + ASSERT(!isolate->has_pending_exception());
|
| + if (configurable->IsFalse()) {
|
| + Handle<Object> args[] = { Handle<Object>(proxy->handler()), proxy, name };
|
| + Handle<Object> error = isolate->factory()->NewTypeError(
|
| + "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
|
| + return isolate->Throw(*error);
|
| + }
|
| + ASSERT(configurable->IsTrue());
|
| +
|
| + // Check for AccessorDescriptor.
|
| + Handle<String> set_name = isolate->factory()->LookupAsciiSymbol("set_");
|
| + Handle<Object> setter(v8::internal::GetProperty(desc, set_name));
|
| + ASSERT(!isolate->has_pending_exception());
|
| + if (!setter->IsUndefined()) {
|
| + // We have a setter -- invoke it.
|
| + return proxy->SetPropertyWithDefinedSetter(
|
| + JSFunction::cast(*setter), *value);
|
| + } else {
|
| + Handle<String> get_name = isolate->factory()->LookupAsciiSymbol("get_");
|
| + Handle<Object> getter(v8::internal::GetProperty(desc, get_name));
|
| + ASSERT(!isolate->has_pending_exception());
|
| + if (!getter->IsUndefined()) {
|
| + // We have a getter but no setter -- the property may not be
|
| + // written. In strict mode, throw an error.
|
| + if (strict_mode == kNonStrictMode) return *value;
|
| + Handle<Object> args[] = { name, proxy };
|
| + Handle<Object> error = isolate->factory()->NewTypeError(
|
| + "no_setter_in_callback", HandleVector(args, ARRAY_SIZE(args)));
|
| + return isolate->Throw(*error);
|
| + }
|
| + }
|
| + // Fall-through.
|
| + }
|
| +
|
| + // The proxy does not define the property as an accessor.
|
| + *found = false;
|
| + return *value;
|
| +}
|
| +
|
| +
|
| MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
|
| String* name_raw, DeleteMode mode) {
|
| Isolate* isolate = GetIsolate();
|
| @@ -2286,11 +2380,22 @@ MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
|
| }
|
|
|
|
|
| +MUST_USE_RESULT MaybeObject* JSProxy::DeleteElementWithHandler(
|
| + uint32_t index,
|
| + DeleteMode mode) {
|
| + Isolate* isolate = GetIsolate();
|
| + HandleScope scope(isolate);
|
| + Handle<String> name = isolate->factory()->Uint32ToString(index);
|
| + return JSProxy::DeletePropertyWithHandler(*name, mode);
|
| +}
|
| +
|
| +
|
| MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
|
| JSReceiver* receiver_raw,
|
| String* name_raw) {
|
| Isolate* isolate = GetIsolate();
|
| HandleScope scope(isolate);
|
| + Handle<JSProxy> proxy(this);
|
| Handle<JSReceiver> receiver(receiver_raw);
|
| Handle<Object> name(name_raw);
|
|
|
| @@ -2309,16 +2414,26 @@ MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
|
| if (has_pending_exception) return NONE;
|
|
|
| // Convert result to PropertyAttributes.
|
| - Handle<String> enum_name = isolate->factory()->LookupAsciiSymbol("enumerable");
|
| + Handle<String> enum_name =
|
| + isolate->factory()->LookupAsciiSymbol("enumerable_");
|
| Handle<Object> enumerable(v8::internal::GetProperty(desc, enum_name));
|
| if (isolate->has_pending_exception()) return NONE;
|
| - Handle<String> conf_name = isolate->factory()->LookupAsciiSymbol("configurable");
|
| + Handle<String> conf_name =
|
| + isolate->factory()->LookupAsciiSymbol("configurable_");
|
| Handle<Object> configurable(v8::internal::GetProperty(desc, conf_name));
|
| if (isolate->has_pending_exception()) return NONE;
|
| - Handle<String> writ_name = isolate->factory()->LookupAsciiSymbol("writable");
|
| + Handle<String> writ_name = isolate->factory()->LookupAsciiSymbol("writable_");
|
| Handle<Object> writable(v8::internal::GetProperty(desc, writ_name));
|
| if (isolate->has_pending_exception()) return NONE;
|
|
|
| + if (configurable->IsFalse()) {
|
| + Handle<Object> args[] = { Handle<Object>(proxy->handler()), proxy, name };
|
| + Handle<Object> error = isolate->factory()->NewTypeError(
|
| + "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
|
| + isolate->Throw(*error);
|
| + return NONE;
|
| + }
|
| +
|
| int attributes = NONE;
|
| if (enumerable->ToBoolean()->IsFalse()) attributes |= DONT_ENUM;
|
| if (configurable->ToBoolean()->IsFalse()) attributes |= DONT_DELETE;
|
| @@ -2327,6 +2442,16 @@ MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
|
| }
|
|
|
|
|
| +MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler(
|
| + JSReceiver* receiver,
|
| + uint32_t index) {
|
| + Isolate* isolate = GetIsolate();
|
| + HandleScope scope(isolate);
|
| + Handle<String> name = isolate->factory()->Uint32ToString(index);
|
| + return GetPropertyAttributeWithHandler(receiver, *name);
|
| +}
|
| +
|
| +
|
| void JSProxy::Fix() {
|
| Isolate* isolate = GetIsolate();
|
| HandleScope scope(isolate);
|
| @@ -2355,7 +2480,7 @@ MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(
|
| if (isolate->has_pending_exception()) return trap;
|
|
|
| if (trap->IsUndefined()) {
|
| - if (*derived == NULL) {
|
| + if (derived.is_null()) {
|
| Handle<Object> args[] = { handler, trap_name };
|
| Handle<Object> error = isolate->factory()->NewTypeError(
|
| "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
|
| @@ -2424,53 +2549,17 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
|
| } else if (accessor_result.type() == HANDLER) {
|
| // There is a proxy in the prototype chain. Invoke its
|
| // getOwnPropertyDescriptor trap.
|
| - Isolate* isolate = heap->isolate();
|
| + bool found = false;
|
| Handle<JSObject> self(this);
|
| Handle<String> hname(name);
|
| Handle<Object> hvalue(value);
|
| - Handle<JSProxy> proxy(accessor_result.proxy());
|
| - Handle<Object> args[] = { hname };
|
| - Handle<Object> result = proxy->CallTrap(
|
| - "getOwnPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
|
| - if (isolate->has_pending_exception()) return Failure::Exception();
|
| -
|
| - if (!result->IsUndefined()) {
|
| - // The proxy handler cares about this property.
|
| - // Check whether it is virtualized as an accessor.
|
| - Handle<String> getter_name =
|
| - isolate->factory()->LookupAsciiSymbol("get");
|
| - Handle<Object> getter(
|
| - v8::internal::GetProperty(result, getter_name));
|
| - if (isolate->has_pending_exception()) return Failure::Exception();
|
| - Handle<String> setter_name =
|
| - isolate->factory()->LookupAsciiSymbol("set");
|
| - Handle<Object> setter(
|
| - v8::internal::GetProperty(result, setter_name));
|
| - if (isolate->has_pending_exception()) return Failure::Exception();
|
| -
|
| - if (!setter->IsUndefined()) {
|
| - // We have a setter -- invoke it.
|
| - if (setter->IsJSFunction()) {
|
| - return proxy->SetPropertyWithDefinedSetter(
|
| - JSFunction::cast(*setter), *hvalue);
|
| - }
|
| - Handle<Object> args[] = { setter };
|
| - Handle<Object> error = isolate->factory()->NewTypeError(
|
| - "setter_must_be_callable", HandleVector(args, ARRAY_SIZE(args)));
|
| - return isolate->Throw(*error);
|
| - } else if (!getter->IsUndefined()) {
|
| - // We have a getter but no setter -- the property may not be
|
| - // written. In strict mode, throw an error.
|
| - if (strict_mode == kNonStrictMode) return *hvalue;
|
| - Handle<Object> args[] = { hname, proxy };
|
| - Handle<Object> error = isolate->factory()->NewTypeError(
|
| - "no_setter_in_callback", HandleVector(args, ARRAY_SIZE(args)));
|
| - return isolate->Throw(*error);
|
| - }
|
| - // The proxy does not define the property as an accessor.
|
| - // Consequently, it has no effect on setting the receiver.
|
| - return self->AddProperty(*hname, *hvalue, attributes, strict_mode);
|
| - }
|
| + MaybeObject* result =
|
| + accessor_result.proxy()->SetPropertyWithHandlerIfDefiningSetter(
|
| + name, value, attributes, strict_mode, &found);
|
| + if (found) return result;
|
| + // The proxy does not define the property as an accessor.
|
| + // Consequently, it has no effect on setting the receiver.
|
| + return self->AddProperty(*hname, *hvalue, attributes, strict_mode);
|
| }
|
| }
|
| }
|
| @@ -2717,9 +2806,8 @@ PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
|
| String* key) {
|
| uint32_t index = 0;
|
| if (IsJSObject() && key->AsArrayIndex(&index)) {
|
| - if (JSObject::cast(this)->HasElementWithReceiver(receiver, index))
|
| - return NONE;
|
| - return ABSENT;
|
| + return JSObject::cast(this)->HasElementWithReceiver(receiver, index)
|
| + ? NONE : ABSENT;
|
| }
|
| // Named property.
|
| LookupResult result;
|
| @@ -3252,9 +3340,16 @@ MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
|
| MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
|
| if (IsJSProxy()) {
|
| return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
|
| - } else {
|
| - return JSObject::cast(this)->DeleteProperty(name, mode);
|
| }
|
| + return JSObject::cast(this)->DeleteProperty(name, mode);
|
| +}
|
| +
|
| +
|
| +MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) {
|
| + if (IsJSProxy()) {
|
| + return JSProxy::cast(this)->DeleteElementWithHandler(index, mode);
|
| + }
|
| + return JSObject::cast(this)->DeleteElement(index, mode);
|
| }
|
|
|
|
|
| @@ -7887,6 +7982,11 @@ bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
|
|
|
| Object* pt = GetPrototype();
|
| if (pt->IsNull()) return false;
|
| + if (pt->IsJSProxy()) {
|
| + // We need to follow the spec and simulate a call to [[GetOwnProperty]].
|
| + return JSProxy::cast(pt)->GetElementAttributeWithHandler(
|
| + receiver, index) != ABSENT;
|
| + }
|
| return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
|
| }
|
|
|
| @@ -8143,6 +8243,11 @@ bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
|
|
|
| Object* pt = GetPrototype();
|
| if (pt->IsNull()) return false;
|
| + if (pt->IsJSProxy()) {
|
| + // We need to follow the spec and simulate a call to [[GetOwnProperty]].
|
| + return JSProxy::cast(pt)->GetElementAttributeWithHandler(
|
| + receiver, index) != ABSENT;
|
| + }
|
| return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
|
| }
|
|
|
| @@ -8575,6 +8680,17 @@ MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
|
| }
|
|
|
|
|
| +MaybeObject* JSReceiver::SetElement(uint32_t index,
|
| + Object* value,
|
| + StrictModeFlag strict_mode,
|
| + bool check_proto) {
|
| + return IsJSProxy()
|
| + ? JSProxy::cast(this)->SetElementWithHandler(index, value, strict_mode)
|
| + : JSObject::cast(this)->SetElement(index, value, strict_mode, check_proto)
|
| + ;
|
| +}
|
| +
|
| +
|
| MaybeObject* JSObject::SetElement(uint32_t index,
|
| Object* value,
|
| StrictModeFlag strict_mode,
|
|
|