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

Reply via email to