Adds native/leaf runtime call stub and redirection on MIPS.

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

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@20813 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
zra@google.com 2013-04-02 20:24:55 +00:00
parent c3777f14fd
commit 3e080d1b34
9 changed files with 188 additions and 18 deletions

View file

@ -70,13 +70,9 @@ dart/*: Skip
[ $arch == simmips ]
# Tests needing an assembler.
cc/CallLeafRuntimeStubCode: Skip
cc/CallRuntimeStubCode: Skip
cc/Dart2JSCompileAll: Skip
cc/FrameLookup: Skip
cc/IcDataAccess: Skip
cc/Jump: Skip
cc/PatchStaticCall: Skip
cc/UseDartApi: Skip
# Tests needing Dart execution.
dart/*: Skip

View file

@ -515,6 +515,15 @@ class Assembler : public ValueObject {
jr(TMP);
}
void BranchPatchable(const ExternalLabel* label) {
const uint16_t low = Utils::Low16Bits(label->address());
const uint16_t high = Utils::High16Bits(label->address());
lui(TMP, Immediate(high));
ori(TMP, TMP, Immediate(low));
jr(TMP);
delay_slot()->nop();
}
void BranchLink(const ExternalLabel* label) {
LoadImmediate(TMP, label->address());
jalr(TMP);
@ -525,6 +534,7 @@ class Assembler : public ValueObject {
Array::data_offset() + 4*AddExternalLabel(label) - kHeapObjectTag;
LoadWordFromPoolOffset(TMP, offset);
jalr(TMP);
delay_slot()->nop();
}
// If the signed value in rs is less than value, rd is 1, and 0 otherwise.

View file

@ -252,6 +252,7 @@ void FlowGraphCompiler::EmitFrameEntry() {
__ EnterDartFrame((StackSize() * kWordSize));
}
// Input parameters:
// RA: return address.
// SP: address of last argument.
@ -404,7 +405,9 @@ void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
const ExternalLabel* label,
PcDescriptors::Kind kind,
LocationSummary* locs) {
UNIMPLEMENTED();
__ BranchLinkPatchable(label);
AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos);
RecordSafepoint(locs);
}

View file

@ -162,19 +162,37 @@ JumpPattern::JumpPattern(uword pc) : pc_(pc) { }
bool JumpPattern::IsValid() const {
UNIMPLEMENTED();
return false;
Instr* lui = Instr::At(pc_ + (0 * Instr::kInstrSize));
Instr* ori = Instr::At(pc_ + (1 * Instr::kInstrSize));
Instr* jr = Instr::At(pc_ + (2 * Instr::kInstrSize));
Instr* nop = Instr::At(pc_ + (3 * Instr::kInstrSize));
return (lui->OpcodeField() == LUI) &&
(ori->OpcodeField() == ORI) &&
(jr->OpcodeField() == SPECIAL) &&
(jr->FunctionField() == JR) &&
(nop->InstructionBits() == Instr::kNopInstruction);
}
uword JumpPattern::TargetAddress() const {
UNIMPLEMENTED();
return 0;
Instr* lui = Instr::At(pc_ + (0 * Instr::kInstrSize));
Instr* ori = Instr::At(pc_ + (1 * Instr::kInstrSize));
const uint16_t target_lo = ori->UImmField();
const uint16_t target_hi = lui->UImmField();
return (target_hi << 16) | target_lo;
}
void JumpPattern::SetTargetAddress(uword target_address) const {
UNIMPLEMENTED();
Instr* lui = Instr::At(pc_ + (0 * Instr::kInstrSize));
Instr* ori = Instr::At(pc_ + (1 * Instr::kInstrSize));
const int32_t lui_bits = lui->InstructionBits();
const int32_t ori_bits = ori->InstructionBits();
const uint16_t target_lo = target_address & 0xffff;
const uint16_t target_hi = target_address >> 16;
lui->SetInstructionBits((lui_bits & 0xffff0000) | target_hi);
ori->SetInstructionBits((ori_bits & 0xffff0000) | target_lo);
}
} // namespace dart

View file

@ -46,7 +46,8 @@ class JumpPattern : public ValueObject {
public:
explicit JumpPattern(uword pc);
static const int kLengthInBytes = 3*Instr::kInstrSize;
// lui; ori; jr; nop (in delay slot) = 4.
static const int kLengthInBytes = 4*Instr::kInstrSize;
int pattern_length_in_bytes() const {
return kLengthInBytes;

View file

@ -33,7 +33,8 @@ ASSEMBLER_TEST_RUN(Call, test) {
ASSEMBLER_TEST_GENERATE(Jump, assembler) {
UNIMPLEMENTED();
__ BranchPatchable(&StubCode::InstanceFunctionLookupLabel());
__ BranchPatchable(&StubCode::AllocateArrayLabel());
}

View file

@ -197,13 +197,47 @@ void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler,
LocationSummary* NativeCallInstr::MakeLocationSummary() const {
UNIMPLEMENTED();
return NULL;
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 3;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
locs->set_temp(0, Location::RegisterLocation(A1));
locs->set_temp(1, Location::RegisterLocation(A2));
locs->set_temp(2, Location::RegisterLocation(T5));
locs->set_out(Location::RegisterLocation(V0));
return locs;
}
void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
UNIMPLEMENTED();
ASSERT(locs()->temp(0).reg() == A1);
ASSERT(locs()->temp(1).reg() == A2);
ASSERT(locs()->temp(2).reg() == T5);
Register result = locs()->out().reg();
// Push the result place holder initialized to NULL.
__ PushObject(Object::ZoneHandle());
// Pass a pointer to the first argument in A2.
if (!function().HasOptionalParameters()) {
__ addiu(A2, FP, Immediate((kLastParamSlotIndex +
function().NumParameters() - 1) * kWordSize));
} else {
__ addiu(A2, FP, Immediate(kFirstLocalSlotIndex * kWordSize));
}
// Compute the effective address. When running under the simulator,
// this is a redirection address that forces the simulator to call
// into the runtime system.
uword entry = reinterpret_cast<uword>(native_c_function());
#if defined(USING_SIMULATOR)
entry = Simulator::RedirectExternalReference(entry, Simulator::kNativeCall);
#endif
__ LoadImmediate(T5, entry);
__ LoadImmediate(A1, NativeArguments::ComputeArgcTag(function()));
compiler->GenerateCall(token_pos(),
&StubCode::CallNativeCFunctionLabel(),
PcDescriptors::kOther,
locs());
__ Pop(result);
}

View file

@ -100,8 +100,91 @@ void StubCode::GeneratePrintStopMessageStub(Assembler* assembler) {
}
// Input parameters:
// RA : return address.
// SP : address of return value.
// T5 : address of the native function to call.
// A2 : address of first argument in argument array.
// A1 : argc_tag including number of arguments and function kind.
void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) {
__ Unimplemented("CallNativeCFunction stub");
const intptr_t isolate_offset = NativeArguments::isolate_offset();
const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset();
const intptr_t argv_offset = NativeArguments::argv_offset();
const intptr_t retval_offset = NativeArguments::retval_offset();
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ sw(RA, Address(SP, 1 * kWordSize));
__ sw(FP, Address(SP, 0 * kWordSize));
__ mov(FP, SP);
// Load current Isolate pointer from Context structure into A0.
__ lw(A0, FieldAddress(CTX, Context::isolate_offset()));
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
__ sw(SP, Address(A0, Isolate::top_exit_frame_info_offset()));
// Save current Context pointer into Isolate structure.
__ sw(CTX, Address(A0, Isolate::top_context_offset()));
// Cache Isolate pointer into CTX while executing native code.
__ mov(CTX, A0);
// Reserve space for the native arguments structure passed on the stack (the
// outgoing pointer parameter to the native arguments structure is passed in
// R0) and align frame before entering the C++ world.
__ ReserveAlignedFrameSpace(sizeof(NativeArguments));
// Initialize NativeArguments structure and call native function.
// Registers A0, A1, A2, and A3 are used.
ASSERT(isolate_offset == 0 * kWordSize);
// Set isolate in NativeArgs: A0 already contains CTX.
// There are no native calls to closures, so we do not need to set the tag
// bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_.
ASSERT(argc_tag_offset == 1 * kWordSize);
// Set argc in NativeArguments: T1 already contains argc.
ASSERT(argv_offset == 2 * kWordSize);
// Set argv in NativeArguments: T2 already contains argv.
ASSERT(retval_offset == 3 * kWordSize);
__ addiu(A3, FP, Immediate(2 * kWordSize)); // Set retval in NativeArgs.
// TODO(regis): Should we pass the structure by value as in runtime calls?
// It would require changing Dart API for native functions.
// For now, space is reserved on the stack and we pass a pointer to it.
__ addiu(SP, SP, Immediate(-4 * kWordSize));
__ sw(A3, Address(SP, 3 * kWordSize));
__ sw(A2, Address(SP, 2 * kWordSize));
__ sw(A1, Address(SP, 1 * kWordSize));
__ sw(A0, Address(SP, 0 * kWordSize));
__ mov(A0, SP); // Pass the pointer to the NativeArguments.
// Call native function or redirection via simulator.
__ jalr(T5);
// Reset exit frame information in Isolate structure.
__ LoadImmediate(A2, 0);
__ sw(A2, Address(CTX, Isolate::top_exit_frame_info_offset()));
// Load Context pointer from Isolate structure into R2.
__ lw(A2, Address(CTX, Isolate::top_context_offset()));
// Reset Context pointer in Isolate structure.
__ LoadImmediate(A3, reinterpret_cast<intptr_t>(Object::null()));
__ sw(A3, Address(CTX, Isolate::top_context_offset()));
// Cache Context pointer into CTX while executing Dart code.
__ mov(CTX, A2);
__ mov(SP, FP);
__ lw(RA, Address(SP, 1 * kWordSize));
__ lw(FP, Address(SP, 0 * kWordSize));
__ addiu(SP, SP, Immediate(2 * kWordSize));
__ Ret();
}

View file

@ -39,7 +39,23 @@ static Function* CreateFunction(const char* name) {
// Test calls to stub code which calls into the runtime.
static void GenerateCallToCallRuntimeStub(Assembler* assembler,
int value1, int value2) {
UNIMPLEMENTED();
const int argc = 2;
const Smi& smi1 = Smi::ZoneHandle(Smi::New(value1));
const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
const Object& result = Object::ZoneHandle();
const Context& context = Context::ZoneHandle(Context::New(0, Heap::kOld));
ASSERT(context.isolate() == Isolate::Current());
__ EnterDartFrame(0);
__ LoadObject(CTX, context);
__ PushObject(result); // Push Null object for return value.
__ PushObject(smi1); // Push argument 1 smi1.
__ PushObject(smi2); // Push argument 2 smi2.
ASSERT(kTestSmiSubRuntimeEntry.argument_count() == argc);
__ CallRuntime(kTestSmiSubRuntimeEntry); // Call SmiSub runtime func.
__ addiu(SP, SP, Immediate(argc * kWordSize));
__ Pop(V0); // Pop return value from return slot.
__ LeaveDartFrame();
__ Ret();
}
@ -64,7 +80,15 @@ TEST_CASE(CallRuntimeStubCode) {
static void GenerateCallToCallLeafRuntimeStub(Assembler* assembler,
int value1,
int value2) {
UNIMPLEMENTED();
const Smi& smi1 = Smi::ZoneHandle(Smi::New(value1));
const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
__ EnterDartFrame(0);
__ ReserveAlignedFrameSpace(0);
__ LoadObject(A0, smi1); // Set up argument 1 smi1.
__ LoadObject(A1, smi2); // Set up argument 2 smi2.
__ CallRuntime(kTestLeafSmiAddRuntimeEntry); // Call SmiAdd runtime func.
__ LeaveDartFrame();
__ Ret(); // Return value is in R0.
}