| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 | 40 |
| 41 // Only build the simulator if not compiling for real ARM hardware. | 41 // Only build the simulator if not compiling for real ARM hardware. |
| 42 namespace assembler { | 42 namespace assembler { |
| 43 namespace arm { | 43 namespace arm { |
| 44 | 44 |
| 45 using ::v8::internal::Object; | 45 using ::v8::internal::Object; |
| 46 using ::v8::internal::PrintF; | 46 using ::v8::internal::PrintF; |
| 47 using ::v8::internal::OS; | 47 using ::v8::internal::OS; |
| 48 using ::v8::internal::ReadLine; | 48 using ::v8::internal::ReadLine; |
| 49 using ::v8::internal::DeleteArray; | 49 using ::v8::internal::DeleteArray; |
| 50 using ::v8::internal::Isolate; |
| 50 | 51 |
| 51 // This macro provides a platform independent use of sscanf. The reason for | 52 // This macro provides a platform independent use of sscanf. The reason for |
| 52 // SScanF not being implemented in a platform independent way through | 53 // SScanF not being implemented in a platform independent way through |
| 53 // ::v8::internal::OS in the same way as SNPrintF is that the | 54 // ::v8::internal::OS in the same way as SNPrintF is that the |
| 54 // Windows C Run-Time Library does not provide vsscanf. | 55 // Windows C Run-Time Library does not provide vsscanf. |
| 55 #define SScanF sscanf // NOLINT | 56 #define SScanF sscanf // NOLINT |
| 56 | 57 |
| 57 // The Debugger class is used by the simulator while debugging simulated ARM | 58 // The Debugger class is used by the simulator while debugging simulated ARM |
| 58 // code. | 59 // code. |
| 59 class Debugger { | 60 class Debugger { |
| (...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 488 } | 489 } |
| 489 | 490 |
| 490 | 491 |
| 491 static bool AllOnOnePage(uintptr_t start, int size) { | 492 static bool AllOnOnePage(uintptr_t start, int size) { |
| 492 intptr_t start_page = (start & ~CachePage::kPageMask); | 493 intptr_t start_page = (start & ~CachePage::kPageMask); |
| 493 intptr_t end_page = ((start + size) & ~CachePage::kPageMask); | 494 intptr_t end_page = ((start + size) & ~CachePage::kPageMask); |
| 494 return start_page == end_page; | 495 return start_page == end_page; |
| 495 } | 496 } |
| 496 | 497 |
| 497 | 498 |
| 498 void Simulator::FlushICache(void* start_addr, size_t size) { | 499 void Simulator::FlushICache(v8::internal::HashMap* i_cache, |
| 500 void* start_addr, |
| 501 size_t size) { |
| 499 intptr_t start = reinterpret_cast<intptr_t>(start_addr); | 502 intptr_t start = reinterpret_cast<intptr_t>(start_addr); |
| 500 int intra_line = (start & CachePage::kLineMask); | 503 int intra_line = (start & CachePage::kLineMask); |
| 501 start -= intra_line; | 504 start -= intra_line; |
| 502 size += intra_line; | 505 size += intra_line; |
| 503 size = ((size - 1) | CachePage::kLineMask) + 1; | 506 size = ((size - 1) | CachePage::kLineMask) + 1; |
| 504 int offset = (start & CachePage::kPageMask); | 507 int offset = (start & CachePage::kPageMask); |
| 505 while (!AllOnOnePage(start, size - 1)) { | 508 while (!AllOnOnePage(start, size - 1)) { |
| 506 int bytes_to_flush = CachePage::kPageSize - offset; | 509 int bytes_to_flush = CachePage::kPageSize - offset; |
| 507 FlushOnePage(start, bytes_to_flush); | 510 FlushOnePage(i_cache, start, bytes_to_flush); |
| 508 start += bytes_to_flush; | 511 start += bytes_to_flush; |
| 509 size -= bytes_to_flush; | 512 size -= bytes_to_flush; |
| 510 ASSERT_EQ(0, start & CachePage::kPageMask); | 513 ASSERT_EQ(0, start & CachePage::kPageMask); |
| 511 offset = 0; | 514 offset = 0; |
| 512 } | 515 } |
| 513 if (size != 0) { | 516 if (size != 0) { |
| 514 FlushOnePage(start, size); | 517 FlushOnePage(i_cache, start, size); |
| 515 } | 518 } |
| 516 } | 519 } |
| 517 | 520 |
| 518 | 521 |
| 519 CachePage* Simulator::GetCachePage(void* page) { | 522 CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) { |
| 520 v8::internal::HashMap::Entry* entry = i_cache_->Lookup(page, | 523 v8::internal::HashMap::Entry* entry = i_cache->Lookup(page, |
| 521 ICacheHash(page), | 524 ICacheHash(page), |
| 522 true); | 525 true); |
| 523 if (entry->value == NULL) { | 526 if (entry->value == NULL) { |
| 524 CachePage* new_page = new CachePage(); | 527 CachePage* new_page = new CachePage(); |
| 525 entry->value = new_page; | 528 entry->value = new_page; |
| 526 } | 529 } |
| 527 return reinterpret_cast<CachePage*>(entry->value); | 530 return reinterpret_cast<CachePage*>(entry->value); |
| 528 } | 531 } |
| 529 | 532 |
| 530 | 533 |
| 531 // Flush from start up to and not including start + size. | 534 // Flush from start up to and not including start + size. |
| 532 void Simulator::FlushOnePage(intptr_t start, int size) { | 535 void Simulator::FlushOnePage(v8::internal::HashMap* i_cache, |
| 536 intptr_t start, |
| 537 int size) { |
| 533 ASSERT(size <= CachePage::kPageSize); | 538 ASSERT(size <= CachePage::kPageSize); |
| 534 ASSERT(AllOnOnePage(start, size - 1)); | 539 ASSERT(AllOnOnePage(start, size - 1)); |
| 535 ASSERT((start & CachePage::kLineMask) == 0); | 540 ASSERT((start & CachePage::kLineMask) == 0); |
| 536 ASSERT((size & CachePage::kLineMask) == 0); | 541 ASSERT((size & CachePage::kLineMask) == 0); |
| 537 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask)); | 542 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask)); |
| 538 int offset = (start & CachePage::kPageMask); | 543 int offset = (start & CachePage::kPageMask); |
| 539 CachePage* cache_page = GetCachePage(page); | 544 CachePage* cache_page = GetCachePage(i_cache, page); |
| 540 char* valid_bytemap = cache_page->ValidityByte(offset); | 545 char* valid_bytemap = cache_page->ValidityByte(offset); |
| 541 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift); | 546 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift); |
| 542 } | 547 } |
| 543 | 548 |
| 544 | 549 |
| 545 void Simulator::CheckICache(Instr* instr) { | 550 void Simulator::CheckICache(v8::internal::HashMap* i_cache, Instr* instr) { |
| 546 intptr_t address = reinterpret_cast<intptr_t>(instr); | 551 intptr_t address = reinterpret_cast<intptr_t>(instr); |
| 547 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask)); | 552 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask)); |
| 548 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask)); | 553 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask)); |
| 549 int offset = (address & CachePage::kPageMask); | 554 int offset = (address & CachePage::kPageMask); |
| 550 CachePage* cache_page = GetCachePage(page); | 555 CachePage* cache_page = GetCachePage(i_cache, page); |
| 551 char* cache_valid_byte = cache_page->ValidityByte(offset); | 556 char* cache_valid_byte = cache_page->ValidityByte(offset); |
| 552 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID); | 557 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID); |
| 553 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask); | 558 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask); |
| 554 if (cache_hit) { | 559 if (cache_hit) { |
| 555 // Check that the data in memory matches the contents of the I-cache. | 560 // Check that the data in memory matches the contents of the I-cache. |
| 556 CHECK(memcmp(reinterpret_cast<void*>(instr), | 561 CHECK(memcmp(reinterpret_cast<void*>(instr), |
| 557 cache_page->CachedData(offset), | 562 cache_page->CachedData(offset), |
| 558 Instr::kInstrSize) == 0); | 563 Instr::kInstrSize) == 0); |
| 559 } else { | 564 } else { |
| 560 // Cache miss. Load memory into the cache. | 565 // Cache miss. Load memory into the cache. |
| 561 memcpy(cached_line, line, CachePage::kLineLength); | 566 memcpy(cached_line, line, CachePage::kLineLength); |
| 562 *cache_valid_byte = CachePage::LINE_VALID; | 567 *cache_valid_byte = CachePage::LINE_VALID; |
| 563 } | 568 } |
| 564 } | 569 } |
| 565 | 570 |
| 566 | 571 |
| 567 // Create one simulator per thread and keep it in thread local storage. | |
| 568 static v8::internal::Thread::LocalStorageKey simulator_key; | |
| 569 | |
| 570 | |
| 571 bool Simulator::initialized_ = false; | |
| 572 | |
| 573 | |
| 574 void Simulator::Initialize() { | 572 void Simulator::Initialize() { |
| 575 if (initialized_) return; | 573 if (Isolate::Current()->simulator_initialized()) return; |
| 576 simulator_key = v8::internal::Thread::CreateThreadLocalKey(); | 574 Isolate::Current()->set_simulator_initialized(true); |
| 577 initialized_ = true; | |
| 578 ::v8::internal::ExternalReference::set_redirector(&RedirectExternalReference); | 575 ::v8::internal::ExternalReference::set_redirector(&RedirectExternalReference); |
| 579 } | 576 } |
| 580 | 577 |
| 581 | 578 |
| 582 v8::internal::HashMap* Simulator::i_cache_ = NULL; | 579 Simulator::Simulator() : isolate_(Isolate::Current()) { |
| 583 | 580 i_cache_ = isolate_->simulator_i_cache(); |
| 584 | |
| 585 Simulator::Simulator() { | |
| 586 if (i_cache_ == NULL) { | 581 if (i_cache_ == NULL) { |
| 587 i_cache_ = new v8::internal::HashMap(&ICacheMatch); | 582 i_cache_ = new v8::internal::HashMap(&ICacheMatch); |
| 583 isolate_->set_simulator_i_cache(i_cache_); |
| 588 } | 584 } |
| 589 Initialize(); | 585 Initialize(); |
| 590 // Setup simulator support first. Some of this information is needed to | 586 // Setup simulator support first. Some of this information is needed to |
| 591 // setup the architecture state. | 587 // setup the architecture state. |
| 592 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack | 588 size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack |
| 593 stack_ = reinterpret_cast<char*>(malloc(stack_size)); | 589 stack_ = reinterpret_cast<char*>(malloc(stack_size)); |
| 594 pc_modified_ = false; | 590 pc_modified_ = false; |
| 595 icount_ = 0; | 591 icount_ = 0; |
| 596 break_pc_ = NULL; | 592 break_pc_ = NULL; |
| 597 break_instr_ = 0; | 593 break_instr_ = 0; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 642 // execute it with the simulator. We do that by redirecting the external | 638 // execute it with the simulator. We do that by redirecting the external |
| 643 // reference to a swi (software-interrupt) instruction that is handled by | 639 // reference to a swi (software-interrupt) instruction that is handled by |
| 644 // the simulator. We write the original destination of the jump just at a known | 640 // the simulator. We write the original destination of the jump just at a known |
| 645 // offset from the swi instruction so the simulator knows what to call. | 641 // offset from the swi instruction so the simulator knows what to call. |
| 646 class Redirection { | 642 class Redirection { |
| 647 public: | 643 public: |
| 648 Redirection(void* external_function, bool fp_return) | 644 Redirection(void* external_function, bool fp_return) |
| 649 : external_function_(external_function), | 645 : external_function_(external_function), |
| 650 swi_instruction_((AL << 28) | (0xf << 24) | call_rt_redirected), | 646 swi_instruction_((AL << 28) | (0xf << 24) | call_rt_redirected), |
| 651 fp_return_(fp_return), | 647 fp_return_(fp_return), |
| 652 next_(list_) { | 648 next_(NULL) { |
| 653 Simulator::current()-> | 649 v8::internal::Isolate* isolate = Isolate::Current(); |
| 654 FlushICache(reinterpret_cast<void*>(&swi_instruction_), | 650 next_ = isolate->simulator_redirection(); |
| 655 Instr::kInstrSize); | 651 Simulator::FlushICache(isolate->simulator_i_cache(), |
| 656 list_ = this; | 652 reinterpret_cast<void*>(&swi_instruction_), |
| 653 Instr::kInstrSize); |
| 654 isolate->set_simulator_redirection(this); |
| 657 } | 655 } |
| 658 | 656 |
| 659 void* address_of_swi_instruction() { | 657 void* address_of_swi_instruction() { |
| 660 return reinterpret_cast<void*>(&swi_instruction_); | 658 return reinterpret_cast<void*>(&swi_instruction_); |
| 661 } | 659 } |
| 662 | 660 |
| 663 void* external_function() { return external_function_; } | 661 void* external_function() { return external_function_; } |
| 664 bool fp_return() { return fp_return_; } | 662 bool fp_return() { return fp_return_; } |
| 665 | 663 |
| 666 static Redirection* Get(void* external_function, bool fp_return) { | 664 static Redirection* Get(void* external_function, bool fp_return) { |
| 667 Redirection* current; | 665 Isolate* isolate = Isolate::Current(); |
| 668 for (current = list_; current != NULL; current = current->next_) { | 666 Redirection* current = isolate->simulator_redirection(); |
| 667 for (; current != NULL; current = current->next_) { |
| 669 if (current->external_function_ == external_function) return current; | 668 if (current->external_function_ == external_function) return current; |
| 670 } | 669 } |
| 671 return new Redirection(external_function, fp_return); | 670 return new Redirection(external_function, fp_return); |
| 672 } | 671 } |
| 673 | 672 |
| 674 static Redirection* FromSwiInstruction(Instr* swi_instruction) { | 673 static Redirection* FromSwiInstruction(Instr* swi_instruction) { |
| 675 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction); | 674 char* addr_of_swi = reinterpret_cast<char*>(swi_instruction); |
| 676 char* addr_of_redirection = | 675 char* addr_of_redirection = |
| 677 addr_of_swi - OFFSET_OF(Redirection, swi_instruction_); | 676 addr_of_swi - OFFSET_OF(Redirection, swi_instruction_); |
| 678 return reinterpret_cast<Redirection*>(addr_of_redirection); | 677 return reinterpret_cast<Redirection*>(addr_of_redirection); |
| 679 } | 678 } |
| 680 | 679 |
| 681 private: | 680 private: |
| 682 void* external_function_; | 681 void* external_function_; |
| 683 uint32_t swi_instruction_; | 682 uint32_t swi_instruction_; |
| 684 bool fp_return_; | 683 bool fp_return_; |
| 685 Redirection* next_; | 684 Redirection* next_; |
| 686 static Redirection* list_; | |
| 687 }; | 685 }; |
| 688 | 686 |
| 689 | 687 |
| 690 Redirection* Redirection::list_ = NULL; | |
| 691 | |
| 692 | |
| 693 void* Simulator::RedirectExternalReference(void* external_function, | 688 void* Simulator::RedirectExternalReference(void* external_function, |
| 694 bool fp_return) { | 689 bool fp_return) { |
| 695 Redirection* redirection = Redirection::Get(external_function, fp_return); | 690 Redirection* redirection = Redirection::Get(external_function, fp_return); |
| 696 return redirection->address_of_swi_instruction(); | 691 return redirection->address_of_swi_instruction(); |
| 697 } | 692 } |
| 698 | 693 |
| 699 | 694 |
| 700 // Get the active Simulator for the current thread. | 695 // Get the active Simulator for the current thread. |
| 701 Simulator* Simulator::current() { | 696 Simulator* Simulator::current(Isolate* isolate) { |
| 697 v8::internal::Thread::LocalStorageKey* simulator_key = |
| 698 Isolate::Current()->simulator_key(); |
| 702 Initialize(); | 699 Initialize(); |
| 703 Simulator* sim = reinterpret_cast<Simulator*>( | 700 Simulator* sim = reinterpret_cast<Simulator*>( |
| 704 v8::internal::Thread::GetThreadLocal(simulator_key)); | 701 v8::internal::Thread::GetThreadLocal(*simulator_key)); |
| 705 if (sim == NULL) { | 702 if (sim == NULL) { |
| 706 // TODO(146): delete the simulator object when a thread goes away. | 703 // TODO(146): delete the simulator object when a thread goes away. |
| 707 sim = new Simulator(); | 704 sim = new Simulator(); |
| 708 v8::internal::Thread::SetThreadLocal(simulator_key, sim); | 705 v8::internal::Thread::SetThreadLocal(*simulator_key, sim); |
| 709 } | 706 } |
| 710 return sim; | 707 return sim; |
| 711 } | 708 } |
| 712 | 709 |
| 713 | 710 |
| 714 // Sets the register in the architecture state. It will also deal with updating | 711 // Sets the register in the architecture state. It will also deal with updating |
| 715 // Simulator internal state for special registers such as PC. | 712 // Simulator internal state for special registers such as PC. |
| 716 void Simulator::set_register(int reg, int32_t value) { | 713 void Simulator::set_register(int reg, int32_t value) { |
| 717 ASSERT((reg >= 0) && (reg < num_registers)); | 714 ASSERT((reg >= 0) && (reg < num_registers)); |
| 718 if (reg == pc) { | 715 if (reg == pc) { |
| (...skipping 1842 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2561 } | 2558 } |
| 2562 } else { | 2559 } else { |
| 2563 UNIMPLEMENTED(); // Not used by V8. | 2560 UNIMPLEMENTED(); // Not used by V8. |
| 2564 } | 2561 } |
| 2565 } | 2562 } |
| 2566 | 2563 |
| 2567 | 2564 |
| 2568 // Executes the current instruction. | 2565 // Executes the current instruction. |
| 2569 void Simulator::InstructionDecode(Instr* instr) { | 2566 void Simulator::InstructionDecode(Instr* instr) { |
| 2570 if (v8::internal::FLAG_check_icache) { | 2567 if (v8::internal::FLAG_check_icache) { |
| 2571 CheckICache(instr); | 2568 CheckICache(isolate_->simulator_i_cache(), instr); |
| 2572 } | 2569 } |
| 2573 pc_modified_ = false; | 2570 pc_modified_ = false; |
| 2574 if (::v8::internal::FLAG_trace_sim) { | 2571 if (::v8::internal::FLAG_trace_sim) { |
| 2575 disasm::NameConverter converter; | 2572 disasm::NameConverter converter; |
| 2576 disasm::Disassembler dasm(converter); | 2573 disasm::Disassembler dasm(converter); |
| 2577 // use a reasonably large buffer | 2574 // use a reasonably large buffer |
| 2578 v8::internal::EmbeddedVector<char, 256> buffer; | 2575 v8::internal::EmbeddedVector<char, 256> buffer; |
| 2579 dasm.InstructionDecode(buffer, | 2576 dasm.InstructionDecode(buffer, |
| 2580 reinterpret_cast<byte*>(instr)); | 2577 reinterpret_cast<byte*>(instr)); |
| 2581 PrintF(" 0x%08x %s\n", instr, buffer.start()); | 2578 PrintF(" 0x%08x %s\n", instr, buffer.start()); |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2762 uintptr_t address = *stack_slot; | 2759 uintptr_t address = *stack_slot; |
| 2763 set_register(sp, current_sp + sizeof(uintptr_t)); | 2760 set_register(sp, current_sp + sizeof(uintptr_t)); |
| 2764 return address; | 2761 return address; |
| 2765 } | 2762 } |
| 2766 | 2763 |
| 2767 } } // namespace assembler::arm | 2764 } } // namespace assembler::arm |
| 2768 | 2765 |
| 2769 #endif // __arm__ | 2766 #endif // __arm__ |
| 2770 | 2767 |
| 2771 #endif // V8_TARGET_ARCH_ARM | 2768 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |