diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2011-07-08 16:40:11 -0700 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2011-07-08 16:40:11 -0700 |
commit | e5564a3f29e0a818832a97c7c3b28d7c8b3b0460 (patch) | |
tree | 4b48a6577080d5e44da4d2cbebb7fe7951660de8 /deps/v8/src/arm/simulator-arm.cc | |
parent | 0df2f74d364826053641395b01c2fcb1345057a9 (diff) | |
download | node-new-e5564a3f29e0a818832a97c7c3b28d7c8b3b0460.tar.gz |
Upgrade V8 to 3.4.10
Diffstat (limited to 'deps/v8/src/arm/simulator-arm.cc')
-rw-r--r-- | deps/v8/src/arm/simulator-arm.cc | 555 |
1 files changed, 407 insertions, 148 deletions
diff --git a/deps/v8/src/arm/simulator-arm.cc b/deps/v8/src/arm/simulator-arm.cc index f475a18b09..6af535553f 100644 --- a/deps/v8/src/arm/simulator-arm.cc +++ b/deps/v8/src/arm/simulator-arm.cc @@ -1,4 +1,4 @@ -// Copyright 2010 the V8 project authors. All rights reserved. +// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -49,12 +49,12 @@ namespace internal { // Windows C Run-Time Library does not provide vsscanf. #define SScanF sscanf // NOLINT -// The Debugger class is used by the simulator while debugging simulated ARM +// The ArmDebugger class is used by the simulator while debugging simulated ARM // code. -class Debugger { +class ArmDebugger { public: - explicit Debugger(Simulator* sim); - ~Debugger(); + explicit ArmDebugger(Simulator* sim); + ~ArmDebugger(); void Stop(Instruction* instr); void Debug(); @@ -67,6 +67,7 @@ class Debugger { Simulator* sim_; int32_t GetRegisterValue(int regnum); + double GetRegisterPairDoubleValue(int regnum); double GetVFPDoubleRegisterValue(int regnum); bool GetValue(const char* desc, int32_t* value); bool GetVFPSingleValue(const char* desc, float* value); @@ -83,12 +84,12 @@ class Debugger { }; -Debugger::Debugger(Simulator* sim) { +ArmDebugger::ArmDebugger(Simulator* sim) { sim_ = sim; } -Debugger::~Debugger() { +ArmDebugger::~ArmDebugger() { } @@ -105,7 +106,7 @@ static void InitializeCoverage() { } -void Debugger::Stop(Instruction* instr) { +void ArmDebugger::Stop(Instruction* instr) { // Get the stop code. uint32_t code = instr->SvcValue() & kStopCodeMask; // Retrieve the encoded address, which comes just after this stop. @@ -137,7 +138,7 @@ static void InitializeCoverage() { } -void Debugger::Stop(Instruction* instr) { +void ArmDebugger::Stop(Instruction* instr) { // Get the stop code. uint32_t code = instr->SvcValue() & kStopCodeMask; // Retrieve the encoded address, which comes just after this stop. @@ -159,7 +160,7 @@ void Debugger::Stop(Instruction* instr) { #endif -int32_t Debugger::GetRegisterValue(int regnum) { +int32_t ArmDebugger::GetRegisterValue(int regnum) { if (regnum == kPCRegister) { return sim_->get_pc(); } else { @@ -168,12 +169,17 @@ int32_t Debugger::GetRegisterValue(int regnum) { } -double Debugger::GetVFPDoubleRegisterValue(int regnum) { +double ArmDebugger::GetRegisterPairDoubleValue(int regnum) { + return sim_->get_double_from_register_pair(regnum); +} + + +double ArmDebugger::GetVFPDoubleRegisterValue(int regnum) { return sim_->get_double_from_d_register(regnum); } -bool Debugger::GetValue(const char* desc, int32_t* value) { +bool ArmDebugger::GetValue(const char* desc, int32_t* value) { int regnum = Registers::Number(desc); if (regnum != kNoRegister) { *value = GetRegisterValue(regnum); @@ -189,7 +195,7 @@ bool Debugger::GetValue(const char* desc, int32_t* value) { } -bool Debugger::GetVFPSingleValue(const char* desc, float* value) { +bool ArmDebugger::GetVFPSingleValue(const char* desc, float* value) { bool is_double; int regnum = VFPRegisters::Number(desc, &is_double); if (regnum != kNoRegister && !is_double) { @@ -200,7 +206,7 @@ bool Debugger::GetVFPSingleValue(const char* desc, float* value) { } -bool Debugger::GetVFPDoubleValue(const char* desc, double* value) { +bool ArmDebugger::GetVFPDoubleValue(const char* desc, double* value) { bool is_double; int regnum = VFPRegisters::Number(desc, &is_double); if (regnum != kNoRegister && is_double) { @@ -211,7 +217,7 @@ bool Debugger::GetVFPDoubleValue(const char* desc, double* value) { } -bool Debugger::SetBreakpoint(Instruction* breakpc) { +bool ArmDebugger::SetBreakpoint(Instruction* breakpc) { // Check if a breakpoint can be set. If not return without any side-effects. if (sim_->break_pc_ != NULL) { return false; @@ -226,7 +232,7 @@ bool Debugger::SetBreakpoint(Instruction* breakpc) { } -bool Debugger::DeleteBreakpoint(Instruction* breakpc) { +bool ArmDebugger::DeleteBreakpoint(Instruction* breakpc) { if (sim_->break_pc_ != NULL) { sim_->break_pc_->SetInstructionBits(sim_->break_instr_); } @@ -237,21 +243,21 @@ bool Debugger::DeleteBreakpoint(Instruction* breakpc) { } -void Debugger::UndoBreakpoints() { +void ArmDebugger::UndoBreakpoints() { if (sim_->break_pc_ != NULL) { sim_->break_pc_->SetInstructionBits(sim_->break_instr_); } } -void Debugger::RedoBreakpoints() { +void ArmDebugger::RedoBreakpoints() { if (sim_->break_pc_ != NULL) { sim_->break_pc_->SetInstructionBits(kBreakpointInstr); } } -void Debugger::Debug() { +void ArmDebugger::Debug() { intptr_t last_pc = -1; bool done = false; @@ -305,27 +311,45 @@ void Debugger::Debug() { // Leave the debugger shell. done = true; } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { - if (argc == 2) { + if (argc == 2 || (argc == 3 && strcmp(arg2, "fp") == 0)) { int32_t value; float svalue; double dvalue; if (strcmp(arg1, "all") == 0) { for (int i = 0; i < kNumRegisters; i++) { value = GetRegisterValue(i); - PrintF("%3s: 0x%08x %10d\n", Registers::Name(i), value, value); + PrintF("%3s: 0x%08x %10d", Registers::Name(i), value, value); + if ((argc == 3 && strcmp(arg2, "fp") == 0) && + i < 8 && + (i % 2) == 0) { + dvalue = GetRegisterPairDoubleValue(i); + PrintF(" (%f)\n", dvalue); + } else { + PrintF("\n"); + } } for (int i = 0; i < kNumVFPDoubleRegisters; i++) { dvalue = GetVFPDoubleRegisterValue(i); - PrintF("%3s: %f\n", - VFPRegisters::Name(i, true), dvalue); + uint64_t as_words = BitCast<uint64_t>(dvalue); + PrintF("%3s: %f 0x%08x %08x\n", + VFPRegisters::Name(i, true), + dvalue, + static_cast<uint32_t>(as_words >> 32), + static_cast<uint32_t>(as_words & 0xffffffff)); } } else { if (GetValue(arg1, &value)) { PrintF("%s: 0x%08x %d \n", arg1, value, value); } else if (GetVFPSingleValue(arg1, &svalue)) { - PrintF("%s: %f \n", arg1, svalue); + uint32_t as_word = BitCast<uint32_t>(svalue); + PrintF("%s: %f 0x%08x\n", arg1, svalue, as_word); } else if (GetVFPDoubleValue(arg1, &dvalue)) { - PrintF("%s: %f \n", arg1, dvalue); + uint64_t as_words = BitCast<uint64_t>(dvalue); + PrintF("%s: %f 0x%08x %08x\n", + arg1, + dvalue, + static_cast<uint32_t>(as_words >> 32), + static_cast<uint32_t>(as_words & 0xffffffff)); } else { PrintF("%s unrecognized\n", arg1); } @@ -380,11 +404,24 @@ void Debugger::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) { + } else if (strcmp(cmd, "disasm") == 0 || strcmp(cmd, "di") == 0) { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // use a reasonably large buffer @@ -398,11 +435,23 @@ void Debugger::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*>(sim_->get_pc()); - // Disassemble <arg1> instructions. - end = cur + (value * Instruction::kInstrSize); + int regnum = Registers::Number(arg1); + if (regnum != kNoRegister || 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; @@ -515,6 +564,7 @@ void Debugger::Debug() { PrintF("print <register>\n"); PrintF(" print register content (alias 'p')\n"); PrintF(" use register name 'all' to print all registers\n"); + PrintF(" add argument 'fp' to print register pair double values\n"); PrintF("printobject <register>\n"); PrintF(" print an object from a register (alias 'po')\n"); PrintF("flags\n"); @@ -524,8 +574,10 @@ void Debugger::Debug() { PrintF("mem <address> [<words>]\n"); PrintF(" dump memory content, default dump 10 words)\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"); @@ -539,11 +591,11 @@ void Debugger::Debug() { PrintF(" Stops are debug instructions inserted by\n"); PrintF(" the Assembler::stop() function.\n"); PrintF(" When hitting a stop, the Simulator will\n"); - PrintF(" stop and and give control to the Debugger.\n"); + PrintF(" stop and and give control to the ArmDebugger.\n"); PrintF(" The first %d stop codes are watched:\n", Simulator::kNumOfWatchedStops); PrintF(" - They can be enabled / disabled: the Simulator\n"); - PrintF(" will / won't stop when hitting them.\n"); + PrintF(" will / won't stop when hitting them.\n"); PrintF(" - The Simulator keeps track of how many times they \n"); PrintF(" are met. (See the info command.) Going over a\n"); PrintF(" disabled stop still increases its counter. \n"); @@ -593,7 +645,9 @@ static bool AllOnOnePage(uintptr_t start, int size) { } -void Simulator::FlushICache(void* start_addr, size_t size) { +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; @@ -602,22 +656,22 @@ void Simulator::FlushICache(void* start_addr, size_t size) { int offset = (start & CachePage::kPageMask); while (!AllOnOnePage(start, size - 1)) { int bytes_to_flush = CachePage::kPageSize - offset; - FlushOnePage(start, bytes_to_flush); + 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(start, size); + FlushOnePage(i_cache, start, size); } } -CachePage* Simulator::GetCachePage(void* page) { - v8::internal::HashMap::Entry* entry = i_cache_->Lookup(page, - ICacheHash(page), - true); +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; @@ -627,25 +681,28 @@ CachePage* Simulator::GetCachePage(void* page) { // Flush from start up to and not including start + size. -void Simulator::FlushOnePage(intptr_t start, int 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(page); + 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(Instruction* instr) { +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(page); + 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); @@ -662,29 +719,21 @@ void Simulator::CheckICache(Instruction* instr) { } -// Create one simulator per thread and keep it in thread local storage. -static v8::internal::Thread::LocalStorageKey simulator_key; - - -bool Simulator::initialized_ = false; - - -void Simulator::Initialize() { - if (initialized_) return; - simulator_key = v8::internal::Thread::CreateThreadLocalKey(); - initialized_ = true; - ::v8::internal::ExternalReference::set_redirector(&RedirectExternalReference); +void Simulator::Initialize(Isolate* isolate) { + if (isolate->simulator_initialized()) return; + isolate->set_simulator_initialized(true); + ::v8::internal::ExternalReference::set_redirector(isolate, + &RedirectExternalReference); } -v8::internal::HashMap* Simulator::i_cache_ = NULL; - - -Simulator::Simulator() { +Simulator::Simulator(Isolate* isolate) : isolate_(isolate) { + 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(); + Initialize(isolate); // 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 @@ -748,11 +797,14 @@ class Redirection { : external_function_(external_function), swi_instruction_(al | (0xf*B24) | kCallRtRedirected), type_(type), - next_(list_) { - Simulator::current()-> - FlushICache(reinterpret_cast<void*>(&swi_instruction_), - Instruction::kInstrSize); - list_ = this; + 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() { @@ -764,8 +816,9 @@ class Redirection { static Redirection* Get(void* external_function, ExternalReference::Type type) { - Redirection* current; - for (current = list_; current != NULL; current = current->next_) { + 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, type); @@ -783,13 +836,9 @@ class Redirection { uint32_t swi_instruction_; ExternalReference::Type type_; Redirection* next_; - static Redirection* list_; }; -Redirection* Redirection::list_ = NULL; - - void* Simulator::RedirectExternalReference(void* external_function, ExternalReference::Type type) { Redirection* redirection = Redirection::Get(external_function, type); @@ -798,14 +847,16 @@ void* Simulator::RedirectExternalReference(void* external_function, // 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->FindOrAllocatePerThreadDataForThisThread(); + ASSERT(isolate_data != NULL); + + Simulator* sim = isolate_data->simulator(); if (sim == NULL) { - // TODO(146): delete the simulator object when a thread goes away. - sim = new Simulator(); - v8::internal::Thread::SetThreadLocal(simulator_key, sim); + // TODO(146): delete the simulator object when a thread/isolate goes away. + sim = new Simulator(isolate); + isolate_data->set_simulator(sim); } return sim; } @@ -834,6 +885,19 @@ int32_t Simulator::get_register(int reg) const { } +double Simulator::get_double_from_register_pair(int reg) { + ASSERT((reg >= 0) && (reg < num_registers) && ((reg % 2) == 0)); + + double dm_val = 0.0; + // Read the bits from the unsigned integer register_[] array + // into the double precision floating point value and return it. + char buffer[2 * sizeof(vfp_register[0])]; + memcpy(buffer, ®isters_[reg], 2 * sizeof(registers_[0])); + memcpy(&dm_val, buffer, 2 * sizeof(registers_[0])); + return(dm_val); +} + + void Simulator::set_dw_register(int dreg, const int* dbl) { ASSERT((dreg >= 0) && (dreg < num_d_registers)); registers_[dreg] = dbl[0]; @@ -899,12 +963,7 @@ void Simulator::set_d_register_from_double(int dreg, const double& dbl) { // 2*sreg and 2*sreg+1. char buffer[2 * sizeof(vfp_register[0])]; memcpy(buffer, &dbl, 2 * sizeof(vfp_register[0])); -#ifndef BIG_ENDIAN_FLOATING_POINT memcpy(&vfp_register[dreg * 2], buffer, 2 * sizeof(vfp_register[0])); -#else - memcpy(&vfp_register[dreg * 2], &buffer[4], sizeof(vfp_register[0])); - memcpy(&vfp_register[dreg * 2 + 1], &buffer[0], sizeof(vfp_register[0])); -#endif } @@ -941,37 +1000,80 @@ double Simulator::get_double_from_d_register(int dreg) { // Read the bits from the unsigned integer vfp_register[] array // into the double precision floating point value and return it. char buffer[2 * sizeof(vfp_register[0])]; -#ifdef BIG_ENDIAN_FLOATING_POINT - memcpy(&buffer[0], &vfp_register[2 * dreg + 1], sizeof(vfp_register[0])); - memcpy(&buffer[4], &vfp_register[2 * dreg], sizeof(vfp_register[0])); -#else memcpy(buffer, &vfp_register[2 * dreg], 2 * sizeof(vfp_register[0])); -#endif memcpy(&dm_val, buffer, 2 * sizeof(vfp_register[0])); return(dm_val); } -// For use in calls that take two double values, constructed from r0, r1, r2 -// and r3. +// For use in calls that take two double values, constructed either +// from r0-r3 or d0 and d1. void Simulator::GetFpArgs(double* x, double* y) { - // We use a char buffer to get around the strict-aliasing rules which - // otherwise allow the compiler to optimize away the copy. - char buffer[2 * sizeof(registers_[0])]; - // Registers 0 and 1 -> x. - memcpy(buffer, registers_, sizeof(buffer)); - memcpy(x, buffer, sizeof(buffer)); - // Registers 2 and 3 -> y. - memcpy(buffer, registers_ + 2, sizeof(buffer)); - memcpy(y, buffer, sizeof(buffer)); + if (use_eabi_hardfloat()) { + *x = vfp_register[0]; + *y = vfp_register[1]; + } 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)]; + // Registers 0 and 1 -> x. + memcpy(buffer, registers_, sizeof(*x)); + memcpy(x, buffer, sizeof(*x)); + // Registers 2 and 3 -> y. + memcpy(buffer, registers_ + 2, sizeof(*y)); + memcpy(y, buffer, sizeof(*y)); + } +} + +// For use in calls that take one double value, constructed either +// from r0 and r1 or d0. +void Simulator::GetFpArgs(double* x) { + if (use_eabi_hardfloat()) { + *x = vfp_register[0]; + } 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)]; + // Registers 0 and 1 -> x. + memcpy(buffer, registers_, sizeof(*x)); + memcpy(x, buffer, sizeof(*x)); + } +} + + +// For use in calls that take one double value constructed either +// from r0 and r1 or d0 and one integer value. +void Simulator::GetFpArgs(double* x, int32_t* y) { + if (use_eabi_hardfloat()) { + *x = vfp_register[0]; + *y = registers_[1]; + } 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)]; + // Registers 0 and 1 -> x. + memcpy(buffer, registers_, sizeof(*x)); + memcpy(x, buffer, sizeof(*x)); + // Register 2 -> y. + memcpy(buffer, registers_ + 2, sizeof(*y)); + memcpy(y, buffer, sizeof(*y)); + } } +// The return value is either in r0/r1 or d0. void Simulator::SetFpResult(const double& result) { - char buffer[2 * sizeof(registers_[0])]; - memcpy(buffer, &result, sizeof(buffer)); - // result -> registers 0 and 1. - memcpy(registers_, buffer, sizeof(buffer)); + if (use_eabi_hardfloat()) { + char buffer[2 * sizeof(vfp_register[0])]; + memcpy(buffer, &result, sizeof(buffer)); + // Copy result to d0. + memcpy(vfp_register, buffer, sizeof(buffer)); + } else { + char buffer[2 * sizeof(registers_[0])]; + memcpy(buffer, &result, sizeof(buffer)); + // Copy result to r0 and r1. + memcpy(registers_, buffer, sizeof(buffer)); + } } @@ -1225,12 +1327,13 @@ void Simulator::SetVFlag(bool val) { // Calculate C flag value for additions. -bool Simulator::CarryFrom(int32_t left, int32_t right) { +bool Simulator::CarryFrom(int32_t left, int32_t right, int32_t carry) { uint32_t uleft = static_cast<uint32_t>(left); uint32_t uright = static_cast<uint32_t>(right); uint32_t urest = 0xffffffffU - uleft; - return (uright > urest); + return (uright > urest) || + (carry && (((uright + 1) > urest) || (uright > (urest - 1)))); } @@ -1465,36 +1568,34 @@ static int count_bits(int bit_vector) { } -// Addressing Mode 4 - Load and Store Multiple -void Simulator::HandleRList(Instruction* instr, bool load) { +void Simulator::ProcessPUW(Instruction* instr, + int num_regs, + int reg_size, + intptr_t* start_address, + intptr_t* end_address) { int rn = instr->RnValue(); int32_t rn_val = get_register(rn); - int rlist = instr->RlistValue(); - int num_regs = count_bits(rlist); - - intptr_t start_address = 0; - intptr_t end_address = 0; switch (instr->PUField()) { case da_x: { UNIMPLEMENTED(); break; } case ia_x: { - start_address = rn_val; - end_address = rn_val + (num_regs * 4) - 4; - rn_val = rn_val + (num_regs * 4); + *start_address = rn_val; + *end_address = rn_val + (num_regs * reg_size) - reg_size; + rn_val = rn_val + (num_regs * reg_size); break; } case db_x: { - start_address = rn_val - (num_regs * 4); - end_address = rn_val - 4; - rn_val = start_address; + *start_address = rn_val - (num_regs * reg_size); + *end_address = rn_val - reg_size; + rn_val = *start_address; break; } case ib_x: { - start_address = rn_val + 4; - end_address = rn_val + (num_regs * 4); - rn_val = end_address; + *start_address = rn_val + reg_size; + *end_address = rn_val + (num_regs * reg_size); + rn_val = *end_address; break; } default: { @@ -1505,6 +1606,17 @@ void Simulator::HandleRList(Instruction* instr, bool load) { if (instr->HasW()) { set_register(rn, rn_val); } +} + +// Addressing Mode 4 - Load and Store Multiple +void Simulator::HandleRList(Instruction* instr, bool load) { + int rlist = instr->RlistValue(); + int num_regs = count_bits(rlist); + + intptr_t start_address = 0; + intptr_t end_address = 0; + ProcessPUW(instr, num_regs, kPointerSize, &start_address, &end_address); + intptr_t* address = reinterpret_cast<intptr_t*>(start_address); int reg = 0; while (rlist != 0) { @@ -1523,6 +1635,57 @@ void Simulator::HandleRList(Instruction* instr, bool load) { } +// Addressing Mode 6 - Load and Store Multiple Coprocessor registers. +void Simulator::HandleVList(Instruction* instr) { + VFPRegPrecision precision = + (instr->SzValue() == 0) ? kSinglePrecision : kDoublePrecision; + int operand_size = (precision == kSinglePrecision) ? 4 : 8; + + bool load = (instr->VLValue() == 0x1); + + int vd; + int num_regs; + vd = instr->VFPDRegValue(precision); + if (precision == kSinglePrecision) { + num_regs = instr->Immed8Value(); + } else { + num_regs = instr->Immed8Value() / 2; + } + + intptr_t start_address = 0; + intptr_t end_address = 0; + ProcessPUW(instr, num_regs, operand_size, &start_address, &end_address); + + intptr_t* address = reinterpret_cast<intptr_t*>(start_address); + for (int reg = vd; reg < vd + num_regs; reg++) { + if (precision == kSinglePrecision) { + if (load) { + set_s_register_from_sinteger( + reg, ReadW(reinterpret_cast<int32_t>(address), instr)); + } else { + WriteW(reinterpret_cast<int32_t>(address), + get_sinteger_from_s_register(reg), instr); + } + address += 1; + } else { + if (load) { + set_s_register_from_sinteger( + 2 * reg, ReadW(reinterpret_cast<int32_t>(address), instr)); + set_s_register_from_sinteger( + 2 * reg + 1, ReadW(reinterpret_cast<int32_t>(address + 1), instr)); + } else { + WriteW(reinterpret_cast<int32_t>(address), + get_sinteger_from_s_register(2 * reg), instr); + WriteW(reinterpret_cast<int32_t>(address + 1), + get_sinteger_from_s_register(2 * reg + 1), instr); + } + address += 2; + } + } + ASSERT(reinterpret_cast<intptr_t>(address) - operand_size == end_address); +} + + // Calls into the V8 runtime are based on this very simple interface. // 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 @@ -1533,7 +1696,8 @@ typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, - int32_t arg4); + int32_t arg4, + int32_t arg5); typedef double (*SimulatorRuntimeFPCall)(int32_t arg0, int32_t arg1, int32_t arg2, @@ -1564,28 +1728,94 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { int32_t arg2 = get_register(r2); int32_t arg3 = get_register(r3); int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp)); - int32_t arg4 = *stack_pointer; + int32_t arg4 = stack_pointer[0]; + int32_t arg5 = stack_pointer[1]; + bool fp_call = + (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) || + (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) || + (redirection->type() == ExternalReference::BUILTIN_FP_CALL) || + (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL); + if (use_eabi_hardfloat()) { + // With the hard floating point calling convention, double + // arguments are passed in VFP 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 = vfp_register[0]; + arg1 = vfp_register[1]; + arg2 = vfp_register[2]; + arg3 = vfp_register[3]; + break; + case ExternalReference::BUILTIN_FP_CALL: + arg0 = vfp_register[0]; + arg1 = vfp_register[1]; + break; + case ExternalReference::BUILTIN_FP_INT_CALL: + arg0 = vfp_register[0]; + arg1 = vfp_register[1]; + arg2 = get_register(0); + 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_lr = get_register(lr); intptr_t external = reinterpret_cast<intptr_t>(redirection->external_function()); - if (redirection->type() == ExternalReference::FP_RETURN_CALL) { - SimulatorRuntimeFPCall target = - reinterpret_cast<SimulatorRuntimeFPCall>(external); + if (fp_call) { if (::v8::internal::FLAG_trace_sim || !stack_aligned) { - double x, y; - GetFpArgs(&x, &y); - PrintF("Call to host function at %p with args %f, %f", - FUNCTION_ADDR(target), x, y); + SimulatorRuntimeFPCall target = + reinterpret_cast<SimulatorRuntimeFPCall>(external); + 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), dval0); + 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; + } if (!stack_aligned) { PrintF(" with unaligned stack %08x\n", get_register(sp)); } PrintF("\n"); } CHECK(stack_aligned); - double result = target(arg0, arg1, arg2, arg3); - SetFpResult(result); + if (redirection->type() != ExternalReference::BUILTIN_COMPARE_CALL) { + SimulatorRuntimeFPCall target = + reinterpret_cast<SimulatorRuntimeFPCall>(external); + double result = target(arg0, arg1, arg2, arg3); + SetFpResult(result); + } else { + SimulatorRuntimeCall target = + reinterpret_cast<SimulatorRuntimeCall>(external); + int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5); + 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); + } + set_register(r0, lo_res); + set_register(r1, hi_res); + } } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) { SimulatorRuntimeDirectApiCall target = reinterpret_cast<SimulatorRuntimeDirectApiCall>(external); @@ -1627,20 +1857,22 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { reinterpret_cast<SimulatorRuntimeCall>(external); if (::v8::internal::FLAG_trace_sim || !stack_aligned) { PrintF( - "Call to host function at %p args %08x, %08x, %08x, %08x, %0xc", + "Call to host function at %p" + "args %08x, %08x, %08x, %08x, %08x, %08x", FUNCTION_ADDR(target), arg0, arg1, arg2, arg3, - arg4); + arg4, + arg5); if (!stack_aligned) { PrintF(" with unaligned stack %08x\n", get_register(sp)); } PrintF("\n"); } CHECK(stack_aligned); - int64_t result = target(arg0, arg1, arg2, arg3, arg4); + int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5); 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) { @@ -1654,7 +1886,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { break; } case kBreakpoint: { - Debugger dbg(this); + ArmDebugger dbg(this); dbg.Debug(); break; } @@ -1668,7 +1900,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { // Stop if it is enabled, otherwise go on jumping over the stop // and the message address. if (isEnabledStop(code)) { - Debugger dbg(this); + ArmDebugger dbg(this); dbg.Stop(instr); } else { set_pc(get_pc() + 2 * Instruction::kInstrSize); @@ -1976,7 +2208,7 @@ void Simulator::DecodeType01(Instruction* instr) { break; } case BKPT: { - Debugger dbg(this); + ArmDebugger dbg(this); PrintF("Simulator hit BKPT.\n"); dbg.Debug(); break; @@ -2088,8 +2320,15 @@ void Simulator::DecodeType01(Instruction* instr) { } case ADC: { - Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm"); - Format(instr, "adc'cond's 'rd, 'rn, 'imm"); + // Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm"); + // Format(instr, "adc'cond's 'rd, 'rn, 'imm"); + alu_out = rn_val + shifter_operand + GetCarry(); + set_register(rd, alu_out); + if (instr->HasS()) { + SetNZFlags(alu_out); + SetCFlag(CarryFrom(rn_val, shifter_operand, GetCarry())); + SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true)); + } break; } @@ -2467,6 +2706,8 @@ void Simulator::DecodeType7(Instruction* instr) { // vmov :Rt = Sn // vcvt: Dd = Sm // vcvt: Sd = Dm +// Dd = vabs(Dm) +// Dd = vneg(Dm) // Dd = vadd(Dn, Dm) // Dd = vsub(Dn, Dm) // Dd = vmul(Dn, Dm) @@ -2502,6 +2743,11 @@ void Simulator::DecodeTypeVFP(Instruction* instr) { double dm_value = get_double_from_d_register(vm); double dd_value = fabs(dm_value); set_d_register_from_double(vd, dd_value); + } else if ((instr->Opc2Value() == 0x1) && (instr->Opc3Value() == 0x1)) { + // vneg + double dm_value = get_double_from_d_register(vm); + double dd_value = -dm_value; + set_d_register_from_double(vd, dd_value); } else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) { DecodeVCVTBetweenDoubleAndSingle(instr); } else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) { @@ -2895,9 +3141,17 @@ void Simulator::DecodeType6CoprocessorIns(Instruction* instr) { } break; } + case 0x4: + case 0x5: + case 0x6: + case 0x7: + case 0x9: + case 0xB: + // Load/store multiple single from memory: vldm/vstm. + HandleVList(instr); + break; default: UNIMPLEMENTED(); // Not used by V8. - break; } } else if (instr->CoprocessorValue() == 0xB) { switch (instr->OpcodeValue()) { @@ -2944,9 +3198,14 @@ void Simulator::DecodeType6CoprocessorIns(Instruction* instr) { } break; } + case 0x4: + case 0x5: + case 0x9: + // Load/store multiple double from memory: vldm/vstm. + HandleVList(instr); + break; default: UNIMPLEMENTED(); // Not used by V8. - break; } } else { UNIMPLEMENTED(); // Not used by V8. @@ -2957,7 +3216,7 @@ void Simulator::DecodeType6CoprocessorIns(Instruction* instr) { // Executes the current instruction. void Simulator::InstructionDecode(Instruction* instr) { if (v8::internal::FLAG_check_icache) { - CheckICache(instr); + CheckICache(isolate_->simulator_i_cache(), instr); } pc_modified_ = false; if (::v8::internal::FLAG_trace_sim) { @@ -3040,7 +3299,7 @@ void Simulator::Execute() { Instruction* instr = reinterpret_cast<Instruction*>(program_counter); icount_++; if (icount_ == ::v8::internal::FLAG_stop_sim_at) { - Debugger dbg(this); + ArmDebugger dbg(this); dbg.Debug(); } else { InstructionDecode(instr); |