| Index: src/arm/full-codegen-arm.cc
|
| ===================================================================
|
| --- src/arm/full-codegen-arm.cc (revision 6683)
|
| +++ src/arm/full-codegen-arm.cc (working copy)
|
| @@ -45,6 +45,67 @@
|
|
|
| #define __ ACCESS_MASM(masm_)
|
|
|
| +
|
| +// A patch site is a location in the code which it is possible to patch. This
|
| +// class has a number of methods to emit the code which is patchable and the
|
| +// method EmitPatchInfo to record a marker back to the patchable code. This
|
| +// marker is a cmp rx, #yyy instruction, and x * 0x00000fff + yyy (raw 12 bit
|
| +// immediate value is used) is the delta from the pc to the first instruction of
|
| +// the patchable code.
|
| +class JumpPatchSite BASE_EMBEDDED {
|
| + public:
|
| + explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
|
| +#ifdef DEBUG
|
| + info_emitted_ = false;
|
| +#endif
|
| + }
|
| +
|
| + ~JumpPatchSite() {
|
| + ASSERT(patch_site_.is_bound() == info_emitted_);
|
| + }
|
| +
|
| + // When initially emitting this ensure that a jump is always generated to skip
|
| + // the inlined smi code.
|
| + void EmitJumpIfNotSmi(Register reg, Label* target) {
|
| + ASSERT(!patch_site_.is_bound() && !info_emitted_);
|
| + __ bind(&patch_site_);
|
| + __ cmp(reg, Operand(reg));
|
| + // Don't use b(al, ...) as that might emit the constant pool right after the
|
| + // branch. After patching when the branch is no longer unconditional
|
| + // execution can continue into the constant pool.
|
| + __ b(eq, target); // Always taken before patched.
|
| + }
|
| +
|
| + // When initially emitting this ensure that a jump is never generated to skip
|
| + // the inlined smi code.
|
| + void EmitJumpIfSmi(Register reg, Label* target) {
|
| + ASSERT(!patch_site_.is_bound() && !info_emitted_);
|
| + __ bind(&patch_site_);
|
| + __ cmp(reg, Operand(reg));
|
| + __ b(ne, target); // Never taken before patched.
|
| + }
|
| +
|
| + void EmitPatchInfo() {
|
| + int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_);
|
| + Register reg;
|
| + reg.set_code(delta_to_patch_site / kOff12Mask);
|
| + __ cmp_raw_immediate(reg, delta_to_patch_site % kOff12Mask);
|
| +#ifdef DEBUG
|
| + info_emitted_ = true;
|
| +#endif
|
| + }
|
| +
|
| + bool is_bound() const { return patch_site_.is_bound(); }
|
| +
|
| + private:
|
| + MacroAssembler* masm_;
|
| + Label patch_site_;
|
| +#ifdef DEBUG
|
| + bool info_emitted_;
|
| +#endif
|
| +};
|
| +
|
| +
|
| // Generate code for a JS function. On entry to the function the receiver
|
| // and arguments have been pushed on the stack left to right. The actual
|
| // argument count matches the formal parameter count expected by the
|
| @@ -752,24 +813,24 @@
|
| // Perform the comparison as if via '==='.
|
| __ ldr(r1, MemOperand(sp, 0)); // Switch value.
|
| bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
|
| + JumpPatchSite patch_site(masm_);
|
| if (inline_smi_code) {
|
| Label slow_case;
|
| __ orr(r2, r1, r0);
|
| - __ tst(r2, Operand(kSmiTagMask));
|
| - __ b(ne, &slow_case);
|
| + patch_site.EmitJumpIfNotSmi(r2, &slow_case);
|
| +
|
| __ cmp(r1, r0);
|
| __ b(ne, &next_test);
|
| __ Drop(1); // Switch value is no longer needed.
|
| __ b(clause->body_target()->entry_label());
|
| - __ bind(&slow_case);
|
| + __ bind(&slow_case);
|
| }
|
|
|
| - CompareFlags flags = inline_smi_code
|
| - ? NO_SMI_COMPARE_IN_STUB
|
| - : NO_COMPARE_FLAGS;
|
| - CompareStub stub(eq, true, flags, r1, r0);
|
| - __ CallStub(&stub);
|
| - __ cmp(r0, Operand(0, RelocInfo::NONE));
|
| + // Record position before stub call for type feedback.
|
| + SetSourcePosition(clause->position());
|
| + Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
|
| + EmitCallIC(ic, &patch_site);
|
| + __ cmp(r0, Operand(0));
|
| __ b(ne, &next_test);
|
| __ Drop(1); // Switch value is no longer needed.
|
| __ b(clause->body_target()->entry_label());
|
| @@ -3510,21 +3571,22 @@
|
| }
|
|
|
| bool inline_smi_code = ShouldInlineSmiCase(op);
|
| + JumpPatchSite patch_site(masm_);
|
| if (inline_smi_code) {
|
| Label slow_case;
|
| __ orr(r2, r0, Operand(r1));
|
| - __ JumpIfNotSmi(r2, &slow_case);
|
| + patch_site.EmitJumpIfNotSmi(r2, &slow_case);
|
| __ cmp(r1, r0);
|
| Split(cond, if_true, if_false, NULL);
|
| __ bind(&slow_case);
|
| }
|
| - CompareFlags flags = inline_smi_code
|
| - ? NO_SMI_COMPARE_IN_STUB
|
| - : NO_COMPARE_FLAGS;
|
| - CompareStub stub(cond, strict, flags, r1, r0);
|
| - __ CallStub(&stub);
|
| +
|
| + // Record position and call the compare IC.
|
| + SetSourcePosition(expr->position());
|
| + Handle<Code> ic = CompareIC::GetUninitialized(op);
|
| + EmitCallIC(ic, &patch_site);
|
| PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| - __ cmp(r0, Operand(0, RelocInfo::NONE));
|
| + __ cmp(r0, Operand(0));
|
| Split(cond, if_true, if_false, fall_through);
|
| }
|
| }
|
| @@ -3591,6 +3653,16 @@
|
| }
|
|
|
|
|
| +void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) {
|
| + __ Call(ic, RelocInfo::CODE_TARGET);
|
| + if (patch_site != NULL && patch_site->is_bound()) {
|
| + patch_site->EmitPatchInfo();
|
| + } else {
|
| + __ nop(); // Signals no inlined code.
|
| + }
|
| +}
|
| +
|
| +
|
| void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
|
| ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
|
| __ str(value, MemOperand(fp, frame_offset));
|
|
|