// Copyright 2019 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include 'src/builtins/builtins-proxy-gen.h' namespace proxy { extern transitioning runtime SetPropertyWithReceiver(implicit context: Context)( Object, Name, Object, Object): void; transitioning macro CallThrowTypeErrorIfStrict(implicit context: Context)( message: constexpr MessageTemplate): void { ThrowTypeErrorIfStrict(SmiConstant(message), Null, Null); } // ES #sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver // https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver transitioning builtin ProxySetProperty(implicit context: Context)( proxy: JSProxy, name: PropertyKey|PrivateSymbol, value: JSAny, receiverValue: JSAny): JSAny { // 1. Assert: IsPropertyKey(P) is true. dcheck(TaggedIsNotSmi(name)); dcheck(Is(name)); let key: PropertyKey; typeswitch (name) { case (PrivateSymbol): { CallThrowTypeErrorIfStrict(MessageTemplate::kProxyPrivate); return Undefined; } case (name: PropertyKey): { key = name; } } try { // 2. Let handler be O.[[ProxyHandler]]. // 3. If handler is null, throw a TypeError exception. // 4. Assert: Type(handler) is Object. dcheck(proxy.handler == Null || Is(proxy.handler)); const handler = Cast(proxy.handler) otherwise ThrowProxyHandlerRevoked; // 5. Let target be O.[[ProxyTarget]]. const target = UnsafeCast(proxy.target); // 6. Let trap be ? GetMethod(handler, "set"). // 7. If trap is undefined, then (see 7.a below). const trap: Callable = GetMethod(handler, 'set') otherwise goto TrapUndefined(target); // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, // « target, P, V, Receiver »)). // 9. If booleanTrapResult is false, return false. // 10. Let targetDesc be ? target.[[GetOwnProperty]](P). // 11. If targetDesc is not undefined and targetDesc.[[Configurable]] is // false, then // a. If IsDataDescriptor(targetDesc) is true and // targetDesc.[[Writable]] is false, then // i. If SameValue(V, targetDesc.[[Value]]) is false, throw a // TypeError exception. // b. If IsAccessorDescriptor(targetDesc) is true, then // i. If targetDesc.[[Set]] is undefined, throw a TypeError // exception. // 12. Return true. const trapResult = Call(context, trap, handler, target, key, value, receiverValue); if (ToBoolean(trapResult)) { CheckGetSetTrapResult(target, proxy, name, value, kProxySet); return value; } ThrowTypeErrorIfStrict( SmiConstant(MessageTemplate::kProxyTrapReturnedFalsishFor), 'set', name); return value; } label TrapUndefined(target: Object) { // 7.a. Return ? target.[[Set]](P, V, Receiver). SetPropertyWithReceiver(target, name, value, receiverValue); return value; } label ThrowProxyHandlerRevoked deferred { ThrowTypeError(MessageTemplate::kProxyRevoked, 'set'); } } }