Skip to content

Commit

Permalink
97 add objects (#99)
Browse files Browse the repository at this point in the history
* #82: Fixed strings, added loading of klasses

* #82: make format

* #94: corresponding cpp files

* #94: Added commentary

* #94: make format

* #94: Removed Data, added `isObject` field

* #94: getStringByStringPoolPos

* #97: Added instructions to yaml

* #97: make format

* #97: Implemented AllocRef, LdraRef, StarRef

* #97: Added tests

* #97: Added test for GetField

* #97: make format

* #97: Edited todo

* #97: Returned cmakelist back

* #97: Added todo
  • Loading branch information
levBagryansky authored Jun 12, 2024
1 parent 858ac6a commit 7e6e7a8
Show file tree
Hide file tree
Showing 12 changed files with 417 additions and 73 deletions.
6 changes: 5 additions & 1 deletion include/ChaiVM/interpreter/code-manager/klass.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ struct Field {

struct Klass {
public:
/**
* Id of string in constant pool.
*/
chai::interpreter::Immidiate name_;
std::vector<Field> fields_;

chsize_t size();
chsize_t nFields() const;
chsize_t instanceSize() const;
};

} // namespace chai::interpreter
138 changes: 84 additions & 54 deletions include/ChaiVM/interpreter/executor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ class Executor {
public:
using Handler = void (Executor::*)(Instruction);

Executor(CodeManager *manager, memory::LinearBuffer &buffer);
Executor(CodeManager *manager, memory::LinearBuffer &framesBuffer,
memory::LinearBuffer &objectsBuffer);

/**
* Loads the first frame (public static void main).
Expand Down Expand Up @@ -79,68 +80,97 @@ class Executor {
void newf64array(Instruction ins);
void get_f64from_arr(Instruction ins);
void set_f64in_arr(Instruction ins);

// @todo #97:90min Implement array of objects.
void new_ref_arr(Instruction ins) {
std::cout << "new_ref_arr " << ins.operation << std::endl;
}
void get_ref_from_arr(Instruction ins) {
std::cout << "get_ref_from_arr " << ins.operation << std::endl;
}
void set_ref_in_arr(Instruction ins) {
std::cout << "set_ref_in_arr " << ins.operation << std::endl;
}
void string_print(Instruction ins);
void string_concat(Instruction ins);
void string_len(Instruction ins);
void string_slice(Instruction ins);
void alloc_ref(Instruction ins);
void mov_ref(Instruction ins);
void ldra_ref(Instruction ins);
void star_ref(Instruction ins);
void get_field(Instruction ins);
void set_field(Instruction ins);

static constexpr Handler HANDLER_ARR[] = {&Executor::inv,
&Executor::nop,
&Executor::ret,
&Executor::mov,
&Executor::ldia,
&Executor::ldra,
&Executor::star,
&Executor::add,
&Executor::addi,
&Executor::sub,
&Executor::subi,
&Executor::mul,
&Executor::muli,
&Executor::div,
&Executor::divi,
&Executor::ldiaf,
&Executor::addf,
&Executor::addif,
&Executor::subf,
&Executor::subif,
&Executor::mulf,
&Executor::mulif,
&Executor::divf,
&Executor::divif,
&Executor::icprint,
&Executor::icscani,
&Executor::icscanf,
&Executor::icsqrt,
&Executor::icsin,
&Executor::iccos,
&Executor::if_icmpeq,
&Executor::if_icmpne,
&Executor::if_icmpgt,
&Executor::if_icmpge,
&Executor::if_icmplt,
&Executor::if_icmple,
&Executor::if_acmpeq,
&Executor::if_acmpne,
&Executor::cmpgf,
&Executor::cmplf,
&Executor::g0t0,
&Executor::call,
&Executor::newi64array,
&Executor::get_i64from_arr,
&Executor::set_i64in_arr,
&Executor::newf64array,
&Executor::get_f64from_arr,
&Executor::set_f64in_arr,
&Executor::string_print,
&Executor::string_concat,
&Executor::string_len,
&Executor::string_slice};
static constexpr Handler HANDLER_ARR[] = {
&Executor::inv,
&Executor::nop,
&Executor::ret,
&Executor::mov,
&Executor::ldia,
&Executor::ldra,
&Executor::star,
&Executor::add,
&Executor::addi,
&Executor::sub,
&Executor::subi,
&Executor::mul,
&Executor::muli,
&Executor::div,
&Executor::divi,
&Executor::ldiaf,
&Executor::addf,
&Executor::addif,
&Executor::subf,
&Executor::subif,
&Executor::mulf,
&Executor::mulif,
&Executor::divf,
&Executor::divif,
&Executor::icprint,
&Executor::icscani,
&Executor::icscanf,
&Executor::icsqrt,
&Executor::icsin,
&Executor::iccos,
&Executor::if_icmpeq,
&Executor::if_icmpne,
&Executor::if_icmpgt,
&Executor::if_icmpge,
&Executor::if_icmplt,
&Executor::if_icmple,
&Executor::if_acmpeq,
&Executor::if_acmpne,
&Executor::cmpgf,
&Executor::cmplf,
&Executor::g0t0,
&Executor::call,
&Executor::newi64array,
&Executor::get_i64from_arr,
&Executor::set_i64in_arr,
&Executor::newf64array,
&Executor::get_f64from_arr,
&Executor::set_f64in_arr,
&Executor::new_ref_arr,
&Executor::get_ref_from_arr,
&Executor::set_ref_in_arr,
&Executor::string_print,
&Executor::string_concat,
&Executor::string_len,
&Executor::string_slice,
&Executor::alloc_ref,
&Executor::mov_ref,
&Executor::ldra_ref,
&Executor::star_ref,
&Executor::get_field,
&Executor::set_field,
};

private:
chsize_t acc_;
CodeManager *codeManager_;
memory::LinearBuffer &buffer_;
memory::LinearBuffer &framesBuffer_;
memory::LinearBuffer &objectsBuffer_;
Frame *currentFrame_ = nullptr;
};

Expand Down
42 changes: 42 additions & 0 deletions include/ChaiVM/interpreter/objects.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#pragma once

#include "ChaiVM/interpreter/code-manager/klass.hpp"
#include "ChaiVM/memory/linear-allocator.hpp"
#include "ChaiVM/memory/linear-buffer.hpp"
#include <cassert>

namespace chai::interpreter {

// @todo #97:90min Add allocator here.
struct ObjectHeader {
chsize_t size_;
Immidiate klassId_;
};

/**
* Facade to manage object.
* Note, it does not own header and fields.
* @todo #97:30min Consider refactoring object to just cast it from raw pointer.
* It can be faster.
*/
class Object {

public:
explicit Object(ObjectHeader *header, chsize_t *fields);
/**
* Ctor.
* Create object from ref to object.
* @param ref Ref to object (usually contains in register).
*/
explicit Object(chsize_t ref);

chsize_t getField(Immidiate offset) const;

void setField(Immidiate offset, chsize_t value) const;

private:
ObjectHeader *header_;
chsize_t *fields_;
};

} // namespace chai::interpreter
1 change: 1 addition & 0 deletions src/ChaiVM/interpreter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ target_sources(chai_interpreter PRIVATE
./code-manager/code-manager.cpp
./code-manager/klass.cpp
./frame.cpp
./objects.cpp
)
7 changes: 6 additions & 1 deletion src/ChaiVM/interpreter/code-manager/klass.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
#include "ChaiVM/interpreter/code-manager/klass.hpp"
#include "ChaiVM/interpreter/objects.hpp"

namespace chai::interpreter {

chsize_t Klass::size() { return fields_.size(); }
chsize_t Klass::nFields() const { return fields_.size(); }

chsize_t Klass::instanceSize() const {
return nFields() * sizeof(chsize_t) + sizeof(ObjectHeader);
}

} // namespace chai::interpreter
68 changes: 59 additions & 9 deletions src/ChaiVM/interpreter/executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "ChaiVM/interpreter/executor.hpp"
#include "ChaiVM/interpreter/frame.hpp"
#include "ChaiVM/interpreter/objects.hpp"

namespace chai::interpreter {

Expand All @@ -11,13 +12,16 @@ namespace chai::interpreter {
decoder::parse(currentFrame_->func_.code[pc() / sizeof(bytecode_t)]); \
(this->*HANDLER_ARR[newIns.operation])(newIns);

Executor::Executor(CodeManager *manager, memory::LinearBuffer &buffer)
: codeManager_(manager), buffer_(buffer) {}
Executor::Executor(CodeManager *manager, memory::LinearBuffer &framesBuffer,
memory::LinearBuffer &objectsBuffer)
: codeManager_(manager), framesBuffer_(framesBuffer),
objectsBuffer_(objectsBuffer) {}

void Executor::init() {
assert(currentFrame_ == nullptr); // No current frame
currentFrame_ = new (memory::LinearAllocator<Frame>{buffer_}.allocate(1))
Frame(nullptr, codeManager_->getStartFunc(), buffer_);
currentFrame_ =
new (memory::LinearAllocator<Frame>{framesBuffer_}.allocate(1))
Frame(nullptr, codeManager_->getStartFunc(), framesBuffer_);
pc() = 0;
}

Expand Down Expand Up @@ -306,16 +310,16 @@ void Executor::g0t0(Instruction ins) {
DO_NEXT_INS()
}
void Executor::call(Instruction ins) {
memory::LinearAllocator<Frame> allocator{buffer_};
currentFrame_ = new (allocator.allocate(1))
Frame(currentFrame_, codeManager_->getFunc(ins.immidiate), buffer_);
memory::LinearAllocator<Frame> allocator{framesBuffer_};
currentFrame_ = new (allocator.allocate(1)) Frame(
currentFrame_, codeManager_->getFunc(ins.immidiate), framesBuffer_);
currentFrame_->passArgs();
pc() = 0;
DO_NEXT_INS();
}
void Executor::newi64array(Instruction ins) {
auto n = static_cast<int64_t>(acc());
memory::LinearAllocator<int64_t> allocator{buffer_};
memory::LinearAllocator<int64_t> allocator{framesBuffer_};
assert(n >= 0);
auto *arr = new (allocator.allocate(n)) int64_t[n]();
acc() = reinterpret_cast<chsize_t>(arr);
Expand All @@ -340,7 +344,7 @@ void Executor::set_i64in_arr(Instruction ins) {

void Executor::newf64array(Instruction ins) {
auto n = static_cast<int64_t>(acc());
memory::LinearAllocator<double> allocator{buffer_};
memory::LinearAllocator<double> allocator{framesBuffer_};
assert(n >= 0);
auto *arr = new (allocator.allocate(n)) double[n]();
acc() = reinterpret_cast<chsize_t>(arr);
Expand Down Expand Up @@ -388,12 +392,58 @@ void Executor::string_len(Instruction ins) {
}
void Executor::string_slice(Instruction ins) {
const std::string &str = codeManager_->getStringByStringPoolPos(acc());
std::cout << "string_slice" << std::endl;
acc() = codeManager_->getCnst(codeManager_->addCnstString(
str.substr((*currentFrame_)[ins.r1],
(*currentFrame_)[ins.r2] - (*currentFrame_)[ins.r1])));
advancePc();
DO_NEXT_INS();
}
void Executor::alloc_ref(Instruction ins) {
const Klass &klass = codeManager_->getKlass(ins.immidiate);
assert(klass.instanceSize() > 0);
memory::LinearAllocator<uint8_t> allocator{objectsBuffer_};
auto *object = new (allocator.allocate(klass.instanceSize()))
uint8_t[klass.instanceSize()]();
auto *pheader = reinterpret_cast<ObjectHeader *>(object);
auto *fields = reinterpret_cast<chsize_t *>(object + sizeof(*pheader));
pheader->size_ = klass.instanceSize();
pheader->klassId_ = ins.immidiate;
for (int i = 0; i < klass.nFields(); ++i) {
assert(fields[i] == 0);
}
acc() = std::bit_cast<chsize_t>(object);
advancePc();
DO_NEXT_INS()
}
void Executor::mov_ref(Instruction ins) {
std::cout << ins.operation << ": mov_ref is not implemented" << std::endl;
assert(1 == 0);
}
void Executor::ldra_ref(Instruction ins) {
acc() = (*currentFrame_)[ins.r1];
advancePc();
DO_NEXT_INS()
}
void Executor::star_ref(Instruction ins) {
(*currentFrame_)[ins.r1] = acc();
advancePc();
DO_NEXT_INS()
}
void Executor::get_field(Instruction ins) {
Immidiate offset = ins.immidiate;
Object object{acc()};
acc() = object.getField(offset);
advancePc();
DO_NEXT_INS()
}
void Executor::set_field(Instruction ins) {
Immidiate offset = ins.immidiate;
Object object{acc()};
object.setField(offset, (*currentFrame_)[ins.r1]);
advancePc();
DO_NEXT_INS()
}

InvalidInstruction::InvalidInstruction(const char *msg) : runtime_error(msg) {}
InvalidInstruction::InvalidInstruction(const std::string &msg)
Expand Down
25 changes: 25 additions & 0 deletions src/ChaiVM/interpreter/objects.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <cassert>

#include "ChaiVM/interpreter/frame.hpp"
#include "ChaiVM/interpreter/objects.hpp"

namespace chai::interpreter {

Object::Object(ObjectHeader *header, chsize_t *fields)
: header_(header), fields_(fields) {}

Object::Object(chsize_t ref)
: header_(std::bit_cast<ObjectHeader *>(ref)),
fields_(std::bit_cast<chsize_t *>(header_ + 1)) {}

chsize_t Object::getField(Immidiate offset) const {
assert(offset % 8 == 0);
return fields_[offset / 8];
}

void Object::setField(Immidiate offset, chsize_t value) const {
assert(offset % 8 == 0);
fields_[offset / 8] = value;
}

} // namespace chai::interpreter
8 changes: 6 additions & 2 deletions test/ChaiVM/interpreter/executor-test-fixture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ class ExecutorTest : public ::testing::Test {
protected:
chai::utils::fileformat::ChaiFile chaiFile_;
chai::interpreter::CodeManager codeManager_;
chai::memory::LinearBuffer buffer_ = chai::memory::LinearBuffer(1024 * 256);
chai::interpreter::Executor exec_{&codeManager_, buffer_};
chai::memory::LinearBuffer frameBuffer_ =
chai::memory::LinearBuffer(1024 * 256);
chai::memory::LinearBuffer objectBuffer_ =
chai::memory::LinearBuffer(1024 * 256);
chai::interpreter::Executor exec_{&codeManager_, frameBuffer_,
objectBuffer_};
};
Loading

3 comments on commit 7e6e7a8

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 7e6e7a8 Jun 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 97-491954b0 discovered in include/ChaiVM/interpreter/executor.hpp) and submitted as #100. Please, remember that the puzzle was not necessarily added in this particular commit. Maybe it was added earlier, but we discovered it only now.

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 7e6e7a8 Jun 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 97-0dcc99de discovered in include/ChaiVM/interpreter/objects.hpp) and submitted as #101. Please, remember that the puzzle was not necessarily added in this particular commit. Maybe it was added earlier, but we discovered it only now.

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 7e6e7a8 Jun 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 97-fe6e6775 discovered in include/ChaiVM/interpreter/objects.hpp) and submitted as #102. Please, remember that the puzzle was not necessarily added in this particular commit. Maybe it was added earlier, but we discovered it only now.

Please sign in to comment.