Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(801)

Unified Diff: src/objects.cc

Issue 7795055: Make integer indexed properties ("elements") work for proxies. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Oops. Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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,
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698