MIPS: Assembler support for internal references.
Port 49cbe537e7
BUG=
Review URL: https://codereview.chromium.org/911623003
Cr-Commit-Position: refs/heads/master@{#26534}
This commit is contained in:
parent
07c6814d0f
commit
e094f909fc
@ -673,8 +673,6 @@ int Assembler::target_at(int32_t pos) {
|
||||
return (imm18 + pos);
|
||||
}
|
||||
}
|
||||
// Check we have a branch or jump instruction.
|
||||
DCHECK(IsBranch(instr) || IsJ(instr) || IsLui(instr));
|
||||
// Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
|
||||
// the compiler uses arithmectic shifts for signed integers.
|
||||
if (IsBranch(instr)) {
|
||||
@ -702,7 +700,7 @@ int Assembler::target_at(int32_t pos) {
|
||||
DCHECK(pos > delta);
|
||||
return pos - delta;
|
||||
}
|
||||
} else {
|
||||
} else if (IsJ(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.
|
||||
@ -714,6 +712,14 @@ int Assembler::target_at(int32_t pos) {
|
||||
DCHECK(pos > delta);
|
||||
return pos - delta;
|
||||
}
|
||||
} else { // IsLabel(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 {
|
||||
return pos + imm28;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -728,7 +734,6 @@ void Assembler::target_at_put(int32_t pos, int32_t target_pos) {
|
||||
return;
|
||||
}
|
||||
|
||||
DCHECK(IsBranch(instr) || IsJ(instr) || IsLui(instr));
|
||||
if (IsBranch(instr)) {
|
||||
int32_t imm18 = target_pos - (pos + kBranchPCOffset);
|
||||
DCHECK((imm18 & 3) == 0);
|
||||
@ -752,7 +757,7 @@ void Assembler::target_at_put(int32_t pos, int32_t target_pos) {
|
||||
instr_lui | ((imm & kHiMask) >> kLuiShift));
|
||||
instr_at_put(pos + 1 * Assembler::kInstrSize,
|
||||
instr_ori | (imm & kImm16Mask));
|
||||
} else {
|
||||
} else if (IsJ(instr)) {
|
||||
uint32_t imm28 = reinterpret_cast<uint32_t>(buffer_) + target_pos;
|
||||
imm28 &= kImm28Mask;
|
||||
DCHECK((imm28 & 3) == 0);
|
||||
@ -762,6 +767,9 @@ void Assembler::target_at_put(int32_t pos, int32_t target_pos) {
|
||||
DCHECK(is_uint26(imm26));
|
||||
|
||||
instr_at_put(pos, instr | (imm26 & kImm26Mask));
|
||||
} else {
|
||||
uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
|
||||
instr_at_put(pos, imm);
|
||||
}
|
||||
}
|
||||
|
||||
@ -816,7 +824,6 @@ void Assembler::bind_to(Label* L, int pos) {
|
||||
}
|
||||
target_at_put(fixup_pos, pos);
|
||||
} else {
|
||||
DCHECK(IsJ(instr) || IsLui(instr) || IsEmittedConstant(instr));
|
||||
target_at_put(fixup_pos, pos);
|
||||
}
|
||||
}
|
||||
@ -2358,7 +2365,6 @@ void Assembler::RecordDeoptReason(const int reason, const int raw_position) {
|
||||
|
||||
int Assembler::RelocateInternalReference(byte* pc, intptr_t pc_delta) {
|
||||
Instr instr = instr_at(pc);
|
||||
DCHECK(IsJ(instr) || IsLui(instr));
|
||||
if (IsLui(instr)) {
|
||||
Instr instr_lui = instr_at(pc + 0 * Assembler::kInstrSize);
|
||||
Instr instr_ori = instr_at(pc + 1 * Assembler::kInstrSize);
|
||||
@ -2379,7 +2385,7 @@ int Assembler::RelocateInternalReference(byte* pc, intptr_t pc_delta) {
|
||||
instr_at_put(pc + 1 * Assembler::kInstrSize,
|
||||
instr_ori | (imm & kImm16Mask));
|
||||
return 2; // Number of instructions patched.
|
||||
} else {
|
||||
} else if (IsJ(instr)) {
|
||||
uint32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
|
||||
if (static_cast<int32_t>(imm28) == kEndOfJumpChain) {
|
||||
return 0; // Number of instructions patched.
|
||||
@ -2394,6 +2400,14 @@ int Assembler::RelocateInternalReference(byte* pc, intptr_t pc_delta) {
|
||||
|
||||
instr_at_put(pc, instr | (imm26 & kImm26Mask));
|
||||
return 1; // Number of instructions patched.
|
||||
} else { // IsLabel(instr)
|
||||
int32_t* p = reinterpret_cast<int32_t*>(pc);
|
||||
uint32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
|
||||
if (static_cast<int32_t>(imm28) == kEndOfJumpChain) {
|
||||
return 0; // Number of instructions patched.
|
||||
}
|
||||
*p += pc_delta;
|
||||
return 1; // Number of instructions patched.
|
||||
}
|
||||
}
|
||||
|
||||
@ -2458,6 +2472,35 @@ void Assembler::dd(uint32_t data) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::dd(Label* label) {
|
||||
CheckBuffer();
|
||||
RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
|
||||
if (label->is_bound()) {
|
||||
uint32_t data = reinterpret_cast<uint32_t>(buffer_ + label->pos());
|
||||
*reinterpret_cast<uint32_t*>(pc_) = data;
|
||||
pc_ += sizeof(uint32_t);
|
||||
} else {
|
||||
int target_pos;
|
||||
if (label->is_linked()) {
|
||||
// Point to previous instruction that uses the link.
|
||||
target_pos = label->pos();
|
||||
} else {
|
||||
// First entry of the link chain points to itself.
|
||||
target_pos = pc_offset();
|
||||
}
|
||||
label->link_to(pc_offset());
|
||||
// Encode internal reference to unbound label. We set the least significant
|
||||
// bit to distinguish unbound internal references in GrowBuffer() below.
|
||||
int diff = target_pos - pc_offset();
|
||||
DCHECK_EQ(0, diff & 3);
|
||||
int imm26 = diff >> 2;
|
||||
DCHECK(is_int26(imm26));
|
||||
// Emit special LABEL instruction.
|
||||
emit(LABEL | (imm26 & kImm26Mask));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Assembler::emit_code_stub_address(Code* stub) {
|
||||
CheckBuffer();
|
||||
*reinterpret_cast<uint32_t*>(pc_) =
|
||||
|
@ -1027,6 +1027,7 @@ class Assembler : public AssemblerBase {
|
||||
// inline tables, e.g., jump-tables.
|
||||
void db(uint8_t data);
|
||||
void dd(uint32_t data);
|
||||
void dd(Label* label);
|
||||
|
||||
// Emits the address of the code stub's first instruction.
|
||||
void emit_code_stub_address(Code* stub);
|
||||
|
@ -339,6 +339,7 @@ enum Opcode {
|
||||
|
||||
DADDI = ((3 << 3) + 0) << kOpcodeShift, // This is also BNEC.
|
||||
SPECIAL2 = ((3 << 3) + 4) << kOpcodeShift,
|
||||
LABEL = ((3 << 3) + 5) << kOpcodeShift,
|
||||
SPECIAL3 = ((3 << 3) + 7) << kOpcodeShift,
|
||||
|
||||
LB = ((4 << 3) + 0) << kOpcodeShift,
|
||||
|
@ -25,6 +25,8 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <iostream> // NOLINT(readability/streams)
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/disassembler.h"
|
||||
@ -35,6 +37,7 @@
|
||||
|
||||
#include "test/cctest/cctest.h"
|
||||
|
||||
|
||||
using namespace v8::internal;
|
||||
|
||||
|
||||
@ -1272,4 +1275,216 @@ TEST(MIPS15) {
|
||||
__ nop();
|
||||
}
|
||||
|
||||
|
||||
TEST(jump_tables1) {
|
||||
// Test jump tables with forward jumps.
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
HandleScope scope(isolate);
|
||||
Assembler assm(isolate, nullptr, 0);
|
||||
|
||||
const int kNumCases = 512;
|
||||
int values[kNumCases];
|
||||
isolate->random_number_generator()->NextBytes(values, sizeof(values));
|
||||
Label labels[kNumCases];
|
||||
|
||||
__ addiu(sp, sp, -4);
|
||||
__ sw(ra, MemOperand(sp));
|
||||
|
||||
Label done;
|
||||
{
|
||||
PredictableCodeSizeScope predictable(
|
||||
&assm, (kNumCases + 7) * Assembler::kInstrSize);
|
||||
Label here;
|
||||
|
||||
__ bal(&here);
|
||||
__ nop();
|
||||
__ bind(&here);
|
||||
__ sll(at, a0, 2);
|
||||
__ addu(at, at, ra);
|
||||
__ lw(at, MemOperand(at, 5 * Assembler::kInstrSize));
|
||||
__ jr(at);
|
||||
__ nop();
|
||||
for (int i = 0; i < kNumCases; ++i) {
|
||||
__ dd(&labels[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < kNumCases; ++i) {
|
||||
__ bind(&labels[i]);
|
||||
__ lui(v0, (values[i] >> 16) & 0xffff);
|
||||
__ ori(v0, v0, values[i] & 0xffff);
|
||||
__ b(&done);
|
||||
__ nop();
|
||||
}
|
||||
|
||||
__ bind(&done);
|
||||
__ lw(ra, MemOperand(sp));
|
||||
__ addiu(sp, sp, 4);
|
||||
__ jr(ra);
|
||||
__ nop();
|
||||
|
||||
CodeDesc desc;
|
||||
assm.GetCode(&desc);
|
||||
Handle<Code> code = isolate->factory()->NewCode(
|
||||
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
|
||||
#ifdef OBJECT_PRINT
|
||||
code->Print(std::cout);
|
||||
#endif
|
||||
F1 f = FUNCTION_CAST<F1>(code->entry());
|
||||
for (int i = 0; i < kNumCases; ++i) {
|
||||
int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, i, 0, 0, 0, 0));
|
||||
::printf("f(%d) = %d\n", i, res);
|
||||
CHECK_EQ(values[i], res);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(jump_tables2) {
|
||||
// Test jump tables with backward jumps.
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
HandleScope scope(isolate);
|
||||
Assembler assm(isolate, nullptr, 0);
|
||||
|
||||
const int kNumCases = 512;
|
||||
int values[kNumCases];
|
||||
isolate->random_number_generator()->NextBytes(values, sizeof(values));
|
||||
Label labels[kNumCases];
|
||||
|
||||
__ addiu(sp, sp, -4);
|
||||
__ sw(ra, MemOperand(sp));
|
||||
|
||||
Label done, dispatch;
|
||||
__ b(&dispatch);
|
||||
__ nop();
|
||||
|
||||
for (int i = 0; i < kNumCases; ++i) {
|
||||
__ bind(&labels[i]);
|
||||
__ lui(v0, (values[i] >> 16) & 0xffff);
|
||||
__ ori(v0, v0, values[i] & 0xffff);
|
||||
__ b(&done);
|
||||
__ nop();
|
||||
}
|
||||
|
||||
__ bind(&dispatch);
|
||||
{
|
||||
PredictableCodeSizeScope predictable(
|
||||
&assm, (kNumCases + 7) * Assembler::kInstrSize);
|
||||
Label here;
|
||||
|
||||
__ bal(&here);
|
||||
__ nop();
|
||||
__ bind(&here);
|
||||
__ sll(at, a0, 2);
|
||||
__ addu(at, at, ra);
|
||||
__ lw(at, MemOperand(at, 5 * Assembler::kInstrSize));
|
||||
__ jr(at);
|
||||
__ nop();
|
||||
for (int i = 0; i < kNumCases; ++i) {
|
||||
__ dd(&labels[i]);
|
||||
}
|
||||
}
|
||||
|
||||
__ bind(&done);
|
||||
__ lw(ra, MemOperand(sp));
|
||||
__ addiu(sp, sp, 4);
|
||||
__ jr(ra);
|
||||
__ nop();
|
||||
|
||||
CodeDesc desc;
|
||||
assm.GetCode(&desc);
|
||||
Handle<Code> code = isolate->factory()->NewCode(
|
||||
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
|
||||
#ifdef OBJECT_PRINT
|
||||
code->Print(std::cout);
|
||||
#endif
|
||||
F1 f = FUNCTION_CAST<F1>(code->entry());
|
||||
for (int i = 0; i < kNumCases; ++i) {
|
||||
int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, i, 0, 0, 0, 0));
|
||||
::printf("f(%d) = %d\n", i, res);
|
||||
CHECK_EQ(values[i], res);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(jump_tables3) {
|
||||
// Test jump tables with backward jumps and embedded heap objects.
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
HandleScope scope(isolate);
|
||||
Assembler assm(isolate, nullptr, 0);
|
||||
|
||||
const int kNumCases = 256;
|
||||
Handle<Object> values[kNumCases];
|
||||
for (int i = 0; i < kNumCases; ++i) {
|
||||
double value = isolate->random_number_generator()->NextDouble();
|
||||
values[i] = isolate->factory()->NewHeapNumber(value, IMMUTABLE, TENURED);
|
||||
}
|
||||
Label labels[kNumCases];
|
||||
Object* obj;
|
||||
int32_t imm32;
|
||||
|
||||
__ addiu(sp, sp, -4);
|
||||
__ sw(ra, MemOperand(sp));
|
||||
|
||||
Label done, dispatch;
|
||||
__ b(&dispatch);
|
||||
|
||||
|
||||
for (int i = 0; i < kNumCases; ++i) {
|
||||
__ bind(&labels[i]);
|
||||
obj = *values[i];
|
||||
imm32 = reinterpret_cast<intptr_t>(obj);
|
||||
__ lui(v0, (imm32 >> 16) & 0xffff);
|
||||
__ ori(v0, v0, imm32 & 0xffff);
|
||||
__ b(&done);
|
||||
__ nop();
|
||||
}
|
||||
|
||||
__ bind(&dispatch);
|
||||
{
|
||||
PredictableCodeSizeScope predictable(
|
||||
&assm, (kNumCases + 7) * Assembler::kInstrSize);
|
||||
Label here;
|
||||
|
||||
__ bal(&here);
|
||||
__ nop();
|
||||
__ bind(&here);
|
||||
__ sll(at, a0, 2);
|
||||
__ addu(at, at, ra);
|
||||
__ lw(at, MemOperand(at, 5 * Assembler::kInstrSize));
|
||||
__ jr(at);
|
||||
__ nop();
|
||||
for (int i = 0; i < kNumCases; ++i) {
|
||||
__ dd(&labels[i]);
|
||||
}
|
||||
}
|
||||
|
||||
__ bind(&done);
|
||||
__ lw(ra, MemOperand(sp));
|
||||
__ addiu(sp, sp, 4);
|
||||
__ jr(ra);
|
||||
__ nop();
|
||||
|
||||
CodeDesc desc;
|
||||
assm.GetCode(&desc);
|
||||
Handle<Code> code = isolate->factory()->NewCode(
|
||||
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
|
||||
#ifdef OBJECT_PRINT
|
||||
code->Print(std::cout);
|
||||
#endif
|
||||
F1 f = FUNCTION_CAST<F1>(code->entry());
|
||||
for (int i = 0; i < kNumCases; ++i) {
|
||||
Handle<Object> result(CALL_GENERATED_CODE(f, i, 0, 0, 0, 0), isolate);
|
||||
#ifdef OBJECT_PRINT
|
||||
::printf("f(%d) = ", i);
|
||||
result->Print(std::cout);
|
||||
::printf("\n");
|
||||
#endif
|
||||
CHECK(values[i].is_identical_to(result));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#undef __
|
||||
|
Loading…
Reference in New Issue
Block a user