Revision: 5116
Author: [email protected]
Date: Thu Jul 22 01:17:40 2010
Log: Port inlined in-object property stores to ARM.
Review URL: http://codereview.chromium.org/2878043
http://code.google.com/p/v8/source/detail?r=5116
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/ic-arm.cc
/branches/bleeding_edge/src/jump-target-light.h
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.cc Wed Jul 21 00:42:51
2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.cc Thu Jul 22 01:17:40
2010
@@ -443,6 +443,37 @@
// Set the actual offset.
return (instr & ~Off12Mask) | 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) {
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.h Wed Jul 21 00:42:51 2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.h Thu Jul 22 01:17:40 2010
@@ -1120,6 +1120,10 @@
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);
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc Fri Jul 16 04:21:08 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc Thu Jul 22 01:17:40 2010
@@ -6205,6 +6205,48 @@
__ BlockConstPoolFor(1);
}
}
+
+
+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.
@@ -6277,11 +6319,61 @@
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());
}
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h Fri Jul 16 04:21:08 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.h Thu Jul 22 01:17:40 2010
@@ -281,6 +281,9 @@
return FLAG_debug_code ? 27 : 13;
}
static const int kInlinedKeyedStoreInstructionsAfterPatch = 5;
+ static int GetInlinedNamedStoreInstructionsAfterPatch() {
+ return FLAG_debug_code ? 33 : 14;
+ }
private:
// Construction/Destruction
=======================================
--- /branches/bleeding_edge/src/arm/ic-arm.cc Wed Jul 21 00:42:51 2010
+++ /branches/bleeding_edge/src/arm/ic-arm.cc Thu Jul 22 01:17:40 2010
@@ -989,8 +989,49 @@
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;
}
=======================================
--- /branches/bleeding_edge/src/jump-target-light.h Thu Jun 24 00:54:48 2010
+++ /branches/bleeding_edge/src/jump-target-light.h Thu Jul 22 01:17:40 2010
@@ -101,8 +101,7 @@
// 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
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev