Skip to content

Commit

Permalink
Implement simple linear allocator (#57)
Browse files Browse the repository at this point in the history
Closes #50
  • Loading branch information
c71n93 authored Nov 3, 2023
1 parent 2099e0a commit 5f57234
Show file tree
Hide file tree
Showing 20 changed files with 223 additions and 13 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ build/

# ide stuff
.idea
cmake-build-debug
cmake-build*
include/ChaiVM/interpreter/autogen
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ cmake_minimum_required(VERSION 3.26)
project(ChaiVM)
set(CMAKE_CXX_STANDARD 20)

set(COMPILER_WARNINGS "-Wall -Wextra -Wpedantic -Werror -Wno-missing-field-initializers")
set(CMAKE_C_FLAGS ${COMPILER_WARNINGS})
set(CMAKE_C_FLAGS_DEBUG "-O0 -g ${COMPILER_WARNINGS}")
set(CMAKE_C_FLAGS_RELEASE "-O2 ${COMPILER_WARNINGS}")
set(CMAKE_CXX_FLAGS ${COMPILER_WARNINGS})
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g ${COMPILER_WARNINGS}")
set(CMAKE_CXX_FLAGS_RELEASE "-O2 ${COMPILER_WARNINGS}")

add_subdirectory(third_party)
add_subdirectory(test)
add_subdirectory(src)
Expand Down
3 changes: 3 additions & 0 deletions bench/square_equation_bench.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ static void initSquareEquatino(CodeManWrapper &codeman) {
const RegisterId r7 = 7;
const RegisterId r8 = 8;
const RegisterId r9 = 9;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
const RegisterId r10 = 10;
#pragma GCC diagnostic pop
const RegisterId r11 = 11;

// r1 = 1.0, r2 = -5.0, r3 = 6.0
Expand Down
4 changes: 2 additions & 2 deletions include/ChaiVM/interpreter/reg-file.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ namespace chai::interpreter {
class RegisterFile {
public:
RegisterFile(chsize_t pc);
chsize_t &operator[](int n) &;
const chsize_t &operator[](int n) const &;
chsize_t &operator[](size_t n) &;
const chsize_t &operator[](size_t n) const &;
chsize_t &pc();
chsize_t pc() const;
chsize_t &acc();
Expand Down
16 changes: 16 additions & 0 deletions include/ChaiVM/memory/allocator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include <cstdlib>

namespace chai::memory {

template <class T> class IAllocator {
public:
using value_type = T;
IAllocator() noexcept = default;
virtual T *allocate(size_t n) = 0;
virtual void deallocate(T *p, size_t n) = 0;
virtual ~IAllocator() {}
};

} // namespace chai::memory
36 changes: 36 additions & 0 deletions include/ChaiVM/memory/linear-allocator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#pragma once

#include <cstdlib>
#include <new>
#include <numeric>

#include "ChaiVM/memory/allocator.hpp"
#include "ChaiVM/memory/linear-buffer.hpp"
#include "ChaiVM/utils/non-copyable.hpp"

namespace chai::memory {

template <class T> class LinearAllocator : IAllocator<T> {
public:
using value_type = T;

explicit LinearAllocator(LinearBuffer &buffer) : buffer_(buffer) {}

T *allocate(std::size_t n) override {
if (n > (buffer_.size() - buffer_.offset()) / sizeof(T)) {
throw std::bad_array_new_length();
}
void *current = buffer_.currentPosition();
buffer_.shiftOffset(n * sizeof(T));
return reinterpret_cast<T *>(current);
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
void deallocate(T *p, std::size_t n) override {}
#pragma GCC diagnostic pop

private:
LinearBuffer &buffer_;
};

} // namespace chai::memory
28 changes: 28 additions & 0 deletions include/ChaiVM/memory/linear-buffer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include <cstdlib>
#include <iostream>

#include "ChaiVM/utils/non-copyable.hpp"

namespace chai::memory {

class LinearBuffer final : public INonCopyable {
public:
explicit LinearBuffer(size_t sz);
LinearBuffer(LinearBuffer &&other) noexcept;
LinearBuffer &operator=(LinearBuffer &&other) noexcept;
~LinearBuffer();

size_t size() const;
size_t offset() const;
void *currentPosition() const;
void shiftOffset(size_t n);

private:
size_t size_ = 0;
size_t offset_ = 0;
char *buf_ = nullptr;
};

} // namespace chai::memory
1 change: 0 additions & 1 deletion include/ChaiVM/utils/constant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ struct Constant {
virtual void write(std::ofstream &ofs) = 0;
virtual int8_t getType() = 0;
virtual ~Constant() = default;
;
};

struct ConstI64 : public Constant {
Expand Down
4 changes: 3 additions & 1 deletion include/ChaiVM/utils/non-copyable.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#pragma once

class INonCopyable {
protected:
INonCopyable() {}

public:
INonCopyable(const INonCopyable &rhs) = delete;
INonCopyable &operator=(const INonCopyable &rhs) = delete;
virtual ~INonCopyable() = 0;
};
2 changes: 1 addition & 1 deletion src/ChaiVM/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
set(DIRS interpreter utils)
set(DIRS interpreter utils memory)
foreach(DIR ${DIRS})
add_subdirectory(${DIR})
endforeach()
3 changes: 3 additions & 0 deletions src/ChaiVM/interpreter/executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ Executor::Executor(CodeManager *manager)
void Executor::run() { DO_NEXT_INS() }
void Executor::restart() { regFile_.pc() = codeManager_->startPC(); }
const RegisterFile &Executor::getState() const & { return regFile_; }

#pragma GCC diagnostic ignored "-Wunused-parameter"

void Executor::inv(Instruction ins) {
throw InvalidInstruction("Invalid operation at pc: " +
std::to_string(regFile_.pc()));
Expand Down
8 changes: 4 additions & 4 deletions src/ChaiVM/interpreter/reg-file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@

namespace chai::interpreter {

chai::chsize_t &RegisterFile::operator[](int n) & {
chai::chsize_t &RegisterFile::operator[](size_t n) & {
assert(n <= Size);
return registers_[n];
}
const chsize_t &RegisterFile::operator[](int n) const & {
const chsize_t &RegisterFile::operator[](size_t n) const & {
assert(n <= Size);
return registers_[n];
}
chai::chsize_t &RegisterFile::pc() { return pc_; }
chai::chsize_t RegisterFile::pc() const { return pc_; }
chai::chsize_t &RegisterFile::acc() { return acc_; }
chai::chsize_t RegisterFile::acc() const { return acc_; }
RegisterFile::RegisterFile(chsize_t pc) : pc_(pc), acc_(0), registers_{} {}
RegisterFile::RegisterFile(chsize_t pc) : acc_(0), pc_(pc), registers_{} {}

void RegisterFile::dump() {
std::cout << "pc = " << pc_ << ", acc = " << std::bit_cast<int64_t>(acc_)
<< " = " << std::bit_cast<double>(acc_) << std::endl;
for (int i = 0; i < Size; ++i) {
for (size_t i = 0; i < Size; ++i) {
if (registers_[i] != 0) {
std::cout << "rf[" << i
<< "] = " << std::bit_cast<int64_t>(registers_[i])
Expand Down
8 changes: 8 additions & 0 deletions src/ChaiVM/memory/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
add_library(chai_memory STATIC)
target_sources(chai_memory PRIVATE
./linear-buffer.cpp
)
target_link_libraries(chai_memory
PRIVATE
chai_include
)
22 changes: 22 additions & 0 deletions src/ChaiVM/memory/linear-buffer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include "ChaiVM/memory/linear-buffer.hpp"

namespace chai::memory {

LinearBuffer::LinearBuffer(size_t sz) : size_(sz), buf_(new char[size_]) {}
LinearBuffer::LinearBuffer(LinearBuffer &&other) noexcept {
std::swap(size_, other.size_);
std::swap(buf_, other.buf_);
}
LinearBuffer &LinearBuffer::operator=(LinearBuffer &&other) noexcept {
std::swap(size_, other.size_);
std::swap(buf_, other.buf_);
return *this;
}
LinearBuffer::~LinearBuffer() { delete[] buf_; }

size_t LinearBuffer::size() const { return size_; }
size_t LinearBuffer::offset() const { return offset_; }
void *LinearBuffer::currentPosition() const { return buf_ + offset_; }
void LinearBuffer::shiftOffset(size_t n) { offset_ += n; }

} // namespace chai::memory
1 change: 0 additions & 1 deletion src/ChaiVM/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

add_library(chai_utils STATIC)
target_sources(chai_utils PRIVATE
./instr2Raw.cpp
Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ target_link_libraries(chai_testif INTERFACE
chai_include
chai_interpreter
chai_utils
chai_memory
gmock_main
gmock
gtest
Expand Down
2 changes: 1 addition & 1 deletion test/ChaiVM/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
set(DIRS interpreter utils)
set(DIRS interpreter utils memory)
foreach(DIR ${DIRS})
add_subdirectory(${DIR})
endforeach()
2 changes: 1 addition & 1 deletion test/ChaiVM/interpreter/code-manager-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ TEST(CodeManager, returnsBytecodes) {
}

const chai::chsize_t initial_pc = manager.startPC();
for (int i = 0; i < seq.size(); ++i) {
for (size_t i = 0; i < seq.size(); ++i) {
chai::chsize_t pc = initial_pc + i * sizeof(chai::bytecode_t);
EXPECT_EQ(manager.getBytecode(pc), seq[i]);
}
Expand Down
1 change: 1 addition & 0 deletions test/ChaiVM/memory/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
chai_test(./linear-allocator-test.cpp)
84 changes: 84 additions & 0 deletions test/ChaiVM/memory/linear-allocator-test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#include "ChaiVM/memory/linear-allocator.hpp"
#include <gtest/gtest.h>

using namespace chai::memory;

class LinearAllocatorTest : public ::testing::Test {
protected:
static constexpr size_t BUFFER_SIZE = 1024;
LinearBuffer buffer_ = LinearBuffer(BUFFER_SIZE);
};

class Stub {
public:
static constexpr int DFT = -1;
explicit Stub(int num) : stub(num) {}
Stub() {}
int stub = DFT;
};

TEST_F(LinearAllocatorTest, Primitives) {
size_t n = 5;
LinearAllocator<int> allocator{buffer_};
int *buf = allocator.allocate(n);
int *arr = new (buf) int[n];
for (size_t i = 0; i < n; ++i) {
arr[i] = i;
}
for (size_t i = 0; i < n; ++i) {
EXPECT_EQ(arr[i], i);
}
}
TEST_F(LinearAllocatorTest, Classes) {
size_t n = 1;
LinearAllocator<Stub> allocator{buffer_};
Stub *buf = allocator.allocate(n);
Stub *inst = new (buf) Stub;
inst->stub = 10;
EXPECT_EQ(inst->stub, 10);
inst->~Stub();
}
TEST_F(LinearAllocatorTest, StdContainersDefault) {
size_t n = 10;
LinearAllocator<Stub> allocator{buffer_};
std::vector<Stub, decltype(allocator)> vec(n, allocator);
for (auto &e : vec) {
EXPECT_EQ(e.stub, Stub::DFT);
}
}
TEST_F(LinearAllocatorTest, StdContainers) {
size_t n = 10;
LinearAllocator<Stub> allocator{buffer_};
std::vector<Stub, decltype(allocator)> vec(n, allocator);
for (auto &e : vec) {
e = Stub(42);
}
for (auto &e : vec) {
EXPECT_EQ(e.stub, 42);
}
}

TEST_F(LinearAllocatorTest, PrimitiveAllocation) {
size_t n = 42;
LinearAllocator<int> allocator{buffer_};
allocator.allocate(n);
EXPECT_EQ(buffer_.offset(), n * sizeof(int));
}
TEST_F(LinearAllocatorTest, ClassAllocation) {
size_t n = 80;
LinearAllocator<Stub> allocator{buffer_};
allocator.allocate(n);
EXPECT_EQ(buffer_.offset(), n * sizeof(Stub));
}
TEST_F(LinearAllocatorTest, StdContainersAllocation) {
size_t n = 23;
LinearAllocator<Stub> allocator{buffer_};
std::vector<Stub, decltype(allocator)> vec(n, allocator);
EXPECT_EQ(buffer_.offset(), n * sizeof(Stub));
}

TEST_F(LinearAllocatorTest, BadArrayNewLength) {
size_t n = BUFFER_SIZE / sizeof(Stub) + 1;
LinearAllocator<Stub> allocator{buffer_};
EXPECT_THROW(allocator.allocate(n), std::bad_array_new_length);
}

0 comments on commit 5f57234

Please sign in to comment.