1// Copyright 2019 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include 'src/builtins/builtins-proxy-gen.h'
6
7namespace proxy {
8
9// ES #sec-proxy-object-internal-methods-and-internal-slots-preventextensions
10// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-preventextensions
11transitioning builtin
12ProxyPreventExtensions(implicit context: Context)(
13    proxy: JSProxy, doThrow: Boolean): JSAny {
14  PerformStackCheck();
15  const kTrapName: constexpr string = 'preventExtensions';
16  try {
17    // 1. Let handler be O.[[ProxyHandler]].
18    // 2. If handler is null, throw a TypeError exception.
19    // 3. Assert: Type(handler) is Object.
20    dcheck(proxy.handler == Null || Is<JSReceiver>(proxy.handler));
21    const handler =
22        Cast<JSReceiver>(proxy.handler) otherwise ThrowProxyHandlerRevoked;
23
24    // 4. Let target be O.[[ProxyTarget]].
25    const target = proxy.target;
26
27    // 5. Let trap be ? GetMethod(handler, "preventExtensions").
28    // 6. If trap is undefined, then (see 6.a below).
29    const trap: Callable = GetMethod(handler, kTrapName)
30        otherwise goto TrapUndefined(target);
31
32    // 7. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «
33    // target»)).
34    const trapResult = Call(context, trap, handler, target);
35
36    // 8. If booleanTrapResult is true, then
37    //    8.a. Let extensibleTarget be ? IsExtensible(target).
38    //    8.b If extensibleTarget is true, throw a TypeError exception.
39    if (ToBoolean(trapResult)) {
40      const extensibleTarget: JSAny = object::ObjectIsExtensibleImpl(target);
41      dcheck(extensibleTarget == True || extensibleTarget == False);
42      if (extensibleTarget == True) {
43        ThrowTypeError(MessageTemplate::kProxyPreventExtensionsExtensible);
44      }
45    } else {
46      if (doThrow == True) {
47        ThrowTypeError(MessageTemplate::kProxyTrapReturnedFalsish, kTrapName);
48      }
49      return False;
50    }
51
52    // 9. Return booleanTrapResult.
53    return True;
54  } label TrapUndefined(target: JSAny) {
55    // 6.a. Return ? target.[[PreventExtensions]]().
56    if (doThrow == True) {
57      return object::ObjectPreventExtensionsThrow(target);
58    }
59    return object::ObjectPreventExtensionsDontThrow(target);
60  } label ThrowProxyHandlerRevoked deferred {
61    ThrowTypeError(MessageTemplate::kProxyRevoked, kTrapName);
62  }
63}
64}  // namespace proxy
65