 Chromium Code Reviews
 Chromium Code Reviews Issue 1216823003:
  MIPS64: Fix hidden bug in relocations for j and jal. 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master
    
  
    Issue 1216823003:
  MIPS64: Fix hidden bug in relocations for j and jal. 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master| Index: src/mips64/assembler-mips64.cc | 
| diff --git a/src/mips64/assembler-mips64.cc b/src/mips64/assembler-mips64.cc | 
| index 61b72968a6b66f6677260b78f387816874747a7c..4ed7635dcf75f1e438298f6e3ad29bbcebf4499f 100644 | 
| --- a/src/mips64/assembler-mips64.cc | 
| +++ b/src/mips64/assembler-mips64.cc | 
| @@ -681,11 +681,9 @@ int Assembler::target_at(int pos, bool is_internal) { | 
| // 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; | 
| + // Sign extend 28-bit offset. | 
| + int32_t delta = static_cast<int32_t>((imm28 << 4) >> 4); | 
| + return pos + delta; | 
| } | 
| } | 
| } | 
| @@ -706,7 +704,6 @@ void Assembler::target_at_put(int pos, int target_pos, bool is_internal) { | 
| return; | 
| } | 
| - DCHECK(IsBranch(instr) || IsJ(instr) || IsJal(instr) || IsLui(instr)); | 
| if (IsBranch(instr)) { | 
| int32_t imm18 = target_pos - (pos + kBranchPCOffset); | 
| DCHECK((imm18 & 3) == 0); | 
| @@ -736,16 +733,25 @@ void Assembler::target_at_put(int pos, int target_pos, bool is_internal) { | 
| instr_ori | ((imm >> 16) & kImm16Mask)); | 
| instr_at_put(pos + 3 * Assembler::kInstrSize, | 
| instr_ori2 | (imm & kImm16Mask)); | 
| - } else { | 
| - DCHECK(IsJ(instr) || IsJal(instr)); | 
| - uint64_t imm28 = reinterpret_cast<uint64_t>(buffer_) + target_pos; | 
| - imm28 &= kImm28Mask; | 
| + } else if (IsJ(instr) || IsJal(instr)) { | 
| + int32_t imm28 = target_pos - pos; | 
| DCHECK((imm28 & 3) == 0); | 
| - instr &= ~kImm26Mask; | 
| uint32_t imm26 = static_cast<uint32_t>(imm28 >> 2); | 
| DCHECK(is_uint26(imm26)); | 
| + // Place 26-bit signed offset with markings. | 
| + // When code is committed it will be resolved to j/jal. | 
| + int32_t mark = IsJ(instr) ? kJRawMark : kJalRawMark; | 
| + instr_at_put(pos, mark | (imm26 & kImm26Mask)); | 
| + } else { | 
| + int32_t imm28 = target_pos - pos; | 
| + DCHECK((imm28 & 3) == 0); | 
| + uint32_t imm26 = static_cast<uint32_t>(imm28 >> 2); | 
| + DCHECK(is_uint26(imm26)); | 
| + // Place raw 26-bit signed offset. | 
| + // When code is committed it will be resolved to j/jal. | 
| + instr &= ~kImm26Mask; | 
| instr_at_put(pos, instr | (imm26 & kImm26Mask)); | 
| } | 
| } | 
| @@ -1027,6 +1033,26 @@ uint64_t Assembler::jump_address(Label* L) { | 
| } | 
| +uint64_t Assembler::jump_offset(Label* L) { | 
| + int64_t target_pos; | 
| + if (L->is_bound()) { | 
| + target_pos = L->pos(); | 
| + } else { | 
| + if (L->is_linked()) { | 
| + target_pos = L->pos(); // L's link. | 
| + L->link_to(pc_offset()); | 
| + } else { | 
| + L->link_to(pc_offset()); | 
| + return kEndOfJumpChain; | 
| + } | 
| + } | 
| + int64_t imm = target_pos - pc_offset(); | 
| + DCHECK((imm & 3) == 0); | 
| + | 
| + return static_cast<uint64_t>(imm); | 
| +} | 
| + | 
| + | 
| int32_t Assembler::branch_offset(Label* L, bool jump_elimination_allowed) { | 
| int32_t target_pos; | 
| if (L->is_bound()) { | 
| @@ -1405,19 +1431,32 @@ void Assembler::bnezc(Register rs, int32_t offset) { | 
| void Assembler::j(int64_t target) { | 
| -#if DEBUG | 
| - // Get pc of delay slot. | 
| - 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, static_cast<uint32_t>(target >> 2) & kImm26Mask); | 
| } | 
| +void Assembler::j(Label* target) { | 
| + uint64_t imm = jump_offset(target); | 
| + if (target->is_bound()) { | 
| + GenInstrJump(static_cast<Opcode>(kJRawMark), | 
| + static_cast<uint32_t>(imm >> 2) & kImm26Mask); | 
| + } else { | 
| + j(imm); | 
| + } | 
| +} | 
| + | 
| + | 
| +void Assembler::jal(Label* target) { | 
| + uint64_t imm = jump_offset(target); | 
| + if (target->is_bound()) { | 
| + GenInstrJump(static_cast<Opcode>(kJalRawMark), | 
| + static_cast<uint32_t>(imm >> 2) & kImm26Mask); | 
| + } else { | 
| + j(imm); | 
| 
paul.l...
2015/08/01 17:02:22
typo: this should be jal()
 | 
| + } | 
| +} | 
| + | 
| + | 
| void Assembler::jr(Register rs) { | 
| if (kArchVariant != kMips64r6) { | 
| BlockTrampolinePoolScope block_trampoline_pool(this); | 
| @@ -1433,15 +1472,6 @@ void Assembler::jr(Register rs) { | 
| void Assembler::jal(int64_t target) { | 
| -#ifdef DEBUG | 
| - // Get pc of delay slot. | 
| - 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, static_cast<uint32_t>(target >> 2) & kImm26Mask); | 
| } | 
| @@ -2920,7 +2950,6 @@ 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); | 
| @@ -2951,22 +2980,30 @@ int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, byte* pc, | 
| instr_at_put(pc + 3 * Assembler::kInstrSize, | 
| instr_ori2 | (imm & kImm16Mask)); | 
| return 4; // Number of instructions patched. | 
| - } else { | 
| + } else if (IsJ(instr) || IsJal(instr)) { | 
| + // Regular j/jal relocation. | 
| 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)); | 
| - | 
| + DCHECK((imm28 & 3) == 0); | 
| + uint32_t imm26 = static_cast<uint32_t>(imm28 >> 2); | 
| instr_at_put(pc, instr | (imm26 & kImm26Mask)); | 
| return 1; // Number of instructions patched. | 
| + } else { | 
| + // Unbox raw offset and emit j/jal. | 
| + int32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2; | 
| + // Sign extend 28-bit offset to 32-bit. | 
| + imm28 = (imm28 << 4) >> 4; | 
| + uint64_t target = | 
| + static_cast<int64_t>(imm28) + reinterpret_cast<uint64_t>(pc); | 
| + target &= kImm28Mask; | 
| + DCHECK((imm28 & 3) == 0); | 
| + uint32_t imm26 = static_cast<uint32_t>(target >> 2); | 
| + // Check markings whether to emit j or jal. | 
| + uint32_t unbox = (instr & kJRawMark) ? J : JAL; | 
| + instr_at_put(pc, unbox | (imm26 & kImm26Mask)); | 
| + return 1; // Number of instructions patched. | 
| } | 
| } | 
| @@ -3009,8 +3046,7 @@ void Assembler::GrowBuffer() { | 
| // Relocate runtime entries. | 
| for (RelocIterator it(desc); !it.done(); it.next()) { | 
| RelocInfo::Mode rmode = it.rinfo()->rmode(); | 
| - if (rmode == RelocInfo::INTERNAL_REFERENCE_ENCODED || | 
| - rmode == RelocInfo::INTERNAL_REFERENCE) { | 
| + if (rmode == RelocInfo::INTERNAL_REFERENCE) { | 
| byte* p = reinterpret_cast<byte*>(it.rinfo()->pc()); | 
| RelocateInternalReference(rmode, p, pc_delta); | 
| } | 
| @@ -3130,14 +3166,12 @@ void Assembler::CheckTrampolinePool() { | 
| int pool_start = pc_offset(); | 
| for (int i = 0; i < unbound_labels_count_; i++) { | 
| - uint64_t imm64; | 
| - imm64 = jump_address(&after_pool); | 
| { BlockGrowBufferScope block_buf_growth(this); | 
| // Buffer growth (and relocation) must be blocked for internal | 
| // references until associated instructions are emitted and available | 
| // to be patched. | 
| RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); | 
| - j(imm64); | 
| + j(&after_pool); | 
| } | 
| nop(); | 
| } |