MIPS64: Improve deopt jump table code size.
authordusan.milosavljevic <dusan.milosavljevic@imgtec.com>
Fri, 3 Apr 2015 18:02:17 +0000 (11:02 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 3 Apr 2015 18:02:19 +0000 (18:02 +0000)
The number of generated instructions per table entry is reduced from six to
two, or four in worst-case scenario.

TEST=
BUG=

Review URL: https://codereview.chromium.org/1059213002

Cr-Commit-Position: refs/heads/master@{#27599}

src/mips64/lithium-codegen-mips64.cc
src/mips64/lithium-codegen-mips64.h

index 3b19379..6154584 100644 (file)
@@ -301,50 +301,71 @@ bool LCodeGen::GenerateDeferredCode() {
 bool LCodeGen::GenerateJumpTable() {
   if (jump_table_.length() > 0) {
     Comment(";;; -------------------- Jump table --------------------");
-  }
-  Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
-  Label table_start, call_deopt_entry;
-  __ bind(&table_start);
-  Label needs_frame;
-  for (int i = 0; i < jump_table_.length(); i++) {
-    Deoptimizer::JumpTableEntry* table_entry = &jump_table_[i];
-    __ bind(&table_entry->label);
-    Address entry = table_entry->address;
-    DeoptComment(table_entry->deopt_info);
-    __ li(t9, Operand(ExternalReference::ForDeoptEntry(entry)));
-    if (table_entry->needs_frame) {
-      DCHECK(!info()->saves_caller_doubles());
-      Comment(";;; call deopt with frame");
-      __ MultiPush(cp.bit() | fp.bit() | ra.bit());
-      __ Call(&needs_frame);
-    } else {
-      __ Call(&call_deopt_entry);
-    }
-    info()->LogDeoptCallPosition(masm()->pc_offset(),
-                                 table_entry->deopt_info.inlining_id);
-  }
-  if (needs_frame.is_linked()) {
-    __ bind(&needs_frame);
-    // This variant of deopt can only be used with stubs. Since we don't
-    // have a function pointer to install in the stack frame that we're
-    // building, install a special marker there instead.
-    DCHECK(info()->IsStub());
-    __ li(at, Operand(Smi::FromInt(StackFrame::STUB)));
-    __ push(at);
-    __ Daddu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
-  }
+    Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
+    Label table_start, call_deopt_entry;
+
+    __ bind(&table_start);
+    Label needs_frame;
+    Address base = jump_table_[0]->address;
+    for (int i = 0; i < jump_table_.length(); i++) {
+      Deoptimizer::JumpTableEntry* table_entry = jump_table_[i];
+      __ bind(&table_entry->label);
+      Address entry = table_entry->address;
+      DeoptComment(table_entry->deopt_info);
+
+      // Second-level deopt table entries are contiguous and small, so instead
+      // of loading the full, absolute address of each one, load the base
+      // address and add an immediate offset.
+      if (is_int16(entry - base)) {
+        if (table_entry->needs_frame) {
+          DCHECK(!info()->saves_caller_doubles());
+          Comment(";;; call deopt with frame");
+          __ MultiPush(cp.bit() | fp.bit() | ra.bit());
+          __ BranchAndLink(&needs_frame, USE_DELAY_SLOT);
+          __ li(t9, Operand(entry - base));
+        } else {
+          __ BranchAndLink(&call_deopt_entry, USE_DELAY_SLOT);
+          __ li(t9, Operand(entry - base));
+        }
 
-  Comment(";;; call deopt");
-  __ bind(&call_deopt_entry);
+      } else {
+        __ li(t9, Operand(entry - base));
+        if (table_entry->needs_frame) {
+          DCHECK(!info()->saves_caller_doubles());
+          Comment(";;; call deopt with frame");
+          __ MultiPush(cp.bit() | fp.bit() | ra.bit());
+          __ BranchAndLink(&needs_frame);
+        } else {
+          __ BranchAndLink(&call_deopt_entry);
+        }
+      }
+      info()->LogDeoptCallPosition(masm()->pc_offset(),
+                                   table_entry->deopt_info.inlining_id);
+    }
+    if (needs_frame.is_linked()) {
+      __ bind(&needs_frame);
+      // This variant of deopt can only be used with stubs. Since we don't
+      // have a function pointer to install in the stack frame that we're
+      // building, install a special marker there instead.
+      DCHECK(info()->IsStub());
+      __ li(at, Operand(Smi::FromInt(StackFrame::STUB)));
+      __ push(at);
+      __ Daddu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+    }
 
-  if (info()->saves_caller_doubles()) {
-    DCHECK(info()->IsStub());
-    RestoreCallerDoubles();
-  }
-  __ Jump(t9);
+    Comment(";;; call deopt");
+    __ bind(&call_deopt_entry);
 
-  __ RecordComment("]");
+    if (info()->saves_caller_doubles()) {
+      DCHECK(info()->IsStub());
+      RestoreCallerDoubles();
+    }
 
+    __ li(at,
+          Operand(reinterpret_cast<int64_t>(base), RelocInfo::RUNTIME_ENTRY));
+    __ Daddu(t9, t9, Operand(at));
+    __ Jump(t9);
+  }
   // The deoptimization jump table is the last part of the instruction
   // sequence. Mark the generated code as done unless we bailed out.
   if (!is_aborted()) status_ = DONE;
@@ -824,16 +845,17 @@ void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
     __ Call(entry, RelocInfo::RUNTIME_ENTRY, condition, src1, src2);
     info()->LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
   } else {
-    Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
-                                            !frame_is_built_);
+    Deoptimizer::JumpTableEntry* table_entry =
+        new (zone()) Deoptimizer::JumpTableEntry(
+            entry, deopt_info, bailout_type, !frame_is_built_);
     // We often have several deopts to the same entry, reuse the last
     // jump entry if this is the case.
     if (FLAG_trace_deopt || isolate()->cpu_profiler()->is_profiling() ||
         jump_table_.is_empty() ||
-        !table_entry.IsEquivalentTo(jump_table_.last())) {
+        !table_entry->IsEquivalentTo(*jump_table_.last())) {
       jump_table_.Add(table_entry, zone());
     }
-    __ Branch(&jump_table_.last().label, condition, src1, src2);
+    __ Branch(&jump_table_.last()->label, condition, src1, src2);
   }
 }
 
index 38890b3..8f0e82c 100644 (file)
@@ -358,7 +358,7 @@ class LCodeGen: public LCodeGenBase {
   void EmitVectorLoadICRegisters(T* instr);
 
   ZoneList<LEnvironment*> deoptimizations_;
-  ZoneList<Deoptimizer::JumpTableEntry> jump_table_;
+  ZoneList<Deoptimizer::JumpTableEntry*> jump_table_;
   ZoneList<Handle<Object> > deoptimization_literals_;
   int inlined_function_count_;
   Scope* const scope_;