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 to emit the code which is patchable and the |
| 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(reg, delta_to_patch_site % kOff12Mask); |
| 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 __ cmp(r0, Operand(0)); |
772 __ cmp(r0, Operand(0, RelocInfo::NONE)); | |
773 __ b(ne, &next_test); | 834 __ b(ne, &next_test); |
774 __ Drop(1); // Switch value is no longer needed. | 835 __ Drop(1); // Switch value is no longer needed. |
775 __ b(clause->body_target()->entry_label()); | 836 __ b(clause->body_target()->entry_label()); |
776 } | 837 } |
777 | 838 |
778 // Discard the test value and jump to the default if present, otherwise to | 839 // Discard the test value and jump to the default if present, otherwise to |
779 // the end of the statement. | 840 // the end of the statement. |
780 __ bind(&next_test); | 841 __ bind(&next_test); |
781 __ Drop(1); // Switch value is no longer needed. | 842 __ Drop(1); // Switch value is no longer needed. |
782 if (default_clause == NULL) { | 843 if (default_clause == NULL) { |
(...skipping 2720 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3503 cond = ge; | 3564 cond = ge; |
3504 __ pop(r1); | 3565 __ pop(r1); |
3505 break; | 3566 break; |
3506 case Token::IN: | 3567 case Token::IN: |
3507 case Token::INSTANCEOF: | 3568 case Token::INSTANCEOF: |
3508 default: | 3569 default: |
3509 UNREACHABLE(); | 3570 UNREACHABLE(); |
3510 } | 3571 } |
3511 | 3572 |
3512 bool inline_smi_code = ShouldInlineSmiCase(op); | 3573 bool inline_smi_code = ShouldInlineSmiCase(op); |
| 3574 JumpPatchSite patch_site(masm_); |
3513 if (inline_smi_code) { | 3575 if (inline_smi_code) { |
3514 Label slow_case; | 3576 Label slow_case; |
3515 __ orr(r2, r0, Operand(r1)); | 3577 __ orr(r2, r0, Operand(r1)); |
3516 __ JumpIfNotSmi(r2, &slow_case); | 3578 patch_site.EmitJumpIfNotSmi(r2, &slow_case); |
3517 __ cmp(r1, r0); | 3579 __ cmp(r1, r0); |
3518 Split(cond, if_true, if_false, NULL); | 3580 Split(cond, if_true, if_false, NULL); |
3519 __ bind(&slow_case); | 3581 __ bind(&slow_case); |
3520 } | 3582 } |
3521 CompareFlags flags = inline_smi_code | 3583 |
3522 ? NO_SMI_COMPARE_IN_STUB | 3584 // Record position and call the compare IC. |
3523 : NO_COMPARE_FLAGS; | 3585 SetSourcePosition(expr->position()); |
3524 CompareStub stub(cond, strict, flags, r1, r0); | 3586 Handle<Code> ic = CompareIC::GetUninitialized(op); |
3525 __ CallStub(&stub); | 3587 EmitCallIC(ic, &patch_site); |
3526 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 3588 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
3527 __ cmp(r0, Operand(0, RelocInfo::NONE)); | 3589 __ cmp(r0, Operand(0)); |
3528 Split(cond, if_true, if_false, fall_through); | 3590 Split(cond, if_true, if_false, fall_through); |
3529 } | 3591 } |
3530 } | 3592 } |
3531 | 3593 |
3532 // Convert the result of the comparison into one expected for this | 3594 // Convert the result of the comparison into one expected for this |
3533 // expression's context. | 3595 // expression's context. |
3534 context()->Plug(if_true, if_false); | 3596 context()->Plug(if_true, if_false); |
3535 } | 3597 } |
3536 | 3598 |
3537 | 3599 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3584 } | 3646 } |
3585 | 3647 |
3586 | 3648 |
3587 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) { | 3649 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) { |
3588 ASSERT(mode == RelocInfo::CODE_TARGET || | 3650 ASSERT(mode == RelocInfo::CODE_TARGET || |
3589 mode == RelocInfo::CODE_TARGET_CONTEXT); | 3651 mode == RelocInfo::CODE_TARGET_CONTEXT); |
3590 __ Call(ic, mode); | 3652 __ Call(ic, mode); |
3591 } | 3653 } |
3592 | 3654 |
3593 | 3655 |
| 3656 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) { |
| 3657 __ Call(ic, RelocInfo::CODE_TARGET); |
| 3658 if (patch_site != NULL && patch_site->is_bound()) { |
| 3659 patch_site->EmitPatchInfo(); |
| 3660 } else { |
| 3661 __ nop(); // Signals no inlined code. |
| 3662 } |
| 3663 } |
| 3664 |
| 3665 |
3594 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { | 3666 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { |
3595 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); | 3667 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); |
3596 __ str(value, MemOperand(fp, frame_offset)); | 3668 __ str(value, MemOperand(fp, frame_offset)); |
3597 } | 3669 } |
3598 | 3670 |
3599 | 3671 |
3600 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { | 3672 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { |
3601 __ ldr(dst, ContextOperand(cp, context_index)); | 3673 __ ldr(dst, ContextOperand(cp, context_index)); |
3602 } | 3674 } |
3603 | 3675 |
(...skipping 24 matching lines...) Expand all Loading... |
3628 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. | 3700 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. |
3629 __ add(pc, r1, Operand(masm_->CodeObject())); | 3701 __ add(pc, r1, Operand(masm_->CodeObject())); |
3630 } | 3702 } |
3631 | 3703 |
3632 | 3704 |
3633 #undef __ | 3705 #undef __ |
3634 | 3706 |
3635 } } // namespace v8::internal | 3707 } } // namespace v8::internal |
3636 | 3708 |
3637 #endif // V8_TARGET_ARCH_ARM | 3709 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |