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:
balazs.kilvady 2015-02-09 12:49:46 -08:00 committed by Commit bot
parent 07c6814d0f
commit e094f909fc
4 changed files with 268 additions and 8 deletions

View File

@ -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_) =

View File

@ -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);

View File

@ -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,

View File

@ -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 __