Revision: 21608
Author:   [email protected]
Date:     Mon Jun  2 13:12:12 2014 UTC
Log:      ARM64: Restructure the L1 deopt jump table.

This restructures the L1 deopt jump table so that the base address of
the L2 table is only loaded once. This significantly reduces the size of
the generated code because only one big immediate needs to be loaded.

The total size of all L1 deopt tables generated during Octane is almost
halved in size, from about 1105kB to 584kB.

BUG=
[email protected]

Review URL: https://codereview.chromium.org/305963010
http://code.google.com/p/v8/source/detail?r=21608

Modified:
 /branches/bleeding_edge/src/arm64/lithium-codegen-arm64.cc

=======================================
--- /branches/bleeding_edge/src/arm64/lithium-codegen-arm64.cc Mon Jun 2 07:02:24 2014 UTC +++ /branches/bleeding_edge/src/arm64/lithium-codegen-arm64.cc Mon Jun 2 13:12:12 2014 UTC
@@ -832,51 +832,82 @@


 bool LCodeGen::GenerateDeoptJumpTable() {
+  Label needs_frame, restore_caller_doubles, call_deopt_entry;
+
   if (deopt_jump_table_.length() > 0) {
     Comment(";;; -------------------- Jump table --------------------");
-  }
-  Label table_start;
-  __ bind(&table_start);
-  Label needs_frame;
-  for (int i = 0; i < deopt_jump_table_.length(); i++) {
-    __ Bind(&deopt_jump_table_[i]->label);
-    Address entry = deopt_jump_table_[i]->address;
-    Deoptimizer::BailoutType type = deopt_jump_table_[i]->bailout_type;
-    int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type);
-    if (id == Deoptimizer::kNotDeoptimizationEntry) {
-      Comment(";;; jump table entry %d.", i);
-    } else {
- Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
-    }
-    if (deopt_jump_table_[i]->needs_frame) {
-      ASSERT(!info()->saves_caller_doubles());
+    Address base = deopt_jump_table_[0]->address;

-      UseScratchRegisterScope temps(masm());
-      Register stub_deopt_entry = temps.AcquireX();
-      Register stub_marker = temps.AcquireX();
+    UseScratchRegisterScope temps(masm());
+    Register entry_offset = temps.AcquireX();

-      __ Mov(stub_deopt_entry, ExternalReference::ForDeoptEntry(entry));
-      if (needs_frame.is_bound()) {
-        __ B(&needs_frame);
+    int length = deopt_jump_table_.length();
+    for (int i = 0; i < length; i++) {
+      __ Bind(&deopt_jump_table_[i]->label);
+
+      Deoptimizer::BailoutType type = deopt_jump_table_[i]->bailout_type;
+      Address entry = deopt_jump_table_[i]->address;
+      int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type);
+      if (id == Deoptimizer::kNotDeoptimizationEntry) {
+        Comment(";;; jump table entry %d.", i);
       } else {
-        __ 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.
-        ASSERT(info()->IsStub());
-        __ Mov(stub_marker, Smi::FromInt(StackFrame::STUB));
-        __ Push(lr, fp, cp, stub_marker);
-        __ Add(fp, __ StackPointer(), 2 * kPointerSize);
-        __ Call(stub_deopt_entry);
+ Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
       }
-    } else {
-      if (info()->saves_caller_doubles()) {
+
+ // 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.
+      __ Mov(entry_offset, entry - base);
+
+ // The last entry can fall through into `call_deopt_entry`, avoiding a
+      // branch.
+      bool last_entry = (i + 1) == length;
+
+      if (deopt_jump_table_[i]->needs_frame) {
+        ASSERT(!info()->saves_caller_doubles());
+        if (!needs_frame.is_bound()) {
+ // 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.
+          ASSERT(info()->IsStub());
+
+          UseScratchRegisterScope temps(masm());
+          Register stub_marker = temps.AcquireX();
+          __ Bind(&needs_frame);
+          __ Mov(stub_marker, Smi::FromInt(StackFrame::STUB));
+          __ Push(lr, fp, cp, stub_marker);
+          __ Add(fp, __ StackPointer(), 2 * kPointerSize);
+          if (!last_entry) __ B(&call_deopt_entry);
+        } else {
+          // Reuse the existing needs_frame code.
+          __ B(&needs_frame);
+        }
+      } else if (info()->saves_caller_doubles()) {
         ASSERT(info()->IsStub());
-        RestoreCallerDoubles();
+        if (!restore_caller_doubles.is_bound()) {
+          __ Bind(&restore_caller_doubles);
+          RestoreCallerDoubles();
+          if (!last_entry) __ B(&call_deopt_entry);
+        } else {
+          // Reuse the existing restore_caller_doubles code.
+          __ B(&restore_caller_doubles);
+        }
+      } else {
+ // There is nothing special to do, so just continue to the second-level
+        // table.
+        if (!last_entry) __ B(&call_deopt_entry);
       }
-      __ Call(entry, RelocInfo::RUNTIME_ENTRY);
+
+      masm()->CheckConstPool(false, last_entry);
     }
-    masm()->CheckConstPool(false, false);
+
+    // Generate common code for calling the second-level deopt table.
+    Register deopt_entry = temps.AcquireX();
+    __ Bind(&call_deopt_entry);
+    __ Mov(deopt_entry, Operand(reinterpret_cast<uint64_t>(base),
+                                RelocInfo::RUNTIME_ENTRY));
+    __ Add(deopt_entry, deopt_entry, entry_offset);
+    __ Call(deopt_entry);
   }

// Force constant pool emission at the end of the deopt jump table to make

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to