diff --git a/src/xenia/base/arena.cc b/src/xenia/base/arena.cc index ec3a44606..9b619cf56 100644 --- a/src/xenia/base/arena.cc +++ b/src/xenia/base/arena.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -13,6 +13,7 @@ #include #include "xenia/base/assert.h" +#include "xenia/base/math.h" namespace xe { @@ -45,12 +46,25 @@ void Arena::DebugFill() { } } -void* Arena::Alloc(size_t size) { +void* Arena::Alloc(size_t size, size_t align) { + assert_true( + xe::bit_count(align) == 1 && align <= 16, + "align needs to be a power of 2 and not greater than Chunk alignment"); + + // for alignment + const auto get_padding = [this, align]() -> size_t { + const size_t mask = align - 1; + size_t deviation = active_chunk_->offset & mask; + return (align - deviation) & mask; + }; + if (active_chunk_) { - if (active_chunk_->capacity - active_chunk_->offset < size + 4096) { + if (active_chunk_->capacity - active_chunk_->offset < + size + get_padding() + 4096) { Chunk* next = active_chunk_->next; if (!next) { - assert_true(size < chunk_size_, "need to support larger chunks"); + assert_true(size + get_padding() < chunk_size_, + "need to support larger chunks"); next = new Chunk(chunk_size_); active_chunk_->next = next; } @@ -61,8 +75,11 @@ void* Arena::Alloc(size_t size) { head_chunk_ = active_chunk_ = new Chunk(chunk_size_); } + active_chunk_->offset += get_padding(); uint8_t* p = active_chunk_->buffer + active_chunk_->offset; active_chunk_->offset += size; + assert_true((reinterpret_cast(p) & (align - 1)) == 0, + "alignment failed"); return p; } @@ -113,6 +130,8 @@ void Arena::CloneContents(void* buffer, size_t buffer_length) { Arena::Chunk::Chunk(size_t chunk_size) : next(nullptr), capacity(chunk_size), buffer(0), offset(0) { buffer = reinterpret_cast(malloc(capacity)); + assert_true((reinterpret_cast(buffer) & size_t(15)) == 0, + "16 byte alignment required"); } Arena::Chunk::~Chunk() { diff --git a/src/xenia/base/arena.h b/src/xenia/base/arena.h index 8b6a90707..7dbdb7c2a 100644 --- a/src/xenia/base/arena.h +++ b/src/xenia/base/arena.h @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -24,11 +24,13 @@ class Arena { void Reset(); void DebugFill(); - void* Alloc(size_t size); + void* Alloc(size_t size, size_t align); template T* Alloc() { - return reinterpret_cast(Alloc(sizeof(T))); + return reinterpret_cast(Alloc(sizeof(T), alignof(T))); } + // When rewinding aligned allocations, any padding that was applied during + // allocation will be leaked void Rewind(size_t size); void* CloneContents(); diff --git a/src/xenia/cpu/compiler/passes/data_flow_analysis_pass.cc b/src/xenia/cpu/compiler/passes/data_flow_analysis_pass.cc index 622af656b..56cf1c769 100644 --- a/src/xenia/cpu/compiler/passes/data_flow_analysis_pass.cc +++ b/src/xenia/cpu/compiler/passes/data_flow_analysis_pass.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2014 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -73,14 +73,14 @@ void DataFlowAnalysisPass::AnalyzeFlow(HIRBuilder* builder, // Stash for value map. We may want to maintain this during building. auto arena = builder->arena(); auto value_map = reinterpret_cast( - arena->Alloc(sizeof(Value*) * max_value_estimate)); + arena->Alloc(sizeof(Value*) * max_value_estimate, alignof(Value))); // Allocate incoming bitvectors for use by blocks. We don't need outgoing // because they are only used during the block iteration. // Mapped by block ordinal. // TODO(benvanik): cache this list, grow as needed, etc. - auto incoming_bitvectors = - (llvm::BitVector**)arena->Alloc(sizeof(llvm::BitVector*) * block_count); + auto incoming_bitvectors = (llvm::BitVector**)arena->Alloc( + sizeof(llvm::BitVector*) * block_count, alignof(llvm::BitVector)); for (auto n = 0u; n < block_count; n++) { incoming_bitvectors[n] = new llvm::BitVector(max_value_estimate); } diff --git a/src/xenia/cpu/compiler/passes/finalization_pass.cc b/src/xenia/cpu/compiler/passes/finalization_pass.cc index ddd22a646..22b386799 100644 --- a/src/xenia/cpu/compiler/passes/finalization_pass.cc +++ b/src/xenia/cpu/compiler/passes/finalization_pass.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2020 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -45,7 +45,7 @@ bool FinalizationPass::Run(HIRBuilder* builder) { while (label) { if (!label->name) { const size_t label_len = 6 + 4; - char* name = reinterpret_cast(arena->Alloc(label_len + 1)); + char* name = reinterpret_cast(arena->Alloc(label_len + 1, 1)); assert_true(label->id <= 9999); auto end = fmt::format_to_n(name, label_len, "_label{}", label->id); name[end.size] = '\0'; diff --git a/src/xenia/cpu/hir/hir_builder.cc b/src/xenia/cpu/hir/hir_builder.cc index b1a908791..fc64b7c2e 100644 --- a/src/xenia/cpu/hir/hir_builder.cc +++ b/src/xenia/cpu/hir/hir_builder.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2020 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -739,7 +739,7 @@ void HIRBuilder::Comment(std::string_view value) { return; } auto size = value.size(); - auto p = reinterpret_cast(arena_->Alloc(size + 1)); + auto p = reinterpret_cast(arena_->Alloc(size + 1, 1)); std::memcpy(p, value.data(), size); p[size] = '\0'; Instr* i = AppendInstr(OPCODE_COMMENT_info, 0); @@ -752,7 +752,7 @@ void HIRBuilder::Comment(const StringBuffer& value) { return; } auto size = value.length(); - auto p = reinterpret_cast(arena_->Alloc(size + 1)); + auto p = reinterpret_cast(arena_->Alloc(size + 1, 1)); std::memcpy(p, value.buffer(), size); p[size] = '\0'; Instr* i = AppendInstr(OPCODE_COMMENT_info, 0); diff --git a/src/xenia/cpu/hir/hir_builder.h b/src/xenia/cpu/hir/hir_builder.h index 00661e4c2..81c406c12 100644 --- a/src/xenia/cpu/hir/hir_builder.h +++ b/src/xenia/cpu/hir/hir_builder.h @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2020 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -75,7 +75,7 @@ class HIRBuilder { template void CommentFormat(const std::string_view format, const Args&... args) { static const uint32_t kMaxCommentSize = 1024; - char* p = reinterpret_cast(arena_->Alloc(kMaxCommentSize)); + char* p = reinterpret_cast(arena_->Alloc(kMaxCommentSize, 1)); auto result = fmt::format_to_n(p, kMaxCommentSize - 1, format, args...); p[result.size] = '\0'; size_t rewind = kMaxCommentSize - 1 - result.size; diff --git a/src/xenia/cpu/ppc/ppc_hir_builder.cc b/src/xenia/cpu/ppc/ppc_hir_builder.cc index 902782f06..460da0894 100644 --- a/src/xenia/cpu/ppc/ppc_hir_builder.cc +++ b/src/xenia/cpu/ppc/ppc_hir_builder.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2020 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -104,8 +104,8 @@ bool PPCHIRBuilder::Emit(GuestFunction* function, uint32_t flags) { // instruction may have a label assigned to it if it hasn't been hit // yet. size_t list_size = instr_count_ * sizeof(void*); - instr_offset_list_ = (Instr**)arena_->Alloc(list_size); - label_list_ = (Label**)arena_->Alloc(list_size); + instr_offset_list_ = (Instr**)arena_->Alloc(list_size, alignof(void*)); + label_list_ = (Label**)arena_->Alloc(list_size, alignof(void*)); std::memset(instr_offset_list_, 0, list_size); std::memset(label_list_, 0, list_size); @@ -244,7 +244,7 @@ void PPCHIRBuilder::AnnotateLabel(uint32_t address, Label* label) { char name_buffer[13]; auto format_result = fmt::format_to_n(name_buffer, 12, "loc_{:08X}", address); name_buffer[format_result.size] = '\0'; - label->name = (char*)arena_->Alloc(sizeof(name_buffer)); + label->name = (char*)arena_->Alloc(sizeof(name_buffer), 1); memcpy(label->name, name_buffer, sizeof(name_buffer)); }