Revision: 4510
Author: [email protected]
Date: Tue Apr 27 04:16:05 2010
Log: Inline keyed load on ARM
This uses the same infrastructure as is used by the inlining of named
property load. The code patching if the inlined code is simpler as the key
is provided in a register os the only patching required is the map check
directing the inlined code to the deferred code block or not.
Review URL: http://codereview.chromium.org/1735007
http://code.google.com/p/v8/source/detail?r=4510
Modified:
/branches/bleeding_edge/src/arm/assembler-arm.cc
/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/arm/virtual-frame-arm.cc
/branches/bleeding_edge/src/arm/virtual-frame-arm.h
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.cc Tue Apr 27 02:09:51
2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.cc Tue Apr 27 04:16:05
2010
@@ -800,9 +800,10 @@
ASSERT(is_int24(imm24));
emit(cond | B27 | B25 | (imm24 & Imm24Mask));
- if (cond == al)
+ if (cond == al) {
// Dead code is a good location to emit the constant pool.
CheckConstPool(false, false);
+ }
}
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc Tue Apr 27 02:23:33 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc Tue Apr 27 04:16:05 2010
@@ -3703,7 +3703,7 @@
LoadAndSpill(property->obj());
LoadAndSpill(property->key());
- EmitKeyedLoad(false);
+ EmitKeyedLoad();
frame_->Drop(); // key
// Put the function below the receiver.
if (property->is_synthetic()) {
@@ -5250,7 +5250,38 @@
__ Call(ic, RelocInfo::CODE_TARGET);
// The call must be followed by a nop(1) instruction to indicate that
the
// in-object has been inlined.
- __ nop(NAMED_PROPERTY_LOAD_INLINED);
+ __ nop(PROPERTY_LOAD_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);
+ }
+}
+
+
+class DeferredReferenceGetKeyedValue: public DeferredCode {
+ public:
+ DeferredReferenceGetKeyedValue() {
+ set_comment("[ DeferredReferenceGetKeyedValue");
+ }
+
+ virtual void Generate();
+};
+
+
+void DeferredReferenceGetKeyedValue::Generate() {
+ __ DecrementCounter(&Counters::keyed_load_inline, 1, r1, r2);
+ __ IncrementCounter(&Counters::keyed_load_inline_miss, 1, r1, r2);
+
+ // The rest of the instructions in the deferred code must be together.
+ { Assembler::BlockConstPoolScope block_const_pool(masm_);
+ // Call keyed load IC. It has all arguments on the stack.
+ Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ __ Call(ic, RelocInfo::CODE_TARGET);
+ // The call must be followed by a nop instruction to indicate that the
+ // keyed load has been inlined.
+ __ nop(PROPERTY_LOAD_INLINED);
// Block the constant pool for one more instruction after leaving this
// constant pool block scope to include the branch instruction ending
the
@@ -5269,7 +5300,7 @@
? RelocInfo::CODE_TARGET_CONTEXT
: RelocInfo::CODE_TARGET);
} else {
- // Inline the inobject property case.
+ // Inline the in-object property case.
Comment cmnt(masm(), "[ Inlined named property load");
DeferredReferenceGetNamedValue* deferred =
@@ -5304,7 +5335,7 @@
__ cmp(r2, r3);
deferred->Branch(ne);
- // Use initially use an invalid index. The index will be patched by
the
+ // Initially use an invalid index. The index will be patched by the
// inline cache code.
__ ldr(r0, MemOperand(r1, 0));
@@ -5318,13 +5349,81 @@
}
-void CodeGenerator::EmitKeyedLoad(bool is_global) {
- Comment cmnt(masm_, "[ Load from keyed Property");
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
- RelocInfo::Mode rmode = is_global
- ? RelocInfo::CODE_TARGET_CONTEXT
- : RelocInfo::CODE_TARGET;
- frame_->CallCodeObject(ic, rmode, 0);
+void CodeGenerator::EmitKeyedLoad() {
+ if (loop_nesting() == 0) {
+ Comment cmnt(masm_, "[ Load from keyed property");
+ frame_->CallKeyedLoadIC();
+ } else {
+ // Inline the keyed load.
+ Comment cmnt(masm_, "[ Inlined load from keyed property");
+
+ DeferredReferenceGetKeyedValue* deferred =
+ new DeferredReferenceGetKeyedValue();
+
+ // Counter will be decremented in the deferred code. Placed here to
avoid
+ // having it in the instruction stream below where patching will occur.
+ __ IncrementCounter(&Counters::keyed_load_inline, 1,
+ frame_->scratch0(), frame_->scratch1());
+
+ // Load the receiver from the stack.
+ __ ldr(r0, MemOperand(sp, kPointerSize));
+
+ // Check that the receiver is a heap object.
+ __ tst(r0, Operand(kSmiTagMask));
+ deferred->Branch(eq);
+
+ // The following instructions are the inlined load keyed property.
Parts
+ // of this code are patched, so the exact number of instructions
generated
+ // need to be fixed. Therefore the constant pool is blocked while
generating
+ // this code.
+#ifdef DEBUG
+ int kInlinedKeyedLoadInstructions = 20;
+ Label check_inlined_codesize;
+ masm_->bind(&check_inlined_codesize);
+#endif
+ { Assembler::BlockConstPoolScope block_const_pool(masm_);
+ // Check the map. The null map used below is patched by the inline
cache
+ // code.
+ __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
+ __ mov(r2, Operand(Factory::null_value()));
+ __ cmp(r1, r2);
+ deferred->Branch(ne);
+
+ // Load the key from the stack.
+ __ ldr(r1, MemOperand(sp, 0));
+
+ // Check that the key is a smi.
+ __ tst(r1, Operand(kSmiTagMask));
+ deferred->Branch(ne);
+
+ // Get the elements array from the receiver and check that it
+ // is not a dictionary.
+ __ ldr(r2, FieldMemOperand(r0, JSObject::kElementsOffset));
+ __ ldr(r3, FieldMemOperand(r2, JSObject::kMapOffset));
+ __ LoadRoot(r4, Heap::kFixedArrayMapRootIndex);
+ __ cmp(r3, r4);
+ deferred->Branch(ne);
+
+ // Check that key is within bounds.
+ __ ldr(r3, FieldMemOperand(r2, FixedArray::kLengthOffset));
+ __ cmp(r3, Operand(r1, ASR, kSmiTagSize));
+ deferred->Branch(ls); // Unsigned less equal.
+
+ // Load and check that the result is not the hole (r1 is a smi).
+ __ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
+ __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+ __ ldr(r0, MemOperand(r2, r1, LSL,
+ kPointerSizeLog2 - (kSmiTagSize +
kSmiShiftSize)));
+ __ cmp(r0, r3);
+ deferred->Branch(eq);
+
+ // Make sure that the expected number of instructions are generated.
+ ASSERT_EQ(kInlinedKeyedLoadInstructions,
+
masm_->InstructionsGeneratedSince(&check_inlined_codesize));
+ }
+
+ deferred->BindExit();
+ }
}
@@ -5383,12 +5482,8 @@
}
case KEYED: {
- // TODO(181): Implement inlined version of array indexing once
- // loop nesting is properly tracked on ARM.
ASSERT(property != NULL);
- Variable* var = expression_->AsVariableProxy()->AsVariable();
- ASSERT(var == NULL || var->is_global());
- cgen_->EmitKeyedLoad(var != NULL);
+ cgen_->EmitKeyedLoad();
cgen_->frame()->EmitPush(r0);
break;
}
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h Fri Apr 23 00:42:45 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.h Tue Apr 27 04:16:05 2010
@@ -157,7 +157,7 @@
// states of the generated code.
enum NopMarkerTypes {
NON_MARKING_NOP = 0,
- NAMED_PROPERTY_LOAD_INLINED
+ PROPERTY_LOAD_INLINED
};
@@ -318,7 +318,7 @@
// Load a keyed property, leaving it in r0. The receiver and key are
// passed on the stack, and remain there.
- void EmitKeyedLoad(bool is_global);
+ void EmitKeyedLoad();
void LoadFromGlobalSlotCheckExtensions(Slot* slot,
TypeofState typeof_state,
=======================================
--- /branches/bleeding_edge/src/arm/ic-arm.cc Mon Apr 26 07:25:29 2010
+++ /branches/bleeding_edge/src/arm/ic-arm.cc Tue Apr 27 04:16:05 2010
@@ -563,15 +563,8 @@
}
-void LoadIC::ClearInlinedVersion(Address address) {
- // Reset the map check of the inlined inobject property load (if
present) to
- // guarantee failure by holding an invalid map (the null value). The
offset
- // can be patched to anything.
- PatchInlinedLoad(address, Heap::null_value(), 0);
-}
-
-
-bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
+static inline bool IsInlinedICSite(Address address,
+ Address* inline_end_address) {
// 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
@@ -579,24 +572,42 @@
// a branch 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::IsNop(instr_after_call, NAMED_PROPERTY_LOAD_INLINED)) {
+ if (!Assembler::IsNop(instr_after_call, 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));
+ Address address_after_nop = address_after_call + Assembler::kInstrSize;
+ Instr instr_after_nop = Assembler::instr_at(address_after_nop);
+ ASSERT(Assembler::IsBranch(instr_after_nop));
// Find the end of the inlined code for handling the load.
int b_offset =
- Assembler::GetBranchOffset(instr_after_nop1) +
Assembler::kPcLoadDelta;
+ Assembler::GetBranchOffset(instr_after_nop) +
Assembler::kPcLoadDelta;
ASSERT(b_offset < 0); // Jumping back from deferred code.
- Address inline_end_address = address_after_nop1 + b_offset;
+ *inline_end_address = address_after_nop + b_offset;
+
+ return true;
+}
+
+
+void LoadIC::ClearInlinedVersion(Address address) {
+ // Reset the map check of the inlined in-object property load (if
present) to
+ // guarantee failure by holding an invalid map (the null value). The
offset
+ // can be patched to anything.
+ PatchInlinedLoad(address, Heap::null_value(), 0);
+}
+
+
+bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
+ // Find the end of the inlined code for handling the load if this is an
+ // inlined IC call site.
+ Address inline_end_address;
+ if (!IsInlinedICSite(address, &inline_end_address)) return false;
// Patch the offset of the property load instruction (ldr r0, [r1,
#+XXX]).
- // The immediate must be represenatble in 12 bits.
+ // The immediate must be representable in 12 bits.
ASSERT((JSObject::kMaxInstanceSize - JSObject::kHeaderSize) < (1 << 12));
- Address ldr_property_instr_address = inline_end_address - 4;
+ Address ldr_property_instr_address =
+ inline_end_address - Assembler::kInstrSize;
ASSERT(Assembler::IsLdrRegisterImmediate(
Assembler::instr_at(ldr_property_instr_address)));
Instr ldr_property_instr =
Assembler::instr_at(ldr_property_instr_address);
@@ -608,18 +619,31 @@
CPU::FlushICache(ldr_property_instr_address, 1 * Assembler::kInstrSize);
// Patch the map check.
- Address ldr_map_instr_address = inline_end_address - 16;
+ Address ldr_map_instr_address =
+ inline_end_address - 4 * Assembler::kInstrSize;
Assembler::set_target_address_at(ldr_map_instr_address,
reinterpret_cast<Address>(map));
return true;
}
-void KeyedLoadIC::ClearInlinedVersion(Address address) {}
+void KeyedLoadIC::ClearInlinedVersion(Address address) {
+ // Reset the map check of the inlined keyed load (if present) to
+ // guarantee failure by holding an invalid map (the null value).
+ PatchInlinedLoad(address, Heap::null_value());
+}
bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
- return false;
+ Address inline_end_address;
+ if (!IsInlinedICSite(address, &inline_end_address)) return false;
+
+ // Patch the map check.
+ Address ldr_map_instr_address =
+ inline_end_address - 19 * Assembler::kInstrSize;
+ Assembler::set_target_address_at(ldr_map_instr_address,
+ reinterpret_cast<Address>(map));
+ return true;
}
=======================================
--- /branches/bleeding_edge/src/arm/virtual-frame-arm.cc Mon Apr 26
07:25:29 2010
+++ /branches/bleeding_edge/src/arm/virtual-frame-arm.cc Tue Apr 27
04:16:05 2010
@@ -301,6 +301,12 @@
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
CallCodeObject(ic, mode, 0);
}
+
+
+void VirtualFrame::CallKeyedLoadIC() {
+ Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
+}
void VirtualFrame::CallCodeObject(Handle<Code> code,
=======================================
--- /branches/bleeding_edge/src/arm/virtual-frame-arm.h Fri Apr 23 00:42:45
2010
+++ /branches/bleeding_edge/src/arm/virtual-frame-arm.h Tue Apr 27 04:16:05
2010
@@ -308,10 +308,14 @@
InvokeJSFlags flag,
int arg_count);
- // Call load IC. Receiver on stack and property name in r2. Result
returned in
- // r0.
+ // Call load IC. Receiver is on the stack and the property name is in r2.
+ // Result is returned in r0.
void CallLoadIC(RelocInfo::Mode mode);
+ // Call keyed load IC. Key and receiver are on the stack. Result is
returned
+ // in r0.
+ void CallKeyedLoadIC();
+
// Call into an IC stub given the number of arguments it removes
// from the stack. Register arguments to the IC stub are implicit,
// and depend on the type of IC stub.
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev