Chromium Code Reviews| 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); |
| } |