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 |