From 698eaeeb886069c64447300a6fd2e0dd317c42e4 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Mon, 6 Jan 2014 23:11:10 -0800 Subject: [PATCH] Custom stack for IVM. 2-3x faster. --- src/alloy/backend/ivm/ivm_backend.cc | 10 ++++ src/alloy/backend/ivm/ivm_backend.h | 3 + src/alloy/backend/ivm/ivm_function.cc | 12 ++-- src/alloy/backend/ivm/ivm_stack.cc | 79 +++++++++++++++++++++++++++ src/alloy/backend/ivm/ivm_stack.h | 57 +++++++++++++++++++ src/alloy/backend/ivm/sources.gypi | 3 +- 6 files changed, 155 insertions(+), 9 deletions(-) create mode 100644 src/alloy/backend/ivm/ivm_stack.cc create mode 100644 src/alloy/backend/ivm/ivm_stack.h diff --git a/src/alloy/backend/ivm/ivm_backend.cc b/src/alloy/backend/ivm/ivm_backend.cc index 5d8955593..bb2a42f67 100644 --- a/src/alloy/backend/ivm/ivm_backend.cc +++ b/src/alloy/backend/ivm/ivm_backend.cc @@ -10,6 +10,7 @@ #include #include +#include #include using namespace alloy; @@ -39,6 +40,15 @@ int IVMBackend::Initialize() { return result; } +void* IVMBackend::AllocThreadData() { + return new IVMStack(); +} + +void IVMBackend::FreeThreadData(void* thread_data) { + auto stack = (IVMStack*)thread_data; + delete stack; +} + Assembler* IVMBackend::CreateAssembler() { return new IVMAssembler(this); } diff --git a/src/alloy/backend/ivm/ivm_backend.h b/src/alloy/backend/ivm/ivm_backend.h index 5cfa4b900..8ed333838 100644 --- a/src/alloy/backend/ivm/ivm_backend.h +++ b/src/alloy/backend/ivm/ivm_backend.h @@ -30,6 +30,9 @@ public: virtual int Initialize(); + virtual void* AllocThreadData(); + virtual void FreeThreadData(void* thread_data); + virtual Assembler* CreateAssembler(); }; diff --git a/src/alloy/backend/ivm/ivm_function.cc b/src/alloy/backend/ivm/ivm_function.cc index 84e31507f..e52c5039f 100644 --- a/src/alloy/backend/ivm/ivm_function.cc +++ b/src/alloy/backend/ivm/ivm_function.cc @@ -9,6 +9,7 @@ #include +#include #include #include #include @@ -103,11 +104,8 @@ void IVMFunction::OnBreakpointHit(ThreadState* thread_state, IntCode* i) { int IVMFunction::CallImpl(ThreadState* thread_state, uint64_t return_address) { // Setup register file on stack. - const size_t max_stack_alloc = 16 * 1024; - size_t register_file_size = register_count_ * sizeof(Register); - Register* register_file = (Register*)( - register_file_size >= max_stack_alloc ? - xe_malloc(register_file_size) : alloca(register_file_size)); + auto stack = (IVMStack*)thread_state->backend_data(); + auto register_file = (Register*)stack->Alloc(register_count_); Memory* memory = thread_state->memory(); @@ -151,9 +149,7 @@ int IVMFunction::CallImpl(ThreadState* thread_state, uint64_t return_address) { } } - if (register_file_size >= max_stack_alloc) { - xe_free(register_file); - } + stack->Free(register_count_); return 0; } diff --git a/src/alloy/backend/ivm/ivm_stack.cc b/src/alloy/backend/ivm/ivm_stack.cc new file mode 100644 index 000000000..4adb8c158 --- /dev/null +++ b/src/alloy/backend/ivm/ivm_stack.cc @@ -0,0 +1,79 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +using namespace alloy; +using namespace alloy::backend; +using namespace alloy::backend::ivm; + + +IVMStack::IVMStack() : + chunk_size_(2 * 1024 * 1024), + head_chunk_(NULL), active_chunk_(NULL) { +} + +IVMStack::~IVMStack() { + Chunk* chunk = head_chunk_; + while (chunk) { + Chunk* next = chunk->next; + delete chunk; + chunk = next; + } + head_chunk_ = NULL; +} + +Register* IVMStack::Alloc(size_t register_count) { + size_t size = register_count * sizeof(Register); + if (active_chunk_) { + if (active_chunk_->capacity - active_chunk_->offset < size) { + Chunk* next = active_chunk_->next; + if (!next) { + XEASSERT(size < chunk_size_); // need to support larger chunks + next = new Chunk(chunk_size_); + next->prev = active_chunk_; + active_chunk_->next = next; + } + next->offset = 0; + active_chunk_ = next; + } + } else { + head_chunk_ = active_chunk_ = new Chunk(chunk_size_); + } + + uint8_t* p = active_chunk_->buffer + active_chunk_->offset; + active_chunk_->offset += size; + return (Register*)p; +} + +void IVMStack::Free(size_t register_count) { + size_t size = register_count * sizeof(Register); + if (active_chunk_->offset == size) { + // Moving back a chunk. + active_chunk_->offset = 0; + if (active_chunk_->prev) { + active_chunk_ = active_chunk_->prev; + } + } else { + // Still in same chunk. + active_chunk_->offset -= size; + } +} + +IVMStack::Chunk::Chunk(size_t chunk_size) : + prev(NULL), next(NULL), + capacity(chunk_size), buffer(0), offset(0) { + buffer = (uint8_t*)xe_malloc(capacity); +} + +IVMStack::Chunk::~Chunk() { + if (buffer) { + xe_free(buffer); + } +} diff --git a/src/alloy/backend/ivm/ivm_stack.h b/src/alloy/backend/ivm/ivm_stack.h new file mode 100644 index 000000000..f2e955265 --- /dev/null +++ b/src/alloy/backend/ivm/ivm_stack.h @@ -0,0 +1,57 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_BACKEND_IVM_IVM_STACK_H_ +#define ALLOY_BACKEND_IVM_IVM_STACK_H_ + +#include + +#include + + +namespace alloy { +namespace backend { +namespace ivm { + + +class IVMStack { +public: + IVMStack(); + ~IVMStack(); + + Register* Alloc(size_t register_count); + void Free(size_t register_count); + +private: + class Chunk { + public: + Chunk(size_t chunk_size); + ~Chunk(); + + Chunk* prev; + Chunk* next; + + size_t capacity; + uint8_t* buffer; + size_t offset; + }; + +private: + size_t chunk_size_; + Chunk* head_chunk_; + Chunk* active_chunk_; +}; + + +} // namespace ivm +} // namespace backend +} // namespace alloy + + +#endif // ALLOY_BACKEND_IVM_IVM_STACK_H_ diff --git a/src/alloy/backend/ivm/sources.gypi b/src/alloy/backend/ivm/sources.gypi index 4b285c6e6..3216510e2 100644 --- a/src/alloy/backend/ivm/sources.gypi +++ b/src/alloy/backend/ivm/sources.gypi @@ -8,7 +8,8 @@ 'ivm_backend.cc', 'ivm_backend.h', 'ivm_function.cc', - 'ivm_function.h', + 'ivm_stack.cc', + 'ivm_stack.h', 'tracing.h', ], }