Commit a36bf8f0 authored by ager@chromium.org's avatar ager@chromium.org

Port inlined in-object property stores to ARM.

Review URL: http://codereview.chromium.org/2878043

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5116 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent dc45fcb2
......@@ -445,6 +445,37 @@ Instr Assembler::SetLdrRegisterImmediateOffset(Instr instr, int offset) {
}
bool Assembler::IsStrRegisterImmediate(Instr instr) {
return (instr & (B27 | B26 | B25 | B22 | B20)) == B26;
}
Instr Assembler::SetStrRegisterImmediateOffset(Instr instr, int offset) {
ASSERT(IsStrRegisterImmediate(instr));
bool positive = offset >= 0;
if (!positive) offset = -offset;
ASSERT(is_uint12(offset));
// Set bit indicating whether the offset should be added.
instr = (instr & ~B23) | (positive ? B23 : 0);
// Set the actual offset.
return (instr & ~Off12Mask) | offset;
}
bool Assembler::IsAddRegisterImmediate(Instr instr) {
return (instr & (B27 | B26 | B25 | B24 | B23 | B22 | B21)) == (B25 | B23);
}
Instr Assembler::SetAddRegisterImmediateOffset(Instr instr, int offset) {
ASSERT(IsAddRegisterImmediate(instr));
ASSERT(offset >= 0);
ASSERT(is_uint12(offset));
// Set the offset.
return (instr & ~Off12Mask) | offset;
}
Register Assembler::GetRd(Instr instr) {
Register reg;
reg.code_ = ((instr & kRdMask) >> kRdShift);
......
......@@ -1120,6 +1120,10 @@ class Assembler : public Malloced {
static bool IsLdrRegisterImmediate(Instr instr);
static int GetLdrRegisterImmediateOffset(Instr instr);
static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
static bool IsStrRegisterImmediate(Instr instr);
static Instr SetStrRegisterImmediateOffset(Instr instr, int offset);
static bool IsAddRegisterImmediate(Instr instr);
static Instr SetAddRegisterImmediateOffset(Instr instr, int offset);
static Register GetRd(Instr instr);
static bool IsPush(Instr instr);
static bool IsPop(Instr instr);
......
......@@ -6207,6 +6207,48 @@ void DeferredReferenceSetKeyedValue::Generate() {
}
class DeferredReferenceSetNamedValue: public DeferredCode {
public:
DeferredReferenceSetNamedValue(Register value,
Register receiver,
Handle<String> name)
: value_(value), receiver_(receiver), name_(name) {
set_comment("[ DeferredReferenceSetNamedValue");
}
virtual void Generate();
private:
Register value_;
Register receiver_;
Handle<String> name_;
};
void DeferredReferenceSetNamedValue::Generate() {
// Ensure value in r0, receiver in r1 to match store ic calling
// convention.
ASSERT(value_.is(r0) && receiver_.is(r1));
__ mov(r2, Operand(name_));
// The rest of the instructions in the deferred code must be together.
{ Assembler::BlockConstPoolScope block_const_pool(masm_);
// Call keyed store IC. It has the arguments value, key and receiver in r0,
// r1 and r2.
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// The call must be followed by a nop instruction to indicate that the
// named store has been inlined.
__ nop(PROPERTY_ACCESS_INLINED);
// Block the constant pool for one more instruction after leaving this
// constant pool block scope to include the branch instruction ending the
// deferred code.
__ BlockConstPoolFor(1);
}
}
// Consumes the top of stack (the receiver) and pushes the result instead.
void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) {
......@@ -6277,11 +6319,61 @@ void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
void CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
#ifdef DEBUG
int expected_height = frame_->height() - (is_contextual ? 1 : 2);
int expected_height = frame()->height() - (is_contextual ? 1 : 2);
#endif
frame_->CallStoreIC(name, is_contextual);
ASSERT_EQ(expected_height, frame_->height());
Result result;
if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) {
frame()->CallStoreIC(name, is_contextual);
} else {
// Inline the in-object property case.
JumpTarget slow, done;
// Get the value and receiver from the stack.
frame()->PopToR0();
Register value = r0;
frame()->PopToR1();
Register receiver = r1;
DeferredReferenceSetNamedValue* deferred =
new DeferredReferenceSetNamedValue(value, receiver, name);
// Check that the receiver is a heap object.
__ tst(receiver, Operand(kSmiTagMask));
deferred->Branch(eq);
// The following instructions are the part of the inlined
// in-object property store code which can be patched. Therefore
// the exact number of instructions generated must be fixed, so
// the constant pool is blocked while generating this code.
{ Assembler::BlockConstPoolScope block_const_pool(masm_);
Register scratch0 = VirtualFrame::scratch0();
Register scratch1 = VirtualFrame::scratch1();
// Check the map. Initially use an invalid map to force a
// failure. The map check will be patched in the runtime system.
__ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
#ifdef DEBUG
Label check_inlined_codesize;
masm_->bind(&check_inlined_codesize);
#endif
__ mov(scratch0, Operand(Factory::null_value()));
__ cmp(scratch0, scratch1);
deferred->Branch(ne);
int offset = 0;
__ str(value, MemOperand(receiver, offset));
// Update the write barrier.
__ RecordWrite(receiver, Operand(offset), scratch0, scratch1);
// Make sure that the expected number of instructions are generated.
ASSERT_EQ(GetInlinedNamedStoreInstructionsAfterPatch(),
masm_->InstructionsGeneratedSince(&check_inlined_codesize));
}
deferred->BindExit();
}
ASSERT_EQ(expected_height, frame()->height());
}
......
......@@ -281,6 +281,9 @@ class CodeGenerator: public AstVisitor {
return FLAG_debug_code ? 27 : 13;
}
static const int kInlinedKeyedStoreInstructionsAfterPatch = 5;
static int GetInlinedNamedStoreInstructionsAfterPatch() {
return FLAG_debug_code ? 33 : 14;
}
private:
// Construction/Destruction
......
......@@ -989,8 +989,49 @@ bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
// TODO(787): Implement inline stores on arm.
return false;
// Find the end of the inlined code for the store if there is an
// inlined version of the store.
Address inline_end_address;
if (!IsInlinedICSite(address, &inline_end_address)) return false;
// Compute the address of the map load instruction.
Address ldr_map_instr_address =
inline_end_address -
(CodeGenerator::GetInlinedNamedStoreInstructionsAfterPatch() *
Assembler::kInstrSize);
// Update the offsets if initializing the inlined store. No reason
// to update the offsets when clearing the inlined version because
// it will bail out in the map check.
if (map != Heap::null_value()) {
// Patch the offset in the actual store instruction.
Address str_property_instr_address =
ldr_map_instr_address + 3 * Assembler::kInstrSize;
Instr str_property_instr = Assembler::instr_at(str_property_instr_address);
ASSERT(Assembler::IsStrRegisterImmediate(str_property_instr));
str_property_instr = Assembler::SetStrRegisterImmediateOffset(
str_property_instr, offset - kHeapObjectTag);
Assembler::instr_at_put(str_property_instr_address, str_property_instr);
// Patch the offset in the add instruction that is part of the
// write barrier.
Address add_offset_instr_address =
str_property_instr_address + 4 * Assembler::kInstrSize;
Instr add_offset_instr = Assembler::instr_at(add_offset_instr_address);
ASSERT(Assembler::IsAddRegisterImmediate(add_offset_instr));
add_offset_instr = Assembler::SetAddRegisterImmediateOffset(
add_offset_instr, offset - kHeapObjectTag);
Assembler::instr_at_put(add_offset_instr_address, add_offset_instr);
// Indicate that code has changed.
CPU::FlushICache(str_property_instr_address, 5 * Assembler::kInstrSize);
}
// Patch the map check.
Assembler::set_target_address_at(ldr_map_instr_address,
reinterpret_cast<Address>(map));
return true;
}
......
......@@ -101,8 +101,7 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
// Emit a conditional branch to the target. There must be a current
// frame at the branch. The current frame will fall through to the
// code after the branch. The arg is a result that is live both at
// the target and the fall-through.
// code after the branch.
virtual void Branch(Condition cc, Hint hint = no_hint);
// Bind a jump target. If there is no current frame at the binding
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment