Custom stack for IVM. 2-3x faster.

This commit is contained in:
Ben Vanik 2014-01-06 23:11:10 -08:00
parent 2ed6f478c1
commit 698eaeeb88
6 changed files with 155 additions and 9 deletions

View File

@ -10,6 +10,7 @@
#include <alloy/backend/ivm/ivm_backend.h>
#include <alloy/backend/ivm/ivm_assembler.h>
#include <alloy/backend/ivm/ivm_stack.h>
#include <alloy/backend/ivm/tracing.h>
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);
}

View File

@ -30,6 +30,9 @@ public:
virtual int Initialize();
virtual void* AllocThreadData();
virtual void FreeThreadData(void* thread_data);
virtual Assembler* CreateAssembler();
};

View File

@ -9,6 +9,7 @@
#include <alloy/backend/ivm/ivm_function.h>
#include <alloy/backend/ivm/ivm_stack.h>
#include <alloy/backend/tracing.h>
#include <alloy/runtime/runtime.h>
#include <alloy/runtime/thread_state.h>
@ -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;
}

View File

@ -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 <alloy/backend/ivm/ivm_stack.h>
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);
}
}

View File

@ -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 <alloy/core.h>
#include <alloy/backend/ivm/ivm_intcode.h>
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_

View File

@ -8,7 +8,8 @@
'ivm_backend.cc',
'ivm_backend.h',
'ivm_function.cc',
'ivm_function.h',
'ivm_stack.cc',
'ivm_stack.h',
'tracing.h',
],
}