Adds support for debugger API on MIPS.

Enable debugger api tests on MIPS.
Enable isolate tests on MIPS.
Enable code descriptors tests on MIPS.
Enable snapshot tests on MIPS.
Enable heap tests on MIPS.

Review URL: https://codereview.chromium.org//14284020

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@22042 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
zra@google.com 2013-04-25 18:03:15 +00:00
parent 81eb689947
commit a49ab3a890
15 changed files with 259 additions and 77 deletions

View file

@ -331,9 +331,9 @@ void Assembler::EnterStubFrame(bool uses_pp) {
addiu(SP, SP, Immediate(-4 * kWordSize));
sw(ZR, Address(SP, 3 * kWordSize)); // PC marker is 0 in stubs.
sw(RA, Address(SP, 2 * kWordSize));
sw(PP, Address(SP, 1 * kWordSize));
sw(FP, Address(SP, 0 * kWordSize));
mov(FP, SP);
sw(FP, Address(SP, 1 * kWordSize));
sw(PP, Address(SP, 0 * kWordSize));
addiu(FP, SP, Immediate(1 * kWordSize));
// Setup pool pointer for this stub.
Label next;
bal(&next);
@ -356,13 +356,14 @@ void Assembler::EnterStubFrame(bool uses_pp) {
void Assembler::LeaveStubFrame(bool uses_pp) {
mov(SP, FP);
if (uses_pp) {
addiu(SP, FP, Immediate(-1 * kWordSize));
lw(RA, Address(SP, 2 * kWordSize));
lw(PP, Address(SP, 1 * kWordSize));
lw(FP, Address(SP, 0 * kWordSize));
lw(FP, Address(SP, 1 * kWordSize));
lw(PP, Address(SP, 0 * kWordSize));
addiu(SP, SP, Immediate(4 * kWordSize));
} else {
mov(SP, FP);
lw(RA, Address(SP, 1 * kWordSize));
lw(FP, Address(SP, 0 * kWordSize));
addiu(SP, SP, Immediate(3 * kWordSize));
@ -449,6 +450,8 @@ void Assembler::EnterCallRuntimeFrame(intptr_t frame_space) {
2 * kWordSize + // FP and RA.
kDartVolatileFpuRegCount * kWordSize;
TraceSimMsg("EnterCallRuntimeFrame");
if (prologue_offset_ == -1) {
prologue_offset_ = CodeSize();
}
@ -491,6 +494,8 @@ void Assembler::LeaveCallRuntimeFrame() {
2 * kWordSize + // FP and RA.
kDartVolatileFpuRegCount * kWordSize;
TraceSimMsg("LeaveCallRuntimeFrame");
// SP might have been modified to reserve space for arguments
// and ensure proper alignment of the stack frame.
// We need to restore it before restoring registers.

View file

@ -17,10 +17,6 @@
namespace dart {
#if defined(TARGET_ARCH_IA32) || \
defined(TARGET_ARCH_X64) || \
defined(TARGET_ARCH_ARM)
static const intptr_t kPos = Scanner::kDummyTokenIndex;
@ -285,7 +281,5 @@ TEST_CASE(StackmapGC) {
EXPECT(!result.IsError());
}
#endif // TARGET_ARCH_IA32 || TARGET_ARCH_X64 || TARGET_ARCH_ARM
} // namespace dart

View file

@ -33,7 +33,8 @@ void CodePatcher::PatchInstanceCallAt(uword return_address,
const Code& code,
uword new_target) {
ASSERT(code.ContainsInstructionAt(return_address));
UNIMPLEMENTED();
CallPattern call(return_address, code);
call.SetTargetAddress(new_target);
}

View file

@ -5,6 +5,8 @@
#ifndef VM_CONSTANTS_MIPS_H_
#define VM_CONSTANTS_MIPS_H_
#include "platform/assert.h"
namespace dart {
enum Register {
@ -412,6 +414,25 @@ class Instr {
*reinterpret_cast<int32_t*>(this) = value;
}
inline void SetImmInstrBits(Opcode op, Register rs, Register rt,
uint16_t imm) {
SetInstructionBits(
op << kOpcodeShift |
rs << kRsShift |
rt << kRtShift |
imm << kImmShift);
}
inline void SetSpecialInstrBits(SpecialFunction f,
Register rs, Register rt, Register rd) {
SetInstructionBits(
SPECIAL << kOpcodeShift |
f << kFunctionShift |
rs << kRsShift |
rt << kRtShift |
rd << kRdShift);
}
// Read one particular bit out of the instruction bits.
inline int32_t Bit(int nr) const {
return (InstructionBits() >> nr) & 1;
@ -502,6 +523,21 @@ class Instr {
// Use the At(pc) function to create references to Instr.
static Instr* At(uword pc) { return reinterpret_cast<Instr*>(pc); }
#if defined(DEBUG)
inline void AssertIsImmInstr(Opcode op, Register rs, Register rt,
int32_t imm) {
ASSERT((OpcodeField() == op) && (RsField() == rs) && (RtField() == rt) &&
(SImmField() == imm));
}
inline void AssertIsSpecialInstr(SpecialFunction f, Register rs, Register rt,
Register rd) {
ASSERT((OpcodeField() == SPECIAL) && (FunctionField() == f) &&
(RsField() == rs) && (RtField() == rt) &&
(RdField() == rd));
}
#endif // defined(DEBUG)
private:
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(Instr);

View file

@ -10,10 +10,6 @@
namespace dart {
#if defined(TARGET_ARCH_IA32) || \
defined(TARGET_ARCH_X64) || \
defined(TARGET_ARCH_ARM)
static bool breakpoint_hit = false;
static int breakpoint_hit_counter = 0;
static Dart_Handle script_lib = NULL;
@ -1534,6 +1530,4 @@ TEST_CASE(Debug_StackTraceDump2) {
EXPECT_EQ(1, breakpoint_hit_counter);
}
#endif // TARGET_ARCH_IA32 || TARGET_ARCH_X64 || TARGET_ARCH_ARM
} // namespace dart

View file

@ -5,30 +5,86 @@
#include "vm/globals.h"
#if defined(TARGET_ARCH_MIPS)
#include "vm/cpu.h"
#include "vm/debugger.h"
#include "vm/instructions.h"
#include "vm/stub_code.h"
namespace dart {
// TODO(hausner): Handle captured variables.
RawInstance* ActivationFrame::GetLocalVarValue(intptr_t slot_index) {
UNIMPLEMENTED();
return NULL;
uword var_address = fp() + slot_index * kWordSize;
return reinterpret_cast<RawInstance*>(
*reinterpret_cast<uword*>(var_address));
}
RawInstance* ActivationFrame::GetInstanceCallReceiver(
intptr_t num_actual_args) {
UNIMPLEMENTED();
return NULL;
ASSERT(num_actual_args > 0); // At minimum we have a receiver on the stack.
// Stack pointer points to last argument that was pushed on the stack.
uword receiver_addr = sp() + ((num_actual_args - 1) * kWordSize);
return reinterpret_cast<RawInstance*>(
*reinterpret_cast<uword*>(receiver_addr));
}
void CodeBreakpoint::PatchFunctionReturn() {
UNIMPLEMENTED();
Instr* instr1 = Instr::At(pc_ - 6 * Instr::kInstrSize);
Instr* instr2 = Instr::At(pc_ - 5 * Instr::kInstrSize);
Instr* instr3 = Instr::At(pc_ - 4 * Instr::kInstrSize);
Instr* instr4 = Instr::At(pc_ - 3 * Instr::kInstrSize);
Instr* instr5 = Instr::At(pc_ - 2 * Instr::kInstrSize);
Instr* instr6 = Instr::At(pc_ - 1 * Instr::kInstrSize);
#if defined(DEBUG)
instr1->AssertIsImmInstr(LW, SP, RA, 2 * kWordSize);
instr2->AssertIsImmInstr(LW, SP, FP, 1 * kWordSize);
instr3->AssertIsImmInstr(LW, SP, PP, 0 * kWordSize);
instr4->AssertIsImmInstr(ADDIU, SP, SP, 4 * kWordSize);
instr5->AssertIsSpecialInstr(JR, RA, ZR, ZR);
ASSERT(instr6->InstructionBits() == Instr::kNopInstruction);
#endif // defined(DEBUG)
// Smash code with call instruction and target address.
uword stub_addr = StubCode::BreakpointReturnEntryPoint();
uint16_t target_lo = stub_addr & 0xffff;
uint16_t target_hi = stub_addr >> 16;
// Unlike other architectures, the sequence we are patching in is shorter
// than the sequence we are replacing. We pad at the top with nops so that
// the end of the new sequence is lined up with the code descriptor.
instr1->SetInstructionBits(Instr::kNopInstruction);
instr2->SetInstructionBits(Instr::kNopInstruction);
instr3->SetImmInstrBits(LUI, ZR, TMP1, target_hi);
instr4->SetImmInstrBits(ORI, TMP1, TMP1, target_lo);
instr5->SetSpecialInstrBits(JALR, TMP1, ZR, RA);
instr6->SetInstructionBits(Instr::kNopInstruction);
CPU::FlushICache(pc_ - 6 * Instr::kInstrSize, 6 * Instr::kInstrSize);
}
void CodeBreakpoint::RestoreFunctionReturn() {
UNIMPLEMENTED();
Instr* instr1 = Instr::At(pc_ - 6 * Instr::kInstrSize);
Instr* instr2 = Instr::At(pc_ - 5 * Instr::kInstrSize);
Instr* instr3 = Instr::At(pc_ - 4 * Instr::kInstrSize);
Instr* instr4 = Instr::At(pc_ - 3 * Instr::kInstrSize);
Instr* instr5 = Instr::At(pc_ - 2 * Instr::kInstrSize);
Instr* instr6 = Instr::At(pc_ - 1 * Instr::kInstrSize);
ASSERT(instr3->OpcodeField() == LUI && instr3->RtField() == TMP1);
instr1->SetImmInstrBits(LW, SP, RA, 2 * kWordSize);
instr2->SetImmInstrBits(LW, SP, FP, 1 * kWordSize);
instr3->SetImmInstrBits(LW, SP, PP, 0 * kWordSize);
instr4->SetImmInstrBits(ADDIU, SP, SP, 4 * kWordSize);
instr5->SetSpecialInstrBits(JR, RA, ZR, ZR);
instr6->SetInstructionBits(Instr::kNopInstruction);
CPU::FlushICache(pc_ - 6 * Instr::kInstrSize, 6 * Instr::kInstrSize);
}
} // namespace dart

View file

@ -9,10 +9,6 @@
namespace dart {
#if defined(TARGET_ARCH_IA32) || \
defined(TARGET_ARCH_X64) || \
defined(TARGET_ARCH_ARM)
TEST_CASE(OldGC) {
const char* kScriptChars =
"main() {\n"
@ -50,6 +46,4 @@ TEST_CASE(LargeSweep) {
Dart_ExitScope();
heap->CollectGarbage(Heap::kOld);
}
#endif // TARGET_ARCH_IA32 || TARGET_ARCH_X64 || TARGET_ARCH_ARM
}

View file

@ -73,7 +73,7 @@ int CallPattern::DecodeLoadWordImmediate(int end, Register* reg, int* value) {
instr = Instr::At(reinterpret_cast<uword>(&i));
ASSERT(instr->OpcodeField() == LUI);
ASSERT(instr->RtField() == *reg);
imm |= instr->UImmField();
imm |= (instr->UImmField() << 16);
*value = imm;
return end;
}

View file

@ -99,13 +99,11 @@ void ReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ Bind(&stack_ok);
}
#endif
// This sequence is patched by a debugger breakpoint. There is no need for
// extra NOP instructions here because the sequence patched in for a
// breakpoint is shorter than the sequence here.
__ LeaveDartFrame();
__ Ret();
// Generate 2 NOP instructions so that the debugger can patch the return
// pattern (1 instruction) with a call to the debug stub (3 instructions).
__ nop();
__ nop();
compiler->AddCurrentDescriptor(PcDescriptors::kReturn,
Isolate::kNoDeoptId,
token_pos());
@ -1682,15 +1680,26 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
case Token::kMUL: {
// Keep left value tagged and untag right value.
const intptr_t value = Smi::Cast(constant).Value();
if (value == 2) {
__ sll(result, left, 1);
if (deopt == NULL) {
if (value == 2) {
__ sll(result, left, 1);
} else {
__ LoadImmediate(TMP1, value);
__ mult(left, TMP1);
__ mflo(result);
}
} else {
__ LoadImmediate(TMP1, value);
__ mult(left, TMP1);
__ mflo(result);
}
if (deopt != NULL) {
UNIMPLEMENTED();
if (value == 2) {
__ sra(TMP1, left, 31); // TMP1 = sign of left.
__ sll(result, left, 1);
} else {
__ LoadImmediate(TMP1, value);
__ mult(left, TMP1);
__ mflo(result);
__ mfhi(TMP1);
}
__ sra(TMP2, result, 31);
__ bne(TMP1, TMP2, deopt);
}
break;
}
@ -2379,24 +2388,47 @@ void BooleanNegateInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
LocationSummary* ChainContextInstr::MakeLocationSummary() const {
UNIMPLEMENTED();
return NULL;
return LocationSummary::Make(1,
Location::NoLocation(),
LocationSummary::kNoCall);
}
void ChainContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
UNIMPLEMENTED();
Register context_value = locs()->in(0).reg();
// Chain the new context in context_value to its parent in CTX.
__ StoreIntoObject(context_value,
FieldAddress(context_value, Context::parent_offset()),
CTX);
// Set new context as current context.
__ mov(CTX, context_value);
}
LocationSummary* StoreVMFieldInstr::MakeLocationSummary() const {
UNIMPLEMENTED();
return NULL;
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
locs->set_in(0, value()->NeedsStoreBuffer() ? Location::WritableRegister()
: Location::RequiresRegister());
locs->set_in(1, Location::RequiresRegister());
return locs;
}
void StoreVMFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
UNIMPLEMENTED();
Register value_reg = locs()->in(0).reg();
Register dest_reg = locs()->in(1).reg();
if (value()->NeedsStoreBuffer()) {
__ StoreIntoObject(dest_reg, FieldAddress(dest_reg, offset_in_bytes()),
value_reg);
} else {
__ StoreIntoObjectNoBarrier(
dest_reg, FieldAddress(dest_reg, offset_in_bytes()), value_reg);
}
}

View file

@ -18,10 +18,6 @@ UNIT_TEST_CASE(IsolateCurrent) {
}
#if defined(TARGET_ARCH_IA32) || \
defined(TARGET_ARCH_X64) || \
defined(TARGET_ARCH_ARM)
// Test to ensure that an exception is thrown if no isolate creation
// callback has been set by the embedder when an isolate is spawned.
TEST_CASE(IsolateSpawn) {
@ -44,6 +40,4 @@ TEST_CASE(IsolateSpawn) {
EXPECT_VALID(exception_result);
}
#endif // TARGET_ARCH_IA32 || TARGET_ARCH_X64 || TARGET_ARCH_ARM
} // namespace dart

View file

@ -104,10 +104,7 @@ bool ObjectStore::PreallocateObjects() {
ASSERT(this->stack_overflow() == Instance::null());
ASSERT(this->out_of_memory() == Instance::null());
ASSERT(this->preallocated_stack_trace() == Stacktrace::null());
// TODO(regis): Reenable this code for mips when possible.
#if defined(TARGET_ARCH_IA32) || \
defined(TARGET_ARCH_X64) || \
defined(TARGET_ARCH_ARM)
Object& result = Object::Handle();
result = Exceptions::Create(Exceptions::kStackOverflow,
@ -133,7 +130,7 @@ bool ObjectStore::PreallocateObjects() {
Array::New(Stacktrace::kPreallocatedStackdepth, Heap::kOld));
result = Stacktrace::New(func_array, code_array, pc_offset_array);
set_preallocated_stack_trace(Stacktrace::Cast(result));
#endif
return true;
}

View file

@ -905,11 +905,6 @@ TEST_CASE(GenerateSource) {
}
#if defined(TARGET_ARCH_IA32) || \
defined(TARGET_ARCH_X64) || \
defined(TARGET_ARCH_ARM)
UNIT_TEST_CASE(FullSnapshot) {
const char* kScriptChars =
"class Fields {\n"
@ -2497,6 +2492,4 @@ UNIT_TEST_CASE(PostCObject) {
Dart_ExitScope();
}
#endif // TARGET_ARCH_IA32 || TARGET_ARCH_X64 || TARGET_ARCH_ARM
} // namespace dart

View file

@ -11,6 +11,7 @@ namespace dart {
// The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
// code in the InvokeDartCode stub.
static const int kSavedContextOffsetInEntryFrame = -11 * kWordSize;
static const int kExitLinkOffsetInEntryFrame = -10 * kWordSize;
static const int kPcAddressOffsetFromSp = -2 * kWordSize;
static const int kEntrypointMarkerOffsetFromFp = 2 * kWordSize;
@ -43,8 +44,7 @@ intptr_t EntryFrame::ExitLinkOffset() const {
intptr_t EntryFrame::SavedContextOffset() const {
UNIMPLEMENTED();
return 0;
return kSavedContextOffsetInEntryFrame;
}

View file

@ -1525,7 +1525,7 @@ void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) {
// calling into the runtime.
__ EnterStubFrame();
__ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null()));
// // Preserve arguments descriptor and make room for result.
// Preserve arguments descriptor and make room for result.
__ PushList((1 << R0) | (1 << R4));
__ CallRuntime(kBreakpointStaticHandlerRuntimeEntry);
// Pop code object result and restore arguments descriptor.

View file

@ -230,8 +230,29 @@ void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) {
}
// Called from a static call only when an invalid code has been entered
// (invalid because its function was optimized or deoptimized).
// S4: arguments descriptor array.
void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
__ Unimplemented("FixCallersTarget stub");
// Create a stub frame as we are pushing some objects on the stack before
// calling into the runtime.
__ EnterStubFrame();
// Setup space on stack for return value and preserve arguments descriptor.
__ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null()));
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ sw(S4, Address(SP, 1 * kWordSize));
__ sw(T0, Address(SP, 0 * kWordSize));
__ CallRuntime(kFixCallersTargetRuntimeEntry);
// Get Code object result and restore arguments descriptor array.
__ lw(T0, Address(SP, 0 * kWordSize));
__ lw(S4, Address(SP, 1 * kWordSize));
__ addiu(SP, SP, Immediate(2 * kWordSize));
// Remove the stub frame.
__ LeaveStubFrame();
// Jump to the dart function.
__ lw(T0, FieldAddress(T0, Code::instructions_offset()));
__ AddImmediate(T0, T0, Instructions::HeaderSize() - kHeapObjectTag);
__ jr(T0);
}
@ -578,7 +599,7 @@ void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) {
// TOS + 1: Arguments descriptor array.
// TOS + 2: Place for result from the call.
// TOS + 3: Saved FP of previous frame.
// TOS + 4: Dart code return address
// TOS + 4: Dart code return address.
// TOS + 5: PC marker (0 for stub).
// TOS + 6: Last argument of caller.
// ....
@ -1517,18 +1538,83 @@ void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) {
}
// RA: return address (Dart code).
// S4: Arguments descriptor array.
void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) {
__ Unimplemented("BreakpointStatic stub");
__ TraceSimMsg("BreakpointStaticStub");
// Create a stub frame as we are pushing some objects on the stack before
// calling into the runtime.
__ EnterStubFrame();
__ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null()));
// Preserve arguments descriptor and make room for result.
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ sw(S4, Address(SP, 1 * kWordSize));
__ sw(T0, Address(SP, 0 * kWordSize));
__ CallRuntime(kBreakpointStaticHandlerRuntimeEntry);
// Pop code object result and restore arguments descriptor.
__ lw(T0, Address(SP, 0 * kWordSize));
__ lw(S4, Address(SP, 1 * kWordSize));
__ addiu(SP, SP, Immediate(2 * kWordSize));
__ LeaveStubFrame();
// Now call the static function. The breakpoint handler function
// ensures that the call target is compiled.
__ lw(T0, FieldAddress(T0, Code::instructions_offset()));
__ AddImmediate(T0, Instructions::HeaderSize() - kHeapObjectTag);
__ jr(T0);
}
// V0: return value.
void StubCode::GenerateBreakpointReturnStub(Assembler* assembler) {
__ Unimplemented("BreakpointReturn stub");
__ TraceSimMsg("BreakpoingReturnStub");
// Create a stub frame as we are pushing some objects on the stack before
// calling into the runtime.
__ EnterStubFrame();
__ Push(V0);
__ CallRuntime(kBreakpointReturnHandlerRuntimeEntry);
__ Pop(V0);
__ LeaveStubFrame();
// Instead of returning to the patched Dart function, emulate the
// smashed return code pattern and return to the function's caller.
__ LeaveDartFrame();
__ Ret();
}
// RA: return address (Dart code).
// S5: Inline cache data array.
// S4: Arguments descriptor array.
void StubCode::GenerateBreakpointDynamicStub(Assembler* assembler) {
__ Unimplemented("BreakpointDynamic stub");
// Create a stub frame as we are pushing some objects on the stack before
// calling into the runtime.
__ EnterStubFrame();
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ sw(S5, Address(SP, 1 * kWordSize));
__ sw(S4, Address(SP, 0 * kWordSize));
__ CallRuntime(kBreakpointDynamicHandlerRuntimeEntry);
__ lw(S4, Address(SP, 0 * kWordSize));
__ lw(S5, Address(SP, 1 * kWordSize));
__ addiu(SP, SP, Immediate(2 * kWordSize));
__ LeaveStubFrame();
// Find out which dispatch stub to call.
__ lw(TMP1, FieldAddress(S5, ICData::num_args_tested_offset()));
Label one_arg, two_args, three_args;
__ BranchEqual(TMP1, 1, &one_arg);
__ BranchEqual(TMP1, 2, &two_args);
__ BranchEqual(TMP1, 3, &three_args);
__ Stop("Unsupported number of arguments tested.");
__ Bind(&one_arg);
__ Branch(&StubCode::OneArgCheckInlineCacheLabel());
__ Bind(&two_args);
__ Branch(&StubCode::TwoArgsCheckInlineCacheLabel());
__ Bind(&three_args);
__ Branch(&StubCode::ThreeArgsCheckInlineCacheLabel());
__ break_(0);
}