diff --git a/libxenia.vcxproj b/libxenia.vcxproj
index 9bfcc742a..35dd76a06 100644
--- a/libxenia.vcxproj
+++ b/libxenia.vcxproj
@@ -299,6 +299,7 @@
+
diff --git a/libxenia.vcxproj.filters b/libxenia.vcxproj.filters
index 1c4a2eac9..48681189a 100644
--- a/libxenia.vcxproj.filters
+++ b/libxenia.vcxproj.filters
@@ -1497,6 +1497,9 @@
src\xenia\cpu\compiler\passes
+
+ src\xenia\cpu\backend
+
diff --git a/src/xenia/cpu/backend/backend.cc b/src/xenia/cpu/backend/backend.cc
index 741957d66..090cb13f7 100644
--- a/src/xenia/cpu/backend/backend.cc
+++ b/src/xenia/cpu/backend/backend.cc
@@ -13,7 +13,8 @@ namespace xe {
namespace cpu {
namespace backend {
-Backend::Backend(Processor* processor) : processor_(processor) {
+Backend::Backend(Processor* processor)
+ : processor_(processor), code_cache_(nullptr) {
std::memset(&machine_info_, 0, sizeof(machine_info_));
}
diff --git a/src/xenia/cpu/backend/backend.h b/src/xenia/cpu/backend/backend.h
index 0777bb89f..463a2321b 100644
--- a/src/xenia/cpu/backend/backend.h
+++ b/src/xenia/cpu/backend/backend.h
@@ -25,6 +25,7 @@ namespace cpu {
namespace backend {
class Assembler;
+class CodeCache;
class Backend {
public:
@@ -33,6 +34,7 @@ class Backend {
Processor* processor() const { return processor_; }
const MachineInfo* machine_info() const { return &machine_info_; }
+ CodeCache* code_cache() const { return code_cache_; }
virtual bool Initialize();
@@ -47,6 +49,7 @@ class Backend {
protected:
Processor* processor_;
MachineInfo machine_info_;
+ CodeCache* code_cache_;
};
} // namespace backend
diff --git a/src/xenia/cpu/backend/code_cache.h b/src/xenia/cpu/backend/code_cache.h
new file mode 100644
index 000000000..c00e3302a
--- /dev/null
+++ b/src/xenia/cpu/backend/code_cache.h
@@ -0,0 +1,33 @@
+/**
+ ******************************************************************************
+ * Xenia : Xbox 360 Emulator Research Project *
+ ******************************************************************************
+ * Copyright 2015 Ben Vanik. All rights reserved. *
+ * Released under the BSD license - see LICENSE in the root for more details. *
+ ******************************************************************************
+ */
+
+#ifndef XENIA_BACKEND_CODE_CACHE_H_
+#define XENIA_BACKEND_CODE_CACHE_H_
+
+#include
+
+namespace xe {
+namespace cpu {
+namespace backend {
+
+class CodeCache {
+ public:
+ CodeCache() = default;
+ virtual ~CodeCache() = default;
+
+ virtual std::wstring file_name() const = 0;
+ virtual uint32_t base_address() const = 0;
+ virtual uint32_t total_size() const = 0;
+};
+
+} // namespace backend
+} // namespace cpu
+} // namespace xe
+
+#endif // XENIA_BACKEND_CODE_CACHE_H_
diff --git a/src/xenia/cpu/backend/x64/x64_backend.cc b/src/xenia/cpu/backend/x64/x64_backend.cc
index d77ff60aa..f892453b5 100644
--- a/src/xenia/cpu/backend/x64/x64_backend.cc
+++ b/src/xenia/cpu/backend/x64/x64_backend.cc
@@ -62,6 +62,7 @@ bool X64Backend::Initialize() {
};
code_cache_ = new X64CodeCache();
+ Backend::code_cache_ = code_cache_;
if (!code_cache_->Initialize()) {
return false;
}
diff --git a/src/xenia/cpu/backend/x64/x64_code_cache.cc b/src/xenia/cpu/backend/x64/x64_code_cache.cc
index 6b02e65e4..be027ab74 100644
--- a/src/xenia/cpu/backend/x64/x64_code_cache.cc
+++ b/src/xenia/cpu/backend/x64/x64_code_cache.cc
@@ -10,6 +10,7 @@
#include "xenia/cpu/backend/x64/x64_code_cache.h"
#include "xenia/base/assert.h"
+#include "xenia/base/clock.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/base/memory.h"
@@ -24,7 +25,8 @@ namespace x64 {
const static uint32_t kUnwindInfoSize = 4 + (2 * 1 + 2 + 2);
X64CodeCache::X64CodeCache()
- : indirection_default_value_(0xFEEDF00D),
+ : mapping_(nullptr),
+ indirection_default_value_(0xFEEDF00D),
indirection_table_base_(nullptr),
generated_code_base_(nullptr),
generated_code_offset_(0),
@@ -39,8 +41,11 @@ X64CodeCache::~X64CodeCache() {
if (indirection_table_base_) {
VirtualFree(indirection_table_base_, 0, MEM_RELEASE);
}
- if (generated_code_base_) {
- VirtualFree(generated_code_base_, 0, MEM_RELEASE);
+ // Unmap all views and close mapping.
+ if (mapping_) {
+ UnmapViewOfFile(generated_code_base_);
+ CloseHandle(mapping_);
+ mapping_ = 0;
}
}
@@ -57,9 +62,22 @@ bool X64CodeCache::Initialize() {
return false;
}
- generated_code_base_ = reinterpret_cast(
- VirtualAlloc(reinterpret_cast(kGeneratedCodeBase),
- kGeneratedCodeSize, MEM_RESERVE, PAGE_EXECUTE_READWRITE));
+ // Create mmap file. This allows us to share the code cache with the debugger.
+ wchar_t file_name[256];
+ wsprintf(file_name, L"Local\\xenia_code_cache_%p", Clock::QueryHostTickCount());
+ file_name_ = file_name;
+ mapping_ = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
+ PAGE_EXECUTE_READWRITE | SEC_RESERVE, 0,
+ kGeneratedCodeSize, file_name_.c_str());
+ if (!mapping_) {
+ XELOGE("Unable to create code cache mmap");
+ return false;
+ }
+
+ // Mapp generated code region into the file. Pages are committed as required.
+ generated_code_base_ = reinterpret_cast(MapViewOfFileEx(
+ mapping_, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0,
+ kGeneratedCodeSize, reinterpret_cast(kGeneratedCodeBase)));
if (!generated_code_base_) {
XELOGE("Unable to allocate code cache generated code storage");
XELOGE(
@@ -103,7 +121,7 @@ void X64CodeCache::CommitExecutableRange(uint32_t guest_low,
uint32_t guest_high) {
// Commit the memory.
VirtualAlloc(indirection_table_base_ + (guest_low - kIndirectionTableBase),
- guest_high - guest_low, MEM_COMMIT, PAGE_READWRITE);
+ guest_high - guest_low, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// Fill memory with the default value.
uint32_t* p = reinterpret_cast(indirection_table_base_);
diff --git a/src/xenia/cpu/backend/x64/x64_code_cache.h b/src/xenia/cpu/backend/x64/x64_code_cache.h
index 2ee785c5d..5fe7cb529 100644
--- a/src/xenia/cpu/backend/x64/x64_code_cache.h
+++ b/src/xenia/cpu/backend/x64/x64_code_cache.h
@@ -10,27 +10,31 @@
#ifndef XENIA_BACKEND_X64_X64_CODE_CACHE_H_
#define XENIA_BACKEND_X64_X64_CODE_CACHE_H_
-// For RUNTIME_FUNCTION:
-#include "xenia/base/platform.h"
-
#include
#include
+#include
#include
#include "xenia/base/mutex.h"
+#include "xenia/base/platform.h"
+#include "xenia/cpu/backend/code_cache.h"
namespace xe {
namespace cpu {
namespace backend {
namespace x64 {
-class X64CodeCache {
+class X64CodeCache : public CodeCache {
public:
X64CodeCache();
- virtual ~X64CodeCache();
+ ~X64CodeCache() override;
bool Initialize();
+ std::wstring file_name() const override { return file_name_; }
+ uint32_t base_address() const override { return kGeneratedCodeBase; }
+ uint32_t total_size() const override { return kGeneratedCodeSize; }
+
// TODO(benvanik): ELF serialization/etc
// TODO(benvanik): keep track of code blocks
// TODO(benvanik): padding/guards/etc
@@ -55,6 +59,9 @@ class X64CodeCache {
size_t unwind_table_slot, uint8_t* code_address,
size_t code_size, size_t stack_size);
+ std::wstring file_name_;
+ HANDLE mapping_;
+
// Must be held when manipulating the offsets or counts of anything, to keep
// the tables consistent and ordered.
xe::mutex allocation_mutex_;