Add checks to the ARM simulator to ensure that we flush the icache all
the places we should. Review URL: http://codereview.chromium.org/1523030 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4474 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
0720377a66
commit
5fab20edcd
@ -26,7 +26,7 @@
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// CPU specific code for arm independent of OS goes here.
|
||||
#if defined(__arm__)
|
||||
#ifdef __arm__
|
||||
#include <sys/syscall.h> // for cache flushing.
|
||||
#endif
|
||||
|
||||
@ -35,6 +35,10 @@
|
||||
#include "cpu.h"
|
||||
#include "macro-assembler.h"
|
||||
|
||||
#ifndef __arm__
|
||||
#include "simulator-arm.h" // for cache flushing.
|
||||
#endif
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
@ -46,9 +50,11 @@ void CPU::Setup() {
|
||||
void CPU::FlushICache(void* start, size_t size) {
|
||||
#if !defined (__arm__)
|
||||
// Not generating ARM instructions for C-code. This means that we are
|
||||
// building an ARM emulator based target. No I$ flushes are necessary.
|
||||
// building an ARM emulator based target. We should notify the simulator
|
||||
// that the Icache was flushed.
|
||||
// None of this code ends up in the snapshot so there are no issues
|
||||
// around whether or not to generate the code when building snapshots.
|
||||
assembler::arm::Simulator::FlushICache(start, size);
|
||||
#else
|
||||
// Ideally, we would call
|
||||
// syscall(__ARM_NR_cacheflush, start,
|
||||
|
@ -474,6 +474,96 @@ void Debugger::Debug() {
|
||||
}
|
||||
|
||||
|
||||
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 @@ void Simulator::Initialize() {
|
||||
}
|
||||
|
||||
|
||||
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 @@ class Redirection {
|
||||
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 @@ void Simulator::DecodeType6CoprocessorIns(Instr* instr) {
|
||||
|
||||
// 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 @@ uintptr_t Simulator::PopAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace assembler::arm
|
||||
|
||||
#endif // __arm__
|
||||
|
@ -89,11 +89,43 @@ class SimulatorStack : public v8::internal::AllStatic {
|
||||
|
||||
|
||||
#include "constants-arm.h"
|
||||
#include "hashmap.h"
|
||||
|
||||
|
||||
namespace assembler {
|
||||
namespace arm {
|
||||
|
||||
class CachePage {
|
||||
public:
|
||||
static const int LINE_VALID = 0;
|
||||
static const int LINE_INVALID = 1;
|
||||
|
||||
static const int kPageShift = 12;
|
||||
static const int kPageSize = 1 << kPageShift;
|
||||
static const int kPageMask = kPageSize - 1;
|
||||
static const int kLineShift = 2; // The cache line is only 4 bytes right now.
|
||||
static const int kLineLength = 1 << kLineShift;
|
||||
static const int kLineMask = kLineLength - 1;
|
||||
|
||||
CachePage() {
|
||||
memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
|
||||
}
|
||||
|
||||
char* ValidityByte(int offset) {
|
||||
return &validity_map_[offset >> kLineShift];
|
||||
}
|
||||
|
||||
char* CachedData(int offset) {
|
||||
return &data_[offset];
|
||||
}
|
||||
|
||||
private:
|
||||
char data_[kPageSize]; // The cached data.
|
||||
static const int kValidityMapSize = kPageSize >> kLineShift;
|
||||
char validity_map_[kValidityMapSize]; // One byte per line.
|
||||
};
|
||||
|
||||
|
||||
class Simulator {
|
||||
public:
|
||||
friend class Debugger;
|
||||
@ -162,6 +194,9 @@ class Simulator {
|
||||
// Pop an address from the JS stack.
|
||||
uintptr_t PopAddress();
|
||||
|
||||
// ICache checking.
|
||||
static void FlushICache(void* start, size_t size);
|
||||
|
||||
private:
|
||||
enum special_values {
|
||||
// Known bad pc value to ensure that the simulator does not execute
|
||||
@ -239,6 +274,11 @@ class Simulator {
|
||||
// Executes one instruction.
|
||||
void InstructionDecode(Instr* instr);
|
||||
|
||||
// ICache.
|
||||
static void CheckICache(Instr* instr);
|
||||
static void FlushOnePage(intptr_t start, int size);
|
||||
static CachePage* GetCachePage(void* page);
|
||||
|
||||
// Runtime call support.
|
||||
static void* RedirectExternalReference(void* external_function,
|
||||
bool fp_return);
|
||||
@ -276,6 +316,9 @@ class Simulator {
|
||||
int icount_;
|
||||
static bool initialized_;
|
||||
|
||||
// Icache simulation
|
||||
static v8::internal::HashMap* i_cache_;
|
||||
|
||||
// Registered breakpoints.
|
||||
Instr* break_pc_;
|
||||
instr_t break_instr_;
|
||||
|
@ -836,6 +836,9 @@ void Deserializer::ReadChunk(Object** current,
|
||||
case START_NEW_PAGE_SERIALIZATION: {
|
||||
int space = source_->Get();
|
||||
pages_[space].Add(last_object_address_);
|
||||
if (space == CODE_SPACE) {
|
||||
CPU::FlushICache(last_object_address_, Page::kPageSize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NATIVES_STRING_RESOURCE: {
|
||||
|
Loading…
Reference in New Issue
Block a user