Line data Source code
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 :
5 : #include "src/builtins/builtins-proxy-gen.h"
6 : #include "src/builtins/builtins-utils-gen.h"
7 : #include "src/builtins/builtins-utils.h"
8 : #include "src/builtins/builtins.h"
9 :
10 : #include "src/counters.h"
11 : #include "src/objects-inl.h"
12 :
13 : namespace v8 {
14 : namespace internal {
15 :
16 224 : void ProxiesCodeStubAssembler::GotoIfRevokedProxy(Node* object,
17 : Label* if_proxy_revoked) {
18 224 : Label proxy_not_revoked(this);
19 224 : GotoIfNot(IsJSProxy(object), &proxy_not_revoked);
20 448 : Branch(IsJSReceiver(CAST(LoadObjectField(object, JSProxy::kHandlerOffset))),
21 224 : &proxy_not_revoked, if_proxy_revoked);
22 224 : BIND(&proxy_not_revoked);
23 224 : }
24 :
25 112 : Node* ProxiesCodeStubAssembler::AllocateProxy(Node* target, Node* handler,
26 : Node* context) {
27 112 : VARIABLE(map, MachineRepresentation::kTagged);
28 :
29 224 : Label callable_target(this), constructor_target(this), none_target(this),
30 224 : create_proxy(this);
31 :
32 112 : Node* nativeContext = LoadNativeContext(context);
33 :
34 112 : Branch(IsCallable(target), &callable_target, &none_target);
35 :
36 112 : BIND(&callable_target);
37 : {
38 : // Every object that is a constructor is implicitly callable
39 : // so it's okay to nest this check here
40 112 : GotoIf(IsConstructor(target), &constructor_target);
41 : map.Bind(
42 112 : LoadContextElement(nativeContext, Context::PROXY_CALLABLE_MAP_INDEX));
43 112 : Goto(&create_proxy);
44 : }
45 112 : BIND(&constructor_target);
46 : {
47 : map.Bind(LoadContextElement(nativeContext,
48 112 : Context::PROXY_CONSTRUCTOR_MAP_INDEX));
49 112 : Goto(&create_proxy);
50 : }
51 112 : BIND(&none_target);
52 : {
53 112 : map.Bind(LoadContextElement(nativeContext, Context::PROXY_MAP_INDEX));
54 112 : Goto(&create_proxy);
55 : }
56 :
57 112 : BIND(&create_proxy);
58 112 : Node* proxy = Allocate(JSProxy::kSize);
59 112 : StoreMapNoWriteBarrier(proxy, map.value());
60 : StoreObjectFieldRoot(proxy, JSProxy::kPropertiesOrHashOffset,
61 112 : RootIndex::kEmptyPropertyDictionary);
62 112 : StoreObjectFieldNoWriteBarrier(proxy, JSProxy::kTargetOffset, target);
63 112 : StoreObjectFieldNoWriteBarrier(proxy, JSProxy::kHandlerOffset, handler);
64 :
65 224 : return proxy;
66 : }
67 :
68 112 : Node* ProxiesCodeStubAssembler::AllocateJSArrayForCodeStubArguments(
69 : Node* context, CodeStubArguments& args, Node* argc, ParameterMode mode) {
70 112 : Comment("AllocateJSArrayForCodeStubArguments");
71 :
72 224 : Label if_empty_array(this), allocate_js_array(this);
73 : // Do not use AllocateJSArray since {elements} might end up in LOS.
74 224 : VARIABLE(elements, MachineRepresentation::kTagged);
75 :
76 112 : TNode<Smi> length = ParameterToTagged(argc, mode);
77 112 : GotoIf(SmiEqual(length, SmiConstant(0)), &if_empty_array);
78 : {
79 112 : Label if_large_object(this, Label::kDeferred);
80 : Node* allocated_elements = AllocateFixedArray(PACKED_ELEMENTS, argc, mode,
81 112 : kAllowLargeObjectAllocation);
82 112 : elements.Bind(allocated_elements);
83 :
84 224 : TVARIABLE(IntPtrT, offset,
85 : IntPtrConstant(FixedArrayBase::kHeaderSize - kHeapObjectTag));
86 224 : VariableList list({&offset}, zone());
87 :
88 112 : GotoIf(SmiGreaterThan(length, SmiConstant(FixedArray::kMaxRegularLength)),
89 112 : &if_large_object);
90 112 : args.ForEach(list, [=, &offset](Node* arg) {
91 : StoreNoWriteBarrier(MachineRepresentation::kTagged, allocated_elements,
92 112 : offset.value(), arg);
93 112 : Increment(&offset, kTaggedSize);
94 224 : });
95 112 : Goto(&allocate_js_array);
96 :
97 112 : BIND(&if_large_object);
98 : {
99 112 : args.ForEach(list, [=, &offset](Node* arg) {
100 112 : Store(allocated_elements, offset.value(), arg);
101 112 : Increment(&offset, kTaggedSize);
102 224 : });
103 112 : Goto(&allocate_js_array);
104 112 : }
105 : }
106 :
107 112 : BIND(&if_empty_array);
108 : {
109 112 : elements.Bind(EmptyFixedArrayConstant());
110 112 : Goto(&allocate_js_array);
111 : }
112 :
113 112 : BIND(&allocate_js_array);
114 : // Allocate the result JSArray.
115 112 : Node* native_context = LoadNativeContext(context);
116 : TNode<Map> array_map =
117 112 : LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
118 : TNode<JSArray> array =
119 112 : AllocateJSArray(array_map, CAST(elements.value()), length);
120 :
121 224 : return array;
122 : }
123 :
124 56 : Node* ProxiesCodeStubAssembler::CreateProxyRevokeFunctionContext(
125 : Node* proxy, Node* native_context) {
126 56 : Node* const context = Allocate(FixedArray::SizeFor(kProxyContextLength));
127 56 : StoreMapNoWriteBarrier(context, RootIndex::kFunctionContextMap);
128 56 : InitializeFunctionContext(native_context, context, kProxyContextLength);
129 56 : StoreContextElementNoWriteBarrier(context, kProxySlot, proxy);
130 56 : return context;
131 : }
132 :
133 56 : Node* ProxiesCodeStubAssembler::AllocateProxyRevokeFunction(Node* proxy,
134 : Node* context) {
135 56 : Node* const native_context = LoadNativeContext(context);
136 :
137 : Node* const proxy_context =
138 56 : CreateProxyRevokeFunctionContext(proxy, native_context);
139 : Node* const revoke_map = LoadContextElement(
140 56 : native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
141 : Node* const revoke_info =
142 56 : LoadContextElement(native_context, Context::PROXY_REVOKE_SHARED_FUN);
143 :
144 : return AllocateFunctionWithMapAndContext(revoke_map, revoke_info,
145 56 : proxy_context);
146 : }
147 :
148 : // ES #sec-proxy-constructor
149 448 : TF_BUILTIN(ProxyConstructor, ProxiesCodeStubAssembler) {
150 56 : Node* context = Parameter(Descriptor::kContext);
151 :
152 : // 1. If NewTarget is undefined, throw a TypeError exception.
153 56 : Node* new_target = Parameter(Descriptor::kJSNewTarget);
154 112 : Label throwtypeerror(this, Label::kDeferred), createproxy(this);
155 56 : Branch(IsUndefined(new_target), &throwtypeerror, &createproxy);
156 :
157 56 : BIND(&throwtypeerror);
158 : {
159 56 : ThrowTypeError(context, MessageTemplate::kConstructorNotFunction, "Proxy");
160 : }
161 :
162 : // 2. Return ? ProxyCreate(target, handler).
163 56 : BIND(&createproxy);
164 : {
165 : // https://tc39.github.io/ecma262/#sec-proxycreate
166 56 : Node* target = Parameter(Descriptor::kTarget);
167 56 : Node* handler = Parameter(Descriptor::kHandler);
168 :
169 : // 1. If Type(target) is not Object, throw a TypeError exception.
170 : // 2. If target is a Proxy exotic object and target.[[ProxyHandler]] is
171 : // null, throw a TypeError exception.
172 : // 3. If Type(handler) is not Object, throw a TypeError exception.
173 : // 4. If handler is a Proxy exotic object and handler.[[ProxyHandler]]
174 : // is null, throw a TypeError exception.
175 56 : Label throw_proxy_non_object(this, Label::kDeferred),
176 112 : throw_proxy_handler_or_target_revoked(this, Label::kDeferred),
177 112 : return_create_proxy(this);
178 :
179 56 : GotoIf(TaggedIsSmi(target), &throw_proxy_non_object);
180 56 : GotoIfNot(IsJSReceiver(target), &throw_proxy_non_object);
181 56 : GotoIfRevokedProxy(target, &throw_proxy_handler_or_target_revoked);
182 :
183 56 : GotoIf(TaggedIsSmi(handler), &throw_proxy_non_object);
184 56 : GotoIfNot(IsJSReceiver(handler), &throw_proxy_non_object);
185 56 : GotoIfRevokedProxy(handler, &throw_proxy_handler_or_target_revoked);
186 :
187 : // 5. Let P be a newly created object.
188 : // 6. Set P's essential internal methods (except for [[Call]] and
189 : // [[Construct]]) to the definitions specified in 9.5.
190 : // 7. If IsCallable(target) is true, then
191 : // a. Set P.[[Call]] as specified in 9.5.12.
192 : // b. If IsConstructor(target) is true, then
193 : // 1. Set P.[[Construct]] as specified in 9.5.13.
194 : // 8. Set P.[[ProxyTarget]] to target.
195 : // 9. Set P.[[ProxyHandler]] to handler.
196 : // 10. Return P.
197 56 : Return(AllocateProxy(target, handler, context));
198 :
199 56 : BIND(&throw_proxy_non_object);
200 56 : ThrowTypeError(context, MessageTemplate::kProxyNonObject);
201 :
202 56 : BIND(&throw_proxy_handler_or_target_revoked);
203 112 : ThrowTypeError(context, MessageTemplate::kProxyHandlerOrTargetRevoked);
204 56 : }
205 56 : }
206 :
207 392 : TF_BUILTIN(ProxyRevocable, ProxiesCodeStubAssembler) {
208 56 : Node* const target = Parameter(Descriptor::kTarget);
209 56 : Node* const handler = Parameter(Descriptor::kHandler);
210 56 : Node* const context = Parameter(Descriptor::kContext);
211 56 : Node* const native_context = LoadNativeContext(context);
212 :
213 56 : Label throw_proxy_non_object(this, Label::kDeferred),
214 112 : throw_proxy_handler_or_target_revoked(this, Label::kDeferred),
215 112 : return_create_proxy(this);
216 :
217 56 : GotoIf(TaggedIsSmi(target), &throw_proxy_non_object);
218 56 : GotoIfNot(IsJSReceiver(target), &throw_proxy_non_object);
219 56 : GotoIfRevokedProxy(target, &throw_proxy_handler_or_target_revoked);
220 :
221 56 : GotoIf(TaggedIsSmi(handler), &throw_proxy_non_object);
222 56 : GotoIfNot(IsJSReceiver(handler), &throw_proxy_non_object);
223 56 : GotoIfRevokedProxy(handler, &throw_proxy_handler_or_target_revoked);
224 :
225 56 : Node* const proxy = AllocateProxy(target, handler, context);
226 56 : Node* const revoke = AllocateProxyRevokeFunction(proxy, context);
227 :
228 56 : Node* const result = Allocate(JSProxyRevocableResult::kSize);
229 : Node* const result_map = LoadContextElement(
230 56 : native_context, Context::PROXY_REVOCABLE_RESULT_MAP_INDEX);
231 56 : StoreMapNoWriteBarrier(result, result_map);
232 : StoreObjectFieldRoot(result, JSProxyRevocableResult::kPropertiesOrHashOffset,
233 56 : RootIndex::kEmptyFixedArray);
234 : StoreObjectFieldRoot(result, JSProxyRevocableResult::kElementsOffset,
235 56 : RootIndex::kEmptyFixedArray);
236 : StoreObjectFieldNoWriteBarrier(result, JSProxyRevocableResult::kProxyOffset,
237 56 : proxy);
238 : StoreObjectFieldNoWriteBarrier(result, JSProxyRevocableResult::kRevokeOffset,
239 56 : revoke);
240 56 : Return(result);
241 :
242 56 : BIND(&throw_proxy_non_object);
243 56 : ThrowTypeError(context, MessageTemplate::kProxyNonObject);
244 :
245 56 : BIND(&throw_proxy_handler_or_target_revoked);
246 112 : ThrowTypeError(context, MessageTemplate::kProxyHandlerOrTargetRevoked);
247 56 : }
248 :
249 : // Proxy Revocation Functions
250 : // https://tc39.github.io/ecma262/#sec-proxy-revocation-functions
251 280 : TF_BUILTIN(ProxyRevoke, ProxiesCodeStubAssembler) {
252 56 : Node* const context = Parameter(Descriptor::kContext);
253 :
254 : // 1. Let p be F.[[RevocableProxy]].
255 56 : Node* const proxy_slot = IntPtrConstant(kProxySlot);
256 56 : Node* const proxy = LoadContextElement(context, proxy_slot);
257 :
258 56 : Label revoke_called(this);
259 :
260 : // 2. If p is null, ...
261 56 : GotoIf(IsNull(proxy), &revoke_called);
262 :
263 : // 3. Set F.[[RevocableProxy]] to null.
264 56 : StoreContextElement(context, proxy_slot, NullConstant());
265 :
266 : // 4. Assert: p is a Proxy object.
267 : CSA_ASSERT(this, IsJSProxy(proxy));
268 :
269 : // 5. Set p.[[ProxyTarget]] to null.
270 56 : StoreObjectField(proxy, JSProxy::kTargetOffset, NullConstant());
271 :
272 : // 6. Set p.[[ProxyHandler]] to null.
273 56 : StoreObjectField(proxy, JSProxy::kHandlerOffset, NullConstant());
274 :
275 : // 7. Return undefined.
276 56 : Return(UndefinedConstant());
277 :
278 56 : BIND(&revoke_called);
279 : // 2. ... return undefined.
280 56 : Return(UndefinedConstant());
281 56 : }
282 :
283 392 : TF_BUILTIN(CallProxy, ProxiesCodeStubAssembler) {
284 56 : Node* argc = Parameter(Descriptor::kActualArgumentsCount);
285 56 : Node* argc_ptr = ChangeInt32ToIntPtr(argc);
286 56 : Node* proxy = Parameter(Descriptor::kFunction);
287 56 : Node* context = Parameter(Descriptor::kContext);
288 :
289 : CSA_ASSERT(this, IsJSProxy(proxy));
290 : CSA_ASSERT(this, IsCallable(proxy));
291 :
292 56 : PerformStackCheck(CAST(context));
293 :
294 56 : Label throw_proxy_handler_revoked(this, Label::kDeferred),
295 112 : trap_undefined(this);
296 :
297 : // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
298 56 : Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
299 :
300 : // 2. If handler is null, throw a TypeError exception.
301 : CSA_ASSERT(this, IsNullOrJSReceiver(handler));
302 56 : GotoIfNot(IsJSReceiver(handler), &throw_proxy_handler_revoked);
303 :
304 : // 3. Assert: Type(handler) is Object.
305 : CSA_ASSERT(this, IsJSReceiver(handler));
306 :
307 : // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
308 56 : Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
309 :
310 : // 5. Let trap be ? GetMethod(handler, "apply").
311 : // 6. If trap is undefined, then
312 56 : Handle<Name> trap_name = factory()->apply_string();
313 56 : Node* trap = GetMethod(context, handler, trap_name, &trap_undefined);
314 :
315 56 : CodeStubArguments args(this, argc_ptr);
316 56 : Node* receiver = args.GetReceiver();
317 :
318 : // 7. Let argArray be CreateArrayFromList(argumentsList).
319 : Node* array = AllocateJSArrayForCodeStubArguments(context, args, argc_ptr,
320 56 : INTPTR_PARAMETERS);
321 :
322 : // 8. Return Call(trap, handler, «target, thisArgument, argArray»).
323 : Node* result = CallJS(CodeFactory::Call(isolate()), context, trap, handler,
324 56 : target, receiver, array);
325 56 : args.PopAndReturn(result);
326 :
327 56 : BIND(&trap_undefined);
328 : {
329 : // 6.a. Return Call(target, thisArgument, argumentsList).
330 56 : TailCallStub(CodeFactory::Call(isolate()), context, target, argc);
331 : }
332 :
333 56 : BIND(&throw_proxy_handler_revoked);
334 112 : { ThrowTypeError(context, MessageTemplate::kProxyRevoked, "apply"); }
335 56 : }
336 :
337 448 : TF_BUILTIN(ConstructProxy, ProxiesCodeStubAssembler) {
338 56 : Node* argc = Parameter(Descriptor::kActualArgumentsCount);
339 56 : Node* argc_ptr = ChangeInt32ToIntPtr(argc);
340 56 : Node* proxy = Parameter(Descriptor::kTarget);
341 56 : Node* new_target = Parameter(Descriptor::kNewTarget);
342 56 : Node* context = Parameter(Descriptor::kContext);
343 :
344 : CSA_ASSERT(this, IsJSProxy(proxy));
345 : CSA_ASSERT(this, IsCallable(proxy));
346 :
347 56 : Label throw_proxy_handler_revoked(this, Label::kDeferred),
348 112 : trap_undefined(this), not_an_object(this, Label::kDeferred);
349 :
350 : // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
351 56 : Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
352 :
353 : // 2. If handler is null, throw a TypeError exception.
354 : CSA_ASSERT(this, IsNullOrJSReceiver(handler));
355 56 : GotoIfNot(IsJSReceiver(handler), &throw_proxy_handler_revoked);
356 :
357 : // 3. Assert: Type(handler) is Object.
358 : CSA_ASSERT(this, IsJSReceiver(handler));
359 :
360 : // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
361 56 : Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
362 :
363 : // 5. Let trap be ? GetMethod(handler, "construct").
364 : // 6. If trap is undefined, then
365 56 : Handle<Name> trap_name = factory()->construct_string();
366 56 : Node* trap = GetMethod(context, handler, trap_name, &trap_undefined);
367 :
368 56 : CodeStubArguments args(this, argc_ptr);
369 :
370 : // 7. Let argArray be CreateArrayFromList(argumentsList).
371 : Node* array = AllocateJSArrayForCodeStubArguments(context, args, argc_ptr,
372 56 : INTPTR_PARAMETERS);
373 :
374 : // 8. Let newObj be ? Call(trap, handler, « target, argArray, newTarget »).
375 : Node* new_obj = CallJS(CodeFactory::Call(isolate()), context, trap, handler,
376 56 : target, array, new_target);
377 :
378 : // 9. If Type(newObj) is not Object, throw a TypeError exception.
379 56 : GotoIf(TaggedIsSmi(new_obj), ¬_an_object);
380 56 : GotoIfNot(IsJSReceiver(new_obj), ¬_an_object);
381 :
382 : // 10. Return newObj.
383 56 : args.PopAndReturn(new_obj);
384 :
385 56 : BIND(¬_an_object);
386 : {
387 56 : ThrowTypeError(context, MessageTemplate::kProxyConstructNonObject, new_obj);
388 : }
389 :
390 56 : BIND(&trap_undefined);
391 : {
392 : // 6.a. Assert: target has a [[Construct]] internal method.
393 : CSA_ASSERT(this, IsConstructor(target));
394 :
395 : // 6.b. Return ? Construct(target, argumentsList, newTarget).
396 : TailCallStub(CodeFactory::Construct(isolate()), context, target, new_target,
397 56 : argc);
398 : }
399 :
400 56 : BIND(&throw_proxy_handler_revoked);
401 112 : { ThrowTypeError(context, MessageTemplate::kProxyRevoked, "construct"); }
402 56 : }
403 :
404 392 : TF_BUILTIN(ProxyHasProperty, ProxiesCodeStubAssembler) {
405 56 : Node* context = Parameter(Descriptor::kContext);
406 56 : Node* proxy = Parameter(Descriptor::kProxy);
407 56 : Node* name = Parameter(Descriptor::kName);
408 :
409 : CSA_ASSERT(this, IsJSProxy(proxy));
410 :
411 56 : PerformStackCheck(CAST(context));
412 :
413 : // 1. Assert: IsPropertyKey(P) is true.
414 : CSA_ASSERT(this, IsName(name));
415 : CSA_ASSERT(this, Word32Equal(IsPrivateSymbol(name), Int32Constant(0)));
416 :
417 56 : Label throw_proxy_handler_revoked(this, Label::kDeferred),
418 112 : trap_undefined(this),
419 112 : if_try_get_own_property_bailout(this, Label::kDeferred),
420 112 : trap_not_callable(this, Label::kDeferred), return_true(this),
421 112 : return_false(this), check_target_desc(this);
422 :
423 : // 2. Let handler be O.[[ProxyHandler]].
424 56 : Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
425 :
426 : // 3. If handler is null, throw a TypeError exception.
427 : // 4. Assert: Type(handler) is Object.
428 56 : GotoIfNot(IsJSReceiver(handler), &throw_proxy_handler_revoked);
429 :
430 : // 5. Let target be O.[[ProxyTarget]].
431 56 : Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
432 :
433 : // 6. Let trap be ? GetMethod(handler, "has").
434 : // 7. If trap is undefined, then (see 7.a below).
435 56 : Handle<Name> trap_name = factory()->has_string();
436 56 : Node* trap = GetMethod(context, handler, trap_name, &trap_undefined);
437 :
438 56 : GotoIf(TaggedIsSmi(trap), &trap_not_callable);
439 56 : GotoIfNot(IsCallable(trap), &trap_not_callable);
440 :
441 : // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, P
442 : // »)).
443 : BranchIfToBooleanIsTrue(CallJS(CodeFactory::Call(isolate()), context, trap,
444 : handler, target, name),
445 56 : &return_true, &check_target_desc);
446 :
447 56 : BIND(&check_target_desc);
448 : {
449 : // 9. If booleanTrapResult is false, then (see 9.a. in CheckHasTrapResult).
450 : CheckHasTrapResult(context, target, proxy, name, &return_false,
451 56 : &if_try_get_own_property_bailout);
452 : }
453 :
454 56 : BIND(&if_try_get_own_property_bailout);
455 : {
456 56 : CallRuntime(Runtime::kCheckProxyHasTrap, context, name, target);
457 56 : Return(FalseConstant());
458 : }
459 :
460 56 : BIND(&trap_undefined);
461 : {
462 : // 7.a. Return ? target.[[HasProperty]](P).
463 56 : TailCallBuiltin(Builtins::kHasProperty, context, target, name);
464 : }
465 :
466 56 : BIND(&return_false);
467 56 : Return(FalseConstant());
468 :
469 56 : BIND(&return_true);
470 56 : Return(TrueConstant());
471 :
472 56 : BIND(&throw_proxy_handler_revoked);
473 56 : ThrowTypeError(context, MessageTemplate::kProxyRevoked, "has");
474 :
475 56 : BIND(&trap_not_callable);
476 : ThrowTypeError(context, MessageTemplate::kPropertyNotFunction, trap,
477 112 : StringConstant("has"), proxy);
478 56 : }
479 :
480 504 : TF_BUILTIN(ProxyGetProperty, ProxiesCodeStubAssembler) {
481 56 : Node* context = Parameter(Descriptor::kContext);
482 56 : Node* proxy = Parameter(Descriptor::kProxy);
483 56 : Node* name = Parameter(Descriptor::kName);
484 56 : Node* receiver = Parameter(Descriptor::kReceiverValue);
485 56 : Node* on_non_existent = Parameter(Descriptor::kOnNonExistent);
486 :
487 : CSA_ASSERT(this, IsJSProxy(proxy));
488 :
489 : // 1. Assert: IsPropertyKey(P) is true.
490 : CSA_ASSERT(this, TaggedIsNotSmi(name));
491 : CSA_ASSERT(this, IsName(name));
492 : CSA_ASSERT(this, Word32Equal(IsPrivateSymbol(name), Int32Constant(0)));
493 :
494 56 : Label throw_proxy_handler_revoked(this, Label::kDeferred),
495 112 : trap_undefined(this);
496 :
497 : // 2. Let handler be O.[[ProxyHandler]].
498 56 : Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
499 :
500 : // 3. If handler is null, throw a TypeError exception.
501 56 : GotoIf(IsNull(handler), &throw_proxy_handler_revoked);
502 :
503 : // 4. Assert: Type(handler) is Object.
504 : CSA_ASSERT(this, IsJSReceiver(handler));
505 :
506 : // 5. Let target be O.[[ProxyTarget]].
507 56 : Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
508 :
509 : // 6. Let trap be ? GetMethod(handler, "get").
510 : // 7. If trap is undefined, then (see 7.a below).
511 56 : Handle<Name> trap_name = factory()->get_string();
512 56 : Node* trap = GetMethod(context, handler, trap_name, &trap_undefined);
513 :
514 : // 8. Let trapResult be ? Call(trap, handler, « target, P, Receiver »).
515 : Node* trap_result = CallJS(
516 : CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined),
517 56 : context, trap, handler, target, name, receiver);
518 :
519 : // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
520 112 : Label return_result(this);
521 : CheckGetSetTrapResult(context, target, proxy, name, trap_result,
522 56 : &return_result, JSProxy::kGet);
523 :
524 56 : BIND(&return_result);
525 : {
526 : // 11. Return trapResult.
527 56 : Return(trap_result);
528 : }
529 :
530 56 : BIND(&trap_undefined);
531 : {
532 : // 7.a. Return ? target.[[Get]](P, Receiver).
533 : // TODO(mslekova): Introduce GetPropertyWithReceiver stub
534 : Return(CallRuntime(Runtime::kGetPropertyWithReceiver, context, target, name,
535 56 : receiver, on_non_existent));
536 : }
537 :
538 56 : BIND(&throw_proxy_handler_revoked);
539 112 : ThrowTypeError(context, MessageTemplate::kProxyRevoked, "get");
540 56 : }
541 :
542 504 : TF_BUILTIN(ProxySetProperty, ProxiesCodeStubAssembler) {
543 56 : Node* context = Parameter(Descriptor::kContext);
544 56 : Node* proxy = Parameter(Descriptor::kProxy);
545 56 : Node* name = Parameter(Descriptor::kName);
546 56 : Node* value = Parameter(Descriptor::kValue);
547 56 : Node* receiver = Parameter(Descriptor::kReceiverValue);
548 :
549 : CSA_ASSERT(this, IsJSProxy(proxy));
550 :
551 : // 1. Assert: IsPropertyKey(P) is true.
552 : CSA_ASSERT(this, TaggedIsNotSmi(name));
553 : CSA_ASSERT(this, IsName(name));
554 :
555 56 : Label throw_proxy_handler_revoked(this, Label::kDeferred),
556 112 : trap_undefined(this), failure(this, Label::kDeferred),
557 112 : continue_checks(this), success(this),
558 112 : private_symbol(this, Label::kDeferred);
559 :
560 56 : GotoIf(IsPrivateSymbol(name), &private_symbol);
561 :
562 : // 2. Let handler be O.[[ProxyHandler]].
563 56 : Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
564 :
565 : // 3. If handler is null, throw a TypeError exception.
566 56 : GotoIfNot(IsJSReceiver(handler), &throw_proxy_handler_revoked);
567 :
568 : // 4. Assert: Type(handler) is Object.
569 : CSA_ASSERT(this, IsJSReceiver(handler));
570 :
571 : // 5. Let target be O.[[ProxyTarget]].
572 56 : Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
573 :
574 : // 6. Let trap be ? GetMethod(handler, "set").
575 : // 7. If trap is undefined, then (see 7.a below).
576 56 : Handle<Name> set_string = factory()->set_string();
577 56 : Node* trap = GetMethod(context, handler, set_string, &trap_undefined);
578 :
579 : // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler,
580 : // « target, P, V, Receiver »)).
581 : // 9. If booleanTrapResult is false, return false.
582 : BranchIfToBooleanIsTrue(
583 : CallJS(CodeFactory::Call(isolate(),
584 : ConvertReceiverMode::kNotNullOrUndefined),
585 : context, trap, handler, target, name, value, receiver),
586 56 : &continue_checks, &failure);
587 :
588 56 : BIND(&continue_checks);
589 : {
590 : // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
591 56 : Label return_result(this);
592 : CheckGetSetTrapResult(context, target, proxy, name, value, &success,
593 56 : JSProxy::kSet);
594 : }
595 :
596 56 : BIND(&failure);
597 : {
598 : CallRuntime(Runtime::kThrowTypeErrorIfStrict, context,
599 : SmiConstant(MessageTemplate::kProxyTrapReturnedFalsishFor),
600 56 : HeapConstant(set_string), name);
601 56 : Goto(&success);
602 : }
603 :
604 : // 12. Return true.
605 56 : BIND(&success);
606 56 : Return(value);
607 :
608 56 : BIND(&private_symbol);
609 : {
610 56 : Label failure(this);
611 :
612 : CallRuntime(Runtime::kThrowTypeErrorIfStrict, context,
613 56 : SmiConstant(MessageTemplate::kProxyPrivate));
614 56 : Return(UndefinedConstant());
615 : }
616 :
617 56 : BIND(&trap_undefined);
618 : {
619 : // 7.a. Return ? target.[[Set]](P, V, Receiver).
620 : CallRuntime(Runtime::kSetPropertyWithReceiver, context, target, name, value,
621 56 : receiver);
622 56 : Return(value);
623 : }
624 :
625 56 : BIND(&throw_proxy_handler_revoked);
626 112 : ThrowTypeError(context, MessageTemplate::kProxyRevoked, "set");
627 56 : }
628 :
629 112 : void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
630 : Node* context, Node* target, Node* proxy, Node* name, Node* trap_result,
631 : Label* check_passed, JSProxy::AccessKind access_kind) {
632 112 : Node* map = LoadMap(target);
633 112 : VARIABLE(var_value, MachineRepresentation::kTagged);
634 224 : VARIABLE(var_details, MachineRepresentation::kWord32);
635 224 : VARIABLE(var_raw_value, MachineRepresentation::kTagged);
636 :
637 224 : Label if_found_value(this), check_in_runtime(this, Label::kDeferred);
638 :
639 112 : Node* instance_type = LoadInstanceType(target);
640 : TryGetOwnProperty(context, target, target, map, instance_type, name,
641 : &if_found_value, &var_value, &var_details, &var_raw_value,
642 112 : check_passed, &check_in_runtime, kReturnAccessorPair);
643 :
644 112 : BIND(&if_found_value);
645 : {
646 112 : Label throw_non_configurable_data(this, Label::kDeferred),
647 224 : throw_non_configurable_accessor(this, Label::kDeferred),
648 224 : check_accessor(this), check_data(this);
649 :
650 : // If targetDesc is not undefined and targetDesc.[[Configurable]] is
651 : // false, then:
652 : GotoIfNot(IsSetWord32(var_details.value(),
653 224 : PropertyDetails::kAttributesDontDeleteMask),
654 112 : check_passed);
655 :
656 : // If IsDataDescriptor(targetDesc) is true and
657 : // targetDesc.[[Writable]] is false, then:
658 112 : BranchIfAccessorPair(var_raw_value.value(), &check_accessor, &check_data);
659 :
660 112 : BIND(&check_data);
661 : {
662 : Node* read_only = IsSetWord32(var_details.value(),
663 112 : PropertyDetails::kAttributesReadOnlyMask);
664 112 : GotoIfNot(read_only, check_passed);
665 :
666 : // If SameValue(trapResult, targetDesc.[[Value]]) is false,
667 : // throw a TypeError exception.
668 : BranchIfSameValue(trap_result, var_value.value(), check_passed,
669 112 : &throw_non_configurable_data);
670 : }
671 :
672 112 : BIND(&check_accessor);
673 : {
674 112 : Node* accessor_pair = var_raw_value.value();
675 :
676 112 : if (access_kind == JSProxy::kGet) {
677 56 : Label continue_check(this, Label::kDeferred);
678 : // 10.b. If IsAccessorDescriptor(targetDesc) is true and
679 : // targetDesc.[[Get]] is undefined, then:
680 : Node* getter =
681 56 : LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
682 : // Here we check for null as well because if the getter was never
683 : // defined it's set as null.
684 56 : GotoIf(IsUndefined(getter), &continue_check);
685 56 : GotoIf(IsNull(getter), &continue_check);
686 56 : Goto(check_passed);
687 :
688 : // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
689 56 : BIND(&continue_check);
690 56 : GotoIfNot(IsUndefined(trap_result), &throw_non_configurable_accessor);
691 : } else {
692 : // 11.b.i. If targetDesc.[[Set]] is undefined, throw a TypeError
693 : // exception.
694 : Node* setter =
695 56 : LoadObjectField(accessor_pair, AccessorPair::kSetterOffset);
696 56 : GotoIf(IsUndefined(setter), &throw_non_configurable_accessor);
697 56 : GotoIf(IsNull(setter), &throw_non_configurable_accessor);
698 : }
699 112 : Goto(check_passed);
700 : }
701 :
702 112 : BIND(&check_in_runtime);
703 : {
704 : CallRuntime(Runtime::kCheckProxyGetSetTrapResult, context, name, target,
705 112 : trap_result, SmiConstant(access_kind));
706 112 : Return(trap_result);
707 : }
708 :
709 112 : BIND(&throw_non_configurable_data);
710 : {
711 112 : if (access_kind == JSProxy::kGet) {
712 : ThrowTypeError(context, MessageTemplate::kProxyGetNonConfigurableData,
713 56 : name, var_value.value(), trap_result);
714 : } else {
715 56 : ThrowTypeError(context, MessageTemplate::kProxySetFrozenData, name);
716 : }
717 : }
718 :
719 112 : BIND(&throw_non_configurable_accessor);
720 : {
721 112 : if (access_kind == JSProxy::kGet) {
722 : ThrowTypeError(context,
723 : MessageTemplate::kProxyGetNonConfigurableAccessor, name,
724 56 : trap_result);
725 : } else {
726 56 : ThrowTypeError(context, MessageTemplate::kProxySetFrozenAccessor, name);
727 : }
728 112 : }
729 112 : }
730 112 : }
731 :
732 56 : void ProxiesCodeStubAssembler::CheckHasTrapResult(Node* context, Node* target,
733 : Node* proxy, Node* name,
734 : Label* check_passed,
735 : Label* if_bailout) {
736 56 : Node* target_map = LoadMap(target);
737 56 : VARIABLE(var_value, MachineRepresentation::kTagged);
738 112 : VARIABLE(var_details, MachineRepresentation::kWord32);
739 112 : VARIABLE(var_raw_value, MachineRepresentation::kTagged);
740 :
741 112 : Label if_found_value(this, Label::kDeferred),
742 112 : throw_non_configurable(this, Label::kDeferred),
743 112 : throw_non_extensible(this, Label::kDeferred);
744 :
745 : // 9.a. Let targetDesc be ? target.[[GetOwnProperty]](P).
746 56 : Node* instance_type = LoadInstanceType(target);
747 : TryGetOwnProperty(context, target, target, target_map, instance_type, name,
748 : &if_found_value, &var_value, &var_details, &var_raw_value,
749 56 : check_passed, if_bailout, kReturnAccessorPair);
750 :
751 : // 9.b. If targetDesc is not undefined, then (see 9.b.i. below).
752 56 : BIND(&if_found_value);
753 : {
754 : // 9.b.i. If targetDesc.[[Configurable]] is false, throw a TypeError
755 : // exception.
756 : Node* non_configurable = IsSetWord32(
757 56 : var_details.value(), PropertyDetails::kAttributesDontDeleteMask);
758 56 : GotoIf(non_configurable, &throw_non_configurable);
759 :
760 : // 9.b.ii. Let extensibleTarget be ? IsExtensible(target).
761 56 : Node* target_extensible = IsExtensibleMap(target_map);
762 :
763 : // 9.b.iii. If extensibleTarget is false, throw a TypeError exception.
764 56 : GotoIfNot(target_extensible, &throw_non_extensible);
765 56 : Goto(check_passed);
766 : }
767 :
768 56 : BIND(&throw_non_configurable);
769 56 : { ThrowTypeError(context, MessageTemplate::kProxyHasNonConfigurable, name); }
770 :
771 56 : BIND(&throw_non_extensible);
772 112 : { ThrowTypeError(context, MessageTemplate::kProxyHasNonExtensible, name); }
773 56 : }
774 :
775 : } // namespace internal
776 86739 : } // namespace v8
|