Changed inlined property load detection on ARM

Instaed of having a nop after all non-inlined calls to load IC use a different nop (mov r1, r1 instead of mov r0, r0) to detect an inlined load IC.

Added more infrastructure to the deferred code handling to make it possbile to block constant pool emitting in a deferred code block, including the branch instruction ending the deferred code block.

Addressed a couple of comments to http://codereview.chromium.org/1715003, including adding an assert to make sure that the patching of an ldr instruction is always possible.
Review URL: http://codereview.chromium.org/1758003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4480 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
sgjesse@chromium.org 2010-04-23 07:42:45 +00:00
parent c20fcec3af
commit 931f0a031a
10 changed files with 87 additions and 50 deletions

View File

@ -318,6 +318,7 @@ Assembler::Assembler(void* buffer, int buffer_size) {
Assembler::~Assembler() {
ASSERT(const_pool_blocked_nesting_ == 0);
if (own_buffer_) {
if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
spare_buffer_ = buffer_;
@ -349,13 +350,20 @@ void Assembler::Align(int m) {
}
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;
@ -941,6 +949,10 @@ void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
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);
}
@ -1730,6 +1742,13 @@ void Assembler::vmrs(Register dst, Condition cond) {
// 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,

View File

@ -896,7 +896,7 @@ class Assembler : public Malloced {
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);
@ -929,10 +929,10 @@ class Assembler : public Malloced {
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:
@ -958,17 +958,26 @@ class Assembler : public Malloced {
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_; }

View File

@ -5229,22 +5229,34 @@ class DeferredReferenceGetNamedValue: public DeferredCode {
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();
}

View File

@ -153,6 +153,14 @@ enum ArgumentsAllocationMode {
};
// 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
@ -305,7 +313,7 @@ class CodeGenerator: public AstVisitor {
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

View File

@ -700,12 +700,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var,
__ 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) {
@ -1003,12 +998,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
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);
}
@ -1445,12 +1435,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
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 &&

View File

@ -572,22 +572,30 @@ void LoadIC::ClearInlinedVersion(Address address) {
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)));

View File

@ -299,17 +299,9 @@ void VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
}
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();
}
}

View File

@ -309,9 +309,8 @@ class VirtualFrame : public ZoneObject {
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,

View File

@ -77,11 +77,13 @@ void CodeGenerator::ProcessDeferred() {
}
// 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();
}
}

View File

@ -212,6 +212,9 @@ class DeferredCode: public ZoneObject {
void SaveRegisters();
void RestoreRegisters();
virtual void BeforeGenerate() { }
virtual void AfterGenerate() { }
protected:
MacroAssembler* masm_;