| Index: src/mips/simulator-mips.cc
|
| diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
|
| index 8a335441b32e3eb8d2ce22bbf7bc2466ff002102..68fb7ce8747ee830d0dfe377a3565b54fba66a9b 100644
|
| --- a/src/mips/simulator-mips.cc
|
| +++ b/src/mips/simulator-mips.cc
|
| @@ -496,12 +496,27 @@ void MipsDebugger::Debug() {
|
| end = cur + words;
|
|
|
| while (cur < end) {
|
| - PrintF(" 0x%08x: 0x%08x %10d\n",
|
| + PrintF(" 0x%08x: 0x%08x %10d",
|
| reinterpret_cast<intptr_t>(cur), *cur, *cur);
|
| + HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
|
| + int value = *cur;
|
| + Heap* current_heap = v8::internal::Isolate::Current()->heap();
|
| + if (current_heap->Contains(obj) || ((value & 1) == 0)) {
|
| + PrintF(" (");
|
| + if ((value & 1) == 0) {
|
| + PrintF("smi %d", value / 2);
|
| + } else {
|
| + obj->ShortPrint();
|
| + }
|
| + PrintF(")");
|
| + }
|
| + PrintF("\n");
|
| cur++;
|
| }
|
|
|
| - } else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0)) {
|
| + } else if ((strcmp(cmd, "disasm") == 0) ||
|
| + (strcmp(cmd, "dpc") == 0) ||
|
| + (strcmp(cmd, "di") == 0)) {
|
| disasm::NameConverter converter;
|
| disasm::Disassembler dasm(converter);
|
| // Use a reasonably large buffer.
|
| @@ -514,11 +529,23 @@ void MipsDebugger::Debug() {
|
| cur = reinterpret_cast<byte*>(sim_->get_pc());
|
| end = cur + (10 * Instruction::kInstrSize);
|
| } else if (argc == 2) {
|
| - int32_t value;
|
| - if (GetValue(arg1, &value)) {
|
| - cur = reinterpret_cast<byte*>(value);
|
| - // No length parameter passed, assume 10 instructions.
|
| - end = cur + (10 * Instruction::kInstrSize);
|
| + int regnum = Registers::Number(arg1);
|
| + if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
|
| + // The argument is an address or a register name.
|
| + int32_t value;
|
| + if (GetValue(arg1, &value)) {
|
| + cur = reinterpret_cast<byte*>(value);
|
| + // Disassemble 10 instructions at <arg1>.
|
| + end = cur + (10 * Instruction::kInstrSize);
|
| + }
|
| + } else {
|
| + // The argument is the number of instructions.
|
| + int32_t value;
|
| + if (GetValue(arg1, &value)) {
|
| + cur = reinterpret_cast<byte*>(sim_->get_pc());
|
| + // Disassemble <arg1> instructions.
|
| + end = cur + (value * Instruction::kInstrSize);
|
| + }
|
| }
|
| } else {
|
| int32_t value1;
|
| @@ -615,8 +642,10 @@ void MipsDebugger::Debug() {
|
| PrintF("flags\n");
|
| PrintF(" print flags\n");
|
| PrintF("disasm [<instructions>]\n");
|
| - PrintF("disasm [[<address>] <instructions>]\n");
|
| - PrintF(" disassemble code, default is 10 instructions from pc\n");
|
| + PrintF("disasm [<address/register>]\n");
|
| + PrintF("disasm [[<address/register>] <instructions>]\n");
|
| + PrintF(" disassemble code, default is 10 instructions\n");
|
| + PrintF(" from pc (alias 'di')\n");
|
| PrintF("gdb\n");
|
| PrintF(" enter gdb\n");
|
| PrintF("break <address>\n");
|
| @@ -934,6 +963,87 @@ double Simulator::get_fpu_register_double(int fpureg) const {
|
| }
|
|
|
|
|
| +// For use in calls that take two double values, constructed either
|
| +// from a0-a3 or f12 and f14.
|
| +void Simulator::GetFpArgs(double* x, double* y) {
|
| + if (!IsMipsSoftFloatABI) {
|
| + *x = get_fpu_register_double(12);
|
| + *y = get_fpu_register_double(14);
|
| + } else {
|
| + // We use a char buffer to get around the strict-aliasing rules which
|
| + // otherwise allow the compiler to optimize away the copy.
|
| + char buffer[sizeof(*x)];
|
| + int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
|
| +
|
| + // Registers a0 and a1 -> x.
|
| + reg_buffer[0] = get_register(a0);
|
| + reg_buffer[1] = get_register(a1);
|
| + memcpy(x, buffer, sizeof(buffer));
|
| +
|
| + // Registers a2 and a3 -> y.
|
| + reg_buffer[0] = get_register(a2);
|
| + reg_buffer[1] = get_register(a3);
|
| + memcpy(y, buffer, sizeof(buffer));
|
| + }
|
| +}
|
| +
|
| +
|
| +// For use in calls that take one double value, constructed either
|
| +// from a0 and a1 or f12.
|
| +void Simulator::GetFpArgs(double* x) {
|
| + if (!IsMipsSoftFloatABI) {
|
| + *x = get_fpu_register_double(12);
|
| + } else {
|
| + // We use a char buffer to get around the strict-aliasing rules which
|
| + // otherwise allow the compiler to optimize away the copy.
|
| + char buffer[sizeof(*x)];
|
| + int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
|
| + // Registers a0 and a1 -> x.
|
| + reg_buffer[0] = get_register(a0);
|
| + reg_buffer[1] = get_register(a1);
|
| + memcpy(x, buffer, sizeof(buffer));
|
| + }
|
| +}
|
| +
|
| +
|
| +// For use in calls that take one double value constructed either
|
| +// from a0 and a1 or f12 and one integer value.
|
| +void Simulator::GetFpArgs(double* x, int32_t* y) {
|
| + if (!IsMipsSoftFloatABI) {
|
| + *x = get_fpu_register_double(12);
|
| + *y = get_register(a2);
|
| + } else {
|
| + // We use a char buffer to get around the strict-aliasing rules which
|
| + // otherwise allow the compiler to optimize away the copy.
|
| + char buffer[sizeof(*x)];
|
| + int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
|
| + // Registers 0 and 1 -> x.
|
| + reg_buffer[0] = get_register(a0);
|
| + reg_buffer[1] = get_register(a1);
|
| + memcpy(x, buffer, sizeof(buffer));
|
| +
|
| + // Register 2 -> y.
|
| + reg_buffer[0] = get_register(a2);
|
| + memcpy(y, buffer, sizeof(*y));
|
| + }
|
| +}
|
| +
|
| +
|
| +// The return value is either in v0/v1 or f0.
|
| +void Simulator::SetFpResult(const double& result) {
|
| + if (!IsMipsSoftFloatABI) {
|
| + set_fpu_register_double(0, result);
|
| + } else {
|
| + char buffer[2 * sizeof(registers_[0])];
|
| + int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
|
| + memcpy(buffer, &result, sizeof(buffer));
|
| + // Copy result to v0 and v1.
|
| + set_register(v0, reg_buffer[0]);
|
| + set_register(v1, reg_buffer[1]);
|
| + }
|
| +}
|
| +
|
| +
|
| // Helper functions for setting and testing the FCSR register's bits.
|
| void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
|
| if (value) {
|
| @@ -1208,6 +1318,33 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
|
| (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
|
| (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
|
|
|
| + if (!IsMipsSoftFloatABI) {
|
| + // With the hard floating point calling convention, double
|
| + // arguments are passed in FPU registers. Fetch the arguments
|
| + // from there and call the builtin using soft floating point
|
| + // convention.
|
| + switch (redirection->type()) {
|
| + case ExternalReference::BUILTIN_FP_FP_CALL:
|
| + case ExternalReference::BUILTIN_COMPARE_CALL:
|
| + arg0 = get_fpu_register(f12);
|
| + arg1 = get_fpu_register(f13);
|
| + arg2 = get_fpu_register(f14);
|
| + arg3 = get_fpu_register(f15);
|
| + break;
|
| + case ExternalReference::BUILTIN_FP_CALL:
|
| + arg0 = get_fpu_register(f12);
|
| + arg1 = get_fpu_register(f13);
|
| + break;
|
| + case ExternalReference::BUILTIN_FP_INT_CALL:
|
| + arg0 = get_fpu_register(f12);
|
| + arg1 = get_fpu_register(f13);
|
| + arg2 = get_register(a2);
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| + }
|
| +
|
| // This is dodgy but it works because the C entry stubs are never moved.
|
| // See comment in codegen-arm.cc and bug 1242173.
|
| int32_t saved_ra = get_register(ra);
|
| @@ -1218,31 +1355,44 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
|
| // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
|
| // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
|
| // simulator. Soft-float has additional abstraction of ExternalReference,
|
| - // to support serialization. Finally, when simulated on x86 host, the
|
| - // x86 softfloat routines are used, and this Redirection infrastructure
|
| - // lets simulated-mips make calls into x86 C code.
|
| - // When doing that, the 'double' return type must be handled differently
|
| - // than the usual int64_t return. The data is returned in different
|
| - // registers and cannot be cast from one type to the other. However, the
|
| - // calling arguments are passed the same way in both cases.
|
| + // to support serialization.
|
| if (fp_call) {
|
| SimulatorRuntimeFPCall target =
|
| reinterpret_cast<SimulatorRuntimeFPCall>(external);
|
| if (::v8::internal::FLAG_trace_sim) {
|
| - PrintF(
|
| - "Call to host function at %p args %08x, %08x, %08x, %08x\n",
|
| - FUNCTION_ADDR(target),
|
| - arg0,
|
| - arg1,
|
| - arg2,
|
| - arg3);
|
| - }
|
| + double dval0, dval1;
|
| + int32_t ival;
|
| + switch (redirection->type()) {
|
| + case ExternalReference::BUILTIN_FP_FP_CALL:
|
| + case ExternalReference::BUILTIN_COMPARE_CALL:
|
| + GetFpArgs(&dval0, &dval1);
|
| + PrintF("Call to host function at %p with args %f, %f",
|
| + FUNCTION_ADDR(target), dval0, dval1);
|
| + break;
|
| + case ExternalReference::BUILTIN_FP_CALL:
|
| + GetFpArgs(&dval0);
|
| + PrintF("Call to host function at %p with arg %f",
|
| + FUNCTION_ADDR(target), dval1);
|
| + break;
|
| + case ExternalReference::BUILTIN_FP_INT_CALL:
|
| + GetFpArgs(&dval0, &ival);
|
| + PrintF("Call to host function at %p with args %f, %d",
|
| + FUNCTION_ADDR(target), dval0, ival);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| + }
|
| + }
|
| double result = target(arg0, arg1, arg2, arg3);
|
| - // fp result -> registers v0 and v1.
|
| - int32_t gpreg_pair[2];
|
| - memcpy(&gpreg_pair[0], &result, 2 * sizeof(int32_t));
|
| - set_register(v0, gpreg_pair[0]);
|
| - set_register(v1, gpreg_pair[1]);
|
| + if (redirection->type() != ExternalReference::BUILTIN_COMPARE_CALL) {
|
| + SetFpResult(result);
|
| + } else {
|
| + int32_t gpreg_pair[2];
|
| + memcpy(&gpreg_pair[0], &result, 2 * sizeof(int32_t));
|
| + set_register(v0, gpreg_pair[0]);
|
| + set_register(v1, gpreg_pair[1]);
|
| + }
|
| } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
|
| // See DirectCEntryStub::GenerateCall for explanation of register usage.
|
| SimulatorRuntimeDirectApiCall target =
|
|
|