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 448 : 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 224 : 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 112 : map.Bind(
42 224 : LoadContextElement(nativeContext, Context::PROXY_CALLABLE_MAP_INDEX));
43 112 : Goto(&create_proxy);
44 : }
45 112 : BIND(&constructor_target);
46 : {
47 224 : map.Bind(LoadContextElement(nativeContext,
48 336 : 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 112 : 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 224 : Label if_large_object(this, Label::kDeferred);
80 224 : Node* allocated_elements = AllocateFixedArray(PACKED_ELEMENTS, argc, mode,
81 336 : 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 224 : GotoIf(SmiGreaterThan(length, SmiConstant(FixedArray::kMaxRegularLength)),
89 112 : &if_large_object);
90 448 : args.ForEach(list, [=, &offset](Node* arg) {
91 224 : StoreNoWriteBarrier(MachineRepresentation::kTagged, allocated_elements,
92 448 : offset.value(), arg);
93 224 : Increment(&offset, kTaggedSize);
94 224 : });
95 112 : Goto(&allocate_js_array);
96 :
97 112 : BIND(&if_large_object);
98 : {
99 448 : args.ForEach(list, [=, &offset](Node* arg) {
100 224 : Store(allocated_elements, offset.value(), arg);
101 224 : Increment(&offset, kTaggedSize);
102 224 : });
103 112 : Goto(&allocate_js_array);
104 : }
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 112 : Node* const revoke_map = LoadContextElement(
140 168 : 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 56 : 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 112 : 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 56 : ThrowTypeError(context, MessageTemplate::kProxyHandlerOrTargetRevoked);
204 : }
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 112 : 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 112 : Node* const result_map = LoadContextElement(
230 168 : native_context, Context::PROXY_REVOCABLE_RESULT_MAP_INDEX);
231 56 : StoreMapNoWriteBarrier(result, result_map);
232 56 : StoreObjectFieldRoot(result, JSProxyRevocableResult::kPropertiesOrHashOffset,
233 56 : RootIndex::kEmptyFixedArray);
234 56 : StoreObjectFieldRoot(result, JSProxyRevocableResult::kElementsOffset,
235 56 : RootIndex::kEmptyFixedArray);
236 56 : StoreObjectFieldNoWriteBarrier(result, JSProxyRevocableResult::kProxyOffset,
237 56 : proxy);
238 56 : 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 56 : ThrowTypeError(context, MessageTemplate::kProxyHandlerOrTargetRevoked);
247 56 : }
248 :
249 392 : TF_BUILTIN(CallProxy, ProxiesCodeStubAssembler) {
250 56 : Node* argc = Parameter(Descriptor::kActualArgumentsCount);
251 56 : Node* argc_ptr = ChangeInt32ToIntPtr(argc);
252 56 : Node* proxy = Parameter(Descriptor::kFunction);
253 56 : Node* context = Parameter(Descriptor::kContext);
254 :
255 : CSA_ASSERT(this, IsJSProxy(proxy));
256 : CSA_ASSERT(this, IsCallable(proxy));
257 :
258 56 : PerformStackCheck(CAST(context));
259 :
260 112 : Label throw_proxy_handler_revoked(this, Label::kDeferred),
261 112 : trap_undefined(this);
262 :
263 : // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
264 56 : Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
265 :
266 : // 2. If handler is null, throw a TypeError exception.
267 : CSA_ASSERT(this, IsNullOrJSReceiver(handler));
268 56 : GotoIfNot(IsJSReceiver(handler), &throw_proxy_handler_revoked);
269 :
270 : // 3. Assert: Type(handler) is Object.
271 : CSA_ASSERT(this, IsJSReceiver(handler));
272 :
273 : // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
274 56 : Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
275 :
276 : // 5. Let trap be ? GetMethod(handler, "apply").
277 : // 6. If trap is undefined, then
278 56 : Handle<Name> trap_name = factory()->apply_string();
279 56 : Node* trap = GetMethod(context, handler, trap_name, &trap_undefined);
280 :
281 56 : CodeStubArguments args(this, argc_ptr);
282 56 : Node* receiver = args.GetReceiver();
283 :
284 : // 7. Let argArray be CreateArrayFromList(argumentsList).
285 56 : Node* array = AllocateJSArrayForCodeStubArguments(context, args, argc_ptr,
286 56 : INTPTR_PARAMETERS);
287 :
288 : // 8. Return Call(trap, handler, «target, thisArgument, argArray»).
289 112 : Node* result = CallJS(CodeFactory::Call(isolate()), context, trap, handler,
290 56 : target, receiver, array);
291 56 : args.PopAndReturn(result);
292 :
293 56 : BIND(&trap_undefined);
294 : {
295 : // 6.a. Return Call(target, thisArgument, argumentsList).
296 56 : TailCallStub(CodeFactory::Call(isolate()), context, target, argc);
297 : }
298 :
299 56 : BIND(&throw_proxy_handler_revoked);
300 56 : { ThrowTypeError(context, MessageTemplate::kProxyRevoked, "apply"); }
301 56 : }
302 :
303 448 : TF_BUILTIN(ConstructProxy, ProxiesCodeStubAssembler) {
304 56 : Node* argc = Parameter(Descriptor::kActualArgumentsCount);
305 56 : Node* argc_ptr = ChangeInt32ToIntPtr(argc);
306 56 : Node* proxy = Parameter(Descriptor::kTarget);
307 56 : Node* new_target = Parameter(Descriptor::kNewTarget);
308 56 : Node* context = Parameter(Descriptor::kContext);
309 :
310 : CSA_ASSERT(this, IsJSProxy(proxy));
311 : CSA_ASSERT(this, IsCallable(proxy));
312 :
313 112 : Label throw_proxy_handler_revoked(this, Label::kDeferred),
314 112 : trap_undefined(this), not_an_object(this, Label::kDeferred);
315 :
316 : // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
317 56 : Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
318 :
319 : // 2. If handler is null, throw a TypeError exception.
320 : CSA_ASSERT(this, IsNullOrJSReceiver(handler));
321 56 : GotoIfNot(IsJSReceiver(handler), &throw_proxy_handler_revoked);
322 :
323 : // 3. Assert: Type(handler) is Object.
324 : CSA_ASSERT(this, IsJSReceiver(handler));
325 :
326 : // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
327 56 : Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
328 :
329 : // 5. Let trap be ? GetMethod(handler, "construct").
330 : // 6. If trap is undefined, then
331 56 : Handle<Name> trap_name = factory()->construct_string();
332 56 : Node* trap = GetMethod(context, handler, trap_name, &trap_undefined);
333 :
334 56 : CodeStubArguments args(this, argc_ptr);
335 :
336 : // 7. Let argArray be CreateArrayFromList(argumentsList).
337 56 : Node* array = AllocateJSArrayForCodeStubArguments(context, args, argc_ptr,
338 56 : INTPTR_PARAMETERS);
339 :
340 : // 8. Let newObj be ? Call(trap, handler, « target, argArray, newTarget »).
341 112 : Node* new_obj = CallJS(CodeFactory::Call(isolate()), context, trap, handler,
342 56 : target, array, new_target);
343 :
344 : // 9. If Type(newObj) is not Object, throw a TypeError exception.
345 56 : GotoIf(TaggedIsSmi(new_obj), ¬_an_object);
346 56 : GotoIfNot(IsJSReceiver(new_obj), ¬_an_object);
347 :
348 : // 10. Return newObj.
349 56 : args.PopAndReturn(new_obj);
350 :
351 56 : BIND(¬_an_object);
352 : {
353 56 : ThrowTypeError(context, MessageTemplate::kProxyConstructNonObject, new_obj);
354 : }
355 :
356 56 : BIND(&trap_undefined);
357 : {
358 : // 6.a. Assert: target has a [[Construct]] internal method.
359 : CSA_ASSERT(this, IsConstructor(target));
360 :
361 : // 6.b. Return ? Construct(target, argumentsList, newTarget).
362 112 : TailCallStub(CodeFactory::Construct(isolate()), context, target, new_target,
363 56 : argc);
364 : }
365 :
366 56 : BIND(&throw_proxy_handler_revoked);
367 56 : { ThrowTypeError(context, MessageTemplate::kProxyRevoked, "construct"); }
368 56 : }
369 :
370 392 : TF_BUILTIN(ProxyHasProperty, ProxiesCodeStubAssembler) {
371 56 : Node* context = Parameter(Descriptor::kContext);
372 56 : Node* proxy = Parameter(Descriptor::kProxy);
373 56 : Node* name = Parameter(Descriptor::kName);
374 :
375 : CSA_ASSERT(this, IsJSProxy(proxy));
376 :
377 56 : PerformStackCheck(CAST(context));
378 :
379 : // 1. Assert: IsPropertyKey(P) is true.
380 : CSA_ASSERT(this, IsName(name));
381 : CSA_ASSERT(this, Word32Equal(IsPrivateSymbol(name), Int32Constant(0)));
382 :
383 112 : Label throw_proxy_handler_revoked(this, Label::kDeferred),
384 112 : trap_undefined(this),
385 112 : if_try_get_own_property_bailout(this, Label::kDeferred),
386 112 : trap_not_callable(this, Label::kDeferred), return_true(this),
387 112 : return_false(this), check_target_desc(this);
388 :
389 : // 2. Let handler be O.[[ProxyHandler]].
390 56 : Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
391 :
392 : // 3. If handler is null, throw a TypeError exception.
393 : // 4. Assert: Type(handler) is Object.
394 56 : GotoIfNot(IsJSReceiver(handler), &throw_proxy_handler_revoked);
395 :
396 : // 5. Let target be O.[[ProxyTarget]].
397 56 : Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
398 :
399 : // 6. Let trap be ? GetMethod(handler, "has").
400 : // 7. If trap is undefined, then (see 7.a below).
401 56 : Handle<Name> trap_name = factory()->has_string();
402 56 : Node* trap = GetMethod(context, handler, trap_name, &trap_undefined);
403 :
404 56 : GotoIf(TaggedIsSmi(trap), &trap_not_callable);
405 56 : GotoIfNot(IsCallable(trap), &trap_not_callable);
406 :
407 : // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, P
408 : // »)).
409 112 : BranchIfToBooleanIsTrue(CallJS(CodeFactory::Call(isolate()), context, trap,
410 : handler, target, name),
411 56 : &return_true, &check_target_desc);
412 :
413 56 : BIND(&check_target_desc);
414 : {
415 : // 9. If booleanTrapResult is false, then (see 9.a. in CheckHasTrapResult).
416 56 : CheckHasTrapResult(context, target, proxy, name, &return_false,
417 56 : &if_try_get_own_property_bailout);
418 : }
419 :
420 56 : BIND(&if_try_get_own_property_bailout);
421 : {
422 56 : CallRuntime(Runtime::kCheckProxyHasTrap, context, name, target);
423 56 : Return(FalseConstant());
424 : }
425 :
426 56 : BIND(&trap_undefined);
427 : {
428 : // 7.a. Return ? target.[[HasProperty]](P).
429 56 : TailCallBuiltin(Builtins::kHasProperty, context, target, name);
430 : }
431 :
432 56 : BIND(&return_false);
433 56 : Return(FalseConstant());
434 :
435 56 : BIND(&return_true);
436 56 : Return(TrueConstant());
437 :
438 56 : BIND(&throw_proxy_handler_revoked);
439 56 : ThrowTypeError(context, MessageTemplate::kProxyRevoked, "has");
440 :
441 56 : BIND(&trap_not_callable);
442 56 : ThrowTypeError(context, MessageTemplate::kPropertyNotFunction, trap,
443 112 : StringConstant("has"), proxy);
444 56 : }
445 :
446 504 : TF_BUILTIN(ProxyGetProperty, ProxiesCodeStubAssembler) {
447 56 : Node* context = Parameter(Descriptor::kContext);
448 56 : Node* proxy = Parameter(Descriptor::kProxy);
449 56 : Node* name = Parameter(Descriptor::kName);
450 56 : Node* receiver = Parameter(Descriptor::kReceiverValue);
451 56 : Node* on_non_existent = Parameter(Descriptor::kOnNonExistent);
452 :
453 : CSA_ASSERT(this, IsJSProxy(proxy));
454 :
455 : // 1. Assert: IsPropertyKey(P) is true.
456 : CSA_ASSERT(this, TaggedIsNotSmi(name));
457 : CSA_ASSERT(this, IsName(name));
458 : CSA_ASSERT(this, Word32Equal(IsPrivateSymbol(name), Int32Constant(0)));
459 :
460 112 : Label throw_proxy_handler_revoked(this, Label::kDeferred),
461 112 : trap_undefined(this);
462 :
463 : // 2. Let handler be O.[[ProxyHandler]].
464 56 : Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
465 :
466 : // 3. If handler is null, throw a TypeError exception.
467 56 : GotoIf(IsNull(handler), &throw_proxy_handler_revoked);
468 :
469 : // 4. Assert: Type(handler) is Object.
470 : CSA_ASSERT(this, IsJSReceiver(handler));
471 :
472 : // 5. Let target be O.[[ProxyTarget]].
473 56 : Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
474 :
475 : // 6. Let trap be ? GetMethod(handler, "get").
476 : // 7. If trap is undefined, then (see 7.a below).
477 56 : Handle<Name> trap_name = factory()->get_string();
478 56 : Node* trap = GetMethod(context, handler, trap_name, &trap_undefined);
479 :
480 : // 8. Let trapResult be ? Call(trap, handler, « target, P, Receiver »).
481 56 : Node* trap_result = CallJS(
482 112 : CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined),
483 56 : context, trap, handler, target, name, receiver);
484 :
485 : // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
486 112 : Label return_result(this);
487 56 : CheckGetSetTrapResult(context, target, proxy, name, trap_result,
488 56 : &return_result, JSProxy::kGet);
489 :
490 56 : BIND(&return_result);
491 : {
492 : // 11. Return trapResult.
493 56 : Return(trap_result);
494 : }
495 :
496 56 : BIND(&trap_undefined);
497 : {
498 : // 7.a. Return ? target.[[Get]](P, Receiver).
499 : // TODO(mslekova): Introduce GetPropertyWithReceiver stub
500 112 : Return(CallRuntime(Runtime::kGetPropertyWithReceiver, context, target, name,
501 168 : receiver, on_non_existent));
502 : }
503 :
504 56 : BIND(&throw_proxy_handler_revoked);
505 56 : ThrowTypeError(context, MessageTemplate::kProxyRevoked, "get");
506 56 : }
507 :
508 504 : TF_BUILTIN(ProxySetProperty, ProxiesCodeStubAssembler) {
509 56 : Node* context = Parameter(Descriptor::kContext);
510 56 : Node* proxy = Parameter(Descriptor::kProxy);
511 56 : Node* name = Parameter(Descriptor::kName);
512 56 : Node* value = Parameter(Descriptor::kValue);
513 56 : Node* receiver = Parameter(Descriptor::kReceiverValue);
514 :
515 : CSA_ASSERT(this, IsJSProxy(proxy));
516 :
517 : // 1. Assert: IsPropertyKey(P) is true.
518 : CSA_ASSERT(this, TaggedIsNotSmi(name));
519 : CSA_ASSERT(this, IsName(name));
520 :
521 112 : Label throw_proxy_handler_revoked(this, Label::kDeferred),
522 112 : trap_undefined(this), failure(this, Label::kDeferred),
523 112 : continue_checks(this), success(this),
524 112 : private_symbol(this, Label::kDeferred);
525 :
526 56 : GotoIf(IsPrivateSymbol(name), &private_symbol);
527 :
528 : // 2. Let handler be O.[[ProxyHandler]].
529 56 : Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
530 :
531 : // 3. If handler is null, throw a TypeError exception.
532 56 : GotoIfNot(IsJSReceiver(handler), &throw_proxy_handler_revoked);
533 :
534 : // 4. Assert: Type(handler) is Object.
535 : CSA_ASSERT(this, IsJSReceiver(handler));
536 :
537 : // 5. Let target be O.[[ProxyTarget]].
538 56 : Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
539 :
540 : // 6. Let trap be ? GetMethod(handler, "set").
541 : // 7. If trap is undefined, then (see 7.a below).
542 56 : Handle<Name> set_string = factory()->set_string();
543 56 : Node* trap = GetMethod(context, handler, set_string, &trap_undefined);
544 :
545 : // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler,
546 : // « target, P, V, Receiver »)).
547 : // 9. If booleanTrapResult is false, return false.
548 56 : BranchIfToBooleanIsTrue(
549 112 : CallJS(CodeFactory::Call(isolate(),
550 : ConvertReceiverMode::kNotNullOrUndefined),
551 : context, trap, handler, target, name, value, receiver),
552 56 : &continue_checks, &failure);
553 :
554 56 : BIND(&continue_checks);
555 : {
556 : // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
557 112 : Label return_result(this);
558 56 : CheckGetSetTrapResult(context, target, proxy, name, value, &success,
559 56 : JSProxy::kSet);
560 : }
561 :
562 56 : BIND(&failure);
563 : {
564 : CallRuntime(Runtime::kThrowTypeErrorIfStrict, context,
565 : SmiConstant(MessageTemplate::kProxyTrapReturnedFalsishFor),
566 56 : HeapConstant(set_string), name);
567 56 : Goto(&success);
568 : }
569 :
570 : // 12. Return true.
571 56 : BIND(&success);
572 56 : Return(value);
573 :
574 56 : BIND(&private_symbol);
575 : {
576 112 : Label failure(this);
577 :
578 : CallRuntime(Runtime::kThrowTypeErrorIfStrict, context,
579 56 : SmiConstant(MessageTemplate::kProxyPrivate));
580 56 : Return(UndefinedConstant());
581 : }
582 :
583 56 : BIND(&trap_undefined);
584 : {
585 : // 7.a. Return ? target.[[Set]](P, V, Receiver).
586 : CallRuntime(Runtime::kSetPropertyWithReceiver, context, target, name, value,
587 56 : receiver);
588 56 : Return(value);
589 : }
590 :
591 56 : BIND(&throw_proxy_handler_revoked);
592 56 : ThrowTypeError(context, MessageTemplate::kProxyRevoked, "set");
593 56 : }
594 :
595 112 : void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
596 : Node* context, Node* target, Node* proxy, Node* name, Node* trap_result,
597 : Label* check_passed, JSProxy::AccessKind access_kind) {
598 112 : Node* map = LoadMap(target);
599 224 : VARIABLE(var_value, MachineRepresentation::kTagged);
600 224 : VARIABLE(var_details, MachineRepresentation::kWord32);
601 224 : VARIABLE(var_raw_value, MachineRepresentation::kTagged);
602 :
603 224 : Label if_found_value(this), check_in_runtime(this, Label::kDeferred);
604 :
605 112 : GotoIfNot(IsUniqueNameNoIndex(CAST(name)), &check_in_runtime);
606 112 : Node* instance_type = LoadInstanceType(target);
607 112 : TryGetOwnProperty(context, target, target, map, instance_type, name,
608 : &if_found_value, &var_value, &var_details, &var_raw_value,
609 112 : check_passed, &check_in_runtime, kReturnAccessorPair);
610 :
611 112 : BIND(&if_found_value);
612 : {
613 224 : Label throw_non_configurable_data(this, Label::kDeferred),
614 224 : throw_non_configurable_accessor(this, Label::kDeferred),
615 224 : check_accessor(this), check_data(this);
616 :
617 : // If targetDesc is not undefined and targetDesc.[[Configurable]] is
618 : // false, then:
619 224 : GotoIfNot(IsSetWord32(var_details.value(),
620 224 : PropertyDetails::kAttributesDontDeleteMask),
621 112 : check_passed);
622 :
623 : // If IsDataDescriptor(targetDesc) is true and
624 : // targetDesc.[[Writable]] is false, then:
625 112 : BranchIfAccessorPair(var_raw_value.value(), &check_accessor, &check_data);
626 :
627 112 : BIND(&check_data);
628 : {
629 224 : Node* read_only = IsSetWord32(var_details.value(),
630 336 : PropertyDetails::kAttributesReadOnlyMask);
631 112 : GotoIfNot(read_only, check_passed);
632 :
633 : // If SameValue(trapResult, targetDesc.[[Value]]) is false,
634 : // throw a TypeError exception.
635 112 : BranchIfSameValue(trap_result, var_value.value(), check_passed,
636 112 : &throw_non_configurable_data);
637 : }
638 :
639 112 : BIND(&check_accessor);
640 : {
641 112 : Node* accessor_pair = var_raw_value.value();
642 :
643 112 : if (access_kind == JSProxy::kGet) {
644 112 : Label continue_check(this, Label::kDeferred);
645 : // 10.b. If IsAccessorDescriptor(targetDesc) is true and
646 : // targetDesc.[[Get]] is undefined, then:
647 : Node* getter =
648 56 : LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
649 : // Here we check for null as well because if the getter was never
650 : // defined it's set as null.
651 56 : GotoIf(IsUndefined(getter), &continue_check);
652 56 : GotoIf(IsNull(getter), &continue_check);
653 56 : Goto(check_passed);
654 :
655 : // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
656 56 : BIND(&continue_check);
657 56 : GotoIfNot(IsUndefined(trap_result), &throw_non_configurable_accessor);
658 : } else {
659 : // 11.b.i. If targetDesc.[[Set]] is undefined, throw a TypeError
660 : // exception.
661 : Node* setter =
662 56 : LoadObjectField(accessor_pair, AccessorPair::kSetterOffset);
663 56 : GotoIf(IsUndefined(setter), &throw_non_configurable_accessor);
664 56 : GotoIf(IsNull(setter), &throw_non_configurable_accessor);
665 : }
666 112 : Goto(check_passed);
667 : }
668 :
669 112 : BIND(&check_in_runtime);
670 : {
671 : CallRuntime(Runtime::kCheckProxyGetSetTrapResult, context, name, target,
672 112 : trap_result, SmiConstant(access_kind));
673 112 : Return(trap_result);
674 : }
675 :
676 112 : BIND(&throw_non_configurable_data);
677 : {
678 112 : if (access_kind == JSProxy::kGet) {
679 56 : ThrowTypeError(context, MessageTemplate::kProxyGetNonConfigurableData,
680 56 : name, var_value.value(), trap_result);
681 : } else {
682 56 : ThrowTypeError(context, MessageTemplate::kProxySetFrozenData, name);
683 : }
684 : }
685 :
686 112 : BIND(&throw_non_configurable_accessor);
687 : {
688 112 : if (access_kind == JSProxy::kGet) {
689 56 : ThrowTypeError(context,
690 : MessageTemplate::kProxyGetNonConfigurableAccessor, name,
691 56 : trap_result);
692 : } else {
693 56 : ThrowTypeError(context, MessageTemplate::kProxySetFrozenAccessor, name);
694 : }
695 : }
696 : }
697 112 : }
698 :
699 56 : void ProxiesCodeStubAssembler::CheckHasTrapResult(Node* context, Node* target,
700 : Node* proxy, Node* name,
701 : Label* check_passed,
702 : Label* if_bailout) {
703 56 : Node* target_map = LoadMap(target);
704 112 : VARIABLE(var_value, MachineRepresentation::kTagged);
705 112 : VARIABLE(var_details, MachineRepresentation::kWord32);
706 112 : VARIABLE(var_raw_value, MachineRepresentation::kTagged);
707 :
708 112 : Label if_found_value(this, Label::kDeferred),
709 112 : throw_non_configurable(this, Label::kDeferred),
710 112 : throw_non_extensible(this, Label::kDeferred);
711 :
712 : // 9.a. Let targetDesc be ? target.[[GetOwnProperty]](P).
713 56 : GotoIfNot(IsUniqueNameNoIndex(CAST(name)), if_bailout);
714 56 : Node* instance_type = LoadInstanceType(target);
715 56 : TryGetOwnProperty(context, target, target, target_map, instance_type, name,
716 : &if_found_value, &var_value, &var_details, &var_raw_value,
717 56 : check_passed, if_bailout, kReturnAccessorPair);
718 :
719 : // 9.b. If targetDesc is not undefined, then (see 9.b.i. below).
720 56 : BIND(&if_found_value);
721 : {
722 : // 9.b.i. If targetDesc.[[Configurable]] is false, throw a TypeError
723 : // exception.
724 112 : Node* non_configurable = IsSetWord32(
725 168 : var_details.value(), PropertyDetails::kAttributesDontDeleteMask);
726 56 : GotoIf(non_configurable, &throw_non_configurable);
727 :
728 : // 9.b.ii. Let extensibleTarget be ? IsExtensible(target).
729 56 : Node* target_extensible = IsExtensibleMap(target_map);
730 :
731 : // 9.b.iii. If extensibleTarget is false, throw a TypeError exception.
732 56 : GotoIfNot(target_extensible, &throw_non_extensible);
733 56 : Goto(check_passed);
734 : }
735 :
736 56 : BIND(&throw_non_configurable);
737 56 : { ThrowTypeError(context, MessageTemplate::kProxyHasNonConfigurable, name); }
738 :
739 56 : BIND(&throw_non_extensible);
740 56 : { ThrowTypeError(context, MessageTemplate::kProxyHasNonExtensible, name); }
741 56 : }
742 :
743 : } // namespace internal
744 87414 : } // namespace v8
|