Assembler::~Assembler() {
+ ASSERT(const_pool_blocked_nesting_ == 0);
if (own_buffer_) {
if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
spare_buffer_ = buffer_;
}
-bool Assembler::IsB(Instr instr) {
+bool Assembler::IsNop(Instr instr, int type) {
+ // Check for mov rx, rx.
+ ASSERT(0 <= type && type <= 14); // mov pc, pc is not a nop.
+ return instr == (al | 13*B21 | type*B12 | type);
+}
+
+
+bool Assembler::IsBranch(Instr instr) {
return (instr & (B27 | B25)) == (B27 | B25);
}
-int Assembler::GetBOffset(Instr instr) {
- ASSERT(IsB(instr));
+int Assembler::GetBranchOffset(Instr instr) {
+ ASSERT(IsBranch(instr));
// Take the jump offset in the lower 24 bits, sign extend it and multiply it
// with 4 to get the offset in bytes.
return ((instr & Imm24Mask) << 8) >> 6;
if (dst.is(pc)) {
WriteRecordedPositions();
}
+ // Don't allow nop instructions in the form mov rn, rn to be generated using
+ // the mov instruction. They must be generated using nop(int)
+ // pseudo instructions.
+ ASSERT(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al));
addrmod1(cond | 13*B21 | s, r0, dst, src);
}
// Pseudo instructions.
+void Assembler::nop(int type) {
+ // This is mov rx, rx.
+ ASSERT(0 <= type && type <= 14); // mov pc, pc is not a nop.
+ emit(al | 13*B21 | type*B12 | type);
+}
+
+
void Assembler::lea(Register dst,
const MemOperand& x,
SBit s,
const Condition cond = al);
// Pseudo instructions
- void nop() { mov(r0, Operand(r0)); }
+ void nop(int type = 0);
void push(Register src, Condition cond = al) {
str(src, MemOperand(sp, 4, NegPreIndex), cond);
class BlockConstPoolScope {
public:
explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
- assem_->const_pool_blocked_nesting_++;
+ assem_->StartBlockConstPool();
}
~BlockConstPoolScope() {
- assem_->const_pool_blocked_nesting_--;
+ assem_->EndBlockConstPool();
}
private:
int current_position() const { return current_position_; }
int current_statement_position() const { return current_statement_position_; }
+ void StartBlockConstPool() {
+ const_pool_blocked_nesting_++;
+ }
+ void EndBlockConstPool() {
+ const_pool_blocked_nesting_--;
+ }
+
// Read/patch instructions
static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
static void instr_at_put(byte* pc, Instr instr) {
*reinterpret_cast<Instr*>(pc) = instr;
}
- static bool IsB(Instr instr);
- static int GetBOffset(Instr instr);
+ static bool IsNop(Instr instr, int type = 0);
+ static bool IsBranch(Instr instr);
+ static int GetBranchOffset(Instr instr);
static bool IsLdrRegisterImmediate(Instr instr);
static int GetLdrRegisterImmediateOffset(Instr instr);
static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
+
protected:
int buffer_space() const { return reloc_info_writer.pos() - pc_; }
set_comment("[ DeferredReferenceGetNamedValue");
}
+ virtual void BeforeGenerate();
virtual void Generate();
+ virtual void AfterGenerate();
private:
Handle<String> name_;
};
+void DeferredReferenceGetNamedValue::BeforeGenerate() {
+ __ StartBlockConstPool();
+}
+
+
void DeferredReferenceGetNamedValue::Generate() {
__ IncrementCounter(&Counters::named_load_inline_miss, 1, r1, r2);
// Setup the name register and call load IC.
__ mov(r2, Operand(name_));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
- // The call must be followed by a b instruction to indicate that the inobject
- // property case was inlined. Jumping back from the deferred code ensures
- // that.
+ // The call must be followed by a nop(1) instruction to indicate that the
+ // inobject has been inlined.
+ __ nop(NAMED_PROPERTY_LOAD_INLINED);
+}
+
+
+void DeferredReferenceGetNamedValue::AfterGenerate() {
+ __ EndBlockConstPool();
}
};
+// Different nop operations are used by the code generator to detect certain
+// states of the generated code.
+enum NopMarkerTypes {
+ NON_MARKING_NOP = 0,
+ NAMED_PROPERTY_LOAD_INLINED
+};
+
+
// -------------------------------------------------------------------------
// CodeGenerator
void StoreToSlot(Slot* slot, InitState init_state);
// Load a named property, leaving it in r0. The receiver is passed on the
- // stack, and remain there.
+ // stack, and remains there.
void EmitNamedLoad(Handle<String> name, bool is_contextual);
// Load a keyed property, leaving it in r0. The receiver and key are
__ push(ip);
__ mov(r2, Operand(var->name()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
- { Assembler::BlockConstPoolScope block_const_pool(masm_);
- __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
- // A B instruction following the call signals that the load was inlined.
- // Ensure that there is not a B instruction here.
- __ nop();
- }
+ __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
DropAndApply(1, context, r0);
} else if (slot != NULL && slot->type() == Slot::LOOKUP) {
Literal* key = prop->key()->AsLiteral();
__ mov(r2, Operand(key->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
- { Assembler::BlockConstPoolScope block_const_pool(masm_);
- __ Call(ic, RelocInfo::CODE_TARGET);
- // A B instruction following the call signals that the load was inlined.
- // Ensure that there is not a B instruction here.
- __ nop();
- }
+ __ Call(ic, RelocInfo::CODE_TARGET);
}
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
// Use a regular load, not a contextual load, to avoid a reference
// error.
- { Assembler::BlockConstPoolScope block_const_pool(masm_);
- __ Call(ic, RelocInfo::CODE_TARGET);
- // A B instruction following the call signals that the load was
- // inlined. Ensure that there is not a B instruction here.
- __ nop();
- }
+ __ Call(ic, RelocInfo::CODE_TARGET);
__ str(r0, MemOperand(sp));
} else if (proxy != NULL &&
proxy->var()->slot() != NULL &&
bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
- // If the instruction after the call site is not a B instruction then this is
- // not related to an inlined in-object property load. The B instructions is
- // located just after the call to the IC in the deferred code handling the
- // miss in the inlined code. All other calls to a load IC should ensure there
- // in no B instruction directly following the call.
+ // If the instruction after the call site is not the pseudo instruction nop1
+ // then this is not related to an inlined in-object property load. The nop1
+ // instruction is located just after the call to the IC in the deferred code
+ // handling the miss in the inlined code. After the nop1 instruction there is
+ // a B instruction for jumping back from the deferred code.
Address address_after_call = address + Assembler::kCallTargetAddressOffset;
Instr instr_after_call = Assembler::instr_at(address_after_call);
- if (!Assembler::IsB(instr_after_call)) return false;
+ if (!Assembler::IsNop(instr_after_call, NAMED_PROPERTY_LOAD_INLINED)) {
+ return false;
+ }
+ ASSERT_EQ(0, RegisterAllocator::kNumRegisters);
+ Address address_after_nop1 = address_after_call + Assembler::kInstrSize;
+ Instr instr_after_nop1 = Assembler::instr_at(address_after_nop1);
+ ASSERT(Assembler::IsBranch(instr_after_nop1));
// Find the end of the inlined code for handling the load.
int b_offset =
- Assembler::GetBOffset(instr_after_call) + Assembler::kPcLoadDelta;
+ Assembler::GetBranchOffset(instr_after_nop1) + Assembler::kPcLoadDelta;
ASSERT(b_offset < 0); // Jumping back from deferred code.
- Address inline_end_address = address_after_call + b_offset;
+ Address inline_end_address = address_after_nop1 + b_offset;
// Patch the offset of the property load instruction (ldr r0, [r1, #+XXX]).
+ // The immediate must be represenatble in 12 bits.
+ ASSERT((JSObject::kMaxInstanceSize - JSObject::kHeaderSize) < (1 << 12));
Address ldr_property_instr_address = inline_end_address - 4;
ASSERT(Assembler::IsLdrRegisterImmediate(
Assembler::instr_at(ldr_property_instr_address)));
}
-void VirtualFrame::CallLoadIC(RelocInfo::Mode mode, bool load_inlined) {
- // If a nop is generated later make sure the it follows the call directly.
- Assembler::BlockConstPoolScope block_const_pool(masm());
-
+void VirtualFrame::CallLoadIC(RelocInfo::Mode mode) {
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
CallCodeObject(ic, mode, 0);
- if (!load_inlined) {
- // A B instruction following the call signals that the load was inlined.
- // Ensure that there is not a B instruction here.
- __ nop();
- }
}
int arg_count);
// Call load IC. Receiver on stack and property name in r2. Result returned in
- // r0. If load_inlined is false the code generated will make sure that the IC
- // handling will not see this load as having an inlined counterpart.
- void CallLoadIC(RelocInfo::Mode mode, bool load_inlined = false);
+ // r0.
+ void CallLoadIC(RelocInfo::Mode mode);
// Call into an IC stub given the number of arguments it removes
// from the stack. Register arguments to the IC stub are implicit,
}
// Generate the code.
Comment cmnt(masm_, code->comment());
+ code->BeforeGenerate();
masm_->bind(code->entry_label());
code->SaveRegisters();
code->Generate();
code->RestoreRegisters();
masm_->jmp(code->exit_label());
+ code->AfterGenerate();
}
}
void SaveRegisters();
void RestoreRegisters();
+ virtual void BeforeGenerate() { }
+ virtual void AfterGenerate() { }
+
protected:
MacroAssembler* masm_;