Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2008 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. | 11 // with the distribution. |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include <stdlib.h> | 28 #include <stdlib.h> |
| 29 | 29 |
| 30 #include "v8.h" | 30 #include "v8.h" |
| 31 | 31 |
| 32 #include "disasm.h" | 32 #include "disasm.h" |
| 33 #include "assembler.h" | |
| 33 #include "arm/constants-arm.h" | 34 #include "arm/constants-arm.h" |
| 34 #include "arm/simulator-arm.h" | 35 #include "arm/simulator-arm.h" |
| 35 | 36 |
| 36 #if !defined(__arm__) | 37 #if !defined(__arm__) |
| 37 | 38 |
| 38 // Only build the simulator if not compiling for real ARM hardware. | 39 // Only build the simulator if not compiling for real ARM hardware. |
| 39 namespace assembler { | 40 namespace assembler { |
| 40 namespace arm { | 41 namespace arm { |
| 41 | 42 |
| 42 using ::v8::internal::Object; | 43 using ::v8::internal::Object; |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 373 RedoBreakpoints(); | 374 RedoBreakpoints(); |
| 374 | 375 |
| 375 #undef COMMAND_SIZE | 376 #undef COMMAND_SIZE |
| 376 #undef ARG_SIZE | 377 #undef ARG_SIZE |
| 377 | 378 |
| 378 #undef STR | 379 #undef STR |
| 379 #undef XSTR | 380 #undef XSTR |
| 380 } | 381 } |
| 381 | 382 |
| 382 | 383 |
| 384 bool Simulator::initialized_ = false; | |
| 385 | |
| 386 | |
| 387 void Simulator::Initialize() { | |
| 388 if (initialized_) return; | |
| 389 initialized_ = true; | |
| 390 ::v8::internal::ExternalReference::set_redirector(&RedirectExternalReference); | |
| 391 } | |
| 392 | |
| 393 | |
| 383 Simulator::Simulator() { | 394 Simulator::Simulator() { |
| 395 ASSERT(initialized_); | |
| 384 // Setup simulator support first. Some of this information is needed to | 396 // Setup simulator support first. Some of this information is needed to |
| 385 // setup the architecture state. | 397 // setup the architecture state. |
| 386 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack | 398 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack |
| 387 stack_ = reinterpret_cast<char*>(malloc(stack_size)); | 399 stack_ = reinterpret_cast<char*>(malloc(stack_size)); |
| 388 pc_modified_ = false; | 400 pc_modified_ = false; |
| 389 icount_ = 0; | 401 icount_ = 0; |
| 390 break_pc_ = NULL; | 402 break_pc_ = NULL; |
| 391 break_instr_ = 0; | 403 break_instr_ = 0; |
| 392 | 404 |
| 393 // Setup architecture state. | 405 // Setup architecture state. |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 405 // some buffer below. | 417 // some buffer below. |
| 406 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64; | 418 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64; |
| 407 // The lr and pc are initialized to a known bad value that will cause an | 419 // The lr and pc are initialized to a known bad value that will cause an |
| 408 // access violation if the simulator ever tries to execute it. | 420 // access violation if the simulator ever tries to execute it. |
| 409 registers_[pc] = bad_lr; | 421 registers_[pc] = bad_lr; |
| 410 registers_[lr] = bad_lr; | 422 registers_[lr] = bad_lr; |
| 411 InitializeCoverage(); | 423 InitializeCoverage(); |
| 412 } | 424 } |
| 413 | 425 |
| 414 | 426 |
| 427 // When the generated code calls an external reference we need to catch that in | |
| 428 // the simulator. The external reference will be a function compiled for the | |
| 429 // host architecture. We need to call that function instead of trying to | |
| 430 // execute it with the simulator. We do that by redirecting the external | |
| 431 // reference to a swi (software-interrupt) instruction that is handled by | |
| 432 // the simulator. We write the original destination of the jump just after the | |
|
iposva
2009/06/08 21:48:41
Please change the comment to say "We write the ori
| |
| 433 // swi instruction so the simulator knows what to call. | |
| 434 class Redirection { | |
| 435 public: | |
| 436 Redirection(void* external_function, bool fp_return) | |
| 437 : external_function_(external_function), | |
| 438 swi_instruction_((AL << 28) | (0xf << 24) | call_rt_redirected), | |
| 439 fp_return_(fp_return), | |
| 440 next_(list_) { | |
| 441 list_ = this; | |
| 442 } | |
| 443 | |
| 444 void* address_of_swi_instruction() { | |
| 445 return reinterpret_cast<void*>(&swi_instruction_); | |
| 446 } | |
| 447 | |
| 448 void* external_function() { return external_function_; } | |
| 449 bool fp_return() { return fp_return_; } | |
| 450 | |
| 451 static Redirection* Get(void* external_function, bool fp_return) { | |
| 452 Redirection* current; | |
| 453 for (current = list_; current != NULL; current = current->next_) { | |
| 454 if (current->external_function_ == external_function) return current; | |
| 455 } | |
| 456 return new Redirection(external_function, fp_return); | |
| 457 } | |
| 458 | |
| 459 static Redirection* FromSwiInstruction(Instr* swi_instruction) { | |
| 460 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction); | |
| 461 char* addr_of_redirection = | |
| 462 addr_of_swi - OFFSET_OF(Redirection, swi_instruction_); | |
| 463 return reinterpret_cast<Redirection*>(addr_of_redirection); | |
| 464 } | |
| 465 | |
| 466 private: | |
| 467 void* external_function_; | |
| 468 uint32_t swi_instruction_; | |
| 469 bool fp_return_; | |
| 470 Redirection* next_; | |
| 471 static Redirection* list_; | |
| 472 }; | |
| 473 | |
| 474 | |
| 475 Redirection* Redirection::list_ = NULL; | |
| 476 | |
| 477 | |
| 478 void* Simulator::RedirectExternalReference(void* external_function, | |
| 479 bool fp_return) { | |
| 480 Redirection* redirection = Redirection::Get(external_function, fp_return); | |
| 481 return redirection->address_of_swi_instruction(); | |
| 482 } | |
| 483 | |
| 484 | |
| 415 // Create one simulator per thread and keep it in thread local storage. | 485 // Create one simulator per thread and keep it in thread local storage. |
| 416 static v8::internal::Thread::LocalStorageKey simulator_key = | 486 static v8::internal::Thread::LocalStorageKey simulator_key = |
| 417 v8::internal::Thread::CreateThreadLocalKey(); | 487 v8::internal::Thread::CreateThreadLocalKey(); |
|
iposva
2009/06/08 21:48:41
Please move this static initializer into the Initi
| |
| 418 | 488 |
| 489 | |
| 419 // Get the active Simulator for the current thread. | 490 // Get the active Simulator for the current thread. |
| 420 Simulator* Simulator::current() { | 491 Simulator* Simulator::current() { |
| 421 Simulator* sim = reinterpret_cast<Simulator*>( | 492 Simulator* sim = reinterpret_cast<Simulator*>( |
| 422 v8::internal::Thread::GetThreadLocal(simulator_key)); | 493 v8::internal::Thread::GetThreadLocal(simulator_key)); |
| 423 if (sim == NULL) { | 494 if (sim == NULL) { |
| 424 // TODO(146): delete the simulator object when a thread goes away. | 495 // TODO(146): delete the simulator object when a thread goes away. |
| 425 sim = new Simulator(); | 496 sim = new Simulator(); |
| 426 v8::internal::Thread::SetThreadLocal(simulator_key, sim); | 497 v8::internal::Thread::SetThreadLocal(simulator_key, sim); |
| 427 } | 498 } |
| 428 return sim; | 499 return sim; |
| (...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 914 ASSERT(end_address == ((intptr_t)address) - 4); | 985 ASSERT(end_address == ((intptr_t)address) - 4); |
| 915 } | 986 } |
| 916 | 987 |
| 917 | 988 |
| 918 // Calls into the V8 runtime are based on this very simple interface. | 989 // Calls into the V8 runtime are based on this very simple interface. |
| 919 // Note: To be able to return two values from some calls the code in runtime.cc | 990 // Note: To be able to return two values from some calls the code in runtime.cc |
| 920 // uses the ObjectPair which is essentially two 32-bit values stuffed into a | 991 // uses the ObjectPair which is essentially two 32-bit values stuffed into a |
| 921 // 64-bit value. With the code below we assume that all runtime calls return | 992 // 64-bit value. With the code below we assume that all runtime calls return |
| 922 // 64 bits of result. If they don't, the r1 result register contains a bogus | 993 // 64 bits of result. If they don't, the r1 result register contains a bogus |
| 923 // value, which is fine because it is caller-saved. | 994 // value, which is fine because it is caller-saved. |
| 924 typedef int64_t (*SimulatorRuntimeCall)(intptr_t arg0, intptr_t arg1); | 995 typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0, |
| 996 int32_t arg1, | |
| 997 int32_t arg2, | |
| 998 int32_t arg3); | |
| 999 typedef double (*SimulatorRuntimeFPCall)(int32_t arg0, | |
| 1000 int32_t arg1, | |
| 1001 int32_t arg2, | |
| 1002 int32_t arg3); | |
| 925 | 1003 |
| 926 | 1004 |
| 927 // Software interrupt instructions are used by the simulator to call into the | 1005 // Software interrupt instructions are used by the simulator to call into the |
| 928 // C-based V8 runtime. | 1006 // C-based V8 runtime. |
| 929 void Simulator::SoftwareInterrupt(Instr* instr) { | 1007 void Simulator::SoftwareInterrupt(Instr* instr) { |
| 930 int swi = instr->SwiField(); | 1008 int swi = instr->SwiField(); |
| 931 switch (swi) { | 1009 switch (swi) { |
| 932 case call_rt_r5: { | 1010 case call_rt_redirected: { |
| 933 SimulatorRuntimeCall target = | 1011 Redirection* redirection = Redirection::FromSwiInstruction(instr); |
| 934 reinterpret_cast<SimulatorRuntimeCall>(get_register(r5)); | 1012 int32_t arg0 = get_register(r0); |
| 935 intptr_t arg0 = get_register(r0); | 1013 int32_t arg1 = get_register(r1); |
| 936 intptr_t arg1 = get_register(r1); | 1014 int32_t arg2 = get_register(r2); |
| 937 int64_t result = target(arg0, arg1); | 1015 int32_t arg3 = get_register(r3); |
| 938 int32_t lo_res = static_cast<int32_t>(result); | 1016 // This is dodgy but it works because the C entry stubs are never moved. |
| 939 int32_t hi_res = static_cast<int32_t>(result >> 32); | 1017 // See comment in codegen-arm.cc and bug 1242173. |
| 940 set_register(r0, lo_res); | 1018 int32_t saved_lr = get_register(lr); |
| 941 set_register(r1, hi_res); | 1019 if (redirection->fp_return()) { |
| 942 set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); | 1020 intptr_t external = |
| 943 break; | 1021 reinterpret_cast<intptr_t>(redirection->external_function()); |
| 944 } | 1022 SimulatorRuntimeFPCall target = |
| 945 case call_rt_r2: { | 1023 reinterpret_cast<SimulatorRuntimeFPCall>(external); |
| 946 SimulatorRuntimeCall target = | 1024 if (::v8::internal::FLAG_trace_sim) { |
| 947 reinterpret_cast<SimulatorRuntimeCall>(get_register(r2)); | 1025 double x, y; |
| 948 intptr_t arg0 = get_register(r0); | 1026 GetFpArgs(&x, &y); |
| 949 intptr_t arg1 = get_register(r1); | 1027 PrintF("Call to host function at %p with args %f, %f\n", |
| 950 int64_t result = target(arg0, arg1); | 1028 FUNCTION_ADDR(target), x, y); |
| 951 int32_t lo_res = static_cast<int32_t>(result); | 1029 } |
| 952 int32_t hi_res = static_cast<int32_t>(result >> 32); | 1030 double result = target(arg0, arg1, arg2, arg3); |
| 953 set_register(r0, lo_res); | 1031 SetFpResult(result); |
| 954 set_register(r1, hi_res); | 1032 } else { |
| 955 set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); | 1033 intptr_t external = |
| 1034 reinterpret_cast<int32_t>(redirection->external_function()); | |
| 1035 SimulatorRuntimeCall target = | |
| 1036 reinterpret_cast<SimulatorRuntimeCall>(external); | |
| 1037 if (::v8::internal::FLAG_trace_sim) { | |
| 1038 PrintF( | |
| 1039 "Call to host function at %p with args %08x, %08x, %08x, %08x\n", | |
| 1040 FUNCTION_ADDR(target), | |
| 1041 arg0, | |
| 1042 arg1, | |
| 1043 arg2, | |
| 1044 arg3); | |
| 1045 } | |
| 1046 int64_t result = target(arg0, arg1, arg2, arg3); | |
| 1047 int32_t lo_res = static_cast<int32_t>(result); | |
| 1048 int32_t hi_res = static_cast<int32_t>(result >> 32); | |
| 1049 set_register(r0, lo_res); | |
| 1050 set_register(r1, hi_res); | |
| 1051 set_register(r0, result); | |
|
iposva
2009/06/08 21:48:41
Isn't the second write to r0 redundant here? Stran
Erik Corry
2009/06/09 09:27:00
Fixed.
| |
| 1052 } | |
| 1053 set_register(lr, saved_lr); | |
| 1054 set_pc(get_register(lr)); | |
| 956 break; | 1055 break; |
| 957 } | 1056 } |
| 958 case break_point: { | 1057 case break_point: { |
| 959 Debugger dbg(this); | 1058 Debugger dbg(this); |
| 960 dbg.Debug(); | 1059 dbg.Debug(); |
| 961 break; | 1060 break; |
| 962 } | 1061 } |
| 963 { | |
| 964 double x, y, z; | |
| 965 case simulator_fp_add: | |
| 966 GetFpArgs(&x, &y); | |
| 967 z = x + y; | |
| 968 SetFpResult(z); | |
| 969 TrashCallerSaveRegisters(); | |
| 970 set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); | |
| 971 break; | |
| 972 case simulator_fp_sub: | |
| 973 GetFpArgs(&x, &y); | |
| 974 z = x - y; | |
| 975 SetFpResult(z); | |
| 976 TrashCallerSaveRegisters(); | |
| 977 set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); | |
| 978 break; | |
| 979 case simulator_fp_mul: | |
| 980 GetFpArgs(&x, &y); | |
| 981 z = x * y; | |
| 982 SetFpResult(z); | |
| 983 TrashCallerSaveRegisters(); | |
| 984 set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); | |
| 985 break; | |
| 986 } | |
| 987 default: { | 1062 default: { |
| 988 UNREACHABLE(); | 1063 UNREACHABLE(); |
| 989 break; | 1064 break; |
| 990 } | 1065 } |
| 991 } | 1066 } |
| 992 } | 1067 } |
| 993 | 1068 |
| 994 | 1069 |
| 995 // Handle execution based on instruction types. | 1070 // Handle execution based on instruction types. |
| 996 | 1071 |
| (...skipping 682 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1679 set_register(r10, r10_val); | 1754 set_register(r10, r10_val); |
| 1680 set_register(r11, r11_val); | 1755 set_register(r11, r11_val); |
| 1681 | 1756 |
| 1682 int result = get_register(r0); | 1757 int result = get_register(r0); |
| 1683 return reinterpret_cast<Object*>(result); | 1758 return reinterpret_cast<Object*>(result); |
| 1684 } | 1759 } |
| 1685 | 1760 |
| 1686 } } // namespace assembler::arm | 1761 } } // namespace assembler::arm |
| 1687 | 1762 |
| 1688 #endif // !defined(__arm__) | 1763 #endif // !defined(__arm__) |
| OLD | NEW |