| Index: src/arm/codegen-arm.cc
|
| ===================================================================
|
| --- src/arm/codegen-arm.cc (revision 4509)
|
| +++ src/arm/codegen-arm.cc (working copy)
|
| @@ -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,7 @@
|
| __ 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
|
| @@ -5260,6 +5260,37 @@
|
| }
|
|
|
|
|
| +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
|
| + // deferred code.
|
| + __ BlockConstPoolFor(1);
|
| + }
|
| +}
|
| +
|
| +
|
| void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
|
| if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) {
|
| Comment cmnt(masm(), "[ Load from named Property");
|
| @@ -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;
|
| }
|
|
|