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

Unified Diff: src/objects.cc

Issue 1439693002: [runtime] Support Proxy setPrototypeOf trap (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@2015-11-09_new_Proxy_1417063011
Patch Set: more tests Created 5 years, 1 month 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/runtime/runtime-object.cc » ('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 70cbc484136ad4af6439e2825831ce6574110b67..4fa818122fa957bd20fa63cb740aa66633bc39b3 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -624,19 +624,26 @@ bool Object::IsPromise(Handle<Object> object) {
// static
MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
- Handle<Name> name) {
+ Handle<Name> name,
+ ShouldThrow should_throw) {
Handle<Object> func;
Isolate* isolate = receiver->GetIsolate();
- ASSIGN_RETURN_ON_EXCEPTION(isolate, func,
- JSReceiver::GetProperty(receiver, name), Object);
+ // TODO(cbruni,neis): Propagage should_throw here.
Toon Verwaest 2015/11/13 17:28:21 Propagate
+ if (!JSReceiver::GetProperty(receiver, name).ToHandle(&func)) {
+ return MaybeHandle<Object>();
+ }
if (func->IsNull() || func->IsUndefined()) {
return isolate->factory()->undefined_value();
}
if (!func->IsCallable()) {
// TODO(bmeurer): Better error message here?
Toon Verwaest 2015/11/13 17:28:21 The spec says you actually have to throw a TypeErr
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kCalledNonCallable, func),
- Object);
+ if (should_throw == Object::THROW_ON_ERROR) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kCalledNonCallable, func),
+ Object);
+ } else {
+ return MaybeHandle<Object>();
+ }
}
return func;
}
@@ -845,15 +852,20 @@ Handle<FixedArray> JSObject::EnsureWritableFastElements(
}
-// ES6 9.5.1
+// ES6: Section 9.5.1 [[GetPrototypeOf]] ( )
// static
MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
Isolate* isolate = proxy->GetIsolate();
+ Handle<Object> trap;
+ Handle<JSReceiver> handle;
+ Handle<Name> trap_name = isolate->factory()->getPrototypeOf_string();
// 1. Let handler be the value of the [[ProxyHandler]] internal slot.
Handle<Object> raw_handler(proxy->handler(), isolate);
// 2. If handler is null, throw a TypeError exception.
// 3. Assert: Type(handler) is Object.
if (!raw_handler->IsSpecObject()) {
+ DCHECK(raw_handler->IsNull());
+ DCHECK(proxy->target()->IsNull());
// TODO(cbruni): Throw correct error message.
THROW_NEW_ERROR(
isolate, NewTypeError(MessageTemplate::kProxyHandlerNonObject), Object);
@@ -863,8 +875,6 @@ MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
// TODO(cbruni): Change target type to JSReceiver by default.
Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
// 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
- Handle<Object> trap;
- Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name),
Object);
// 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
@@ -879,6 +889,7 @@ MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object);
// 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError.
if (!(handler_proto->IsSpecObject() || handler_proto->IsNull())) {
+ // TODO(cbruni): throw correct error message
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kProxyHandlerTrapMissing,
handler, trap_name),
@@ -905,6 +916,74 @@ MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
}
+// ES6: 9.5.2 [[SetPrototypeOf]] (V)
+// static
+Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
+ bool from_javascript,
+ Object::ShouldThrow should_throw) {
+ Isolate* isolate = proxy->GetIsolate();
+ Handle<Object> trap;
+ Handle<JSReceiver> handle;
+ Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
+ // 1. Assert: Either Type(V) is Object or Type(V) is Null.
+ if (!(value->IsSpecObject() || value->IsNull())) {
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kProtoObjectOrNull, value));
+ }
+ Handle<Object> raw_handler(proxy->handler(), isolate);
+ // 2. If handler is null, throw a TypeError exception.
+ // 3. Assert: Type(handler) is Object.
+ if (!raw_handler->IsSpecObject()) {
+ DCHECK(raw_handler->IsNull());
+ DCHECK(proxy->target()->IsNull());
+ // TODO(cbruni): use proper error message here.
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kProxyHandlerNonObject));
+ }
+ Handle<JSReceiver> handler = Handle<JSReceiver>::cast(raw_handler);
+ // 4. Let target be the value of the [[ProxyTarget]] internal slot.
+ Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
+ // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
+ if (!Object::GetMethod(handler, trap_name, should_throw).ToHandle(&trap)) {
+ if (should_throw == Object::DONT_THROW) {
+ return Just(false);
+ } else {
+ return Nothing<bool>();
+ }
+ }
+ // 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
+ if (trap->IsUndefined()) {
+ return JSReceiver::SetPrototype(target, value, from_javascript,
+ should_throw);
+ }
+ // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)).
+ Handle<Object> argv[] = {target, value};
+ Handle<Object> trap_result;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, trap_result,
+ Execution::Call(isolate, trap, handler, arraysize(argv), argv),
+ Nothing<bool>());
+ Maybe<bool> result = Just(trap_result->BooleanValue());
+ // 9. Let extensibleTarget be ? IsExtensible(target).
+ Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
+ if (is_extensible.IsNothing()) return Nothing<bool>();
+ // 10. If extensibleTarget is true, return booleanTrapResult.
+ if (is_extensible.FromJust()) return result;
+ // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
+ Handle<Object> target_proto;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
+ Object::GetPrototype(isolate, target),
+ Nothing<bool>());
+ // 12. If booleanTrapResult is true and SameValue(V, targetProto) is false,
+ if (result.FromJust() && !value->SameValue(*target_proto)) {
+ RETURN_FAILURE(
+ isolate, should_throw,
+ NewTypeError(MessageTemplate::kObjectSetPrototypeNotExtensible));
+ }
+ // 13. Return booleanTrapResult.
+ return result;
+}
+
MaybeHandle<Object> JSProxy::GetPropertyWithHandler(Handle<JSProxy> proxy,
Handle<Object> receiver,
Handle<Name> name) {
@@ -13955,8 +14034,11 @@ Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object,
Handle<Object> value, bool from_javascript,
ShouldThrow should_throw) {
- if (!object->IsJSObject()) return Just(false);
- // TODO(neis): Deal with proxies.
+ if (!object->IsJSReceiver()) return Just(false);
+ if (object->IsJSProxy()) {
+ return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value,
+ from_javascript, should_throw);
+ }
return JSObject::SetPrototype(Handle<JSObject>::cast(object), value,
from_javascript, should_throw);
}
« no previous file with comments | « src/objects.h ('k') | src/runtime/runtime-object.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698