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