OLD | NEW |
---|---|
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 27 matching lines...) Expand all Loading... | |
38 #include "scopes.h" | 38 #include "scopes.h" |
39 #include "stub-cache.h" | 39 #include "stub-cache.h" |
40 | 40 |
41 #include "arm/code-stubs-arm.h" | 41 #include "arm/code-stubs-arm.h" |
42 | 42 |
43 namespace v8 { | 43 namespace v8 { |
44 namespace internal { | 44 namespace internal { |
45 | 45 |
46 #define __ ACCESS_MASM(masm_) | 46 #define __ ACCESS_MASM(masm_) |
47 | 47 |
48 | |
49 // A patch site is a location in the code which it is possible to patch. This | |
50 // class has a number of methods the emit the code which is patchable and the | |
Alexandre
2011/02/09 13:57:16
typo: "the emit the code" -> "to emit the code" ?
Søren Thygesen Gjesse
2011/02/09 14:48:28
Done.
| |
51 // method EmitPatchInfo to record a marker back to the patchable code. This | |
52 // marker is a cmp rx, #yyy instruction, and x * 0x00000fff + yyy (raw 12 bit | |
53 // immediate value is used) is the delta from the pc to the first instruction of | |
54 // the patchable code. | |
55 class JumpPatchSite BASE_EMBEDDED { | |
56 public: | |
57 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) { | |
58 #ifdef DEBUG | |
59 info_emitted_ = false; | |
60 #endif | |
61 } | |
62 | |
63 ~JumpPatchSite() { | |
64 ASSERT(patch_site_.is_bound() == info_emitted_); | |
65 } | |
66 | |
67 // When initially emitting this ensure that a jump is always generated to skip | |
68 // the inlined smi code. | |
69 void EmitJumpIfNotSmi(Register reg, Label* target) { | |
70 ASSERT(!patch_site_.is_bound() && !info_emitted_); | |
71 __ bind(&patch_site_); | |
72 __ cmp(reg, Operand(reg)); | |
73 // Don't use b(al, ...) as that might emit the constant pool right after the | |
74 // branch. After patching when the branch is no longer unconditional | |
75 // execution can continue into the constant pool. | |
76 __ b(eq, target); // Always taken before patched. | |
77 } | |
78 | |
79 // When initially emitting this ensure that a jump is never generated to skip | |
80 // the inlined smi code. | |
81 void EmitJumpIfSmi(Register reg, Label* target) { | |
82 ASSERT(!patch_site_.is_bound() && !info_emitted_); | |
83 __ bind(&patch_site_); | |
84 __ cmp(reg, Operand(reg)); | |
85 __ b(ne, target); // Never taken before patched. | |
86 } | |
87 | |
88 void EmitPatchInfo() { | |
89 int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_); | |
90 Register reg; | |
91 reg.set_code(delta_to_patch_site / kOff12Mask); | |
92 __ cmp_raw_immediate(r0, delta_to_patch_site % kOff12Mask); | |
Karl Klose
2011/02/09 14:35:30
The destination register of the cmp should be reg.
Søren Thygesen Gjesse
2011/02/09 14:48:28
Good catch, fixed.
| |
93 #ifdef DEBUG | |
94 info_emitted_ = true; | |
95 #endif | |
96 } | |
97 | |
98 bool is_bound() const { return patch_site_.is_bound(); } | |
99 | |
100 private: | |
101 MacroAssembler* masm_; | |
102 Label patch_site_; | |
103 #ifdef DEBUG | |
104 bool info_emitted_; | |
105 #endif | |
106 }; | |
107 | |
108 | |
48 // Generate code for a JS function. On entry to the function the receiver | 109 // Generate code for a JS function. On entry to the function the receiver |
49 // and arguments have been pushed on the stack left to right. The actual | 110 // and arguments have been pushed on the stack left to right. The actual |
50 // argument count matches the formal parameter count expected by the | 111 // argument count matches the formal parameter count expected by the |
51 // function. | 112 // function. |
52 // | 113 // |
53 // The live registers are: | 114 // The live registers are: |
54 // o r1: the JS function object being called (ie, ourselves) | 115 // o r1: the JS function object being called (ie, ourselves) |
55 // o cp: our context | 116 // o cp: our context |
56 // o fp: our caller's frame pointer | 117 // o fp: our caller's frame pointer |
57 // o sp: stack pointer | 118 // o sp: stack pointer |
(...skipping 687 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
745 Comment cmnt(masm_, "[ Case comparison"); | 806 Comment cmnt(masm_, "[ Case comparison"); |
746 __ bind(&next_test); | 807 __ bind(&next_test); |
747 next_test.Unuse(); | 808 next_test.Unuse(); |
748 | 809 |
749 // Compile the label expression. | 810 // Compile the label expression. |
750 VisitForAccumulatorValue(clause->label()); | 811 VisitForAccumulatorValue(clause->label()); |
751 | 812 |
752 // Perform the comparison as if via '==='. | 813 // Perform the comparison as if via '==='. |
753 __ ldr(r1, MemOperand(sp, 0)); // Switch value. | 814 __ ldr(r1, MemOperand(sp, 0)); // Switch value. |
754 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT); | 815 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT); |
816 JumpPatchSite patch_site(masm_); | |
755 if (inline_smi_code) { | 817 if (inline_smi_code) { |
756 Label slow_case; | 818 Label slow_case; |
757 __ orr(r2, r1, r0); | 819 __ orr(r2, r1, r0); |
758 __ tst(r2, Operand(kSmiTagMask)); | 820 patch_site.EmitJumpIfNotSmi(r2, &slow_case); |
759 __ b(ne, &slow_case); | 821 |
760 __ cmp(r1, r0); | 822 __ cmp(r1, r0); |
761 __ b(ne, &next_test); | 823 __ b(ne, &next_test); |
762 __ Drop(1); // Switch value is no longer needed. | 824 __ Drop(1); // Switch value is no longer needed. |
763 __ b(clause->body_target()->entry_label()); | 825 __ b(clause->body_target()->entry_label()); |
764 __ bind(&slow_case); | 826 __ bind(&slow_case); |
765 } | 827 } |
766 | 828 |
767 CompareFlags flags = inline_smi_code | 829 // Record position before stub call for type feedback. |
768 ? NO_SMI_COMPARE_IN_STUB | 830 SetSourcePosition(clause->position()); |
769 : NO_COMPARE_FLAGS; | 831 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); |
770 CompareStub stub(eq, true, flags, r1, r0); | 832 EmitCallIC(ic, &patch_site); |
771 __ CallStub(&stub); | 833 |
772 __ cmp(r0, Operand(0, RelocInfo::NONE)); | 834 __ cmp(r0, Operand(0)); |
773 __ b(ne, &next_test); | 835 __ b(ne, &next_test); |
774 __ Drop(1); // Switch value is no longer needed. | 836 __ Drop(1); // Switch value is no longer needed. |
775 __ b(clause->body_target()->entry_label()); | 837 __ b(clause->body_target()->entry_label()); |
776 } | 838 } |
777 | 839 |
778 // Discard the test value and jump to the default if present, otherwise to | 840 // Discard the test value and jump to the default if present, otherwise to |
779 // the end of the statement. | 841 // the end of the statement. |
780 __ bind(&next_test); | 842 __ bind(&next_test); |
781 __ Drop(1); // Switch value is no longer needed. | 843 __ Drop(1); // Switch value is no longer needed. |
782 if (default_clause == NULL) { | 844 if (default_clause == NULL) { |
(...skipping 2720 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3503 cond = ge; | 3565 cond = ge; |
3504 __ pop(r1); | 3566 __ pop(r1); |
3505 break; | 3567 break; |
3506 case Token::IN: | 3568 case Token::IN: |
3507 case Token::INSTANCEOF: | 3569 case Token::INSTANCEOF: |
3508 default: | 3570 default: |
3509 UNREACHABLE(); | 3571 UNREACHABLE(); |
3510 } | 3572 } |
3511 | 3573 |
3512 bool inline_smi_code = ShouldInlineSmiCase(op); | 3574 bool inline_smi_code = ShouldInlineSmiCase(op); |
3575 JumpPatchSite patch_site(masm_); | |
3513 if (inline_smi_code) { | 3576 if (inline_smi_code) { |
3514 Label slow_case; | 3577 Label slow_case; |
3515 __ orr(r2, r0, Operand(r1)); | 3578 __ orr(r2, r0, Operand(r1)); |
3516 __ JumpIfNotSmi(r2, &slow_case); | 3579 patch_site.EmitJumpIfNotSmi(r2, &slow_case); |
3517 __ cmp(r1, r0); | 3580 __ cmp(r1, r0); |
3518 Split(cond, if_true, if_false, NULL); | 3581 Split(cond, if_true, if_false, NULL); |
3519 __ bind(&slow_case); | 3582 __ bind(&slow_case); |
3520 } | 3583 } |
3521 CompareFlags flags = inline_smi_code | 3584 |
3522 ? NO_SMI_COMPARE_IN_STUB | 3585 // Record position and call the compare IC. |
3523 : NO_COMPARE_FLAGS; | 3586 SetSourcePosition(expr->position()); |
3524 CompareStub stub(cond, strict, flags, r1, r0); | 3587 Handle<Code> ic = CompareIC::GetUninitialized(op); |
3525 __ CallStub(&stub); | 3588 EmitCallIC(ic, &patch_site); |
3526 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 3589 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
3527 __ cmp(r0, Operand(0, RelocInfo::NONE)); | 3590 __ cmp(r0, Operand(0)); |
3528 Split(cond, if_true, if_false, fall_through); | 3591 Split(cond, if_true, if_false, fall_through); |
3529 } | 3592 } |
3530 } | 3593 } |
3531 | 3594 |
3532 // Convert the result of the comparison into one expected for this | 3595 // Convert the result of the comparison into one expected for this |
3533 // expression's context. | 3596 // expression's context. |
3534 context()->Plug(if_true, if_false); | 3597 context()->Plug(if_true, if_false); |
3535 } | 3598 } |
3536 | 3599 |
3537 | 3600 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3584 } | 3647 } |
3585 | 3648 |
3586 | 3649 |
3587 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) { | 3650 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) { |
3588 ASSERT(mode == RelocInfo::CODE_TARGET || | 3651 ASSERT(mode == RelocInfo::CODE_TARGET || |
3589 mode == RelocInfo::CODE_TARGET_CONTEXT); | 3652 mode == RelocInfo::CODE_TARGET_CONTEXT); |
3590 __ Call(ic, mode); | 3653 __ Call(ic, mode); |
3591 } | 3654 } |
3592 | 3655 |
3593 | 3656 |
3657 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) { | |
3658 __ Call(ic, RelocInfo::CODE_TARGET); | |
3659 if (patch_site != NULL && patch_site->is_bound()) { | |
3660 patch_site->EmitPatchInfo(); | |
3661 } else { | |
3662 __ nop(); // Signals no inlined code. | |
3663 } | |
3664 } | |
3665 | |
3666 | |
3594 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { | 3667 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { |
3595 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); | 3668 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); |
3596 __ str(value, MemOperand(fp, frame_offset)); | 3669 __ str(value, MemOperand(fp, frame_offset)); |
3597 } | 3670 } |
3598 | 3671 |
3599 | 3672 |
3600 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { | 3673 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { |
3601 __ ldr(dst, ContextOperand(cp, context_index)); | 3674 __ ldr(dst, ContextOperand(cp, context_index)); |
3602 } | 3675 } |
3603 | 3676 |
(...skipping 24 matching lines...) Expand all Loading... | |
3628 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. | 3701 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. |
3629 __ add(pc, r1, Operand(masm_->CodeObject())); | 3702 __ add(pc, r1, Operand(masm_->CodeObject())); |
3630 } | 3703 } |
3631 | 3704 |
3632 | 3705 |
3633 #undef __ | 3706 #undef __ |
3634 | 3707 |
3635 } } // namespace v8::internal | 3708 } } // namespace v8::internal |
3636 | 3709 |
3637 #endif // V8_TARGET_ARCH_ARM | 3710 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |