| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/code-stubs.h" | 5 #include "src/code-stubs.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "src/bailout-reason.h" | 9 #include "src/bailout-reason.h" |
| 10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
| (...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 369 { | 369 { |
| 370 HValue* argument = Add<HAccessArgumentsAt>(argument_elements, argc, key); | 370 HValue* argument = Add<HAccessArgumentsAt>(argument_elements, argc, key); |
| 371 HValue* index = AddUncasted<HAdd>(key, length); | 371 HValue* index = AddUncasted<HAdd>(key, length); |
| 372 AddElementAccess(elements, index, argument, object, nullptr, kind, STORE); | 372 AddElementAccess(elements, index, argument, object, nullptr, kind, STORE); |
| 373 } | 373 } |
| 374 builder.EndBody(); | 374 builder.EndBody(); |
| 375 return new_length; | 375 return new_length; |
| 376 } | 376 } |
| 377 | 377 |
| 378 template <> | 378 template <> |
| 379 HValue* CodeStubGraphBuilder<FastFunctionBindStub>::BuildCodeStub() { | |
| 380 // TODO(verwaest): Fix deoptimizer messages. | |
| 381 HValue* argc = GetArgumentsLength(); | |
| 382 HInstruction* argument_elements = Add<HArgumentsElements>(false, false); | |
| 383 HInstruction* object = Add<HAccessArgumentsAt>(argument_elements, argc, | |
| 384 graph()->GetConstantMinus1()); | |
| 385 BuildCheckHeapObject(object); | |
| 386 HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap()); | |
| 387 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_JS_FUNCTION); | |
| 388 | |
| 389 // Disallow binding of slow-mode functions. We need to figure out whether the | |
| 390 // length and name property are in the original state. | |
| 391 { | |
| 392 HValue* bit_field3 = | |
| 393 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3()); | |
| 394 HValue* mask = Add<HConstant>(static_cast<int>(Map::DictionaryMap::kMask)); | |
| 395 HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field3, mask); | |
| 396 IfBuilder check(this); | |
| 397 check.If<HCompareNumericAndBranch>(bit, mask, Token::EQ); | |
| 398 check.ThenDeopt(DeoptimizeReason::kFastPathFailed); | |
| 399 check.End(); | |
| 400 } | |
| 401 | |
| 402 // Check whether the length and name properties are still present as | |
| 403 // AccessorInfo objects. In that case, their value can be recomputed even if | |
| 404 // the actual value on the object changes. | |
| 405 { | |
| 406 HValue* descriptors = | |
| 407 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapDescriptors()); | |
| 408 | |
| 409 HValue* descriptors_length = Add<HLoadNamedField>( | |
| 410 descriptors, nullptr, HObjectAccess::ForFixedArrayLength()); | |
| 411 IfBuilder range(this); | |
| 412 range.If<HCompareNumericAndBranch>(descriptors_length, | |
| 413 graph()->GetConstant1(), Token::LTE); | |
| 414 range.ThenDeopt(DeoptimizeReason::kFastPathFailed); | |
| 415 range.End(); | |
| 416 | |
| 417 // Verify .length. | |
| 418 const int length_index = JSFunction::kLengthDescriptorIndex; | |
| 419 HValue* maybe_length = Add<HLoadKeyed>( | |
| 420 descriptors, Add<HConstant>(DescriptorArray::ToKeyIndex(length_index)), | |
| 421 nullptr, nullptr, FAST_ELEMENTS); | |
| 422 Unique<Name> length_string = Unique<Name>::CreateUninitialized( | |
| 423 isolate()->factory()->length_string()); | |
| 424 Add<HCheckValue>(maybe_length, length_string, false); | |
| 425 | |
| 426 HValue* maybe_length_accessor = Add<HLoadKeyed>( | |
| 427 descriptors, | |
| 428 Add<HConstant>(DescriptorArray::ToValueIndex(length_index)), nullptr, | |
| 429 nullptr, FAST_ELEMENTS); | |
| 430 BuildCheckHeapObject(maybe_length_accessor); | |
| 431 Add<HCheckMaps>(maybe_length_accessor, | |
| 432 isolate()->factory()->accessor_info_map()); | |
| 433 | |
| 434 // Verify .name. | |
| 435 const int name_index = JSFunction::kNameDescriptorIndex; | |
| 436 HValue* maybe_name = Add<HLoadKeyed>( | |
| 437 descriptors, Add<HConstant>(DescriptorArray::ToKeyIndex(name_index)), | |
| 438 nullptr, nullptr, FAST_ELEMENTS); | |
| 439 Unique<Name> name_string = | |
| 440 Unique<Name>::CreateUninitialized(isolate()->factory()->name_string()); | |
| 441 Add<HCheckValue>(maybe_name, name_string, false); | |
| 442 | |
| 443 HValue* maybe_name_accessor = Add<HLoadKeyed>( | |
| 444 descriptors, Add<HConstant>(DescriptorArray::ToValueIndex(name_index)), | |
| 445 nullptr, nullptr, FAST_ELEMENTS); | |
| 446 BuildCheckHeapObject(maybe_name_accessor); | |
| 447 Add<HCheckMaps>(maybe_name_accessor, | |
| 448 isolate()->factory()->accessor_info_map()); | |
| 449 } | |
| 450 | |
| 451 // Choose the right bound function map based on whether the target is | |
| 452 // constructable. | |
| 453 { | |
| 454 HValue* bit_field = | |
| 455 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField()); | |
| 456 HValue* mask = Add<HConstant>(static_cast<int>(1 << Map::kIsConstructor)); | |
| 457 HValue* bits = AddUncasted<HBitwise>(Token::BIT_AND, bit_field, mask); | |
| 458 | |
| 459 HValue* native_context = BuildGetNativeContext(); | |
| 460 IfBuilder is_constructor(this); | |
| 461 is_constructor.If<HCompareNumericAndBranch>(bits, mask, Token::EQ); | |
| 462 is_constructor.Then(); | |
| 463 { | |
| 464 HValue* map = Add<HLoadNamedField>( | |
| 465 native_context, nullptr, | |
| 466 HObjectAccess::ForContextSlot( | |
| 467 Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX)); | |
| 468 environment()->Push(map); | |
| 469 } | |
| 470 is_constructor.Else(); | |
| 471 { | |
| 472 HValue* map = Add<HLoadNamedField>( | |
| 473 native_context, nullptr, | |
| 474 HObjectAccess::ForContextSlot( | |
| 475 Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX)); | |
| 476 environment()->Push(map); | |
| 477 } | |
| 478 is_constructor.End(); | |
| 479 } | |
| 480 HValue* bound_function_map = environment()->Pop(); | |
| 481 | |
| 482 // Verify that __proto__ matches that of a the target bound function. | |
| 483 { | |
| 484 HValue* prototype = | |
| 485 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForPrototype()); | |
| 486 HValue* expected_prototype = Add<HLoadNamedField>( | |
| 487 bound_function_map, nullptr, HObjectAccess::ForPrototype()); | |
| 488 IfBuilder equal_prototype(this); | |
| 489 equal_prototype.IfNot<HCompareObjectEqAndBranch>(prototype, | |
| 490 expected_prototype); | |
| 491 equal_prototype.ThenDeopt(DeoptimizeReason::kFastPathFailed); | |
| 492 equal_prototype.End(); | |
| 493 } | |
| 494 | |
| 495 // Allocate the arguments array. | |
| 496 IfBuilder empty_args(this); | |
| 497 empty_args.If<HCompareNumericAndBranch>(argc, graph()->GetConstant1(), | |
| 498 Token::LTE); | |
| 499 empty_args.Then(); | |
| 500 { environment()->Push(Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex)); } | |
| 501 empty_args.Else(); | |
| 502 { | |
| 503 HValue* elements_length = AddUncasted<HSub>(argc, graph()->GetConstant1()); | |
| 504 HValue* elements = | |
| 505 BuildAllocateAndInitializeArray(FAST_ELEMENTS, elements_length); | |
| 506 | |
| 507 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement); | |
| 508 HValue* start = graph()->GetConstant1(); | |
| 509 HValue* key = builder.BeginBody(start, argc, Token::LT); | |
| 510 { | |
| 511 HValue* argument = Add<HAccessArgumentsAt>(argument_elements, argc, key); | |
| 512 HValue* index = AddUncasted<HSub>(key, graph()->GetConstant1()); | |
| 513 AddElementAccess(elements, index, argument, elements, nullptr, | |
| 514 FAST_ELEMENTS, STORE); | |
| 515 } | |
| 516 builder.EndBody(); | |
| 517 environment()->Push(elements); | |
| 518 } | |
| 519 empty_args.End(); | |
| 520 HValue* elements = environment()->Pop(); | |
| 521 | |
| 522 // Find the 'this' to bind. | |
| 523 IfBuilder no_receiver(this); | |
| 524 no_receiver.If<HCompareNumericAndBranch>(argc, graph()->GetConstant0(), | |
| 525 Token::EQ); | |
| 526 no_receiver.Then(); | |
| 527 { environment()->Push(Add<HLoadRoot>(Heap::kUndefinedValueRootIndex)); } | |
| 528 no_receiver.Else(); | |
| 529 { | |
| 530 environment()->Push(Add<HAccessArgumentsAt>(argument_elements, argc, | |
| 531 graph()->GetConstant0())); | |
| 532 } | |
| 533 no_receiver.End(); | |
| 534 HValue* receiver = environment()->Pop(); | |
| 535 | |
| 536 // Allocate the resulting bound function. | |
| 537 HValue* size = Add<HConstant>(JSBoundFunction::kSize); | |
| 538 HValue* bound_function = | |
| 539 Add<HAllocate>(size, HType::JSObject(), NOT_TENURED, | |
| 540 JS_BOUND_FUNCTION_TYPE, graph()->GetConstant0()); | |
| 541 Add<HStoreNamedField>(bound_function, HObjectAccess::ForMap(), | |
| 542 bound_function_map); | |
| 543 HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex); | |
| 544 Add<HStoreNamedField>(bound_function, HObjectAccess::ForPropertiesPointer(), | |
| 545 empty_fixed_array); | |
| 546 Add<HStoreNamedField>(bound_function, HObjectAccess::ForElementsPointer(), | |
| 547 empty_fixed_array); | |
| 548 Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundTargetFunction(), | |
| 549 object); | |
| 550 | |
| 551 Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundThis(), | |
| 552 receiver); | |
| 553 Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundArguments(), | |
| 554 elements); | |
| 555 | |
| 556 return bound_function; | |
| 557 } | |
| 558 | |
| 559 Handle<Code> FastFunctionBindStub::GenerateCode() { | |
| 560 return DoGenerateCode(this); | |
| 561 } | |
| 562 | |
| 563 template <> | |
| 564 HValue* CodeStubGraphBuilder<LoadFastElementStub>::BuildCodeStub() { | 379 HValue* CodeStubGraphBuilder<LoadFastElementStub>::BuildCodeStub() { |
| 565 LoadKeyedHoleMode hole_mode = casted_stub()->convert_hole_to_undefined() | 380 LoadKeyedHoleMode hole_mode = casted_stub()->convert_hole_to_undefined() |
| 566 ? CONVERT_HOLE_TO_UNDEFINED | 381 ? CONVERT_HOLE_TO_UNDEFINED |
| 567 : NEVER_RETURN_HOLE; | 382 : NEVER_RETURN_HOLE; |
| 568 | 383 |
| 569 HInstruction* load = BuildUncheckedMonomorphicElementAccess( | 384 HInstruction* load = BuildUncheckedMonomorphicElementAccess( |
| 570 GetParameter(Descriptor::kReceiver), GetParameter(Descriptor::kName), | 385 GetParameter(Descriptor::kReceiver), GetParameter(Descriptor::kName), |
| 571 NULL, casted_stub()->is_js_array(), casted_stub()->elements_kind(), LOAD, | 386 NULL, casted_stub()->is_js_array(), casted_stub()->elements_kind(), LOAD, |
| 572 hole_mode, STANDARD_STORE); | 387 hole_mode, STANDARD_STORE); |
| 573 return load; | 388 return load; |
| (...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 997 return BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash); | 812 return BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash); |
| 998 } | 813 } |
| 999 | 814 |
| 1000 | 815 |
| 1001 Handle<Code> LoadDictionaryElementStub::GenerateCode() { | 816 Handle<Code> LoadDictionaryElementStub::GenerateCode() { |
| 1002 return DoGenerateCode(this); | 817 return DoGenerateCode(this); |
| 1003 } | 818 } |
| 1004 | 819 |
| 1005 } // namespace internal | 820 } // namespace internal |
| 1006 } // namespace v8 | 821 } // namespace v8 |
| OLD | NEW |