| Index: src/mips/simulator-mips.cc | 
| diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc | 
| index 59a537324f1fc555554e04d0b209392e70cd2b1a..50ad7a18871aa9b9407d811d8db45c7391eb5058 100644 | 
| --- a/src/mips/simulator-mips.cc | 
| +++ b/src/mips/simulator-mips.cc | 
| @@ -26,6 +26,8 @@ | 
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | 
| #include <stdlib.h> | 
| +#include <math.h> | 
| +#include <limits.h> | 
| #include <cstdarg> | 
| #include "v8.h" | 
|  | 
| @@ -37,23 +39,25 @@ | 
| #include "mips/constants-mips.h" | 
| #include "mips/simulator-mips.h" | 
|  | 
| -namespace v8i = v8::internal; | 
| - | 
| -#if !defined(__mips) || defined(USE_SIMULATOR) | 
|  | 
| // Only build the simulator if not compiling for real MIPS hardware. | 
| -namespace assembler { | 
| -namespace mips { | 
| +#if defined(USE_SIMULATOR) | 
|  | 
| -using ::v8::internal::Object; | 
| -using ::v8::internal::PrintF; | 
| -using ::v8::internal::OS; | 
| -using ::v8::internal::ReadLine; | 
| -using ::v8::internal::DeleteArray; | 
| +namespace v8 { | 
| +namespace internal { | 
|  | 
| // Utils functions | 
| bool HaveSameSign(int32_t a, int32_t b) { | 
| -  return ((a ^ b) > 0); | 
| +  return ((a ^ b) >= 0); | 
| +} | 
| + | 
| + | 
| +uint32_t get_fcsr_condition_bit(uint32_t cc) { | 
| +  if (cc == 0) { | 
| +    return 23; | 
| +  } else { | 
| +    return 24 + cc; | 
| +  } | 
| } | 
|  | 
|  | 
| @@ -63,15 +67,18 @@ bool HaveSameSign(int32_t a, int32_t b) { | 
| // Library does not provide vsscanf. | 
| #define SScanF sscanf  // NOLINT | 
|  | 
| -// The Debugger class is used by the simulator while debugging simulated MIPS | 
| +// The MipsDebugger class is used by the simulator while debugging simulated | 
| // code. | 
| -class Debugger { | 
| +class MipsDebugger { | 
| public: | 
| -  explicit Debugger(Simulator* sim); | 
| -  ~Debugger(); | 
| +  explicit MipsDebugger(Simulator* sim); | 
| +  ~MipsDebugger(); | 
|  | 
| void Stop(Instruction* instr); | 
| void Debug(); | 
| +  // Print all registers with a nice formatting. | 
| +  void PrintAllRegs(); | 
| +  void PrintAllRegsIncludingFPU(); | 
|  | 
| private: | 
| // We set the breakpoint code to 0xfffff to easily recognize it. | 
| @@ -81,6 +88,10 @@ class Debugger { | 
| Simulator* sim_; | 
|  | 
| int32_t GetRegisterValue(int regnum); | 
| +  int32_t GetFPURegisterValueInt(int regnum); | 
| +  int64_t GetFPURegisterValueLong(int regnum); | 
| +  float GetFPURegisterValueFloat(int regnum); | 
| +  double GetFPURegisterValueDouble(int regnum); | 
| bool GetValue(const char* desc, int32_t* value); | 
|  | 
| // Set or delete a breakpoint. Returns true if successful. | 
| @@ -91,18 +102,17 @@ class Debugger { | 
| // execution to skip past breakpoints when run from the debugger. | 
| void UndoBreakpoints(); | 
| void RedoBreakpoints(); | 
| - | 
| -  // Print all registers with a nice formatting. | 
| -  void PrintAllRegs(); | 
| }; | 
|  | 
| -Debugger::Debugger(Simulator* sim) { | 
| +MipsDebugger::MipsDebugger(Simulator* sim) { | 
| sim_ = sim; | 
| } | 
|  | 
| -Debugger::~Debugger() { | 
| + | 
| +MipsDebugger::~MipsDebugger() { | 
| } | 
|  | 
| + | 
| #ifdef GENERATED_CODE_COVERAGE | 
| static FILE* coverage_log = NULL; | 
|  | 
| @@ -115,7 +125,7 @@ static void InitializeCoverage() { | 
| } | 
|  | 
|  | 
| -void Debugger::Stop(Instruction* instr) { | 
| +void MipsDebugger::Stop(Instruction* instr) { | 
| UNIMPLEMENTED_MIPS(); | 
| char* str = reinterpret_cast<char*>(instr->InstructionBits()); | 
| if (strlen(str) > 0) { | 
| @@ -125,9 +135,10 @@ void Debugger::Stop(Instruction* instr) { | 
| } | 
| instr->SetInstructionBits(0x0);  // Overwrite with nop. | 
| } | 
| -  sim_->set_pc(sim_->get_pc() + Instruction::kInstructionSize); | 
| +  sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize); | 
| } | 
|  | 
| + | 
| #else  // ndef GENERATED_CODE_COVERAGE | 
|  | 
| #define UNSUPPORTED() printf("Unsupported instruction.\n"); | 
| @@ -135,16 +146,16 @@ void Debugger::Stop(Instruction* instr) { | 
| static void InitializeCoverage() {} | 
|  | 
|  | 
| -void Debugger::Stop(Instruction* instr) { | 
| +void MipsDebugger::Stop(Instruction* instr) { | 
| const char* str = reinterpret_cast<char*>(instr->InstructionBits()); | 
| PrintF("Simulator hit %s\n", str); | 
| -  sim_->set_pc(sim_->get_pc() + Instruction::kInstructionSize); | 
| +  sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize); | 
| Debug(); | 
| } | 
| #endif  // GENERATED_CODE_COVERAGE | 
|  | 
|  | 
| -int32_t Debugger::GetRegisterValue(int regnum) { | 
| +int32_t MipsDebugger::GetRegisterValue(int regnum) { | 
| if (regnum == kNumSimuRegisters) { | 
| return sim_->get_pc(); | 
| } else { | 
| @@ -153,11 +164,54 @@ int32_t Debugger::GetRegisterValue(int regnum) { | 
| } | 
|  | 
|  | 
| -bool Debugger::GetValue(const char* desc, int32_t* value) { | 
| +int32_t MipsDebugger::GetFPURegisterValueInt(int regnum) { | 
| +  if (regnum == kNumFPURegisters) { | 
| +    return sim_->get_pc(); | 
| +  } else { | 
| +    return sim_->get_fpu_register(regnum); | 
| +  } | 
| +} | 
| + | 
| + | 
| +int64_t MipsDebugger::GetFPURegisterValueLong(int regnum) { | 
| +  if (regnum == kNumFPURegisters) { | 
| +    return sim_->get_pc(); | 
| +  } else { | 
| +    return sim_->get_fpu_register_long(regnum); | 
| +  } | 
| +} | 
| + | 
| + | 
| +float MipsDebugger::GetFPURegisterValueFloat(int regnum) { | 
| +  if (regnum == kNumFPURegisters) { | 
| +    return sim_->get_pc(); | 
| +  } else { | 
| +    return sim_->get_fpu_register_float(regnum); | 
| +  } | 
| +} | 
| + | 
| + | 
| +double MipsDebugger::GetFPURegisterValueDouble(int regnum) { | 
| +  if (regnum == kNumFPURegisters) { | 
| +    return sim_->get_pc(); | 
| +  } else { | 
| +    return sim_->get_fpu_register_double(regnum); | 
| +  } | 
| +} | 
| + | 
| + | 
| +bool MipsDebugger::GetValue(const char* desc, int32_t* value) { | 
| int regnum = Registers::Number(desc); | 
| +  int fpuregnum = FPURegisters::Number(desc); | 
| + | 
| if (regnum != kInvalidRegister) { | 
| *value = GetRegisterValue(regnum); | 
| return true; | 
| +  } else if (fpuregnum != kInvalidFPURegister) { | 
| +    *value = GetFPURegisterValueInt(fpuregnum); | 
| +    return true; | 
| +  } else if (strncmp(desc, "0x", 2) == 0) { | 
| +    return SScanF(desc, "%x", reinterpret_cast<uint32_t*>(value)) == 1; | 
| } else { | 
| return SScanF(desc, "%i", value) == 1; | 
| } | 
| @@ -165,7 +219,7 @@ bool Debugger::GetValue(const char* desc, int32_t* value) { | 
| } | 
|  | 
|  | 
| -bool Debugger::SetBreakpoint(Instruction* breakpc) { | 
| +bool MipsDebugger::SetBreakpoint(Instruction* breakpc) { | 
| // Check if a breakpoint can be set. If not return without any side-effects. | 
| if (sim_->break_pc_ != NULL) { | 
| return false; | 
| @@ -180,7 +234,7 @@ bool Debugger::SetBreakpoint(Instruction* breakpc) { | 
| } | 
|  | 
|  | 
| -bool Debugger::DeleteBreakpoint(Instruction* breakpc) { | 
| +bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) { | 
| if (sim_->break_pc_ != NULL) { | 
| sim_->break_pc_->SetInstructionBits(sim_->break_instr_); | 
| } | 
| @@ -191,20 +245,21 @@ bool Debugger::DeleteBreakpoint(Instruction* breakpc) { | 
| } | 
|  | 
|  | 
| -void Debugger::UndoBreakpoints() { | 
| +void MipsDebugger::UndoBreakpoints() { | 
| if (sim_->break_pc_ != NULL) { | 
| sim_->break_pc_->SetInstructionBits(sim_->break_instr_); | 
| } | 
| } | 
|  | 
|  | 
| -void Debugger::RedoBreakpoints() { | 
| +void MipsDebugger::RedoBreakpoints() { | 
| if (sim_->break_pc_ != NULL) { | 
| sim_->break_pc_->SetInstructionBits(kBreakpointInstr); | 
| } | 
| } | 
|  | 
| -void Debugger::PrintAllRegs() { | 
| + | 
| +void MipsDebugger::PrintAllRegs() { | 
| #define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n) | 
|  | 
| PrintF("\n"); | 
| @@ -237,10 +292,45 @@ void Debugger::PrintAllRegs() { | 
| // pc | 
| PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", | 
| REG_INFO(31), REG_INFO(34)); | 
| + | 
| +#undef REG_INFO | 
| +#undef FPU_REG_INFO | 
| +} | 
| + | 
| + | 
| +void MipsDebugger::PrintAllRegsIncludingFPU() { | 
| +#define FPU_REG_INFO(n) FPURegisters::Name(n), FPURegisters::Name(n+1), \ | 
| +        GetFPURegisterValueInt(n+1), \ | 
| +        GetFPURegisterValueInt(n), \ | 
| +                        GetFPURegisterValueDouble(n) | 
| + | 
| +  PrintAllRegs(); | 
| + | 
| +  PrintF("\n\n"); | 
| +  // f0, f1, f2, ... f31 | 
| +  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(0) ); | 
| +  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(2) ); | 
| +  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(4) ); | 
| +  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(6) ); | 
| +  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(8) ); | 
| +  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(10)); | 
| +  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(12)); | 
| +  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(14)); | 
| +  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(16)); | 
| +  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(18)); | 
| +  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(20)); | 
| +  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(22)); | 
| +  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(24)); | 
| +  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(26)); | 
| +  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(28)); | 
| +  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(30)); | 
| + | 
| #undef REG_INFO | 
| +#undef FPU_REG_INFO | 
| } | 
|  | 
| -void Debugger::Debug() { | 
| + | 
| +void MipsDebugger::Debug() { | 
| intptr_t last_pc = -1; | 
| bool done = false; | 
|  | 
| @@ -253,6 +343,7 @@ void Debugger::Debug() { | 
| char cmd[COMMAND_SIZE + 1]; | 
| char arg1[ARG_SIZE + 1]; | 
| char arg2[ARG_SIZE + 1]; | 
| +  char* argv[3] = { cmd, arg1, arg2 }; | 
|  | 
| // make sure to have a proper terminating character if reaching the limit | 
| cmd[COMMAND_SIZE] = 0; | 
| @@ -280,19 +371,21 @@ void Debugger::Debug() { | 
| } else { | 
| // Use sscanf to parse the individual parts of the command line. At the | 
| // moment no command expects more than two parameters. | 
| -      int args = SScanF(line, | 
| +      int argc = SScanF(line, | 
| "%" XSTR(COMMAND_SIZE) "s " | 
| "%" XSTR(ARG_SIZE) "s " | 
| "%" XSTR(ARG_SIZE) "s", | 
| cmd, arg1, arg2); | 
| if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { | 
| -        if (!(reinterpret_cast<Instruction*>(sim_->get_pc())->IsTrap())) { | 
| +        Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc()); | 
| +        if (!(instr->IsTrap()) || | 
| +            instr->InstructionBits() == rtCallRedirInstr) { | 
| sim_->InstructionDecode( | 
| -                                reinterpret_cast<Instruction*>(sim_->get_pc())); | 
| +              reinterpret_cast<Instruction*>(sim_->get_pc())); | 
| } else { | 
| // Allow si to jump over generated breakpoints. | 
| PrintF("/!\\ Jumping over generated breakpoint.\n"); | 
| -          sim_->set_pc(sim_->get_pc() + Instruction::kInstructionSize); | 
| +          sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize); | 
| } | 
| } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { | 
| // Execute the one instruction we broke at with breakpoints disabled. | 
| @@ -300,23 +393,65 @@ void Debugger::Debug() { | 
| // Leave the debugger shell. | 
| done = true; | 
| } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { | 
| -        if (args == 2) { | 
| +        if (argc == 2) { | 
| int32_t value; | 
| +          float fvalue; | 
| if (strcmp(arg1, "all") == 0) { | 
| PrintAllRegs(); | 
| +          } else if (strcmp(arg1, "allf") == 0) { | 
| +            PrintAllRegsIncludingFPU(); | 
| } else { | 
| -            if (GetValue(arg1, &value)) { | 
| +            int regnum = Registers::Number(arg1); | 
| +            int fpuregnum = FPURegisters::Number(arg1); | 
| + | 
| +            if (regnum != kInvalidRegister) { | 
| +              value = GetRegisterValue(regnum); | 
| PrintF("%s: 0x%08x %d \n", arg1, value, value); | 
| +            } else if (fpuregnum != kInvalidFPURegister) { | 
| +              if (fpuregnum % 2 == 1) { | 
| +                value = GetFPURegisterValueInt(fpuregnum); | 
| +                fvalue = GetFPURegisterValueFloat(fpuregnum); | 
| +                PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue); | 
| +              } else { | 
| +                double dfvalue; | 
| +                int32_t lvalue1 = GetFPURegisterValueInt(fpuregnum); | 
| +                int32_t lvalue2 = GetFPURegisterValueInt(fpuregnum + 1); | 
| +                dfvalue = GetFPURegisterValueDouble(fpuregnum); | 
| +                PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", | 
| +                       FPURegisters::Name(fpuregnum+1), | 
| +                       FPURegisters::Name(fpuregnum), | 
| +                       lvalue1, | 
| +                       lvalue2, | 
| +                       dfvalue); | 
| +              } | 
| } else { | 
| PrintF("%s unrecognized\n", arg1); | 
| } | 
| } | 
| } else { | 
| -          PrintF("print <register>\n"); | 
| +          if (argc == 3) { | 
| +            if (strcmp(arg2, "single") == 0) { | 
| +              int32_t value; | 
| +              float fvalue; | 
| +              int fpuregnum = FPURegisters::Number(arg1); | 
| + | 
| +              if (fpuregnum != kInvalidFPURegister) { | 
| +                value = GetFPURegisterValueInt(fpuregnum); | 
| +                fvalue = GetFPURegisterValueFloat(fpuregnum); | 
| +                PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue); | 
| +              } else { | 
| +                PrintF("%s unrecognized\n", arg1); | 
| +              } | 
| +            } else { | 
| +              PrintF("print <fpu register> single\n"); | 
| +            } | 
| +          } else { | 
| +            PrintF("print <register> or print <fpu register> single\n"); | 
| +          } | 
| } | 
| } else if ((strcmp(cmd, "po") == 0) | 
| || (strcmp(cmd, "printobject") == 0)) { | 
| -        if (args == 2) { | 
| +        if (argc == 2) { | 
| int32_t value; | 
| if (GetValue(arg1, &value)) { | 
| Object* obj = reinterpret_cast<Object*>(value); | 
| @@ -333,6 +468,39 @@ void Debugger::Debug() { | 
| } else { | 
| PrintF("printobject <value>\n"); | 
| } | 
| +      } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) { | 
| +        int32_t* cur = NULL; | 
| +        int32_t* end = NULL; | 
| +        int next_arg = 1; | 
| + | 
| +        if (strcmp(cmd, "stack") == 0) { | 
| +          cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp)); | 
| +        } else {  // "mem" | 
| +          int32_t value; | 
| +          if (!GetValue(arg1, &value)) { | 
| +            PrintF("%s unrecognized\n", arg1); | 
| +            continue; | 
| +          } | 
| +          cur = reinterpret_cast<int32_t*>(value); | 
| +          next_arg++; | 
| +        } | 
| + | 
| +        int32_t words; | 
| +        if (argc == next_arg) { | 
| +          words = 10; | 
| +        } else if (argc == next_arg + 1) { | 
| +          if (!GetValue(argv[next_arg], &words)) { | 
| +            words = 10; | 
| +          } | 
| +        } | 
| +        end = cur + words; | 
| + | 
| +        while (cur < end) { | 
| +          PrintF("  0x%08x:  0x%08x %10d\n", | 
| +                 reinterpret_cast<intptr_t>(cur), *cur, *cur); | 
| +          cur++; | 
| +        } | 
| + | 
| } else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0)) { | 
| disasm::NameConverter converter; | 
| disasm::Disassembler dasm(converter); | 
| @@ -342,36 +510,37 @@ void Debugger::Debug() { | 
| byte_* cur = NULL; | 
| byte_* end = NULL; | 
|  | 
| -        if (args == 1) { | 
| +        if (argc == 1) { | 
| cur = reinterpret_cast<byte_*>(sim_->get_pc()); | 
| -          end = cur + (10 * Instruction::kInstructionSize); | 
| -        } else if (args == 2) { | 
| +          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::kInstructionSize); | 
| +            end = cur + (10 * Instruction::kInstrSize); | 
| } | 
| } else { | 
| int32_t value1; | 
| int32_t value2; | 
| if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { | 
| cur = reinterpret_cast<byte_*>(value1); | 
| -            end = cur + (value2 * Instruction::kInstructionSize); | 
| +            end = cur + (value2 * Instruction::kInstrSize); | 
| } | 
| } | 
|  | 
| while (cur < end) { | 
| dasm.InstructionDecode(buffer, cur); | 
| -          PrintF("  0x%08x  %s\n", cur, buffer.start()); | 
| -          cur += Instruction::kInstructionSize; | 
| +          PrintF("  0x%08x  %s\n", | 
| +              reinterpret_cast<intptr_t>(cur), buffer.start()); | 
| +          cur += Instruction::kInstrSize; | 
| } | 
| } else if (strcmp(cmd, "gdb") == 0) { | 
| PrintF("relinquishing control to gdb\n"); | 
| v8::internal::OS::DebugBreak(); | 
| PrintF("regaining control from gdb\n"); | 
| } else if (strcmp(cmd, "break") == 0) { | 
| -        if (args == 2) { | 
| +        if (argc == 2) { | 
| int32_t value; | 
| if (GetValue(arg1, &value)) { | 
| if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) { | 
| @@ -404,29 +573,30 @@ void Debugger::Debug() { | 
| byte_* cur = NULL; | 
| byte_* end = NULL; | 
|  | 
| -        if (args == 1) { | 
| +        if (argc == 1) { | 
| cur = reinterpret_cast<byte_*>(sim_->get_pc()); | 
| -          end = cur + (10 * Instruction::kInstructionSize); | 
| -        } else if (args == 2) { | 
| +          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::kInstructionSize); | 
| +            end = cur + (10 * Instruction::kInstrSize); | 
| } | 
| } else { | 
| int32_t value1; | 
| int32_t value2; | 
| if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { | 
| cur = reinterpret_cast<byte_*>(value1); | 
| -            end = cur + (value2 * Instruction::kInstructionSize); | 
| +            end = cur + (value2 * Instruction::kInstrSize); | 
| } | 
| } | 
|  | 
| while (cur < end) { | 
| dasm.InstructionDecode(buffer, cur); | 
| -          PrintF("  0x%08x  %s\n", cur, buffer.start()); | 
| -          cur += Instruction::kInstructionSize; | 
| +          PrintF("  0x%08x  %s\n", | 
| +                 reinterpret_cast<intptr_t>(cur), buffer.start()); | 
| +          cur += Instruction::kInstrSize; | 
| } | 
| } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { | 
| PrintF("cont\n"); | 
| @@ -438,6 +608,10 @@ void Debugger::Debug() { | 
| PrintF("  use register name 'all' to print all registers\n"); | 
| PrintF("printobject <register>\n"); | 
| PrintF("  print an object from a register (alias 'po')\n"); | 
| +        PrintF("stack [<words>]\n"); | 
| +        PrintF("  dump stack content, default dump 10 words)\n"); | 
| +        PrintF("mem <address> [<words>]\n"); | 
| +        PrintF("  dump memory content, default dump 10 words)\n"); | 
| PrintF("flags\n"); | 
| PrintF("  print flags\n"); | 
| PrintF("disasm [<instructions>]\n"); | 
| @@ -471,29 +645,120 @@ void Debugger::Debug() { | 
| } | 
|  | 
|  | 
| -// Create one simulator per thread and keep it in thread local storage. | 
| -static v8::internal::Thread::LocalStorageKey simulator_key; | 
| +static bool ICacheMatch(void* one, void* two) { | 
| +  ASSERT((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0); | 
| +  ASSERT((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0); | 
| +  return one == two; | 
| +} | 
| + | 
|  | 
| +static uint32_t ICacheHash(void* key) { | 
| +  return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2; | 
| +} | 
|  | 
| -bool Simulator::initialized_ = false; | 
| + | 
| +static bool AllOnOnePage(uintptr_t start, int size) { | 
| +  intptr_t start_page = (start & ~CachePage::kPageMask); | 
| +  intptr_t end_page = ((start + size) & ~CachePage::kPageMask); | 
| +  return start_page == end_page; | 
| +} | 
| + | 
| + | 
| +void Simulator::FlushICache(v8::internal::HashMap* i_cache, | 
| +                            void* start_addr, | 
| +                            size_t size) { | 
| +  intptr_t start = reinterpret_cast<intptr_t>(start_addr); | 
| +  int intra_line = (start & CachePage::kLineMask); | 
| +  start -= intra_line; | 
| +  size += intra_line; | 
| +  size = ((size - 1) | CachePage::kLineMask) + 1; | 
| +  int offset = (start & CachePage::kPageMask); | 
| +  while (!AllOnOnePage(start, size - 1)) { | 
| +    int bytes_to_flush = CachePage::kPageSize - offset; | 
| +    FlushOnePage(i_cache, start, bytes_to_flush); | 
| +    start += bytes_to_flush; | 
| +    size -= bytes_to_flush; | 
| +    ASSERT_EQ(0, start & CachePage::kPageMask); | 
| +    offset = 0; | 
| +  } | 
| +  if (size != 0) { | 
| +    FlushOnePage(i_cache, start, size); | 
| +  } | 
| +} | 
| + | 
| + | 
| +CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) { | 
| +  v8::internal::HashMap::Entry* entry = i_cache->Lookup(page, | 
| +                                                         ICacheHash(page), | 
| +                                                         true); | 
| +  if (entry->value == NULL) { | 
| +    CachePage* new_page = new CachePage(); | 
| +    entry->value = new_page; | 
| +  } | 
| +  return reinterpret_cast<CachePage*>(entry->value); | 
| +} | 
| + | 
| + | 
| +// Flush from start up to and not including start + size. | 
| +void Simulator::FlushOnePage(v8::internal::HashMap* i_cache, | 
| +                             intptr_t start, | 
| +                             int size) { | 
| +  ASSERT(size <= CachePage::kPageSize); | 
| +  ASSERT(AllOnOnePage(start, size - 1)); | 
| +  ASSERT((start & CachePage::kLineMask) == 0); | 
| +  ASSERT((size & CachePage::kLineMask) == 0); | 
| +  void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask)); | 
| +  int offset = (start & CachePage::kPageMask); | 
| +  CachePage* cache_page = GetCachePage(i_cache, page); | 
| +  char* valid_bytemap = cache_page->ValidityByte(offset); | 
| +  memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift); | 
| +} | 
| + | 
| + | 
| +void Simulator::CheckICache(v8::internal::HashMap* i_cache, | 
| +                            Instruction* instr) { | 
| +  intptr_t address = reinterpret_cast<intptr_t>(instr); | 
| +  void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask)); | 
| +  void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask)); | 
| +  int offset = (address & CachePage::kPageMask); | 
| +  CachePage* cache_page = GetCachePage(i_cache, page); | 
| +  char* cache_valid_byte = cache_page->ValidityByte(offset); | 
| +  bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID); | 
| +  char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask); | 
| +  if (cache_hit) { | 
| +    // Check that the data in memory matches the contents of the I-cache. | 
| +    CHECK(memcmp(reinterpret_cast<void*>(instr), | 
| +                 cache_page->CachedData(offset), | 
| +                 Instruction::kInstrSize) == 0); | 
| +  } else { | 
| +    // Cache miss.  Load memory into the cache. | 
| +    memcpy(cached_line, line, CachePage::kLineLength); | 
| +    *cache_valid_byte = CachePage::LINE_VALID; | 
| +  } | 
| +} | 
|  | 
|  | 
| void Simulator::Initialize() { | 
| -  if (initialized_) return; | 
| -  simulator_key = v8::internal::Thread::CreateThreadLocalKey(); | 
| -  initialized_ = true; | 
| +  if (Isolate::Current()->simulator_initialized()) return; | 
| +  Isolate::Current()->set_simulator_initialized(true); | 
| ::v8::internal::ExternalReference::set_redirector(&RedirectExternalReference); | 
| } | 
|  | 
|  | 
| -Simulator::Simulator() { | 
| +Simulator::Simulator() : isolate_(Isolate::Current()) { | 
| +  i_cache_ = isolate_->simulator_i_cache(); | 
| +  if (i_cache_ == NULL) { | 
| +    i_cache_ = new v8::internal::HashMap(&ICacheMatch); | 
| +    isolate_->set_simulator_i_cache(i_cache_); | 
| +  } | 
| Initialize(); | 
| // Setup simulator support first. Some of this information is needed to | 
| // setup the architecture state. | 
| -  size_t stack_size = 1 * 1024*1024;  // allocate 1MB for stack | 
| -  stack_ = reinterpret_cast<char*>(malloc(stack_size)); | 
| +  stack_size_ = 1 * 1024*1024;  // allocate 1MB for stack | 
| +  stack_ = reinterpret_cast<char*>(malloc(stack_size_)); | 
| pc_modified_ = false; | 
| icount_ = 0; | 
| +  break_count_ = 0; | 
| break_pc_ = NULL; | 
| break_instr_ = 0; | 
|  | 
| @@ -502,16 +767,23 @@ Simulator::Simulator() { | 
| for (int i = 0; i < kNumSimuRegisters; i++) { | 
| registers_[i] = 0; | 
| } | 
| +  for (int i = 0; i < kNumFPURegisters; i++) { | 
| +    FPUregisters_[i] = 0; | 
| +  } | 
| +  FCSR_ = 0; | 
|  | 
| // The sp is initialized to point to the bottom (high address) of the | 
| // allocated stack area. To be safe in potential stack underflows we leave | 
| // some buffer below. | 
| -  registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64; | 
| +  registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64; | 
| // The ra and pc are initialized to a known bad value that will cause an | 
| // access violation if the simulator ever tries to execute it. | 
| registers_[pc] = bad_ra; | 
| registers_[ra] = bad_ra; | 
| InitializeCoverage(); | 
| +  for (int i = 0; i < kNumExceptions; i++) { | 
| +    exceptions[i] = 0; | 
| +  } | 
| } | 
|  | 
|  | 
| @@ -524,12 +796,18 @@ Simulator::Simulator() { | 
| // offset from the swi instruction so the simulator knows what to call. | 
| class Redirection { | 
| public: | 
| -  Redirection(void* external_function, bool fp_return) | 
| +  Redirection(void* external_function, ExternalReference::Type type) | 
| : external_function_(external_function), | 
| swi_instruction_(rtCallRedirInstr), | 
| -        fp_return_(fp_return), | 
| -        next_(list_) { | 
| -    list_ = this; | 
| +        type_(type), | 
| +        next_(NULL) { | 
| +    Isolate* isolate = Isolate::Current(); | 
| +    next_ = isolate->simulator_redirection(); | 
| +    Simulator::current(isolate)-> | 
| +        FlushICache(isolate->simulator_i_cache(), | 
| +                    reinterpret_cast<void*>(&swi_instruction_), | 
| +                    Instruction::kInstrSize); | 
| +    isolate->set_simulator_redirection(this); | 
| } | 
|  | 
| void* address_of_swi_instruction() { | 
| @@ -537,14 +815,16 @@ class Redirection { | 
| } | 
|  | 
| void* external_function() { return external_function_; } | 
| -  bool fp_return() { return fp_return_; } | 
| +  ExternalReference::Type type() { return type_; } | 
|  | 
| -  static Redirection* Get(void* external_function, bool fp_return) { | 
| -    Redirection* current; | 
| -    for (current = list_; current != NULL; current = current->next_) { | 
| +  static Redirection* Get(void* external_function, | 
| +                          ExternalReference::Type type) { | 
| +    Isolate* isolate = Isolate::Current(); | 
| +    Redirection* current = isolate->simulator_redirection(); | 
| +    for (; current != NULL; current = current->next_) { | 
| if (current->external_function_ == external_function) return current; | 
| } | 
| -    return new Redirection(external_function, fp_return); | 
| +    return new Redirection(external_function, type); | 
| } | 
|  | 
| static Redirection* FromSwiInstruction(Instruction* swi_instruction) { | 
| @@ -557,31 +837,33 @@ class Redirection { | 
| private: | 
| void* external_function_; | 
| uint32_t swi_instruction_; | 
| -  bool fp_return_; | 
| +  ExternalReference::Type type_; | 
| Redirection* next_; | 
| -  static Redirection* list_; | 
| }; | 
|  | 
|  | 
| -Redirection* Redirection::list_ = NULL; | 
| - | 
| - | 
| void* Simulator::RedirectExternalReference(void* external_function, | 
| -                                           bool fp_return) { | 
| -  Redirection* redirection = Redirection::Get(external_function, fp_return); | 
| +                                           ExternalReference::Type type) { | 
| +  Redirection* redirection = Redirection::Get(external_function, type); | 
| return redirection->address_of_swi_instruction(); | 
| } | 
|  | 
|  | 
| // Get the active Simulator for the current thread. | 
| -Simulator* Simulator::current() { | 
| -  Initialize(); | 
| -  Simulator* sim = reinterpret_cast<Simulator*>( | 
| -      v8::internal::Thread::GetThreadLocal(simulator_key)); | 
| +Simulator* Simulator::current(Isolate* isolate) { | 
| +  v8::internal::Isolate::PerIsolateThreadData* isolate_data = | 
| +      Isolate::CurrentPerIsolateThreadData(); | 
| +  if (isolate_data == NULL) { | 
| +    Isolate::EnterDefaultIsolate(); | 
| +    isolate_data = Isolate::CurrentPerIsolateThreadData(); | 
| +  } | 
| +  ASSERT(isolate_data != NULL); | 
| + | 
| +  Simulator* sim = isolate_data->simulator(); | 
| if (sim == NULL) { | 
| -    // TODO(146): delete the simulator object when a thread goes away. | 
| +    // TODO(146): delete the simulator object when a thread/isolate goes away. | 
| sim = new Simulator(); | 
| -    v8::internal::Thread::SetThreadLocal(simulator_key, sim); | 
| +    isolate_data->set_simulator(sim); | 
| } | 
| return sim; | 
| } | 
| @@ -599,14 +881,22 @@ void Simulator::set_register(int reg, int32_t value) { | 
| registers_[reg] = (reg == 0) ? 0 : value; | 
| } | 
|  | 
| + | 
| void Simulator::set_fpu_register(int fpureg, int32_t value) { | 
| ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); | 
| FPUregisters_[fpureg] = value; | 
| } | 
|  | 
| + | 
| +void Simulator::set_fpu_register_float(int fpureg, float value) { | 
| +  ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); | 
| +  *BitCast<float*>(&FPUregisters_[fpureg]) = value; | 
| +} | 
| + | 
| + | 
| void Simulator::set_fpu_register_double(int fpureg, double value) { | 
| ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0)); | 
| -  *v8i::BitCast<double*>(&FPUregisters_[fpureg]) = value; | 
| +  *BitCast<double*>(&FPUregisters_[fpureg]) = value; | 
| } | 
|  | 
|  | 
| @@ -620,22 +910,75 @@ int32_t Simulator::get_register(int reg) const { | 
| return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0); | 
| } | 
|  | 
| + | 
| int32_t Simulator::get_fpu_register(int fpureg) const { | 
| ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); | 
| return FPUregisters_[fpureg]; | 
| } | 
|  | 
| + | 
| +int64_t Simulator::get_fpu_register_long(int fpureg) const { | 
| +  ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0)); | 
| +  return *BitCast<int64_t*>( | 
| +      const_cast<int32_t*>(&FPUregisters_[fpureg])); | 
| +} | 
| + | 
| + | 
| +float Simulator::get_fpu_register_float(int fpureg) const { | 
| +  ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); | 
| +  return *BitCast<float*>( | 
| +      const_cast<int32_t*>(&FPUregisters_[fpureg])); | 
| +} | 
| + | 
| + | 
| double Simulator::get_fpu_register_double(int fpureg) const { | 
| ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0)); | 
| -  return *v8i::BitCast<double*>(const_cast<int32_t*>(&FPUregisters_[fpureg])); | 
| +  return *BitCast<double*>(const_cast<int32_t*>(&FPUregisters_[fpureg])); | 
| +} | 
| + | 
| + | 
| +// Helper functions for setting and testing the FCSR register's bits. | 
| +void Simulator::set_fcsr_bit(uint32_t cc, bool value) { | 
| +  if (value) { | 
| +    FCSR_ |= (1 << cc); | 
| +  } else { | 
| +    FCSR_ &= ~(1 << cc); | 
| +  } | 
| +} | 
| + | 
| + | 
| +bool Simulator::test_fcsr_bit(uint32_t cc) { | 
| +  return FCSR_ & (1 << cc); | 
| } | 
|  | 
| + | 
| +// Sets the rounding error codes in FCSR based on the result of the rounding. | 
| +// Returns true if the operation was invalid. | 
| +bool Simulator::set_fcsr_round_error(double original, double rounded) { | 
| +  if (!isfinite(original) || | 
| +      rounded > LONG_MAX || | 
| +      rounded < LONG_MIN) { | 
| +    set_fcsr_bit(6, true);  // Invalid operation. | 
| +    return true; | 
| +  } else if (original != static_cast<double>(rounded)) { | 
| +    set_fcsr_bit(2, true);  // Inexact. | 
| +  } | 
| +  return false; | 
| +} | 
| + | 
| + | 
| // Raw access to the PC register. | 
| void Simulator::set_pc(int32_t value) { | 
| pc_modified_ = true; | 
| registers_[pc] = value; | 
| } | 
|  | 
| + | 
| +bool Simulator::has_bad_pc() const { | 
| +  return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc)); | 
| +} | 
| + | 
| + | 
| // Raw access to the PC register without the special adjustment when reading. | 
| int32_t Simulator::get_pc() const { | 
| return registers_[pc]; | 
| @@ -651,24 +994,38 @@ int32_t Simulator::get_pc() const { | 
| // get the correct MIPS-like behaviour on unaligned accesses. | 
|  | 
| int Simulator::ReadW(int32_t addr, Instruction* instr) { | 
| -  if ((addr & v8i::kPointerAlignmentMask) == 0) { | 
| +  if (addr >=0 && addr < 0x400) { | 
| +    // this has to be a NULL-dereference | 
| +    MipsDebugger dbg(this); | 
| +    dbg.Debug(); | 
| +  } | 
| +  if ((addr & kPointerAlignmentMask) == 0) { | 
| intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); | 
| return *ptr; | 
| } | 
| -  PrintF("Unaligned read at 0x%08x, pc=%p\n", addr, instr); | 
| -  OS::Abort(); | 
| +  PrintF("Unaligned read at 0x%08x, pc=%p\n", addr, | 
| +      reinterpret_cast<void*>(instr)); | 
| +  MipsDebugger dbg(this); | 
| +  dbg.Debug(); | 
| return 0; | 
| } | 
|  | 
|  | 
| void Simulator::WriteW(int32_t addr, int value, Instruction* instr) { | 
| -  if ((addr & v8i::kPointerAlignmentMask) == 0) { | 
| +  if (addr >= 0 && addr < 0x400) { | 
| +    // this has to be a NULL-dereference | 
| +    MipsDebugger dbg(this); | 
| +    dbg.Debug(); | 
| +  } | 
| +  if ((addr & kPointerAlignmentMask) == 0) { | 
| intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); | 
| *ptr = value; | 
| return; | 
| } | 
| -  PrintF("Unaligned write at 0x%08x, pc=%p\n", addr, instr); | 
| -  OS::Abort(); | 
| +  PrintF("Unaligned write at 0x%08x, pc=%p\n", addr, | 
| +      reinterpret_cast<void*>(instr)); | 
| +  MipsDebugger dbg(this); | 
| +  dbg.Debug(); | 
| } | 
|  | 
|  | 
| @@ -677,7 +1034,8 @@ double Simulator::ReadD(int32_t addr, Instruction* instr) { | 
| double* ptr = reinterpret_cast<double*>(addr); | 
| return *ptr; | 
| } | 
| -  PrintF("Unaligned read at 0x%08x, pc=%p\n", addr, instr); | 
| +  PrintF("Unaligned (double) read at 0x%08x, pc=%p\n", addr, | 
| +      reinterpret_cast<void*>(instr)); | 
| OS::Abort(); | 
| return 0; | 
| } | 
| @@ -689,7 +1047,8 @@ void Simulator::WriteD(int32_t addr, double value, Instruction* instr) { | 
| *ptr = value; | 
| return; | 
| } | 
| -  PrintF("Unaligned write at 0x%08x, pc=%p\n", addr, instr); | 
| +  PrintF("Unaligned (double) write at 0x%08x, pc=%p\n", addr, | 
| +      reinterpret_cast<void*>(instr)); | 
| OS::Abort(); | 
| } | 
|  | 
| @@ -699,7 +1058,8 @@ uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) { | 
| uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); | 
| return *ptr; | 
| } | 
| -  PrintF("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr); | 
| +  PrintF("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, | 
| +      reinterpret_cast<void*>(instr)); | 
| OS::Abort(); | 
| return 0; | 
| } | 
| @@ -710,7 +1070,8 @@ int16_t Simulator::ReadH(int32_t addr, Instruction* instr) { | 
| int16_t* ptr = reinterpret_cast<int16_t*>(addr); | 
| return *ptr; | 
| } | 
| -  PrintF("Unaligned signed halfword read at 0x%08x, pc=%p\n", addr, instr); | 
| +  PrintF("Unaligned signed halfword read at 0x%08x, pc=%p\n", addr, | 
| +      reinterpret_cast<void*>(instr)); | 
| OS::Abort(); | 
| return 0; | 
| } | 
| @@ -722,7 +1083,8 @@ void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) { | 
| *ptr = value; | 
| return; | 
| } | 
| -  PrintF("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr); | 
| +  PrintF("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, | 
| +      reinterpret_cast<void*>(instr)); | 
| OS::Abort(); | 
| } | 
|  | 
| @@ -733,7 +1095,8 @@ void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) { | 
| *ptr = value; | 
| return; | 
| } | 
| -  PrintF("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr); | 
| +  PrintF("Unaligned halfword write at 0x%08x, pc=%p\n", addr, | 
| +      reinterpret_cast<void*>(instr)); | 
| OS::Abort(); | 
| } | 
|  | 
| @@ -746,7 +1109,7 @@ uint32_t Simulator::ReadBU(int32_t addr) { | 
|  | 
| int32_t Simulator::ReadB(int32_t addr) { | 
| int8_t* ptr = reinterpret_cast<int8_t*>(addr); | 
| -  return ((*ptr << 24) >> 24) & 0xff; | 
| +  return *ptr; | 
| } | 
|  | 
|  | 
| @@ -773,7 +1136,7 @@ uintptr_t Simulator::StackLimit() const { | 
| // Unsupported instructions use Format to print an error and stop execution. | 
| void Simulator::Format(Instruction* instr, const char* format) { | 
| PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n", | 
| -         instr, format); | 
| +         reinterpret_cast<intptr_t>(instr), format); | 
| UNIMPLEMENTED_MIPS(); | 
| } | 
|  | 
| @@ -782,75 +1145,140 @@ void Simulator::Format(Instruction* instr, const char* format) { | 
| // Note: To be able to return two values from some calls the code in runtime.cc | 
| // uses the ObjectPair which is essentially two 32-bit values stuffed into a | 
| // 64-bit value. With the code below we assume that all runtime calls return | 
| -// 64 bits of result. If they don't, the r1 result register contains a bogus | 
| +// 64 bits of result. If they don't, the v1 result register contains a bogus | 
| // value, which is fine because it is caller-saved. | 
| typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0, | 
| int32_t arg1, | 
| int32_t arg2, | 
| -                                        int32_t arg3); | 
| -typedef double (*SimulatorRuntimeFPCall)(double fparg0, | 
| -                                         double fparg1); | 
| - | 
| +                                        int32_t arg3, | 
| +                                        int32_t arg4, | 
| +                                        int32_t arg5); | 
| +typedef double (*SimulatorRuntimeFPCall)(int32_t arg0, | 
| +                                         int32_t arg1, | 
| +                                         int32_t arg2, | 
| +                                         int32_t arg3); | 
|  | 
| // Software interrupt instructions are used by the simulator to call into the | 
| -// C-based V8 runtime. | 
| +// C-based V8 runtime. They are also used for debugging with simulator. | 
| void Simulator::SoftwareInterrupt(Instruction* instr) { | 
| +  // There are several instructions that could get us here, | 
| +  // the break_ instruction, or several variants of traps. All | 
| +  // Are "SPECIAL" class opcode, and are distinuished by function. | 
| +  int32_t func = instr->FunctionFieldRaw(); | 
| +  int32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1; | 
| + | 
| // We first check if we met a call_rt_redirected. | 
| if (instr->InstructionBits() == rtCallRedirInstr) { | 
| +    // Check if stack is aligned. Error if not aligned is reported below to | 
| +    // include information on the function called. | 
| +    bool stack_aligned = | 
| +        (get_register(sp) | 
| +         & (::v8::internal::FLAG_sim_stack_alignment - 1)) == 0; | 
| Redirection* redirection = Redirection::FromSwiInstruction(instr); | 
| int32_t arg0 = get_register(a0); | 
| int32_t arg1 = get_register(a1); | 
| int32_t arg2 = get_register(a2); | 
| int32_t arg3 = get_register(a3); | 
| -    // fp args are (not always) in f12 and f14. | 
| -    // See MIPS conventions for more details. | 
| -    double fparg0 = get_fpu_register_double(f12); | 
| -    double fparg1 = get_fpu_register_double(f14); | 
| +    int32_t arg4 = 0; | 
| +    int32_t arg5 = 0; | 
| + | 
| +    // Need to check if sp is valid before assigning arg4, arg5. | 
| +    // This is a fix for cctest test-api/CatchStackOverflow which causes | 
| +    // the stack to overflow. For some reason arm doesn't need this | 
| +    // stack check here. | 
| +    int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp)); | 
| +    int32_t* stack = reinterpret_cast<int32_t*>(stack_); | 
| +    if (stack_pointer >= stack && stack_pointer < stack + stack_size_) { | 
| +      arg4 = stack_pointer[0]; | 
| +      arg5 = stack_pointer[1]; | 
| +    } | 
| // 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); | 
| -    if (redirection->fp_return()) { | 
| -      intptr_t external = | 
| -          reinterpret_cast<intptr_t>(redirection->external_function()); | 
| + | 
| +    intptr_t external = | 
| +        reinterpret_cast<int32_t>(redirection->external_function()); | 
| + | 
| +    // 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. | 
| +    if (redirection->type() == ExternalReference::FP_RETURN_CALL) { | 
| SimulatorRuntimeFPCall target = | 
| reinterpret_cast<SimulatorRuntimeFPCall>(external); | 
| -      if (::v8::internal::FLAG_trace_sim) { | 
| -        PrintF("Call to host function at %p with args %f, %f\n", | 
| -               FUNCTION_ADDR(target), fparg0, fparg1); | 
| +      if (::v8::internal::FLAG_trace_sim || !stack_aligned) { | 
| +        PrintF("Call to host function at %p with args %08x:%08x %08x:%08x", | 
| +               FUNCTION_ADDR(target), arg0, arg1, arg2, arg3); | 
| +        if (!stack_aligned) { | 
| +          PrintF(" with unaligned stack %08x\n", get_register(sp)); | 
| +        } | 
| +        PrintF("\n"); | 
| } | 
| -      double result = target(fparg0, fparg1); | 
| -      set_fpu_register_double(f0, result); | 
| +      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]); | 
| +    } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) { | 
| +      PrintF("Mips does not yet support ExternalReference::DIRECT_API_CALL\n"); | 
| +      ASSERT(redirection->type() != ExternalReference::DIRECT_API_CALL); | 
| +    } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) { | 
| +      PrintF("Mips does not support ExternalReference::DIRECT_GETTER_CALL\n"); | 
| +      ASSERT(redirection->type() != ExternalReference::DIRECT_GETTER_CALL); | 
| } else { | 
| -      intptr_t external = | 
| -          reinterpret_cast<int32_t>(redirection->external_function()); | 
| +      // Builtin call. | 
| +      ASSERT(redirection->type() == ExternalReference::BUILTIN_CALL); | 
| SimulatorRuntimeCall target = | 
| reinterpret_cast<SimulatorRuntimeCall>(external); | 
| -      if (::v8::internal::FLAG_trace_sim) { | 
| +      if (::v8::internal::FLAG_trace_sim || !stack_aligned) { | 
| PrintF( | 
| -            "Call to host function at %p with args %08x, %08x, %08x, %08x\n", | 
| +            "Call to host function at %p: %08x, %08x, %08x, %08x, %08x, %08x", | 
| FUNCTION_ADDR(target), | 
| arg0, | 
| arg1, | 
| arg2, | 
| -            arg3); | 
| -      } | 
| -      int64_t result = target(arg0, arg1, arg2, arg3); | 
| -      int32_t lo_res = static_cast<int32_t>(result); | 
| -      int32_t hi_res = static_cast<int32_t>(result >> 32); | 
| -      if (::v8::internal::FLAG_trace_sim) { | 
| -        PrintF("Returned %08x\n", lo_res); | 
| +            arg3, | 
| +            arg4, | 
| +            arg5); | 
| +        if (!stack_aligned) { | 
| +          PrintF(" with unaligned stack %08x\n", get_register(sp)); | 
| +        } | 
| +        PrintF("\n"); | 
| } | 
| -      set_register(v0, lo_res); | 
| -      set_register(v1, hi_res); | 
| + | 
| +      int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5); | 
| +      set_register(v0, static_cast<int32_t>(result)); | 
| +      set_register(v1, static_cast<int32_t>(result >> 32)); | 
| +    } | 
| +    if (::v8::internal::FLAG_trace_sim) { | 
| +      PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0)); | 
| } | 
| set_register(ra, saved_ra); | 
| set_pc(get_register(ra)); | 
| + | 
| +  } else if (func == BREAK && code >= 0 && code < 16) { | 
| +    // First 16 break_ codes interpreted as debug markers. | 
| +    MipsDebugger dbg(this); | 
| +    ++break_count_; | 
| +    PrintF("\n---- break %d marker: %3d  (instr count: %8d) ----------" | 
| +           "----------------------------------", | 
| +           code, break_count_, icount_); | 
| +    dbg.PrintAllRegs();  // Print registers and continue running. | 
| } else { | 
| -    Debugger dbg(this); | 
| +    // All remaining break_ codes, and all traps are handled here. | 
| +    MipsDebugger dbg(this); | 
| dbg.Debug(); | 
| } | 
| } | 
|  | 
| + | 
| void Simulator::SignalExceptions() { | 
| for (int i = 1; i < kNumExceptions; i++) { | 
| if (exceptions[i] != 0) { | 
| @@ -859,51 +1287,52 @@ void Simulator::SignalExceptions() { | 
| } | 
| } | 
|  | 
| -// Handle execution based on instruction types. | 
| -void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| -  // Instruction fields | 
| -  Opcode   op     = instr->OpcodeFieldRaw(); | 
| -  int32_t  rs_reg = instr->RsField(); | 
| -  int32_t  rs     = get_register(rs_reg); | 
| -  uint32_t rs_u   = static_cast<uint32_t>(rs); | 
| -  int32_t  rt_reg = instr->RtField(); | 
| -  int32_t  rt     = get_register(rt_reg); | 
| -  uint32_t rt_u   = static_cast<uint32_t>(rt); | 
| -  int32_t  rd_reg = instr->RdField(); | 
| -  uint32_t sa     = instr->SaField(); | 
| - | 
| -  int32_t fs_reg= instr->FsField(); | 
|  | 
| -  // ALU output | 
| -  // It should not be used as is. Instructions using it should always initialize | 
| -  // it first. | 
| -  int32_t alu_out = 0x12345678; | 
| -  // Output or temporary for floating point. | 
| -  double fp_out = 0.0; | 
| +// Handle execution based on instruction types. | 
|  | 
| -  // For break and trap instructions. | 
| -  bool do_interrupt = false; | 
| +void Simulator::ConfigureTypeRegister(Instruction* instr, | 
| +                                      int32_t& alu_out, | 
| +                                      int64_t& i64hilo, | 
| +                                      uint64_t& u64hilo, | 
| +                                      int32_t& next_pc, | 
| +                                      bool& do_interrupt) { | 
| +  // Every local variable declared here needs to be const. | 
| +  // This is to make sure that changed values are sent back to | 
| +  // DecodeTypeRegister correctly. | 
| + | 
| +  // Instruction fields. | 
| +  const Opcode   op     = instr->OpcodeFieldRaw(); | 
| +  const int32_t  rs_reg = instr->RsValue(); | 
| +  const int32_t  rs     = get_register(rs_reg); | 
| +  const uint32_t rs_u   = static_cast<uint32_t>(rs); | 
| +  const int32_t  rt_reg = instr->RtValue(); | 
| +  const int32_t  rt     = get_register(rt_reg); | 
| +  const uint32_t rt_u   = static_cast<uint32_t>(rt); | 
| +  const int32_t  rd_reg = instr->RdValue(); | 
| +  const uint32_t sa     = instr->SaValue(); | 
| + | 
| +  const int32_t  fs_reg = instr->FsValue(); | 
|  | 
| -  // For jr and jalr | 
| -  // Get current pc. | 
| -  int32_t current_pc = get_pc(); | 
| -  // Next pc | 
| -  int32_t next_pc = 0; | 
|  | 
| // ---------- Configuration | 
| switch (op) { | 
| case COP1:    // Coprocessor instructions | 
| switch (instr->RsFieldRaw()) { | 
| -        case BC1:   // branch on coprocessor condition | 
| +        case BC1:   // Handled in DecodeTypeImmed, should never come here. | 
| UNREACHABLE(); | 
| break; | 
| +        case CFC1: | 
| +          // At the moment only FCSR is supported. | 
| +          ASSERT(fs_reg == kFCSRRegister); | 
| +          alu_out = FCSR_; | 
| +          break; | 
| case MFC1: | 
| alu_out = get_fpu_register(fs_reg); | 
| break; | 
| case MFHC1: | 
| -          fp_out = get_fpu_register_double(fs_reg); | 
| -          alu_out = *v8i::BitCast<int32_t*>(&fp_out); | 
| +          UNIMPLEMENTED_MIPS(); | 
| break; | 
| +        case CTC1: | 
| case MTC1: | 
| case MTHC1: | 
| // Do the store in the execution step. | 
| @@ -923,13 +1352,22 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| switch (instr->FunctionFieldRaw()) { | 
| case JR: | 
| case JALR: | 
| -          next_pc = get_register(instr->RsField()); | 
| +          next_pc = get_register(instr->RsValue()); | 
| break; | 
| case SLL: | 
| alu_out = rt << sa; | 
| break; | 
| case SRL: | 
| -          alu_out = rt_u >> sa; | 
| +          if (rs_reg == 0) { | 
| +            // Regular logical right shift of a word by a fixed number of | 
| +            // bits instruction. RS field is always equal to 0. | 
| +            alu_out = rt_u >> sa; | 
| +          } else { | 
| +            // Logical right-rotate of a word by a fixed number of bits. This | 
| +            // is special case of SRL instruction, added in MIPS32 Release 2. | 
| +            // RS field is equal to 00001 | 
| +            alu_out = (rt_u >> sa) | (rt_u << (32 - sa)); | 
| +          } | 
| break; | 
| case SRA: | 
| alu_out = rt >> sa; | 
| @@ -938,7 +1376,16 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| alu_out = rt << rs; | 
| break; | 
| case SRLV: | 
| -          alu_out = rt_u >> rs; | 
| +          if (sa == 0) { | 
| +            // Regular logical right-shift of a word by a variable number of | 
| +            // bits instruction. SA field is always equal to 0. | 
| +            alu_out = rt_u >> rs; | 
| +          } else { | 
| +            // Logical right-rotate of a word by a variable number of bits. | 
| +            // This is special case od SRLV instruction, added in MIPS32 | 
| +            // Release 2. SA field is equal to 00001 | 
| +            alu_out = (rt_u >> rs_u) | (rt_u << (32 - rs_u)); | 
| +          } | 
| break; | 
| case SRAV: | 
| alu_out = rt >> rs; | 
| @@ -950,10 +1397,10 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| alu_out = get_register(LO); | 
| break; | 
| case MULT: | 
| -          UNIMPLEMENTED_MIPS(); | 
| +          i64hilo = static_cast<int64_t>(rs) * static_cast<int64_t>(rt); | 
| break; | 
| case MULTU: | 
| -          UNIMPLEMENTED_MIPS(); | 
| +          u64hilo = static_cast<uint64_t>(rs_u) * static_cast<uint64_t>(rt_u); | 
| break; | 
| case DIV: | 
| case DIVU: | 
| @@ -1005,6 +1452,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| break; | 
| // Break and trap instructions | 
| case BREAK: | 
| + | 
| do_interrupt = true; | 
| break; | 
| case TGE: | 
| @@ -1025,6 +1473,11 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| case TNE: | 
| do_interrupt = rs != rt; | 
| break; | 
| +        case MOVN: | 
| +        case MOVZ: | 
| +        case MOVCI: | 
| +          // No action taken on decode. | 
| +          break; | 
| default: | 
| UNREACHABLE(); | 
| }; | 
| @@ -1034,13 +1487,83 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| case MUL: | 
| alu_out = rs_u * rt_u;  // Only the lower 32 bits are kept. | 
| break; | 
| +        case CLZ: | 
| +          alu_out = __builtin_clz(rs_u); | 
| +          break; | 
| default: | 
| UNREACHABLE(); | 
| -      } | 
| +      }; | 
| +      break; | 
| +    case SPECIAL3: | 
| +      switch (instr->FunctionFieldRaw()) { | 
| +        case INS: {   // Mips32r2 instruction. | 
| +          // Interpret Rd field as 5-bit msb of insert. | 
| +          uint16_t msb = rd_reg; | 
| +          // Interpret sa field as 5-bit lsb of insert. | 
| +          uint16_t lsb = sa; | 
| +          uint16_t size = msb - lsb + 1; | 
| +          uint32_t mask = (1 << size) - 1; | 
| +          alu_out = (rt_u & ~(mask << lsb)) | ((rs_u & mask) << lsb); | 
| +          break; | 
| +        } | 
| +        case EXT: {   // Mips32r2 instruction. | 
| +          // Interpret Rd field as 5-bit msb of extract. | 
| +          uint16_t msb = rd_reg; | 
| +          // Interpret sa field as 5-bit lsb of extract. | 
| +          uint16_t lsb = sa; | 
| +          uint16_t size = msb + 1; | 
| +          uint32_t mask = (1 << size) - 1; | 
| +          alu_out = (rs_u & (mask << lsb)) >> lsb; | 
| +          break; | 
| +        } | 
| +        default: | 
| +          UNREACHABLE(); | 
| +      }; | 
| break; | 
| default: | 
| UNREACHABLE(); | 
| }; | 
| +} | 
| + | 
| + | 
| +void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| +  // Instruction fields. | 
| +  const Opcode   op     = instr->OpcodeFieldRaw(); | 
| +  const int32_t  rs_reg = instr->RsValue(); | 
| +  const int32_t  rs     = get_register(rs_reg); | 
| +  const uint32_t rs_u   = static_cast<uint32_t>(rs); | 
| +  const int32_t  rt_reg = instr->RtValue(); | 
| +  const int32_t  rt     = get_register(rt_reg); | 
| +  const uint32_t rt_u   = static_cast<uint32_t>(rt); | 
| +  const int32_t  rd_reg = instr->RdValue(); | 
| + | 
| +  const int32_t  fs_reg = instr->FsValue(); | 
| +  const int32_t  ft_reg = instr->FtValue(); | 
| +  const int32_t  fd_reg = instr->FdValue(); | 
| +  int64_t  i64hilo = 0; | 
| +  uint64_t u64hilo = 0; | 
| + | 
| +  // ALU output | 
| +  // It should not be used as is. Instructions using it should always | 
| +  // initialize it first. | 
| +  int32_t alu_out = 0x12345678; | 
| + | 
| +  // For break and trap instructions. | 
| +  bool do_interrupt = false; | 
| + | 
| +  // For jr and jalr | 
| +  // Get current pc. | 
| +  int32_t current_pc = get_pc(); | 
| +  // Next pc | 
| +  int32_t next_pc = 0; | 
| + | 
| +  // Setup the variables if needed before executing the instruction. | 
| +  ConfigureTypeRegister(instr, | 
| +                        alu_out, | 
| +                        i64hilo, | 
| +                        u64hilo, | 
| +                        next_pc, | 
| +                        do_interrupt); | 
|  | 
| // ---------- Raise exceptions triggered. | 
| SignalExceptions(); | 
| @@ -1052,25 +1575,42 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| case BC1:   // branch on coprocessor condition | 
| UNREACHABLE(); | 
| break; | 
| +        case CFC1: | 
| +          set_register(rt_reg, alu_out); | 
| case MFC1: | 
| -        case MFHC1: | 
| set_register(rt_reg, alu_out); | 
| break; | 
| +        case MFHC1: | 
| +          UNIMPLEMENTED_MIPS(); | 
| +          break; | 
| +        case CTC1: | 
| +          // At the moment only FCSR is supported. | 
| +          ASSERT(fs_reg == kFCSRRegister); | 
| +          FCSR_ = registers_[rt_reg]; | 
| +          break; | 
| case MTC1: | 
| -          // We don't need to set the higher bits to 0, because MIPS ISA says | 
| -          // they are in an unpredictable state after executing MTC1. | 
| FPUregisters_[fs_reg] = registers_[rt_reg]; | 
| -          FPUregisters_[fs_reg+1] = Unpredictable; | 
| break; | 
| case MTHC1: | 
| -          // Here we need to keep the lower bits unchanged. | 
| -          FPUregisters_[fs_reg+1] = registers_[rt_reg]; | 
| +          UNIMPLEMENTED_MIPS(); | 
| break; | 
| case S: | 
| +          float f; | 
| switch (instr->FunctionFieldRaw()) { | 
| case CVT_D_S: | 
| +              f = get_fpu_register_float(fs_reg); | 
| +              set_fpu_register_double(fd_reg, static_cast<double>(f)); | 
| +              break; | 
| case CVT_W_S: | 
| case CVT_L_S: | 
| +            case TRUNC_W_S: | 
| +            case TRUNC_L_S: | 
| +            case ROUND_W_S: | 
| +            case ROUND_L_S: | 
| +            case FLOOR_W_S: | 
| +            case FLOOR_L_S: | 
| +            case CEIL_W_S: | 
| +            case CEIL_L_S: | 
| case CVT_PS_S: | 
| UNIMPLEMENTED_MIPS(); | 
| break; | 
| @@ -1079,10 +1619,133 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| } | 
| break; | 
| case D: | 
| +          double ft, fs; | 
| +          uint32_t cc, fcsr_cc; | 
| +          int64_t  i64; | 
| +          fs = get_fpu_register_double(fs_reg); | 
| +          ft = get_fpu_register_double(ft_reg); | 
| +          cc = instr->FCccValue(); | 
| +          fcsr_cc = get_fcsr_condition_bit(cc); | 
| switch (instr->FunctionFieldRaw()) { | 
| -            case CVT_S_D: | 
| -            case CVT_W_D: | 
| -            case CVT_L_D: | 
| +            case ADD_D: | 
| +              set_fpu_register_double(fd_reg, fs + ft); | 
| +              break; | 
| +            case SUB_D: | 
| +              set_fpu_register_double(fd_reg, fs - ft); | 
| +              break; | 
| +            case MUL_D: | 
| +              set_fpu_register_double(fd_reg, fs * ft); | 
| +              break; | 
| +            case DIV_D: | 
| +              set_fpu_register_double(fd_reg, fs / ft); | 
| +              break; | 
| +            case ABS_D: | 
| +              set_fpu_register_double(fd_reg, fs < 0 ? -fs : fs); | 
| +              break; | 
| +            case MOV_D: | 
| +              set_fpu_register_double(fd_reg, fs); | 
| +              break; | 
| +            case NEG_D: | 
| +              set_fpu_register_double(fd_reg, -fs); | 
| +              break; | 
| +            case SQRT_D: | 
| +              set_fpu_register_double(fd_reg, sqrt(fs)); | 
| +              break; | 
| +            case C_UN_D: | 
| +              set_fcsr_bit(fcsr_cc, isnan(fs) || isnan(ft)); | 
| +              break; | 
| +            case C_EQ_D: | 
| +              set_fcsr_bit(fcsr_cc, (fs == ft)); | 
| +              break; | 
| +            case C_UEQ_D: | 
| +              set_fcsr_bit(fcsr_cc, (fs == ft) || (isnan(fs) || isnan(ft))); | 
| +              break; | 
| +            case C_OLT_D: | 
| +              set_fcsr_bit(fcsr_cc, (fs < ft)); | 
| +              break; | 
| +            case C_ULT_D: | 
| +              set_fcsr_bit(fcsr_cc, (fs < ft) || (isnan(fs) || isnan(ft))); | 
| +              break; | 
| +            case C_OLE_D: | 
| +              set_fcsr_bit(fcsr_cc, (fs <= ft)); | 
| +              break; | 
| +            case C_ULE_D: | 
| +              set_fcsr_bit(fcsr_cc, (fs <= ft) || (isnan(fs) || isnan(ft))); | 
| +              break; | 
| +            case CVT_W_D:   // Convert double to word. | 
| +              // Rounding modes are not yet supported. | 
| +              ASSERT((FCSR_ & 3) == 0); | 
| +              // In rounding mode 0 it should behave like ROUND. | 
| +            case ROUND_W_D:  // Round double to word. | 
| +              { | 
| +                double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5); | 
| +                int32_t result = static_cast<int32_t>(rounded); | 
| +                set_fpu_register(fd_reg, result); | 
| +                if (set_fcsr_round_error(fs, rounded)) { | 
| +                  set_fpu_register(fd_reg, kFPUInvalidResult); | 
| +                } | 
| +              } | 
| +              break; | 
| +            case TRUNC_W_D:  // Truncate double to word (round towards 0). | 
| +              { | 
| +                int32_t result = static_cast<int32_t>(fs); | 
| +                set_fpu_register(fd_reg, result); | 
| +                if (set_fcsr_round_error(fs, static_cast<double>(result))) { | 
| +                  set_fpu_register(fd_reg, kFPUInvalidResult); | 
| +                } | 
| +              } | 
| +              break; | 
| +            case FLOOR_W_D:  // Round double to word towards negative infinity. | 
| +              { | 
| +                double rounded = floor(fs); | 
| +                int32_t result = static_cast<int32_t>(rounded); | 
| +                set_fpu_register(fd_reg, result); | 
| +                if (set_fcsr_round_error(fs, rounded)) { | 
| +                  set_fpu_register(fd_reg, kFPUInvalidResult); | 
| +                } | 
| +              } | 
| +              break; | 
| +            case CEIL_W_D:  // Round double to word towards positive infinity. | 
| +              { | 
| +                double rounded = ceil(fs); | 
| +                int32_t result = static_cast<int32_t>(rounded); | 
| +                set_fpu_register(fd_reg, result); | 
| +                if (set_fcsr_round_error(fs, rounded)) { | 
| +                  set_fpu_register(fd_reg, kFPUInvalidResult); | 
| +                } | 
| +              } | 
| +              break; | 
| +            case CVT_S_D:  // Convert double to float (single). | 
| +              set_fpu_register_float(fd_reg, static_cast<float>(fs)); | 
| +              break; | 
| +            case CVT_L_D:  // Mips32r2: Truncate double to 64-bit long-word. | 
| +              i64 = static_cast<int64_t>(fs); | 
| +              set_fpu_register(fd_reg, i64 & 0xffffffff); | 
| +              set_fpu_register(fd_reg + 1, i64 >> 32); | 
| +              break; | 
| +            case TRUNC_L_D:  // Mips32r2 instruction. | 
| +              i64 = static_cast<int64_t>(fs); | 
| +              set_fpu_register(fd_reg, i64 & 0xffffffff); | 
| +              set_fpu_register(fd_reg + 1, i64 >> 32); | 
| +              break; | 
| +            case ROUND_L_D: {  // Mips32r2 instruction. | 
| +              double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5); | 
| +              i64 = static_cast<int64_t>(rounded); | 
| +              set_fpu_register(fd_reg, i64 & 0xffffffff); | 
| +              set_fpu_register(fd_reg + 1, i64 >> 32); | 
| +              break; | 
| +            } | 
| +            case FLOOR_L_D:  // Mips32r2 instruction. | 
| +              i64 = static_cast<int64_t>(floor(fs)); | 
| +              set_fpu_register(fd_reg, i64 & 0xffffffff); | 
| +              set_fpu_register(fd_reg + 1, i64 >> 32); | 
| +              break; | 
| +            case CEIL_L_D:  // Mips32r2 instruction. | 
| +              i64 = static_cast<int64_t>(ceil(fs)); | 
| +              set_fpu_register(fd_reg, i64 & 0xffffffff); | 
| +              set_fpu_register(fd_reg + 1, i64 >> 32); | 
| +              break; | 
| +            case C_F_D: | 
| UNIMPLEMENTED_MIPS(); | 
| break; | 
| default: | 
| @@ -1091,11 +1754,13 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| break; | 
| case W: | 
| switch (instr->FunctionFieldRaw()) { | 
| -            case CVT_S_W: | 
| -              UNIMPLEMENTED_MIPS(); | 
| +            case CVT_S_W:   // Convert word to float (single). | 
| +              alu_out = get_fpu_register(fs_reg); | 
| +              set_fpu_register_float(fd_reg, static_cast<float>(alu_out)); | 
| break; | 
| case CVT_D_W:   // Convert word to double. | 
| -              set_fpu_register(rd_reg, static_cast<double>(rs)); | 
| +              alu_out = get_fpu_register(fs_reg); | 
| +              set_fpu_register_double(fd_reg, static_cast<double>(alu_out)); | 
| break; | 
| default: | 
| UNREACHABLE(); | 
| @@ -1103,8 +1768,14 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| break; | 
| case L: | 
| switch (instr->FunctionFieldRaw()) { | 
| +          case CVT_D_L:  // Mips32r2 instruction. | 
| +            // Watch the signs here, we want 2 32-bit vals | 
| +            // to make a sign-64. | 
| +            i64 = (uint32_t) get_fpu_register(fs_reg); | 
| +            i64 |= ((int64_t) get_fpu_register(fs_reg + 1) << 32); | 
| +            set_fpu_register_double(fd_reg, static_cast<double>(i64)); | 
| +            break; | 
| case CVT_S_L: | 
| -            case CVT_D_L: | 
| UNIMPLEMENTED_MIPS(); | 
| break; | 
| default: | 
| @@ -1121,7 +1792,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| switch (instr->FunctionFieldRaw()) { | 
| case JR: { | 
| Instruction* branch_delay_instr = reinterpret_cast<Instruction*>( | 
| -              current_pc+Instruction::kInstructionSize); | 
| +              current_pc+Instruction::kInstrSize); | 
| BranchDelayInstructionDecode(branch_delay_instr); | 
| set_pc(next_pc); | 
| pc_modified_ = true; | 
| @@ -1129,16 +1800,21 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| } | 
| case JALR: { | 
| Instruction* branch_delay_instr = reinterpret_cast<Instruction*>( | 
| -              current_pc+Instruction::kInstructionSize); | 
| +              current_pc+Instruction::kInstrSize); | 
| BranchDelayInstructionDecode(branch_delay_instr); | 
| -          set_register(31, current_pc + 2* Instruction::kInstructionSize); | 
| +          set_register(31, current_pc + 2* Instruction::kInstrSize); | 
| set_pc(next_pc); | 
| pc_modified_ = true; | 
| break; | 
| } | 
| // Instructions using HI and LO registers. | 
| case MULT: | 
| +          set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff)); | 
| +          set_register(HI, static_cast<int32_t>(i64hilo >> 32)); | 
| +          break; | 
| case MULTU: | 
| +          set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff)); | 
| +          set_register(HI, static_cast<int32_t>(u64hilo >> 32)); | 
| break; | 
| case DIV: | 
| // Divide by zero was checked in the configuration step. | 
| @@ -1149,7 +1825,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| set_register(LO, rs_u / rt_u); | 
| set_register(HI, rs_u % rt_u); | 
| break; | 
| -        // Break and trap instructions | 
| +        // Break and trap instructions. | 
| case BREAK: | 
| case TGE: | 
| case TGEU: | 
| @@ -1161,6 +1837,23 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| SoftwareInterrupt(instr); | 
| } | 
| break; | 
| +        // Conditional moves. | 
| +        case MOVN: | 
| +          if (rt) set_register(rd_reg, rs); | 
| +          break; | 
| +        case MOVCI: { | 
| +          uint32_t cc = instr->FCccValue(); | 
| +          uint32_t fcsr_cc = get_fcsr_condition_bit(cc); | 
| +          if (instr->Bit(16)) {  // Read Tf bit | 
| +            if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs); | 
| +          } else { | 
| +            if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs); | 
| +          } | 
| +          break; | 
| +        } | 
| +        case MOVZ: | 
| +          if (!rt) set_register(rd_reg, rs); | 
| +          break; | 
| default:  // For other special opcodes we do the default operation. | 
| set_register(rd_reg, alu_out); | 
| }; | 
| @@ -1173,9 +1866,23 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| set_register(LO, Unpredictable); | 
| set_register(HI, Unpredictable); | 
| break; | 
| +        default:  // For other special2 opcodes we do the default operation. | 
| +          set_register(rd_reg, alu_out); | 
| +      } | 
| +      break; | 
| +    case SPECIAL3: | 
| +      switch (instr->FunctionFieldRaw()) { | 
| +        case INS: | 
| +          // Ins instr leaves result in Rt, rather than Rd. | 
| +          set_register(rt_reg, alu_out); | 
| +          break; | 
| +        case EXT: | 
| +          // Ext instr leaves result in Rt, rather than Rd. | 
| +          set_register(rt_reg, alu_out); | 
| +          break; | 
| default: | 
| UNREACHABLE(); | 
| -      } | 
| +      }; | 
| break; | 
| // Unimplemented opcodes raised an error in the configuration step before, | 
| // so we can use the default here to set the destination register in common | 
| @@ -1185,22 +1892,22 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { | 
| }; | 
| } | 
|  | 
| + | 
| // Type 2: instructions using a 16 bytes immediate. (eg: addi, beq) | 
| void Simulator::DecodeTypeImmediate(Instruction* instr) { | 
| -  // Instruction fields | 
| +  // Instruction fields. | 
| Opcode   op     = instr->OpcodeFieldRaw(); | 
| -  int32_t  rs     = get_register(instr->RsField()); | 
| +  int32_t  rs     = get_register(instr->RsValue()); | 
| uint32_t rs_u   = static_cast<uint32_t>(rs); | 
| -  int32_t  rt_reg = instr->RtField();  // destination register | 
| +  int32_t  rt_reg = instr->RtValue();  // destination register | 
| int32_t  rt     = get_register(rt_reg); | 
| -  int16_t  imm16  = instr->Imm16Field(); | 
| +  int16_t  imm16  = instr->Imm16Value(); | 
|  | 
| -  int32_t  ft_reg = instr->FtField();  // destination register | 
| -  int32_t  ft     = get_register(ft_reg); | 
| +  int32_t  ft_reg = instr->FtValue();  // destination register | 
|  | 
| -  // zero extended immediate | 
| +  // Zero extended immediate. | 
| uint32_t  oe_imm16 = 0xffff & imm16; | 
| -  // sign extended immediate | 
| +  // Sign extended immediate. | 
| int32_t   se_imm16 = imm16; | 
|  | 
| // Get current pc. | 
| @@ -1208,25 +1915,38 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { | 
| // Next pc. | 
| int32_t next_pc = bad_ra; | 
|  | 
| -  // Used for conditional branch instructions | 
| +  // Used for conditional branch instructions. | 
| bool do_branch = false; | 
| bool execute_branch_delay_instruction = false; | 
|  | 
| -  // Used for arithmetic instructions | 
| +  // Used for arithmetic instructions. | 
| int32_t alu_out = 0; | 
| -  // Floating point | 
| +  // Floating point. | 
| double fp_out = 0.0; | 
| +  uint32_t cc, cc_value, fcsr_cc; | 
|  | 
| -  // Used for memory instructions | 
| +  // Used for memory instructions. | 
| int32_t addr = 0x0; | 
| +  // Value to be written in memory | 
| +  uint32_t mem_value = 0x0; | 
|  | 
| // ---------- Configuration (and execution for REGIMM) | 
| switch (op) { | 
| -    // ------------- COP1. Coprocessor instructions | 
| +    // ------------- COP1. Coprocessor instructions. | 
| case COP1: | 
| switch (instr->RsFieldRaw()) { | 
| -        case BC1:   // branch on coprocessor condition | 
| -          UNIMPLEMENTED_MIPS(); | 
| +        case BC1:   // Branch on coprocessor condition. | 
| +          cc = instr->FBccValue(); | 
| +          fcsr_cc = get_fcsr_condition_bit(cc); | 
| +          cc_value = test_fcsr_bit(fcsr_cc); | 
| +          do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value; | 
| +          execute_branch_delay_instruction = true; | 
| +          // Set next_pc | 
| +          if (do_branch) { | 
| +            next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; | 
| +          } else { | 
| +            next_pc = current_pc + kBranchReturnOffset; | 
| +          } | 
| break; | 
| default: | 
| UNREACHABLE(); | 
| @@ -1259,7 +1979,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { | 
| execute_branch_delay_instruction = true; | 
| // Set next_pc | 
| if (do_branch) { | 
| -            next_pc = current_pc + (imm16 << 2) + Instruction::kInstructionSize; | 
| +            next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; | 
| if (instr->IsLinkingInstruction()) { | 
| set_register(31, current_pc + kBranchReturnOffset); | 
| } | 
| @@ -1323,6 +2043,21 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { | 
| addr = rs + se_imm16; | 
| alu_out = ReadB(addr); | 
| break; | 
| +    case LH: | 
| +      addr = rs + se_imm16; | 
| +      alu_out = ReadH(addr, instr); | 
| +      break; | 
| +    case LWL: { | 
| +      // al_offset is an offset of the effective address within an aligned word | 
| +      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; | 
| +      uint8_t byte_shift = kPointerAlignmentMask - al_offset; | 
| +      uint32_t mask = (1 << byte_shift * 8) - 1; | 
| +      addr = rs + se_imm16 - al_offset; | 
| +      alu_out = ReadW(addr, instr); | 
| +      alu_out <<= byte_shift * 8; | 
| +      alu_out |= rt & mask; | 
| +      break; | 
| +    } | 
| case LW: | 
| addr = rs + se_imm16; | 
| alu_out = ReadW(addr, instr); | 
| @@ -1331,12 +2066,47 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { | 
| addr = rs + se_imm16; | 
| alu_out = ReadBU(addr); | 
| break; | 
| +    case LHU: | 
| +      addr = rs + se_imm16; | 
| +      alu_out = ReadHU(addr, instr); | 
| +      break; | 
| +    case LWR: { | 
| +      // al_offset is an offset of the effective address within an aligned word | 
| +      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; | 
| +      uint8_t byte_shift = kPointerAlignmentMask - al_offset; | 
| +      uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0; | 
| +      addr = rs + se_imm16 - al_offset; | 
| +      alu_out = ReadW(addr, instr); | 
| +      alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8; | 
| +      alu_out |= rt & mask; | 
| +      break; | 
| +    } | 
| case SB: | 
| addr = rs + se_imm16; | 
| break; | 
| +    case SH: | 
| +      addr = rs + se_imm16; | 
| +      break; | 
| +    case SWL: { | 
| +      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; | 
| +      uint8_t byte_shift = kPointerAlignmentMask - al_offset; | 
| +      uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0; | 
| +      addr = rs + se_imm16 - al_offset; | 
| +      mem_value = ReadW(addr, instr) & mask; | 
| +      mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8; | 
| +      break; | 
| +    } | 
| case SW: | 
| addr = rs + se_imm16; | 
| break; | 
| +    case SWR: { | 
| +      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask; | 
| +      uint32_t mask = (1 << al_offset * 8) - 1; | 
| +      addr = rs + se_imm16 - al_offset; | 
| +      mem_value = ReadW(addr, instr); | 
| +      mem_value = (rt << al_offset * 8) | (mem_value & mask); | 
| +      break; | 
| +    } | 
| case LWC1: | 
| addr = rs + se_imm16; | 
| alu_out = ReadW(addr, instr); | 
| @@ -1367,12 +2137,12 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { | 
| execute_branch_delay_instruction = true; | 
| // Set next_pc | 
| if (do_branch) { | 
| -        next_pc = current_pc + (imm16 << 2) + Instruction::kInstructionSize; | 
| +        next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; | 
| if (instr->IsLinkingInstruction()) { | 
| -          set_register(31, current_pc + 2* Instruction::kInstructionSize); | 
| +          set_register(31, current_pc + 2* Instruction::kInstrSize); | 
| } | 
| } else { | 
| -        next_pc = current_pc + 2 * Instruction::kInstructionSize; | 
| +        next_pc = current_pc + 2 * Instruction::kInstrSize; | 
| } | 
| break; | 
| // ------------- Arithmetic instructions | 
| @@ -1388,16 +2158,29 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { | 
| break; | 
| // ------------- Memory instructions | 
| case LB: | 
| +    case LH: | 
| +    case LWL: | 
| case LW: | 
| case LBU: | 
| +    case LHU: | 
| +    case LWR: | 
| set_register(rt_reg, alu_out); | 
| break; | 
| case SB: | 
| WriteB(addr, static_cast<int8_t>(rt)); | 
| break; | 
| +    case SH: | 
| +      WriteH(addr, static_cast<uint16_t>(rt), instr); | 
| +      break; | 
| +    case SWL: | 
| +      WriteW(addr, mem_value, instr); | 
| +      break; | 
| case SW: | 
| WriteW(addr, rt, instr); | 
| break; | 
| +    case SWR: | 
| +      WriteW(addr, mem_value, instr); | 
| +      break; | 
| case LWC1: | 
| set_fpu_register(ft_reg, alu_out); | 
| break; | 
| @@ -1410,7 +2193,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { | 
| break; | 
| case SDC1: | 
| addr = rs + se_imm16; | 
| -      WriteD(addr, ft, instr); | 
| +      WriteD(addr, get_fpu_register_double(ft_reg), instr); | 
| break; | 
| default: | 
| break; | 
| @@ -1422,7 +2205,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { | 
| // We don't check for end_sim_pc. First it should not be met as the current | 
| // pc is valid. Secondly a jump should always execute its branch delay slot. | 
| Instruction* branch_delay_instr = | 
| -      reinterpret_cast<Instruction*>(current_pc+Instruction::kInstructionSize); | 
| +      reinterpret_cast<Instruction*>(current_pc+Instruction::kInstrSize); | 
| BranchDelayInstructionDecode(branch_delay_instr); | 
| } | 
|  | 
| @@ -1432,6 +2215,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { | 
| } | 
| } | 
|  | 
| + | 
| // Type 3: instructions using a 26 bytes immediate. (eg: j, jal) | 
| void Simulator::DecodeTypeJump(Instruction* instr) { | 
| // Get current pc. | 
| @@ -1439,35 +2223,39 @@ void Simulator::DecodeTypeJump(Instruction* instr) { | 
| // Get unchanged bits of pc. | 
| int32_t pc_high_bits = current_pc & 0xf0000000; | 
| // Next pc | 
| -  int32_t next_pc = pc_high_bits | (instr->Imm26Field() << 2); | 
| +  int32_t next_pc = pc_high_bits | (instr->Imm26Value() << 2); | 
|  | 
| // Execute branch delay slot | 
| // We don't check for end_sim_pc. First it should not be met as the current pc | 
| // is valid. Secondly a jump should always execute its branch delay slot. | 
| Instruction* branch_delay_instr = | 
| -    reinterpret_cast<Instruction*>(current_pc+Instruction::kInstructionSize); | 
| +    reinterpret_cast<Instruction*>(current_pc+Instruction::kInstrSize); | 
| BranchDelayInstructionDecode(branch_delay_instr); | 
|  | 
| // Update pc and ra if necessary. | 
| // Do this after the branch delay execution. | 
| if (instr->IsLinkingInstruction()) { | 
| -    set_register(31, current_pc + 2* Instruction::kInstructionSize); | 
| +    set_register(31, current_pc + 2* Instruction::kInstrSize); | 
| } | 
| set_pc(next_pc); | 
| pc_modified_ = true; | 
| } | 
|  | 
| + | 
| // Executes the current instruction. | 
| void Simulator::InstructionDecode(Instruction* instr) { | 
| +  if (v8::internal::FLAG_check_icache) { | 
| +    CheckICache(isolate_->simulator_i_cache(), instr); | 
| +  } | 
| pc_modified_ = false; | 
| if (::v8::internal::FLAG_trace_sim) { | 
| disasm::NameConverter converter; | 
| disasm::Disassembler dasm(converter); | 
| // use a reasonably large buffer | 
| v8::internal::EmbeddedVector<char, 256> buffer; | 
| -    dasm.InstructionDecode(buffer, | 
| -                           reinterpret_cast<byte_*>(instr)); | 
| -    PrintF("  0x%08x  %s\n", instr, buffer.start()); | 
| +    dasm.InstructionDecode(buffer, reinterpret_cast<byte_*>(instr)); | 
| +    PrintF("  0x%08x  %s\n", reinterpret_cast<intptr_t>(instr), | 
| +           buffer.start()); | 
| } | 
|  | 
| switch (instr->InstructionType()) { | 
| @@ -1485,7 +2273,7 @@ void Simulator::InstructionDecode(Instruction* instr) { | 
| } | 
| if (!pc_modified_) { | 
| set_register(pc, reinterpret_cast<int32_t>(instr) + | 
| -                 Instruction::kInstructionSize); | 
| +                 Instruction::kInstrSize); | 
| } | 
| } | 
|  | 
| @@ -1511,7 +2299,7 @@ void Simulator::Execute() { | 
| Instruction* instr = reinterpret_cast<Instruction*>(program_counter); | 
| icount_++; | 
| if (icount_ == ::v8::internal::FLAG_stop_sim_at) { | 
| -        Debugger dbg(this); | 
| +        MipsDebugger dbg(this); | 
| dbg.Debug(); | 
| } else { | 
| InstructionDecode(instr); | 
| @@ -1538,7 +2326,7 @@ int32_t Simulator::Call(byte_* entry, int argument_count, ...) { | 
| int original_stack = get_register(sp); | 
| // Compute position of stack on entry to generated code. | 
| int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t) | 
| -                                    - kArgsSlotsSize); | 
| +                                    - kCArgsSlotsSize); | 
| if (OS::ActivationFrameAlignment() != 0) { | 
| entry_stack &= -OS::ActivationFrameAlignment(); | 
| } | 
| @@ -1643,8 +2431,8 @@ uintptr_t Simulator::PopAddress() { | 
|  | 
| #undef UNSUPPORTED | 
|  | 
| -} }  // namespace assembler::mips | 
| +} }  // namespace v8::internal | 
|  | 
| -#endif  // !__mips || USE_SIMULATOR | 
| +#endif  // USE_SIMULATOR | 
|  | 
| #endif  // V8_TARGET_ARCH_MIPS | 
|  |