OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 642 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
653 | 653 |
654 private: | 654 private: |
655 Label patch_site_; | 655 Label patch_site_; |
656 Register dst_; | 656 Register dst_; |
657 Register receiver_; | 657 Register receiver_; |
658 Register key_; | 658 Register key_; |
659 }; | 659 }; |
660 | 660 |
661 | 661 |
662 void DeferredReferenceGetKeyedValue::Generate() { | 662 void DeferredReferenceGetKeyedValue::Generate() { |
663 __ push(receiver_); // First IC argument. | 663 if (receiver_.is(rdx)) { |
664 __ push(key_); // Second IC argument. | 664 if (!key_.is(rax)) { |
665 | 665 __ movq(rax, key_); |
| 666 } // else do nothing. |
| 667 } else if (receiver_.is(rax)) { |
| 668 if (key_.is(rdx)) { |
| 669 __ xchg(rax, rdx); |
| 670 } else if (key_.is(rax)) { |
| 671 __ movq(rdx, receiver_); |
| 672 } else { |
| 673 __ movq(rdx, receiver_); |
| 674 __ movq(rax, key_); |
| 675 } |
| 676 } else if (key_.is(rax)) { |
| 677 __ movq(rdx, receiver_); |
| 678 } else { |
| 679 __ movq(rax, key_); |
| 680 __ movq(rdx, receiver_); |
| 681 } |
666 // Calculate the delta from the IC call instruction to the map check | 682 // Calculate the delta from the IC call instruction to the map check |
667 // movq instruction in the inlined version. This delta is stored in | 683 // movq instruction in the inlined version. This delta is stored in |
668 // a test(rax, delta) instruction after the call so that we can find | 684 // a test(rax, delta) instruction after the call so that we can find |
669 // it in the IC initialization code and patch the movq instruction. | 685 // it in the IC initialization code and patch the movq instruction. |
670 // This means that we cannot allow test instructions after calls to | 686 // This means that we cannot allow test instructions after calls to |
671 // KeyedLoadIC stubs in other places. | 687 // KeyedLoadIC stubs in other places. |
672 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 688 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
673 __ Call(ic, RelocInfo::CODE_TARGET); | 689 __ Call(ic, RelocInfo::CODE_TARGET); |
674 // The delta from the start of the map-compare instruction to the | 690 // The delta from the start of the map-compare instruction to the |
675 // test instruction. We use masm_-> directly here instead of the __ | 691 // test instruction. We use masm_-> directly here instead of the __ |
676 // macro because the macro sometimes uses macro expansion to turn | 692 // macro because the macro sometimes uses macro expansion to turn |
677 // into something that can't return a value. This is encountered | 693 // into something that can't return a value. This is encountered |
678 // when doing generated code coverage tests. | 694 // when doing generated code coverage tests. |
679 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); | 695 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); |
680 // Here we use masm_-> instead of the __ macro because this is the | 696 // Here we use masm_-> instead of the __ macro because this is the |
681 // instruction that gets patched and coverage code gets in the way. | 697 // instruction that gets patched and coverage code gets in the way. |
682 // TODO(X64): Consider whether it's worth switching the test to a | 698 // TODO(X64): Consider whether it's worth switching the test to a |
683 // 7-byte NOP with non-zero immediate (0f 1f 80 xxxxxxxx) which won't | 699 // 7-byte NOP with non-zero immediate (0f 1f 80 xxxxxxxx) which won't |
684 // be generated normally. | 700 // be generated normally. |
685 masm_->testl(rax, Immediate(-delta_to_patch_site)); | 701 masm_->testl(rax, Immediate(-delta_to_patch_site)); |
686 __ IncrementCounter(&Counters::keyed_load_inline_miss, 1); | 702 __ IncrementCounter(&Counters::keyed_load_inline_miss, 1); |
687 | 703 |
688 if (!dst_.is(rax)) __ movq(dst_, rax); | 704 if (!dst_.is(rax)) __ movq(dst_, rax); |
689 __ pop(key_); | |
690 __ pop(receiver_); | |
691 } | 705 } |
692 | 706 |
693 | 707 |
694 class DeferredReferenceSetKeyedValue: public DeferredCode { | 708 class DeferredReferenceSetKeyedValue: public DeferredCode { |
695 public: | 709 public: |
696 DeferredReferenceSetKeyedValue(Register value, | 710 DeferredReferenceSetKeyedValue(Register value, |
697 Register key, | 711 Register key, |
698 Register receiver) | 712 Register receiver) |
699 : value_(value), key_(key), receiver_(receiver) { | 713 : value_(value), key_(key), receiver_(receiver) { |
700 set_comment("[ DeferredReferenceSetKeyedValue"); | 714 set_comment("[ DeferredReferenceSetKeyedValue"); |
(...skipping 5144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5845 // object using keyed load. | 5859 // object using keyed load. |
5846 Result arguments = allocator()->Allocate(); | 5860 Result arguments = allocator()->Allocate(); |
5847 ASSERT(arguments.is_valid()); | 5861 ASSERT(arguments.is_valid()); |
5848 __ movq(arguments.reg(), | 5862 __ movq(arguments.reg(), |
5849 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), | 5863 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), |
5850 arguments, | 5864 arguments, |
5851 slow)); | 5865 slow)); |
5852 frame_->Push(&arguments); | 5866 frame_->Push(&arguments); |
5853 frame_->Push(key_literal->handle()); | 5867 frame_->Push(key_literal->handle()); |
5854 *result = EmitKeyedLoad(); | 5868 *result = EmitKeyedLoad(); |
5855 frame_->Drop(2); // Drop key and receiver. | |
5856 done->Jump(result); | 5869 done->Jump(result); |
5857 } | 5870 } |
5858 } | 5871 } |
5859 } | 5872 } |
5860 } | 5873 } |
5861 } | 5874 } |
5862 | 5875 |
5863 | 5876 |
5864 void CodeGenerator::LoadGlobal() { | 5877 void CodeGenerator::LoadGlobal() { |
5865 if (in_spilled_code()) { | 5878 if (in_spilled_code()) { |
(...skipping 1574 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7440 // the receiver which is needed for the deferred slow case. | 7453 // the receiver which is needed for the deferred slow case. |
7441 // Allocate the temporary early so that we use rax if it is free. | 7454 // Allocate the temporary early so that we use rax if it is free. |
7442 Result elements = allocator()->Allocate(); | 7455 Result elements = allocator()->Allocate(); |
7443 ASSERT(elements.is_valid()); | 7456 ASSERT(elements.is_valid()); |
7444 | 7457 |
7445 Result key = frame_->Pop(); | 7458 Result key = frame_->Pop(); |
7446 Result receiver = frame_->Pop(); | 7459 Result receiver = frame_->Pop(); |
7447 key.ToRegister(); | 7460 key.ToRegister(); |
7448 receiver.ToRegister(); | 7461 receiver.ToRegister(); |
7449 | 7462 |
| 7463 // If key and receiver are shared registers on the frame, their values will |
| 7464 // be automatically saved and restored when going to deferred code. |
| 7465 // The result is returned in elements, which is not shared. |
7450 DeferredReferenceGetKeyedValue* deferred = | 7466 DeferredReferenceGetKeyedValue* deferred = |
7451 new DeferredReferenceGetKeyedValue(elements.reg(), | 7467 new DeferredReferenceGetKeyedValue(elements.reg(), |
7452 receiver.reg(), | 7468 receiver.reg(), |
7453 key.reg()); | 7469 key.reg()); |
7454 | 7470 |
7455 __ JumpIfSmi(receiver.reg(), deferred->entry_label()); | 7471 __ JumpIfSmi(receiver.reg(), deferred->entry_label()); |
7456 | 7472 |
7457 // Check that the receiver has the expected map. | 7473 // Check that the receiver has the expected map. |
7458 // Initially, use an invalid map. The map is patched in the IC | 7474 // Initially, use an invalid map. The map is patched in the IC |
7459 // initialization code. | 7475 // initialization code. |
7460 __ bind(deferred->patch_site()); | 7476 __ bind(deferred->patch_site()); |
7461 // Use masm-> here instead of the double underscore macro since extra | 7477 // Use masm-> here instead of the double underscore macro since extra |
7462 // coverage code can interfere with the patching. Do not use | 7478 // coverage code can interfere with the patching. Do not use a load |
7463 // root array to load null_value, since it must be patched with | 7479 // from the root away to load null_value, since the load must be patched |
7464 // the expected receiver map. | 7480 // with the expected receiver map, which is not in the root array. |
7465 masm_->movq(kScratchRegister, Factory::null_value(), | 7481 masm_->movq(kScratchRegister, Factory::null_value(), |
7466 RelocInfo::EMBEDDED_OBJECT); | 7482 RelocInfo::EMBEDDED_OBJECT); |
7467 masm_->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), | 7483 masm_->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), |
7468 kScratchRegister); | 7484 kScratchRegister); |
7469 deferred->Branch(not_equal); | 7485 deferred->Branch(not_equal); |
7470 | 7486 |
7471 // Check that the key is a non-negative smi. | 7487 // Check that the key is a non-negative smi. |
7472 __ JumpIfNotPositiveSmi(key.reg(), deferred->entry_label()); | 7488 __ JumpIfNotPositiveSmi(key.reg(), deferred->entry_label()); |
7473 | 7489 |
7474 // Get the elements array from the receiver and check that it | 7490 // Get the elements array from the receiver and check that it |
(...skipping 22 matching lines...) Expand all Loading... |
7497 FieldOperand(elements.reg(), | 7513 FieldOperand(elements.reg(), |
7498 index.reg, | 7514 index.reg, |
7499 index.scale, | 7515 index.scale, |
7500 FixedArray::kHeaderSize)); | 7516 FixedArray::kHeaderSize)); |
7501 result = elements; | 7517 result = elements; |
7502 __ CompareRoot(result.reg(), Heap::kTheHoleValueRootIndex); | 7518 __ CompareRoot(result.reg(), Heap::kTheHoleValueRootIndex); |
7503 deferred->Branch(equal); | 7519 deferred->Branch(equal); |
7504 __ IncrementCounter(&Counters::keyed_load_inline, 1); | 7520 __ IncrementCounter(&Counters::keyed_load_inline, 1); |
7505 | 7521 |
7506 deferred->BindExit(); | 7522 deferred->BindExit(); |
7507 frame_->Push(&receiver); | |
7508 frame_->Push(&key); | |
7509 } else { | 7523 } else { |
7510 Comment cmnt(masm_, "[ Load from keyed Property"); | 7524 Comment cmnt(masm_, "[ Load from keyed Property"); |
7511 result = frame_->CallKeyedLoadIC(RelocInfo::CODE_TARGET); | 7525 result = frame_->CallKeyedLoadIC(RelocInfo::CODE_TARGET); |
7512 // Make sure that we do not have a test instruction after the | 7526 // Make sure that we do not have a test instruction after the |
7513 // call. A test instruction after the call is used to | 7527 // call. A test instruction after the call is used to |
7514 // indicate that we have generated an inline version of the | 7528 // indicate that we have generated an inline version of the |
7515 // keyed load. The explicit nop instruction is here because | 7529 // keyed load. The explicit nop instruction is here because |
7516 // the push that follows might be peep-hole optimized away. | 7530 // the push that follows might be peep-hole optimized away. |
7517 __ nop(); | 7531 __ nop(); |
7518 } | 7532 } |
7519 ASSERT(frame()->height() == original_height); | 7533 ASSERT(frame()->height() == original_height - 2); |
7520 return result; | 7534 return result; |
7521 } | 7535 } |
7522 | 7536 |
7523 | 7537 |
7524 #undef __ | 7538 #undef __ |
7525 #define __ ACCESS_MASM(masm) | 7539 #define __ ACCESS_MASM(masm) |
7526 | 7540 |
7527 | 7541 |
7528 Handle<String> Reference::GetName() { | 7542 Handle<String> Reference::GetName() { |
7529 ASSERT(type_ == NAMED); | 7543 ASSERT(type_ == NAMED); |
(...skipping 23 matching lines...) Expand all Loading... |
7553 if (property != NULL) { | 7567 if (property != NULL) { |
7554 cgen_->CodeForSourcePosition(property->position()); | 7568 cgen_->CodeForSourcePosition(property->position()); |
7555 } | 7569 } |
7556 | 7570 |
7557 switch (type_) { | 7571 switch (type_) { |
7558 case SLOT: { | 7572 case SLOT: { |
7559 Comment cmnt(masm, "[ Load from Slot"); | 7573 Comment cmnt(masm, "[ Load from Slot"); |
7560 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 7574 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
7561 ASSERT(slot != NULL); | 7575 ASSERT(slot != NULL); |
7562 cgen_->LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF); | 7576 cgen_->LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF); |
7563 if (!persist_after_get_) set_unloaded(); | |
7564 break; | 7577 break; |
7565 } | 7578 } |
7566 | 7579 |
7567 case NAMED: { | 7580 case NAMED: { |
7568 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 7581 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
7569 bool is_global = var != NULL; | 7582 bool is_global = var != NULL; |
7570 ASSERT(!is_global || var->is_global()); | 7583 ASSERT(!is_global || var->is_global()); |
7571 if (persist_after_get_) { | 7584 if (persist_after_get_) { |
7572 cgen_->frame()->Dup(); | 7585 cgen_->frame()->Dup(); |
7573 } | 7586 } |
7574 Result result = cgen_->EmitNamedLoad(GetName(), is_global); | 7587 Result result = cgen_->EmitNamedLoad(GetName(), is_global); |
7575 cgen_->frame()->Push(&result); | 7588 cgen_->frame()->Push(&result); |
7576 if (!persist_after_get_) { | |
7577 set_unloaded(); | |
7578 } | |
7579 break; | 7589 break; |
7580 } | 7590 } |
7581 | 7591 |
7582 case KEYED: { | 7592 case KEYED: { |
7583 // A load of a bare identifier (load from global) cannot be keyed. | 7593 // A load of a bare identifier (load from global) cannot be keyed. |
7584 ASSERT(expression_->AsVariableProxy()->AsVariable() == NULL); | 7594 ASSERT(expression_->AsVariableProxy()->AsVariable() == NULL); |
7585 | 7595 if (persist_after_get_) { |
| 7596 cgen_->frame()->PushElementAt(1); |
| 7597 cgen_->frame()->PushElementAt(1); |
| 7598 } |
7586 Result value = cgen_->EmitKeyedLoad(); | 7599 Result value = cgen_->EmitKeyedLoad(); |
7587 cgen_->frame()->Push(&value); | 7600 cgen_->frame()->Push(&value); |
7588 if (!persist_after_get_) { | |
7589 cgen_->UnloadReference(this); | |
7590 } | |
7591 break; | 7601 break; |
7592 } | 7602 } |
7593 | 7603 |
7594 default: | 7604 default: |
7595 UNREACHABLE(); | 7605 UNREACHABLE(); |
7596 } | 7606 } |
| 7607 |
| 7608 if (!persist_after_get_) { |
| 7609 set_unloaded(); |
| 7610 } |
7597 } | 7611 } |
7598 | 7612 |
7599 | 7613 |
7600 void Reference::TakeValue() { | 7614 void Reference::TakeValue() { |
7601 // TODO(X64): This function is completely architecture independent. Move | 7615 // TODO(X64): This function is completely architecture independent. Move |
7602 // it somewhere shared. | 7616 // it somewhere shared. |
7603 | 7617 |
7604 // For non-constant frame-allocated slots, we invalidate the value in the | 7618 // For non-constant frame-allocated slots, we invalidate the value in the |
7605 // slot. For all others, we fall back on GetValue. | 7619 // slot. For all others, we fall back on GetValue. |
7606 ASSERT(!cgen_->in_spilled_code()); | 7620 ASSERT(!cgen_->in_spilled_code()); |
(...skipping 4250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11857 } | 11871 } |
11858 | 11872 |
11859 #endif | 11873 #endif |
11860 | 11874 |
11861 | 11875 |
11862 #undef __ | 11876 #undef __ |
11863 | 11877 |
11864 } } // namespace v8::internal | 11878 } } // namespace v8::internal |
11865 | 11879 |
11866 #endif // V8_TARGET_ARCH_X64 | 11880 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |