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