| Index: src/mips64/assembler-mips64.cc | 
| diff --git a/src/mips64/assembler-mips64.cc b/src/mips64/assembler-mips64.cc | 
| index 2bec3f064a3eeb99838d81cbd0c52fb72eedf5d7..75c94459753661348ad10d64cbd5e37f9871ad3f 100644 | 
| --- a/src/mips64/assembler-mips64.cc | 
| +++ b/src/mips64/assembler-mips64.cc | 
| @@ -637,7 +637,7 @@ int Assembler::target_at(int pos, bool is_internal) { | 
| } | 
| } | 
| // Check we have a branch or jump instruction. | 
| -  DCHECK(IsBranch(instr) || IsLui(instr)); | 
| +  DCHECK(IsBranch(instr) || IsJ(instr) || IsJal(instr) || IsLui(instr)); | 
| // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming | 
| // the compiler uses arithmetic shifts for signed integers. | 
| if (IsBranch(instr)) { | 
| @@ -673,8 +673,18 @@ int Assembler::target_at(int pos, bool is_internal) { | 
| return pos - delta; | 
| } | 
| } else { | 
| -    UNREACHABLE(); | 
| -    return 0; | 
| +    DCHECK(IsJ(instr) || IsJal(instr)); | 
| +    int32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2; | 
| +    if (imm28 == kEndOfJumpChain) { | 
| +      // EndOfChain sentinel is returned directly, not relative to pc or pos. | 
| +      return kEndOfChain; | 
| +    } else { | 
| +      uint64_t instr_address = reinterpret_cast<int64_t>(buffer_ + pos); | 
| +      instr_address &= kImm28Mask; | 
| +      int delta = static_cast<int>(instr_address - imm28); | 
| +      DCHECK(pos > delta); | 
| +      return pos - delta; | 
| +    } | 
| } | 
| } | 
|  | 
| @@ -694,7 +704,7 @@ void Assembler::target_at_put(int pos, int target_pos, bool is_internal) { | 
| return; | 
| } | 
|  | 
| -  DCHECK(IsBranch(instr) || IsLui(instr)); | 
| +  DCHECK(IsBranch(instr) || IsJ(instr) || IsJal(instr) || IsLui(instr)); | 
| if (IsBranch(instr)) { | 
| int32_t imm18 = target_pos - (pos + kBranchPCOffset); | 
| DCHECK((imm18 & 3) == 0); | 
| @@ -725,7 +735,16 @@ void Assembler::target_at_put(int pos, int target_pos, bool is_internal) { | 
| instr_at_put(pos + 3 * Assembler::kInstrSize, | 
| instr_ori2 | (imm & kImm16Mask)); | 
| } else { | 
| -    UNREACHABLE(); | 
| +    DCHECK(IsJ(instr) || IsJal(instr)); | 
| +    uint64_t imm28 = reinterpret_cast<uint64_t>(buffer_) + target_pos; | 
| +    imm28 &= kImm28Mask; | 
| +    DCHECK((imm28 & 3) == 0); | 
| + | 
| +    instr &= ~kImm26Mask; | 
| +    uint32_t imm26 = imm28 >> 2; | 
| +    DCHECK(is_uint26(imm26)); | 
| + | 
| +    instr_at_put(pos, instr | (imm26 & kImm26Mask)); | 
| } | 
| } | 
|  | 
| @@ -787,7 +806,8 @@ void Assembler::bind_to(Label* L, int pos) { | 
| } | 
| target_at_put(fixup_pos, pos, false); | 
| } else { | 
| -      DCHECK(IsJ(instr) || IsLui(instr) || IsEmittedConstant(instr)); | 
| +      DCHECK(IsJ(instr) || IsJal(instr) || IsLui(instr) || | 
| +             IsEmittedConstant(instr)); | 
| target_at_put(fixup_pos, pos, false); | 
| } | 
| } | 
| @@ -984,7 +1004,6 @@ uint64_t Assembler::jump_address(Label* L) { | 
| return kEndOfJumpChain; | 
| } | 
| } | 
| - | 
| uint64_t imm = reinterpret_cast<uint64_t>(buffer_) + target_pos; | 
| DCHECK((imm & 3) == 0); | 
|  | 
| @@ -1359,12 +1378,14 @@ void Assembler::bnezc(Register rs, int32_t offset) { | 
| void Assembler::j(int64_t target) { | 
| #if DEBUG | 
| // Get pc of delay slot. | 
| -  uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize); | 
| -  bool in_range = (ipc ^ static_cast<uint64_t>(target) >> | 
| -                  (kImm26Bits + kImmFieldShift)) == 0; | 
| -  DCHECK(in_range && ((target & 3) == 0)); | 
| +  if (target != kEndOfJumpChain) { | 
| +    uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize); | 
| +    bool in_range = ((ipc ^ static_cast<uint64_t>(target)) >> | 
| +                     (kImm26Bits + kImmFieldShift)) == 0; | 
| +    DCHECK(in_range && ((target & 3) == 0)); | 
| +  } | 
| #endif | 
| -  GenInstrJump(J, target >> 2); | 
| +  GenInstrJump(J, (target >> 2) & kImm26Mask); | 
| } | 
|  | 
|  | 
| @@ -1385,13 +1406,15 @@ void Assembler::jr(Register rs) { | 
| void Assembler::jal(int64_t target) { | 
| #ifdef DEBUG | 
| // Get pc of delay slot. | 
| -  uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize); | 
| -  bool in_range = (ipc ^ static_cast<uint64_t>(target) >> | 
| -                  (kImm26Bits + kImmFieldShift)) == 0; | 
| -  DCHECK(in_range && ((target & 3) == 0)); | 
| +  if (target != kEndOfJumpChain) { | 
| +    uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize); | 
| +    bool in_range = ((ipc ^ static_cast<uint64_t>(target)) >> | 
| +                     (kImm26Bits + kImmFieldShift)) == 0; | 
| +    DCHECK(in_range && ((target & 3) == 0)); | 
| +  } | 
| #endif | 
| positions_recorder()->WriteRecordedPositions(); | 
| -  GenInstrJump(JAL, target >> 2); | 
| +  GenInstrJump(JAL, (target >> 2) & kImm26Mask); | 
| } | 
|  | 
|  | 
| @@ -2764,6 +2787,7 @@ int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, byte* pc, | 
| } | 
| Instr instr = instr_at(pc); | 
| DCHECK(RelocInfo::IsInternalReferenceEncoded(rmode)); | 
| +  DCHECK(IsJ(instr) || IsLui(instr) || IsJal(instr)); | 
| if (IsLui(instr)) { | 
| Instr instr_lui = instr_at(pc + 0 * Assembler::kInstrSize); | 
| Instr instr_ori = instr_at(pc + 1 * Assembler::kInstrSize); | 
| @@ -2795,8 +2819,21 @@ int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, byte* pc, | 
| instr_ori2 | (imm & kImm16Mask)); | 
| return 4;  // Number of instructions patched. | 
| } else { | 
| -    UNREACHABLE(); | 
| -    return 0;  // Number of instructions patched. | 
| +    uint32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2; | 
| +    if (static_cast<int32_t>(imm28) == kEndOfJumpChain) { | 
| +      return 0;  // Number of instructions patched. | 
| +    } | 
| + | 
| +    imm28 += pc_delta; | 
| +    imm28 &= kImm28Mask; | 
| +    DCHECK((imm28 & 3) == 0); | 
| + | 
| +    instr &= ~kImm26Mask; | 
| +    uint32_t imm26 = imm28 >> 2; | 
| +    DCHECK(is_uint26(imm26)); | 
| + | 
| +    instr_at_put(pc, instr | (imm26 & kImm26Mask)); | 
| +    return 1;  // Number of instructions patched. | 
| } | 
| } | 
|  | 
| @@ -2958,14 +2995,8 @@ void Assembler::CheckTrampolinePool() { | 
| // references until associated instructions are emitted and available | 
| // to be patched. | 
| RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); | 
| -          // TODO(plind): Verify this, presume I cannot use macro-assembler | 
| -          // here. | 
| -          lui(at, (imm64 >> 32) & kImm16Mask); | 
| -          ori(at, at, (imm64 >> 16) & kImm16Mask); | 
| -          dsll(at, at, 16); | 
| -          ori(at, at, imm64 & kImm16Mask); | 
| +          j(imm64); | 
| } | 
| -        jr(at); | 
| nop(); | 
| } | 
| bind(&after_pool); | 
|  |