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 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 // When initially emitting this ensure that a jump is never generated to skip | 85 // When initially emitting this ensure that a jump is never generated to skip |
86 // the inlined smi code. | 86 // the inlined smi code. |
87 void EmitJumpIfSmi(Register reg, Label* target) { | 87 void EmitJumpIfSmi(Register reg, Label* target) { |
88 ASSERT(!patch_site_.is_bound() && !info_emitted_); | 88 ASSERT(!patch_site_.is_bound() && !info_emitted_); |
89 __ bind(&patch_site_); | 89 __ bind(&patch_site_); |
90 __ cmp(reg, Operand(reg)); | 90 __ cmp(reg, Operand(reg)); |
91 __ b(ne, target); // Never taken before patched. | 91 __ b(ne, target); // Never taken before patched. |
92 } | 92 } |
93 | 93 |
94 void EmitPatchInfo() { | 94 void EmitPatchInfo() { |
95 int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_); | 95 if (patch_site_.is_bound()) { |
96 Register reg; | 96 int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_); |
97 reg.set_code(delta_to_patch_site / kOff12Mask); | 97 Register reg; |
98 __ cmp_raw_immediate(reg, delta_to_patch_site % kOff12Mask); | 98 reg.set_code(delta_to_patch_site / kOff12Mask); |
| 99 __ cmp_raw_immediate(reg, delta_to_patch_site % kOff12Mask); |
99 #ifdef DEBUG | 100 #ifdef DEBUG |
100 info_emitted_ = true; | 101 info_emitted_ = true; |
101 #endif | 102 #endif |
| 103 } else { |
| 104 __ nop(); // Signals no inlined code. |
| 105 } |
102 } | 106 } |
103 | 107 |
104 bool is_bound() const { return patch_site_.is_bound(); } | |
105 | |
106 private: | 108 private: |
107 MacroAssembler* masm_; | 109 MacroAssembler* masm_; |
108 Label patch_site_; | 110 Label patch_site_; |
109 #ifdef DEBUG | 111 #ifdef DEBUG |
110 bool info_emitted_; | 112 bool info_emitted_; |
111 #endif | 113 #endif |
112 }; | 114 }; |
113 | 115 |
114 | 116 |
115 // Generate code for a JS function. On entry to the function the receiver | 117 // Generate code for a JS function. On entry to the function the receiver |
(...skipping 737 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
853 __ cmp(r1, r0); | 855 __ cmp(r1, r0); |
854 __ b(ne, &next_test); | 856 __ b(ne, &next_test); |
855 __ Drop(1); // Switch value is no longer needed. | 857 __ Drop(1); // Switch value is no longer needed. |
856 __ b(clause->body_target()); | 858 __ b(clause->body_target()); |
857 __ bind(&slow_case); | 859 __ bind(&slow_case); |
858 } | 860 } |
859 | 861 |
860 // Record position before stub call for type feedback. | 862 // Record position before stub call for type feedback. |
861 SetSourcePosition(clause->position()); | 863 SetSourcePosition(clause->position()); |
862 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); | 864 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); |
863 EmitCallIC(ic, &patch_site, clause->CompareId()); | 865 EmitCallIC(ic, RelocInfo::CODE_TARGET, clause->CompareId()); |
| 866 patch_site.EmitPatchInfo(); |
864 | 867 |
865 __ cmp(r0, Operand(0)); | 868 __ cmp(r0, Operand(0)); |
866 __ b(ne, &next_test); | 869 __ b(ne, &next_test); |
867 __ Drop(1); // Switch value is no longer needed. | 870 __ Drop(1); // Switch value is no longer needed. |
868 __ b(clause->body_target()); | 871 __ b(clause->body_target()); |
869 } | 872 } |
870 | 873 |
871 // Discard the test value and jump to the default if present, otherwise to | 874 // Discard the test value and jump to the default if present, otherwise to |
872 // the end of the statement. | 875 // the end of the statement. |
873 __ bind(&next_test); | 876 __ bind(&next_test); |
(...skipping 808 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1682 __ pop(left); | 1685 __ pop(left); |
1683 | 1686 |
1684 // Perform combined smi check on both operands. | 1687 // Perform combined smi check on both operands. |
1685 __ orr(scratch1, left, Operand(right)); | 1688 __ orr(scratch1, left, Operand(right)); |
1686 STATIC_ASSERT(kSmiTag == 0); | 1689 STATIC_ASSERT(kSmiTag == 0); |
1687 JumpPatchSite patch_site(masm_); | 1690 JumpPatchSite patch_site(masm_); |
1688 patch_site.EmitJumpIfSmi(scratch1, &smi_case); | 1691 patch_site.EmitJumpIfSmi(scratch1, &smi_case); |
1689 | 1692 |
1690 __ bind(&stub_call); | 1693 __ bind(&stub_call); |
1691 BinaryOpStub stub(op, mode); | 1694 BinaryOpStub stub(op, mode); |
1692 EmitCallIC(stub.GetCode(), &patch_site, expr->id()); | 1695 EmitCallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); |
| 1696 patch_site.EmitPatchInfo(); |
1693 __ jmp(&done); | 1697 __ jmp(&done); |
1694 | 1698 |
1695 __ bind(&smi_case); | 1699 __ bind(&smi_case); |
1696 // Smi case. This code works the same way as the smi-smi case in the type | 1700 // Smi case. This code works the same way as the smi-smi case in the type |
1697 // recording binary operation stub, see | 1701 // recording binary operation stub, see |
1698 // BinaryOpStub::GenerateSmiSmiOperation for comments. | 1702 // BinaryOpStub::GenerateSmiSmiOperation for comments. |
1699 switch (op) { | 1703 switch (op) { |
1700 case Token::SAR: | 1704 case Token::SAR: |
1701 __ b(&stub_call); | 1705 __ b(&stub_call); |
1702 __ GetLeastBitsFromSmi(scratch1, right, 5); | 1706 __ GetLeastBitsFromSmi(scratch1, right, 5); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1763 __ bind(&done); | 1767 __ bind(&done); |
1764 context()->Plug(r0); | 1768 context()->Plug(r0); |
1765 } | 1769 } |
1766 | 1770 |
1767 | 1771 |
1768 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, | 1772 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, |
1769 Token::Value op, | 1773 Token::Value op, |
1770 OverwriteMode mode) { | 1774 OverwriteMode mode) { |
1771 __ pop(r1); | 1775 __ pop(r1); |
1772 BinaryOpStub stub(op, mode); | 1776 BinaryOpStub stub(op, mode); |
1773 EmitCallIC(stub.GetCode(), NULL, expr->id()); | 1777 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. |
| 1778 EmitCallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); |
| 1779 patch_site.EmitPatchInfo(); |
1774 context()->Plug(r0); | 1780 context()->Plug(r0); |
1775 } | 1781 } |
1776 | 1782 |
1777 | 1783 |
1778 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { | 1784 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { |
1779 // Invalid left-hand sides are rewritten to have a 'throw | 1785 // Invalid left-hand sides are rewritten to have a 'throw |
1780 // ReferenceError' on the left-hand side. | 1786 // ReferenceError' on the left-hand side. |
1781 if (!expr->IsValidLeftHandSide()) { | 1787 if (!expr->IsValidLeftHandSide()) { |
1782 VisitForEffect(expr); | 1788 VisitForEffect(expr); |
1783 return; | 1789 return; |
(...skipping 2062 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3846 __ bind(&stub_call); | 3852 __ bind(&stub_call); |
3847 // Call stub. Undo operation first. | 3853 // Call stub. Undo operation first. |
3848 __ sub(r0, r0, Operand(Smi::FromInt(count_value))); | 3854 __ sub(r0, r0, Operand(Smi::FromInt(count_value))); |
3849 } | 3855 } |
3850 __ mov(r1, Operand(Smi::FromInt(count_value))); | 3856 __ mov(r1, Operand(Smi::FromInt(count_value))); |
3851 | 3857 |
3852 // Record position before stub call. | 3858 // Record position before stub call. |
3853 SetSourcePosition(expr->position()); | 3859 SetSourcePosition(expr->position()); |
3854 | 3860 |
3855 BinaryOpStub stub(Token::ADD, NO_OVERWRITE); | 3861 BinaryOpStub stub(Token::ADD, NO_OVERWRITE); |
3856 EmitCallIC(stub.GetCode(), &patch_site, expr->CountId()); | 3862 EmitCallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId()); |
| 3863 patch_site.EmitPatchInfo(); |
3857 __ bind(&done); | 3864 __ bind(&done); |
3858 | 3865 |
3859 // Store the value returned in r0. | 3866 // Store the value returned in r0. |
3860 switch (assign_type) { | 3867 switch (assign_type) { |
3861 case VARIABLE: | 3868 case VARIABLE: |
3862 if (expr->is_postfix()) { | 3869 if (expr->is_postfix()) { |
3863 { EffectContext context(this); | 3870 { EffectContext context(this); |
3864 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3871 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
3865 Token::ASSIGN); | 3872 Token::ASSIGN); |
3866 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3873 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4119 __ orr(r2, r0, Operand(r1)); | 4126 __ orr(r2, r0, Operand(r1)); |
4120 patch_site.EmitJumpIfNotSmi(r2, &slow_case); | 4127 patch_site.EmitJumpIfNotSmi(r2, &slow_case); |
4121 __ cmp(r1, r0); | 4128 __ cmp(r1, r0); |
4122 Split(cond, if_true, if_false, NULL); | 4129 Split(cond, if_true, if_false, NULL); |
4123 __ bind(&slow_case); | 4130 __ bind(&slow_case); |
4124 } | 4131 } |
4125 | 4132 |
4126 // Record position and call the compare IC. | 4133 // Record position and call the compare IC. |
4127 SetSourcePosition(expr->position()); | 4134 SetSourcePosition(expr->position()); |
4128 Handle<Code> ic = CompareIC::GetUninitialized(op); | 4135 Handle<Code> ic = CompareIC::GetUninitialized(op); |
4129 EmitCallIC(ic, &patch_site, expr->id()); | 4136 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 4137 patch_site.EmitPatchInfo(); |
4130 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 4138 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
4131 __ cmp(r0, Operand(0)); | 4139 __ cmp(r0, Operand(0)); |
4132 Split(cond, if_true, if_false, fall_through); | 4140 Split(cond, if_true, if_false, fall_through); |
4133 } | 4141 } |
4134 } | 4142 } |
4135 | 4143 |
4136 // Convert the result of the comparison into one expected for this | 4144 // Convert the result of the comparison into one expected for this |
4137 // expression's context. | 4145 // expression's context. |
4138 context()->Plug(if_true, if_false); | 4146 context()->Plug(if_true, if_false); |
4139 } | 4147 } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4185 Register FullCodeGenerator::context_register() { | 4193 Register FullCodeGenerator::context_register() { |
4186 return cp; | 4194 return cp; |
4187 } | 4195 } |
4188 | 4196 |
4189 | 4197 |
4190 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, | 4198 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, |
4191 RelocInfo::Mode mode, | 4199 RelocInfo::Mode mode, |
4192 unsigned ast_id) { | 4200 unsigned ast_id) { |
4193 ASSERT(mode == RelocInfo::CODE_TARGET || | 4201 ASSERT(mode == RelocInfo::CODE_TARGET || |
4194 mode == RelocInfo::CODE_TARGET_CONTEXT); | 4202 mode == RelocInfo::CODE_TARGET_CONTEXT); |
4195 Counters* counters = isolate()->counters(); | |
4196 switch (ic->kind()) { | |
4197 case Code::LOAD_IC: | |
4198 __ IncrementCounter(counters->named_load_full(), 1, r1, r2); | |
4199 break; | |
4200 case Code::KEYED_LOAD_IC: | |
4201 __ IncrementCounter(counters->keyed_load_full(), 1, r1, r2); | |
4202 break; | |
4203 case Code::STORE_IC: | |
4204 __ IncrementCounter(counters->named_store_full(), 1, r1, r2); | |
4205 break; | |
4206 case Code::KEYED_STORE_IC: | |
4207 __ IncrementCounter(counters->keyed_store_full(), 1, r1, r2); | |
4208 default: | |
4209 break; | |
4210 } | |
4211 if (ast_id == kNoASTId || mode == RelocInfo::CODE_TARGET_CONTEXT) { | 4203 if (ast_id == kNoASTId || mode == RelocInfo::CODE_TARGET_CONTEXT) { |
4212 __ Call(ic, mode); | 4204 __ Call(ic, mode); |
4213 } else { | 4205 } else { |
4214 ASSERT(mode == RelocInfo::CODE_TARGET); | 4206 ASSERT(mode == RelocInfo::CODE_TARGET); |
4215 mode = RelocInfo::CODE_TARGET_WITH_ID; | 4207 __ CallWithAstId(ic, RelocInfo::CODE_TARGET_WITH_ID, ast_id); |
4216 __ CallWithAstId(ic, mode, ast_id); | |
4217 } | 4208 } |
4218 } | 4209 } |
4219 | 4210 |
4220 | 4211 |
4221 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, | |
4222 JumpPatchSite* patch_site, | |
4223 unsigned ast_id) { | |
4224 Counters* counters = isolate()->counters(); | |
4225 switch (ic->kind()) { | |
4226 case Code::LOAD_IC: | |
4227 __ IncrementCounter(counters->named_load_full(), 1, r1, r2); | |
4228 break; | |
4229 case Code::KEYED_LOAD_IC: | |
4230 __ IncrementCounter(counters->keyed_load_full(), 1, r1, r2); | |
4231 break; | |
4232 case Code::STORE_IC: | |
4233 __ IncrementCounter(counters->named_store_full(), 1, r1, r2); | |
4234 break; | |
4235 case Code::KEYED_STORE_IC: | |
4236 __ IncrementCounter(counters->keyed_store_full(), 1, r1, r2); | |
4237 default: | |
4238 break; | |
4239 } | |
4240 | |
4241 if (ast_id == kNoASTId) { | |
4242 __ Call(ic, RelocInfo::CODE_TARGET); | |
4243 } else { | |
4244 __ CallWithAstId(ic, RelocInfo::CODE_TARGET_WITH_ID, ast_id); | |
4245 } | |
4246 if (patch_site != NULL && patch_site->is_bound()) { | |
4247 patch_site->EmitPatchInfo(); | |
4248 } else { | |
4249 __ nop(); // Signals no inlined code. | |
4250 } | |
4251 } | |
4252 | |
4253 | |
4254 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { | 4212 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { |
4255 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); | 4213 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); |
4256 __ str(value, MemOperand(fp, frame_offset)); | 4214 __ str(value, MemOperand(fp, frame_offset)); |
4257 } | 4215 } |
4258 | 4216 |
4259 | 4217 |
4260 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { | 4218 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { |
4261 __ ldr(dst, ContextOperand(cp, context_index)); | 4219 __ ldr(dst, ContextOperand(cp, context_index)); |
4262 } | 4220 } |
4263 | 4221 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4308 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. | 4266 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. |
4309 __ add(pc, r1, Operand(masm_->CodeObject())); | 4267 __ add(pc, r1, Operand(masm_->CodeObject())); |
4310 } | 4268 } |
4311 | 4269 |
4312 | 4270 |
4313 #undef __ | 4271 #undef __ |
4314 | 4272 |
4315 } } // namespace v8::internal | 4273 } } // namespace v8::internal |
4316 | 4274 |
4317 #endif // V8_TARGET_ARCH_ARM | 4275 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |