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, |