v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
builtins-proxy-gen.cc
Go to the documentation of this file.
1// Copyright 2016 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
6
11#include "src/common/globals.h"
15#include "torque-generated/exported-macros-assembler.h"
16
17namespace v8 {
18namespace internal {
19
21
23 TNode<Context> context, TNode<JSReceiver> target,
24 TNode<JSReceiver> handler) {
25 TVARIABLE(Map, map);
26
27 Label callable_target(this), constructor_target(this), none_target(this),
28 create_proxy(this);
29
30 TNode<NativeContext> nativeContext = LoadNativeContext(context);
31
32 Branch(IsCallable(target), &callable_target, &none_target);
33
34 BIND(&callable_target);
35 {
36 // Every object that is a constructor is implicitly callable
37 // so it's okay to nest this check here
38 GotoIf(IsConstructor(target), &constructor_target);
39 map = CAST(
40 LoadContextElement(nativeContext, Context::PROXY_CALLABLE_MAP_INDEX));
41 Goto(&create_proxy);
42 }
43 BIND(&constructor_target);
44 {
45 map = CAST(LoadContextElement(nativeContext,
46 Context::PROXY_CONSTRUCTOR_MAP_INDEX));
47 Goto(&create_proxy);
48 }
49 BIND(&none_target);
50 {
51 map = CAST(LoadContextElement(nativeContext, Context::PROXY_MAP_INDEX));
52 Goto(&create_proxy);
53 }
54
55 BIND(&create_proxy);
56 TNode<HeapObject> proxy = Allocate(JSProxy::kSize);
57 StoreMapNoWriteBarrier(proxy, map.value());
59 ? RootIndex::kEmptySwissPropertyDictionary
60 : RootIndex::kEmptyPropertyDictionary;
61 StoreObjectFieldRoot(proxy, JSProxy::kPropertiesOrHashOffset, empty_dict);
62 StoreObjectFieldNoWriteBarrier(proxy, JSProxy::kTargetOffset, target);
63 StoreObjectFieldNoWriteBarrier(proxy, JSProxy::kHandlerOffset, handler);
64
65 return CAST(proxy);
66}
67
76
85
87 auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
88 TNode<IntPtrT> argc_ptr = ChangeInt32ToIntPtr(argc);
89 auto proxy = Parameter<JSProxy>(Descriptor::kFunction);
90 auto context = Parameter<Context>(Descriptor::kContext);
91
92 CSA_DCHECK(this, IsCallable(proxy));
93
94 PerformStackCheck(context);
95
96 Label throw_proxy_handler_revoked(this, Label::kDeferred),
97 trap_undefined(this);
98
99 // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
101 CAST(LoadObjectField(proxy, JSProxy::kHandlerOffset));
102
103 // 2. If handler is null, throw a TypeError exception.
104 GotoIf(IsNull(handler), &throw_proxy_handler_revoked);
105
106 // 3. Assert: Type(handler) is Object.
107 CSA_DCHECK(this, IsJSReceiver(handler));
108
109 // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
110 TNode<Object> target = LoadObjectField(proxy, JSProxy::kTargetOffset);
111
112 // 5. Let trap be ? GetMethod(handler, "apply").
113 // 6. If trap is undefined, then
114 Handle<Name> trap_name = factory()->apply_string();
115 TNode<Object> trap = GetMethod(context, handler, trap_name, &trap_undefined);
116
117 CodeStubArguments args(this, argc_ptr);
118 TNode<JSAny> receiver = args.GetReceiver();
119
120 // 7. Let argArray be CreateArrayFromList(argumentsList).
121 TNode<JSArray> array = EmitFastNewAllArguments(
122 UncheckedCast<Context>(context),
123 UncheckedCast<RawPtrT>(LoadFramePointer()),
124 UncheckedCast<IntPtrT>(args.GetLengthWithoutReceiver()));
125
126 // 8. Return Call(trap, handler, «target, thisArgument, argArray»).
127 TNode<Object> result = Call(context, trap, handler, target, receiver, array);
128 args.PopAndReturn(CAST(result));
129
130 BIND(&trap_undefined);
131 {
132 // 6.a. Return Call(target, thisArgument, argumentsList).
133 TailCallBuiltin(Builtins::Call(), context, target, argc);
134 }
135
136 BIND(&throw_proxy_handler_revoked);
137 { ThrowTypeError(context, MessageTemplate::kProxyRevoked, "apply"); }
138}
139
141 auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
142 TNode<IntPtrT> argc_ptr = ChangeInt32ToIntPtr(argc);
143 auto proxy = Parameter<JSProxy>(Descriptor::kTarget);
144 auto new_target = Parameter<Object>(Descriptor::kNewTarget);
145 auto context = Parameter<Context>(Descriptor::kContext);
146
147 CSA_DCHECK(this, IsCallable(proxy));
148
149 PerformStackCheck(context);
150
151 Label throw_proxy_handler_revoked(this, Label::kDeferred),
152 trap_undefined(this), not_an_object(this, Label::kDeferred);
153
154 // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
156 CAST(LoadObjectField(proxy, JSProxy::kHandlerOffset));
157
158 // 2. If handler is null, throw a TypeError exception.
159 GotoIf(IsNull(handler), &throw_proxy_handler_revoked);
160
161 // 3. Assert: Type(handler) is Object.
162 CSA_DCHECK(this, IsJSReceiver(handler));
163
164 // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
165 TNode<Object> target = LoadObjectField(proxy, JSProxy::kTargetOffset);
166
167 // 5. Let trap be ? GetMethod(handler, "construct").
168 // 6. If trap is undefined, then
169 Handle<Name> trap_name = factory()->construct_string();
170 TNode<Object> trap = GetMethod(context, handler, trap_name, &trap_undefined);
171
172 CodeStubArguments args(this, argc_ptr);
173
174 // 7. Let argArray be CreateArrayFromList(argumentsList).
175 TNode<JSArray> array = EmitFastNewAllArguments(
176 UncheckedCast<Context>(context),
177 UncheckedCast<RawPtrT>(LoadFramePointer()),
178 UncheckedCast<IntPtrT>(args.GetLengthWithoutReceiver()));
179
180 // 8. Let newObj be ? Call(trap, handler, « target, argArray, newTarget »).
181 TNode<JSAny> new_obj =
182 Call(context, trap, handler, target, array, new_target);
183
184 // 9. If Type(newObj) is not Object, throw a TypeError exception.
185 GotoIf(TaggedIsSmi(new_obj), &not_an_object);
186 GotoIfNot(JSAnyIsNotPrimitive(CAST(new_obj)), &not_an_object);
187
188 // 10. Return newObj.
189 args.PopAndReturn(new_obj);
190
191 BIND(&not_an_object);
192 {
193 ThrowTypeError(context, MessageTemplate::kProxyConstructNonObject, new_obj);
194 }
195
196 BIND(&trap_undefined);
197 {
198 // 6.a. Assert: target has a [[Construct]] internal method.
199 CSA_DCHECK(this, IsConstructor(CAST(target)));
200
201 // 6.b. Return ? Construct(target, argumentsList, newTarget).
202 TailCallBuiltin(Builtin::kConstruct, context, target, new_target, argc);
203 }
204
205 BIND(&throw_proxy_handler_revoked);
206 { ThrowTypeError(context, MessageTemplate::kProxyRevoked, "construct"); }
207}
208
210 TNode<Context> context, TNode<JSReceiver> target, TNode<JSProxy> proxy,
211 TNode<Name> name, TNode<Object> trap_result,
212 JSProxy::AccessKind access_kind) {
213 // TODO(mslekova): Think of a better name for the trap_result param.
214 TNode<Map> map = LoadMap(target);
215 TVARIABLE(Object, var_value);
216 TVARIABLE(Uint32T, var_details);
217 TVARIABLE(Object, var_raw_value);
218
219 Label if_found_value(this), check_in_runtime(this, Label::kDeferred),
220 check_passed(this);
221
222 GotoIfNot(IsUniqueNameNoIndex(name), &check_in_runtime);
223 TNode<Uint16T> instance_type = LoadInstanceType(target);
224 TryGetOwnProperty(context, target, target, map, instance_type, name,
225 &if_found_value, &var_value, &var_details, &var_raw_value,
226 &check_passed, &check_in_runtime, kReturnAccessorPair);
227
228 BIND(&if_found_value);
229 {
230 Label throw_non_configurable_data(this, Label::kDeferred),
231 throw_non_configurable_accessor(this, Label::kDeferred),
232 check_accessor(this), check_data(this);
233
234 // If targetDesc is not undefined and targetDesc.[[Configurable]] is
235 // false, then:
236 GotoIfNot(IsSetWord32(var_details.value(),
238 &check_passed);
239
240 // If IsDataDescriptor(targetDesc) is true and
241 // targetDesc.[[Writable]] is false, then:
242 BranchIfAccessorPair(var_raw_value.value(), &check_accessor, &check_data);
243
244 BIND(&check_data);
245 {
246 TNode<BoolT> read_only = IsSetWord32(
247 var_details.value(), PropertyDetails::kAttributesReadOnlyMask);
248 GotoIfNot(read_only, &check_passed);
249
250 // If SameValue(trapResult, targetDesc.[[Value]]) is false,
251 // throw a TypeError exception.
252 BranchIfSameValue(trap_result, var_value.value(), &check_passed,
253 &throw_non_configurable_data);
254 }
255
256 BIND(&check_accessor);
257 {
258 TNode<HeapObject> accessor_pair = CAST(var_raw_value.value());
259
260 if (access_kind == JSProxy::kGet) {
261 Label continue_check(this, Label::kDeferred);
262 // 10.b. If IsAccessorDescriptor(targetDesc) is true and
263 // targetDesc.[[Get]] is undefined, then:
265 // Here we check for null as well because if the getter was never
266 // defined it's set as null.
267 GotoIf(IsUndefined(getter), &continue_check);
268 GotoIf(IsNull(getter), &continue_check);
269 Goto(&check_passed);
270
271 // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
272 BIND(&continue_check);
273 GotoIfNot(IsUndefined(trap_result), &throw_non_configurable_accessor);
274 } else {
275 // 11.b.i. If targetDesc.[[Set]] is undefined, throw a TypeError
276 // exception.
278 GotoIf(IsUndefined(setter), &throw_non_configurable_accessor);
279 GotoIf(IsNull(setter), &throw_non_configurable_accessor);
280 }
281 Goto(&check_passed);
282 }
283
284 BIND(&throw_non_configurable_data);
285 {
286 if (access_kind == JSProxy::kGet) {
287 ThrowTypeError(context, MessageTemplate::kProxyGetNonConfigurableData,
288 name, var_value.value(), trap_result);
289 } else {
290 ThrowTypeError(context, MessageTemplate::kProxySetFrozenData, name);
291 }
292 }
293
294 BIND(&throw_non_configurable_accessor);
295 {
296 if (access_kind == JSProxy::kGet) {
297 ThrowTypeError(context,
298 MessageTemplate::kProxyGetNonConfigurableAccessor, name,
299 trap_result);
300 } else {
301 ThrowTypeError(context, MessageTemplate::kProxySetFrozenAccessor, name);
302 }
303 }
304
305 BIND(&check_in_runtime);
306 {
307 CallRuntime(Runtime::kCheckProxyGetSetTrapResult, context, name, target,
308 trap_result, SmiConstant(access_kind));
309 Goto(&check_passed);
310 }
311
312 BIND(&check_passed);
313 }
314}
315
317 TNode<JSReceiver> target,
318 TNode<JSProxy> proxy,
319 TNode<Name> name) {
320 TNode<Map> target_map = LoadMap(target);
321 TVARIABLE(Object, var_value);
322 TVARIABLE(Uint32T, var_details);
323 TVARIABLE(Object, var_raw_value);
324
325 Label if_found_value(this, Label::kDeferred),
326 throw_non_configurable(this, Label::kDeferred),
327 throw_non_extensible(this, Label::kDeferred), check_passed(this),
328 check_in_runtime(this, Label::kDeferred);
329
330 // 9.a. Let targetDesc be ? target.[[GetOwnProperty]](P).
331 GotoIfNot(IsUniqueNameNoIndex(name), &check_in_runtime);
332 TNode<Uint16T> instance_type = LoadInstanceType(target);
333 TryGetOwnProperty(context, target, target, target_map, instance_type, name,
334 &if_found_value, &var_value, &var_details, &var_raw_value,
335 &check_passed, &check_in_runtime, kReturnAccessorPair);
336
337 // 9.b. If targetDesc is not undefined, then (see 9.b.i. below).
338 BIND(&if_found_value);
339 {
340 // 9.b.i. If targetDesc.[[Configurable]] is false, throw a TypeError
341 // exception.
342 TNode<BoolT> non_configurable = IsSetWord32(
343 var_details.value(), PropertyDetails::kAttributesDontDeleteMask);
344 GotoIf(non_configurable, &throw_non_configurable);
345
346 // 9.b.ii. Let extensibleTarget be ? IsExtensible(target).
347 TNode<BoolT> target_extensible = IsExtensibleMap(target_map);
348
349 // 9.b.iii. If extensibleTarget is false, throw a TypeError exception.
350 GotoIfNot(target_extensible, &throw_non_extensible);
351 Goto(&check_passed);
352 }
353
354 BIND(&throw_non_configurable);
355 { ThrowTypeError(context, MessageTemplate::kProxyHasNonConfigurable, name); }
356
357 BIND(&throw_non_extensible);
358 { ThrowTypeError(context, MessageTemplate::kProxyHasNonExtensible, name); }
359
360 BIND(&check_in_runtime);
361 {
362 CallRuntime(Runtime::kCheckProxyHasTrapResult, context, name, target);
363 Goto(&check_passed);
364 }
365
366 BIND(&check_passed);
367}
368
370 TNode<JSReceiver> target,
371 TNode<JSProxy> proxy,
372 TNode<Name> name) {
373 TNode<Map> target_map = LoadMap(target);
374 TVARIABLE(Object, var_value);
375 TVARIABLE(Uint32T, var_details);
376 TVARIABLE(Object, var_raw_value);
377
378 Label if_found_value(this, Label::kDeferred),
379 throw_non_configurable(this, Label::kDeferred),
380 throw_non_extensible(this, Label::kDeferred), check_passed(this),
381 check_in_runtime(this, Label::kDeferred);
382
383 // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
384 GotoIfNot(IsUniqueNameNoIndex(name), &check_in_runtime);
385 TNode<Uint16T> instance_type = LoadInstanceType(target);
386 TryGetOwnProperty(context, target, target, target_map, instance_type, name,
387 &if_found_value, &var_value, &var_details, &var_raw_value,
388 &check_passed, &check_in_runtime, kReturnAccessorPair);
389
390 // 11. If targetDesc is undefined, return true.
391 BIND(&if_found_value);
392 {
393 // 12. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
394 TNode<BoolT> non_configurable = IsSetWord32(
395 var_details.value(), PropertyDetails::kAttributesDontDeleteMask);
396 GotoIf(non_configurable, &throw_non_configurable);
397
398 // 13. Let extensibleTarget be ? IsExtensible(target).
399 TNode<BoolT> target_extensible = IsExtensibleMap(target_map);
400
401 // 14. If extensibleTarget is false, throw a TypeError exception.
402 GotoIfNot(target_extensible, &throw_non_extensible);
403 Goto(&check_passed);
404 }
405
406 BIND(&throw_non_configurable);
407 {
408 ThrowTypeError(context,
409 MessageTemplate::kProxyDeletePropertyNonConfigurable, name);
410 }
411
412 BIND(&throw_non_extensible);
413 {
414 ThrowTypeError(context, MessageTemplate::kProxyDeletePropertyNonExtensible,
415 name);
416 }
417
418 BIND(&check_in_runtime);
419 {
420 CallRuntime(Runtime::kCheckProxyDeleteTrapResult, context, name, target);
421 Goto(&check_passed);
422 }
423
424 BIND(&check_passed);
425}
426
428
429} // namespace internal
430} // namespace v8
#define BIND(label)
#define TVARIABLE(...)
#define CSA_DCHECK(csa,...)
#define TF_BUILTIN(Name, AssemblerBase)
PropertyT * getter
static constexpr Builtin Call(ConvertReceiverMode=ConvertReceiverMode::kAny)
TNode< BoolT > IsUniqueNameNoIndex(TNode< HeapObject > object)
void BranchIfSameValue(TNode< Object > lhs, TNode< Object > rhs, Label *if_true, Label *if_false, SameValueMode mode=SameValueMode::kFull)
TNode< BoolT > IsConstructor(TNode< HeapObject > object)
TNode< BoolT > IsExtensibleMap(TNode< Map > map)
void ThrowTypeError(TNode< Context > context, MessageTemplate message, char const *arg0=nullptr, char const *arg1=nullptr)
TNode< HeapObject > Allocate(TNode< IntPtrT > size, AllocationFlags flags=AllocationFlag::kNone)
void StoreObjectFieldRoot(TNode< HeapObject > object, int offset, RootIndex root)
TNode< JSFunction > AllocateRootFunctionWithContext(RootIndex function, TNode< Context > context, std::optional< TNode< NativeContext > > maybe_native_context)
void TryGetOwnProperty(TNode< Context > context, TNode< JSAny > receiver, TNode< JSReceiver > object, TNode< Map > map, TNode< Int32T > instance_type, TNode< Name > unique_name, Label *if_found_value, TVariable< Object > *var_value, Label *if_not_found, Label *if_bailout, ExpectedReceiverMode expected_receiver_mode=kExpectingAnyReceiver)
TNode< BoolT > IsSetWord32(TNode< Word32T > word32)
TNode< Object > LoadAccessorPairGetter(TNode< AccessorPair > accessor_pair)
void StoreObjectFieldNoWriteBarrier(TNode< HeapObject > object, TNode< IntPtrT > offset, TNode< T > value)
TNode< Uint16T > LoadInstanceType(TNode< HeapObject > object)
TNode< NativeContext > LoadNativeContext(TNode< Context > context)
void BranchIfAccessorPair(TNode< Object > value, Label *if_accessor_pair, Label *if_not_accessor_pair)
void StoreContextElementNoWriteBarrier(TNode< Context > context, int slot_index, TNode< Object > value)
TNode< Map > LoadMap(TNode< HeapObject > object)
TNode< Object > LoadAccessorPairSetter(TNode< AccessorPair > accessor_pair)
TNode< BoolT > IsCallable(TNode< HeapObject > object)
void StoreMapNoWriteBarrier(TNode< HeapObject > object, RootIndex map_root_index)
static const int kAttributesReadOnlyMask
static const int kAttributesDontDeleteMask
TNode< JSFunction > AllocateProxyRevokeFunction(TNode< Context > context, TNode< JSProxy > proxy)
TNode< JSProxy > AllocateProxy(TNode< Context > context, TNode< JSReceiver > target, TNode< JSReceiver > handler)
void CheckHasTrapResult(TNode< Context > context, TNode< JSReceiver > target, TNode< JSProxy > proxy, TNode< Name > name)
void CheckDeleteTrapResult(TNode< Context > context, TNode< JSReceiver > target, TNode< JSProxy > proxy, TNode< Name > name)
TNode< Context > CreateProxyRevokeFunctionContext(TNode< JSProxy > proxy, TNode< NativeContext > native_context)
void CheckGetSetTrapResult(TNode< Context > context, TNode< JSReceiver > target, TNode< JSProxy > proxy, TNode< Name > name, TNode< Object > trap_result, JSProxy::AccessKind access_kind)
void GotoIfNot(TNode< IntegralT > condition, Label *false_label, GotoHint goto_hint=GotoHint::kNone)
TNode< Smi > SmiConstant(Tagged< Smi > value)
void GotoIf(TNode< IntegralT > condition, Label *true_label, GotoHint goto_hint=GotoHint::kNone)
TNode< T > CallRuntime(Runtime::FunctionId function, TNode< Object > context, TArgs... args)
void Branch(TNode< IntegralT > condition, Label *true_label, Label *false_label, BranchHint branch_hint=BranchHint::kNone)
#define CAST(x)
#define V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL
Definition globals.h:242
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
DirectHandle< Object > new_target
Definition execution.cc:75
TNode< Context > context
TNode< Object > receiver
ZoneVector< RpoNumber > & result
std::optional< OolTrapLabel > trap
Handle< To > UncheckedCast(Handle< From > value)
Definition handles-inl.h:55
kInstanceDescriptorsOffset kTransitionsOrPrototypeInfoOffset IsNull(value)||IsJSProxy(value)||IsWasmObject(value)||(IsJSObject(value) &&(HeapLayout
Definition map-inl.h:70
!IsContextMap !IsContextMap native_context
Definition map-inl.h:877