Bug 1529559 - ARM64: PatchJump change the branching schema if the target is out of range. r=sstangl
authorNicolas B. Pierron <nicolas.b.pierron@nbp.name>
Tue, 19 Mar 2019 18:23:52 +0000
changeset 465077 d77a06489c3e80ac21c4ab75fb2e8af4236d95d7
parent 465076 f45661298ac32d7f9dc451bd1d1a703a45abffd0
child 465078 a3fd362bd43936ef6d6efcbc06e38ad7079ba88f
push id35732
push useropoprus@mozilla.com
push dateWed, 20 Mar 2019 10:52:37 +0000
treeherdermozilla-central@708979f9c3f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssstangl
bugs1529559
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1529559 - ARM64: PatchJump change the branching schema if the target is out of range. r=sstangl Differential Revision: https://phabricator.services.mozilla.com/D23361
js/src/jit/arm64/Assembler-arm64.cpp
js/src/jit/arm64/MacroAssembler-arm64.h
js/src/jit/arm64/vixl/Instructions-vixl.h
--- a/js/src/jit/arm64/Assembler-arm64.cpp
+++ b/js/src/jit/arm64/Assembler-arm64.cpp
@@ -351,35 +351,42 @@ size_t Assembler::addPatchableJump(Buffe
     addJumpRelocation(src, reloc);
   }
 
   size_t extendedTableIndex = pendingJumps_.length();
   enoughMemory_ &= pendingJumps_.append(RelativePatch(src, nullptr, reloc));
   return extendedTableIndex;
 }
 
-// PatchJump() is only used by the IonCacheIRCompiler.
+// PatchJump() is only used by the IonCacheIRCompiler and patches code generated
+// by jumpWithPatch.
 //
 // The CodeLocationJump is the jump to be patched.
 // The code for the jump is emitted by jumpWithPatch().
 void PatchJump(CodeLocationJump& jump_, CodeLocationLabel label) {
   MOZ_ASSERT(label.isSet());
 
   Instruction* load = (Instruction*)jump_.raw();
   MOZ_ASSERT(load->IsLDR());
 
   Instruction* branch = (Instruction*)load->NextInstruction()->skipPool();
   MOZ_ASSERT(branch->IsUncondB());
 
-  // FIXME: For the moment, just assume that the load isn't needed.
-  // FIXME: That assumption implies that the branch target is always in-range.
   if (branch->IsTargetReachable((Instruction*)label.raw())) {
     branch->SetImmPCOffsetTarget((Instruction*)label.raw());
   } else {
-    MOZ_CRASH("PatchJump target not reachable");
+    // Set the literal read by the load instruction to the target.
+    load->SetLiteral64(uint64_t(label.raw()));
+    // Get the scratch register set by the load instruction.
+    vixl::Register loadTarget = vixl::Register(load->Rt(), 64);
+    // Overwrite the branch instruction to branch on the same register as the
+    // load instruction.
+    Assembler::br(branch, loadTarget);
+    MOZ_ASSERT(branch->IsBR());
+    MOZ_ASSERT(load->Rt() == branch->Rn());
   }
 }
 
 void Assembler::PatchWrite_NearCall(CodeLocationLabel start,
                                     CodeLocationLabel toCall) {
   Instruction* dest = (Instruction*)start.raw();
   ptrdiff_t relTarget = (Instruction*)toCall.raw() - dest;
   ptrdiff_t relTarget00 = relTarget >> 2;
--- a/js/src/jit/arm64/MacroAssembler-arm64.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64.h
@@ -1250,17 +1250,19 @@ class MacroAssemblerCompat : public vixl
     MOZ_ASSERT(!label->bound());
 
     vixl::UseScratchRegisterScope temps(this);
     const ARMRegister scratch64 = temps.AcquireX();
 
     ARMBuffer::PoolEntry pe;
     BufferOffset load_bo;
 
-    // FIXME: This load is currently unused.
+    // This no-op load exists for PatchJump(), in the case of a target outside
+    // the range of +/- 128 MB. If the load is used, then the branch here is
+    // overwritten with a `BR` from the loaded register.
     load_bo = immPool64(scratch64, (uint64_t)label, &pe);
     BufferOffset branch_bo = b(-1, LabelDoc());
 
     label->use(branch_bo.getOffset());
     return CodeOffsetJump(load_bo.getOffset(), pe.index());
   }
 
   void compareDouble(DoubleCondition cond, FloatRegister lhs,
--- a/js/src/jit/arm64/vixl/Instructions-vixl.h
+++ b/js/src/jit/arm64/vixl/Instructions-vixl.h
@@ -457,16 +457,20 @@ class Instruction {
   }
 
   uint64_t Literal64() const {
     uint64_t literal;
     memcpy(&literal, LiteralAddress<const void*>(), sizeof(literal));
     return literal;
   }
 
+  void SetLiteral64(uint64_t literal) const {
+    memcpy(LiteralAddress<void*>(), &literal, sizeof(literal));
+  }
+
   float LiteralFP32() const {
     return rawbits_to_float(Literal32());
   }
 
   double LiteralFP64() const {
     return rawbits_to_double(Literal64());
   }