Revision: 4480
Author: [email protected]
Date: Fri Apr 23 00:42:45 2010
Log: 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
http://code.google.com/p/v8/source/detail?r=4480
Modified:
/branches/bleeding_edge/src/arm/assembler-arm.cc
/branches/bleeding_edge/src/arm/assembler-arm.h
/branches/bleeding_edge/src/arm/codegen-arm.cc
/branches/bleeding_edge/src/arm/codegen-arm.h
/branches/bleeding_edge/src/arm/full-codegen-arm.cc
/branches/bleeding_edge/src/arm/ic-arm.cc
/branches/bleeding_edge/src/arm/virtual-frame-arm.cc
/branches/bleeding_edge/src/arm/virtual-frame-arm.h
/branches/bleeding_edge/src/codegen.cc
/branches/bleeding_edge/src/codegen.h
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.cc Thu Apr 22 00:26:07
2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.cc Fri Apr 23 00:42:45
2010
@@ -318,6 +318,7 @@
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 @@
}
-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 @@
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 @@
// 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,
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.h Thu Apr 22 00:18:30 2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.h Fri Apr 23 00:42:45 2010
@@ -896,7 +896,7 @@
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 BlockConstPoolScope {
public:
explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
- assem_->const_pool_blocked_nesting_++;
+ assem_->StartBlockConstPool();
}
~BlockConstPoolScope() {
- assem_->const_pool_blocked_nesting_--;
+ assem_->EndBlockConstPool();
}
private:
@@ -957,18 +957,27 @@
int pc_offset() const { return pc_ - buffer_; }
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_; }
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc Thu Apr 22 10:25:42 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc Fri Apr 23 00:42:45 2010
@@ -5229,22 +5229,34 @@
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();
}
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h Thu Apr 22 05:20:36 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.h Fri Apr 23 00:42:45 2010
@@ -153,6 +153,14 @@
};
+// 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 @@
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
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Thu Apr 22 00:18:30
2010
+++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Fri Apr 23 00:42:45
2010
@@ -700,12 +700,7 @@
__ 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 @@
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 @@
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 &&
=======================================
--- /branches/bleeding_edge/src/arm/ic-arm.cc Thu Apr 22 00:18:30 2010
+++ /branches/bleeding_edge/src/arm/ic-arm.cc Fri Apr 23 00:42:45 2010
@@ -572,22 +572,30 @@
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)));
=======================================
--- /branches/bleeding_edge/src/arm/virtual-frame-arm.cc Thu Apr 22
00:18:30 2010
+++ /branches/bleeding_edge/src/arm/virtual-frame-arm.cc Fri Apr 23
00:42:45 2010
@@ -299,17 +299,9 @@
}
-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();
- }
}
=======================================
--- /branches/bleeding_edge/src/arm/virtual-frame-arm.h Thu Apr 22 00:18:30
2010
+++ /branches/bleeding_edge/src/arm/virtual-frame-arm.h Fri Apr 23 00:42:45
2010
@@ -309,9 +309,8 @@
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,
=======================================
--- /branches/bleeding_edge/src/codegen.cc Tue Apr 6 03:36:38 2010
+++ /branches/bleeding_edge/src/codegen.cc Fri Apr 23 00:42:45 2010
@@ -77,11 +77,13 @@
}
// 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();
}
}
=======================================
--- /branches/bleeding_edge/src/codegen.h Thu Apr 15 02:34:47 2010
+++ /branches/bleeding_edge/src/codegen.h Fri Apr 23 00:42:45 2010
@@ -211,6 +211,9 @@
void SaveRegisters();
void RestoreRegisters();
+
+ virtual void BeforeGenerate() { }
+ virtual void AfterGenerate() { }
protected:
MacroAssembler* masm_;
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev