Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 70cbc484136ad4af6439e2825831ce6574110b67..fc3c6fee4c8df71d7f13e739a54cdfba99c571f7 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -845,15 +845,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 +868,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 +882,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 +909,67 @@ 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<JSReceiver> handle; |
+ Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string(); |
+ // 1. Assert: Either Type(V) is Object or Type(V) is Null. |
+ DCHECK(value->IsSpecObject() || value->IsNull()); |
+ // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. |
+ Handle<Object> raw_handler(proxy->handler(), isolate); |
+ // 3. If handler is null, throw a TypeError exception. |
+ // 4. Assert: Type(handler) is Object. |
+ if (!raw_handler->IsSpecObject()) { |
+ DCHECK(raw_handler->IsNull()); |
+ DCHECK(proxy->target()->IsNull()); |
+ isolate->Throw(*isolate->factory()->NewTypeError( |
+ MessageTemplate::kProxyHandlerNonObject)); |
+ return Nothing<bool>(); |
+ } |
+ Handle<JSReceiver> handler = Handle<JSReceiver>::cast(raw_handler); |
+ // 5. Let target be the value of the [[ProxyTarget]] internal slot. |
+ Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); |
+ // 6. Let trap be ? GetMethod(handler, "getPrototypeOf"). |
+ Handle<Object> trap; |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
+ isolate, trap, Object::GetMethod(handler, trap_name), 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>()); |
+ bool bool_trap_result = 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 Just(bool_trap_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, |
+ // throw a TypeError exception. |
+ if (bool_trap_result && !value->SameValue(*target_proto)) { |
+ isolate->Throw(*isolate->factory()->NewTypeError( |
+ MessageTemplate::kObjectSetPrototypeNotExtensible)); |
+ } |
+ // 13. Return booleanTrapResult. |
+ return Just(bool_trap_result); |
+} |
+ |
MaybeHandle<Object> JSProxy::GetPropertyWithHandler(Handle<JSProxy> proxy, |
Handle<Object> receiver, |
Handle<Name> name) { |
@@ -13955,8 +14020,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); |
neis
2015/11/16 19:09:53
What's the motivation for this?
|
+ 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); |
} |