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