Index: src/arm/simulator-arm.cc |
=================================================================== |
--- src/arm/simulator-arm.cc (revision 4443) |
+++ src/arm/simulator-arm.cc (working copy) |
@@ -474,6 +474,96 @@ |
} |
+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; |
+} |
+ |
+ |
+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(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(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); |
+ } |
+} |
+ |
+ |
+CachePage* Simulator::GetCachePage(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(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); |
+ char* valid_bytemap = cache_page->ValidityByte(offset); |
+ memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift); |
+} |
+ |
+ |
+void Simulator::CheckICache(Instr* instr) { |
+#ifdef DEBUG |
+ 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); |
+ 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), |
+ Instr::kInstrSize) == 0); |
+ } else { |
+ // Cache miss. Load memory into the cache. |
+ memcpy(cached_line, line, CachePage::kLineLength); |
+ *cache_valid_byte = CachePage::LINE_VALID; |
+ } |
+#endif |
+} |
+ |
+ |
// Create one simulator per thread and keep it in thread local storage. |
static v8::internal::Thread::LocalStorageKey simulator_key; |
@@ -489,7 +579,13 @@ |
} |
+v8::internal::HashMap* Simulator::i_cache_ = NULL; |
+ |
+ |
Simulator::Simulator() { |
+ if (i_cache_ == NULL) { |
+ i_cache_ = new v8::internal::HashMap(&ICacheMatch); |
+ } |
Initialize(); |
// Setup simulator support first. Some of this information is needed to |
// setup the architecture state. |
@@ -554,6 +650,9 @@ |
swi_instruction_((AL << 28) | (0xf << 24) | call_rt_redirected), |
fp_return_(fp_return), |
next_(list_) { |
+ Simulator::current()-> |
+ FlushICache(reinterpret_cast<void*>(&swi_instruction_), |
+ Instr::kInstrSize); |
list_ = this; |
} |
@@ -2342,6 +2441,7 @@ |
// Executes the current instruction. |
void Simulator::InstructionDecode(Instr* instr) { |
+ CheckICache(instr); |
pc_modified_ = false; |
if (::v8::internal::FLAG_trace_sim) { |
disasm::NameConverter converter; |
@@ -2536,7 +2636,6 @@ |
return address; |
} |
- |
} } // namespace assembler::arm |
#endif // __arm__ |