Coverage Report

Created: 2023-02-22 06:51

/src/hermes/lib/VM/JSLib/Proxy.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) Meta Platforms, Inc. and affiliates.
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7
8
//===----------------------------------------------------------------------===//
9
/// \file
10
/// ES9 26.2 Proxy Objects
11
//===----------------------------------------------------------------------===//
12
13
#include "JSLibInternal.h"
14
15
#include "hermes/VM/JSCallableProxy.h"
16
#include "hermes/VM/StackFrame-inline.h"
17
18
namespace hermes {
19
namespace vm {
20
21
namespace {
22
23
// Property storage slots.  This implementation for storing internal
24
// properties is not a great pattern, and may change.
25
enum ProxySlotIndexes { revocableProxy, COUNT };
26
27
SmallHermesValue getRevocableProxySlot(
28
    NativeFunction *revoker,
29
0
    Runtime &runtime) {
30
0
  return NativeFunction::getAdditionalSlotValue(
31
0
      revoker, runtime, ProxySlotIndexes::revocableProxy);
32
0
}
33
34
void setRevocableProxySlot(
35
    NativeFunction *revoker,
36
    Runtime &runtime,
37
0
    SmallHermesValue value) {
38
0
  NativeFunction::setAdditionalSlotValue(
39
0
      revoker, runtime, ProxySlotIndexes::revocableProxy, value);
40
0
}
41
42
// This is shared code between the proxy constructor and the native
43
// Proxy.revocable factory.
44
// \param proxy is the newly created but not yet initialized object
45
// used as the constructor's this.
46
CallResult<Handle<JSObject>> proxyCreate(
47
    Runtime &runtime,
48
    Handle<JSObject> target,
49
    Handle<JSObject> handler,
50
0
    Handle<JSObject> proxy) {
51
  // 1. If Type(target) is not Object, throw a TypeError exception.
52
0
  if (!target) {
53
0
    return runtime.raiseTypeError("new Proxy target must be an Object");
54
0
  }
55
  // 3. If Type(handler) is not Object, throw a TypeError exception.
56
0
  if (!handler) {
57
0
    return runtime.raiseTypeError("new Proxy handler must be an Object");
58
0
  }
59
  // 5. Let P be a newly created object.
60
  // 6. Set P’s essential internal methods (except for [[Call]] and
61
  // [[Construct]]) to the definitions specified in 9.5.
62
  // 7. If IsCallable(target) is true, then
63
0
  if (vmisa<Callable>(*target)) {
64
    //   a. Set P.[[Call]] as specified in 9.5.12.
65
    //   b. If IsConstructor(target) is true, then
66
    //     i. Set P.[[Construct]] as specified in 9.5.13.
67
    // We need to throw away the object passed as this, so we can create
68
    // a CallableProxy instead.  Simply being a CallableProxy has the
69
    // effect of setting the [[Call]] and [[Construct]] internal methods.
70
0
    proxy = runtime.makeHandle(JSCallableProxy::create(runtime));
71
0
  }
72
73
  // 8. Set the [[ProxyTarget]] internal slot of P to target.
74
  // 9. Set the [[ProxyHandler]] internal slot of P to handler.
75
76
0
  JSProxy::setTargetAndHandler(proxy, runtime, target, handler);
77
78
  // Return P.
79
0
  return proxy;
80
0
}
81
82
} // namespace
83
84
CallResult<HermesValue>
85
0
proxyConstructor(void *, Runtime &runtime, NativeArgs args) {
86
  // 1. If NewTarget is undefined, throw a TypeError exception.
87
0
  if (!args.isConstructorCall()) {
88
0
    return runtime.raiseTypeError(
89
0
        "Proxy() called in function context instead of constructor");
90
0
  }
91
  // 2. Return ? ProxyCreate(target, handler).
92
0
  auto proxyRes = proxyCreate(
93
0
      runtime,
94
0
      args.dyncastArg<JSObject>(0),
95
0
      args.dyncastArg<JSObject>(1),
96
0
      args.vmcastThis<JSProxy>());
97
0
  if (proxyRes == ExecutionStatus::EXCEPTION) {
98
0
    return ExecutionStatus::EXCEPTION;
99
0
  }
100
0
  return proxyRes->getHermesValue();
101
0
}
102
103
CallResult<HermesValue>
104
0
proxyRevocationSteps(void *, Runtime &runtime, NativeArgs args) {
105
  // 1. Let p be F.[[RevocableProxy]].
106
0
  auto revoker = vmcast<NativeFunction>(
107
0
      runtime.getCurrentFrame()->getCalleeClosureUnsafe());
108
0
  SmallHermesValue proxyVal = getRevocableProxySlot(revoker, runtime);
109
  // 2. If p is null, return undefined.
110
0
  if (proxyVal.isNull()) {
111
0
    return HermesValue::encodeUndefinedValue();
112
0
  }
113
  // 3. Set F.[[RevocableProxy]] to null.
114
0
  setRevocableProxySlot(revoker, runtime, SmallHermesValue::encodeNullValue());
115
  // 4. Assert: p is a Proxy object.
116
0
  JSObject *proxy = vmcast<JSObject>(proxyVal.getObject(runtime));
117
0
  assert(proxy->isProxyObject() && "[[RevocableProxy]] is not a Proxy");
118
  // 5. Set p.[[ProxyTarget]] to null.
119
  // 6. Set p.[[ProxyHandler]] to null.
120
0
  JSProxy::setTargetAndHandler(
121
0
      runtime.makeHandle(proxy),
122
0
      runtime,
123
0
      runtime.makeNullHandle<JSObject>(),
124
0
      runtime.makeNullHandle<JSObject>());
125
  // 7. Return undefined.
126
0
  return HermesValue::encodeUndefinedValue();
127
0
}
128
129
CallResult<HermesValue>
130
0
proxyRevocable(void *, Runtime &runtime, NativeArgs args) {
131
  // 1. Let p be ? ProxyCreate(target, handler).
132
0
  CallResult<Handle<JSObject>> proxyRes = proxyCreate(
133
0
      runtime,
134
0
      args.dyncastArg<JSObject>(0),
135
0
      args.dyncastArg<JSObject>(1),
136
0
      runtime.makeHandle(vm::JSProxy::create(runtime)));
137
0
  if (proxyRes == ExecutionStatus::EXCEPTION) {
138
0
    return ExecutionStatus::EXCEPTION;
139
0
  }
140
  // 2. Let steps be the algorithm steps defined in Proxy Revocation Functions.
141
  // 3. Let revoker be CreateBuiltinFunction(steps, « [[RevocableProxy]] »).
142
0
  Handle<NativeFunction> revoker = NativeFunction::createWithoutPrototype(
143
0
      runtime,
144
0
      nullptr,
145
0
      proxyRevocationSteps,
146
0
      Predefined::getSymbolID(Predefined::emptyString),
147
0
      0,
148
0
      ProxySlotIndexes::COUNT);
149
  // 4. Set revoker.[[RevocableProxy]] to p.
150
0
  auto shv =
151
0
      SmallHermesValue::encodeHermesValue(proxyRes->getHermesValue(), runtime);
152
0
  setRevocableProxySlot(*revoker, runtime, shv);
153
  // 5. Let result be ObjectCreate(%ObjectPrototype%).
154
0
  Handle<JSObject> result = runtime.makeHandle(JSObject::create(runtime));
155
  // 6. Perform CreateDataProperty(result, "proxy", p).
156
0
  auto res1 = JSObject::putNamed_RJS(
157
0
      result, runtime, Predefined::getSymbolID(Predefined::proxy), *proxyRes);
158
0
  if (res1 == ExecutionStatus::EXCEPTION) {
159
0
    return ExecutionStatus::EXCEPTION;
160
0
  }
161
0
  assert(*res1 && "Failed to set proxy on Proxy.revocable return");
162
  // 7. Perform CreateDataProperty(result, "revoke", revoker).
163
0
  auto res2 = JSObject::putNamed_RJS(
164
0
      result, runtime, Predefined::getSymbolID(Predefined::revoke), revoker);
165
0
  if (res2 == ExecutionStatus::EXCEPTION) {
166
0
    return ExecutionStatus::EXCEPTION;
167
0
  }
168
0
  assert(*res2 && "Failed to set revoke on Proxy.revocable return");
169
  // 8. Return result.
170
0
  return result.getHermesValue();
171
0
}
172
173
99
Handle<JSObject> createProxyConstructor(Runtime &runtime) {
174
99
  Handle<NativeConstructor> cons = defineSystemConstructor<JSProxy>(
175
99
      runtime,
176
99
      Predefined::getSymbolID(Predefined::Proxy),
177
99
      proxyConstructor,
178
99
      runtime.makeNullHandle<JSObject>(),
179
99
      2,
180
99
      CellKind::JSProxyKind);
181
182
99
  defineMethod(
183
99
      runtime,
184
99
      cons,
185
99
      Predefined::getSymbolID(Predefined::revocable),
186
99
      nullptr,
187
99
      proxyRevocable,
188
99
      2);
189
190
99
  return cons;
191
99
}
192
193
} // namespace vm
194
} // namespace hermes