Skip to content

Commit

Permalink
#82: Fixed strings, added loading of klasses (#95)
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: make format
  • Loading branch information
levBagryansky authored Jun 12, 2024
1 parent 0a3f08c commit 858ac6a
Show file tree
Hide file tree
Showing 16 changed files with 291 additions and 30 deletions.
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,35 @@ fn main 8 0 {
Where Ret returns exit code `r0`. "main" is name of the starting function, `8` is number of registers in it, `0` is number of arguments passing into the function.
This script compiled to chai-bytecode should print "0", because '0' == 48.
## Chai file format
Our file format is similar to jvm ClassFile Structure. Its content is the following:
Except for classes, our file format is similar to jvm ClassFile Structure. Its content is the following:
- Constants count (`imm`)
- Constant[]
- klass_info count (`imm`)
- klass_info[]
- func_info count (`imm`)
- func_info[]

Where `imm` is 2 bytes.

`Constant` has a 1 byte tag that specifies its type(ConstI64, or ConstFuncNameAndType and so on) and the payload then.

`klass_info` structure:
```
klass_info {
imm ConstRawStr // Klass name index in constant pool
u1 nFields // Count of fields
field_info[] // field_infos array
}
field_info {
imm ConstRawStr // Field name index in constant pool
u1 type // 0 if primitive, some class otherwise
union {
u1 tag // (first byte 0, second determines) 1 for i64, 2 for f64
imm klassNum // Klass number, counting only klasses from top to bottom
}
}
```
`func_info` structure:
```
func_info {
Expand Down
32 changes: 27 additions & 5 deletions include/ChaiVM/interpreter/code-manager/code-manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "ChaiVM/memory/allocator.hpp"
#include "ChaiVM/memory/linear-allocator.hpp"
#include "ChaiVM/memory/linear-buffer.hpp"
#include "klass.hpp"

namespace chai::interpreter {

Expand Down Expand Up @@ -38,24 +39,45 @@ class CodeManager final {
*/
void loadPool(std::istream &istream);

void loadKlass(std::istream &istream);

void loadFunction(std::istream &istream);

chsize_t getCnst(Immidiate id);

const std::string &getCnstString(Immidiate id);
/**
* Get string by immediate, i.e. its number in constant pool.
* @param imm Number in constant pool.
* @return String.
*/
const std::string &getCnstStringByImm(Immidiate imm);

/**
* Get string by constant that provided constant pool.
* Usually we take constant from constant pool directly. In case of string
* there is just 64-bit number that encodes String. Use this method to get
* string by this number.
* @param reg_val Number from constant pool.
* @return String.
*/
const std::string &getStringByStringPoolPos(chsize_t reg_val);

Immidiate addCnstString(std::string &&str) {
stringPool_.emplace_back(str);
return stringPool_.size() - 1;
}
Immidiate addCnstString(std::string &&str);

bytecode_t getBytecode(size_t func, chsize_t pc);

const Klass &getKlass(Immidiate imm) const;

const Function &getFunc(Immidiate imm) const;

const Function &getStartFunc() const;

private:
/**
* Loaded klasses.
*/
std::vector<Klass> klasses_;

std::vector<Function> funcs_;

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

#include <vector>

#include "ChaiVM/interpreter/instruction.hpp"
#include "ChaiVM/memory/linear-allocator.hpp"
#include "ChaiVM/memory/linear-buffer.hpp"
#include "ChaiVM/types.hpp"

namespace chai::interpreter {

struct Field {
public:
chai::interpreter::Immidiate name_;
bool isObject_;
};

struct Klass {
public:
chai::interpreter::Immidiate name_;
std::vector<Field> fields_;

chsize_t size();
};

} // namespace chai::interpreter
37 changes: 36 additions & 1 deletion include/ChaiVM/utils/file-format/chai-file.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

#include "ChaiVM/utils/file-format/constant.hpp"
#include "ChaiVM/utils/file-format/function-info.hpp"
#include "ChaiVM/utils/file-format/klass-info.hpp"
#include "ChaiVM/utils/instr2Raw.hpp"

namespace chai::utils::fileformat {

/**
* Class for generating .chai files.
*/
class ChaiFile {
public:
ChaiFile(std::vector<chai::bytecode_t> &&instrs,
Expand Down Expand Up @@ -48,20 +52,51 @@ class ChaiFile {
*/
chai::interpreter::Immidiate nextFunc() const;

/**
* Add klass by name only.
* @param name Klass name.
* @return Number of klass.
*/
chai::interpreter::Immidiate registerKlass(const std::string &name);

/**
* Add field to klass.
* @param klass Number of klass.
* @param name Name of the field.
* @param isObject 0 if primitive, otherwise 1.
* @param tagOrKlassNum 1 for i64, 2 for f64, or number of klass.
* @return offset of the field.
*/
chai::interpreter::Immidiate
addField(chai::interpreter::Immidiate klass, const std::string &name,
uint8_t isObject, chai::interpreter::Immidiate tagOrKlassNum);

void toFile(const std::filesystem::path &path) const;

private:
void dumpMainFunc(std::ofstream &ofs) const;

private:
std::vector<chai::bytecode_t> rawInstrs_;
std::vector<std::unique_ptr<Constant>> pool_;

std::vector<KlassInfo> klasses_;

/**
* All functions except main.
*/
std::vector<FunctionInfo> functions_;

/**
* @todo #94:90min Figure out why this is necessary and add commentary or
* remove.
*/
chai::interpreter::Immidiate constFuncNameAndTypeIndex_;

/**
* Number of "code" str in constant pool.
*/
chai::interpreter::Immidiate codeAttStr_;
};

} // namespace chai::utils::fileformat
} // namespace chai::utils::fileformat
30 changes: 30 additions & 0 deletions include/ChaiVM/utils/file-format/klass-info.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include "vector"
#include <cstdint>

#include "ChaiVM/interpreter/instruction.hpp"
#include "ChaiVM/types.hpp"
#include "ChaiVM/utils/io-bytes.hpp"

namespace chai::utils::fileformat {

enum FieldTag : uint8_t { I64 = 1, F64 = 2 };

struct FieldInfo {
interpreter::Immidiate name_;
uint8_t isObject_;
interpreter::Immidiate tagOrKlassNum_;
};

struct KlassInfo {
interpreter::Immidiate name_;
uint8_t nFields_;
std::vector<FieldInfo> fields_;

chai::interpreter::Immidiate addField(FieldInfo field);

void dump(std::ofstream &ofs) const;
};

} // namespace chai::utils::fileformat
1 change: 1 addition & 0 deletions src/ChaiVM/interpreter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ target_sources(chai_interpreter PRIVATE
./executor.cpp
./decoder.cpp
./code-manager/code-manager.cpp
./code-manager/klass.cpp
./frame.cpp
)
53 changes: 50 additions & 3 deletions src/ChaiVM/interpreter/code-manager/code-manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ void CodeManager::load(const std::filesystem::path &path) {
std::ifstream input_file(path, std::ios::binary | std::ios::in);
if (input_file.good() && input_file.is_open()) {
loadPool(input_file);
Immidiate func_count = readBytes<Immidiate>(input_file);
auto klass_count = readBytes<Immidiate>(input_file);
for (int i = 0; i < klass_count; ++i) {
loadKlass(input_file);
}
auto func_count = readBytes<Immidiate>(input_file);
for (int i = 0; i < func_count; ++i) {
loadFunction(input_file);
}
Expand Down Expand Up @@ -67,6 +71,34 @@ void CodeManager::loadPool(std::istream &istream) {
}
}

inline bool typeIsObject(uint8_t type) { return type != 0; }

Field loadField(std::istream &istream) {
auto name = readBytes<Immidiate>(istream);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
auto type = readBytes<uint8_t>(istream);
bool isObject = typeIsObject(type);
if (isObject) {
auto klassNum = readBytes<Immidiate>(istream);
} else {
readBytes<uint8_t>(istream);
char intOrFloat = readBytes<char>(istream);
}
#pragma GCC diagnostic pop
return Field{name, isObject};
}

void CodeManager::loadKlass(std::istream &istream) {
auto name = readBytes<Immidiate>(istream);
auto fields_count = readBytes<uint8_t>(istream);
Klass klass{name, std::vector<Field>{}};
for (int i = 0; i < fields_count; ++i) {
klass.fields_.push_back(loadField(istream));
}
klasses_.push_back(klass);
}

/*
* @todo #1:90min We can use chai::utils::fileformat::FuncInfo here somehow.
* Read to structure and then work with their fields.
Expand Down Expand Up @@ -108,8 +140,18 @@ chsize_t CodeManager::getCnst(Immidiate id) {
return constantPool_[id];
}

const std::string &CodeManager::getCnstString(Immidiate id) {
return stringPool_[id];
const std::string &CodeManager::getCnstStringByImm(Immidiate imm) {
return stringPool_[constantPool_[imm]];
}

const std::string &CodeManager::getStringByStringPoolPos(chsize_t reg_val) {
return stringPool_[reg_val];
}

Immidiate CodeManager::addCnstString(std::string &&str) {
constantPool_.push_back(stringPool_.size());
stringPool_.emplace_back(str);
return constantPool_.size() - 1;
}

bytecode_t CodeManager::getBytecode(size_t func, chsize_t pc) {
Expand All @@ -124,6 +166,11 @@ bytecode_t CodeManager::getBytecode(size_t func, chsize_t pc) {
}
}

const Klass &CodeManager::getKlass(Immidiate imm) const {
assert(klasses_.size() > imm);
return klasses_[imm];
}

const Function &CodeManager::getFunc(Immidiate imm) const {
return funcs_[imm];
}
Expand Down
7 changes: 7 additions & 0 deletions src/ChaiVM/interpreter/code-manager/klass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include "ChaiVM/interpreter/code-manager/klass.hpp"

namespace chai::interpreter {

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

} // namespace chai::interpreter
19 changes: 10 additions & 9 deletions src/ChaiVM/interpreter/executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,32 +364,33 @@ void Executor::set_f64in_arr(Instruction ins) {
}

void Executor::string_print(Instruction ins) {
const std::string &str = codeManager_->getCnstString(acc());
std::cout << str;
const std::string &str = codeManager_->getStringByStringPoolPos(acc());
std::cout << str << std::endl;
advancePc();
DO_NEXT_INS();
}

void Executor::string_concat(Instruction ins) {
const std::string &str1 = codeManager_->getCnstString(acc());
const std::string &str1 = codeManager_->getStringByStringPoolPos(acc());
const std::string &str2 =
codeManager_->getCnstString((*currentFrame_)[ins.r1]);
codeManager_->getStringByStringPoolPos((*currentFrame_)[ins.r1]);
std::string concated = str1 + str2;
acc() = codeManager_->addCnstString(std::move(concated));
acc() =
codeManager_->getCnst(codeManager_->addCnstString(std::move(concated)));
advancePc();
DO_NEXT_INS();
}

void Executor::string_len(Instruction ins) {
acc() = codeManager_->getCnstString(acc()).size();
acc() = codeManager_->getStringByStringPoolPos(acc()).size();
advancePc();
DO_NEXT_INS();
}
void Executor::string_slice(Instruction ins) {
const std::string &str = codeManager_->getCnstString(acc());
acc() = codeManager_->addCnstString(
const std::string &str = codeManager_->getStringByStringPoolPos(acc());
acc() = codeManager_->getCnst(codeManager_->addCnstString(
str.substr((*currentFrame_)[ins.r1],
(*currentFrame_)[ins.r2] - (*currentFrame_)[ins.r1]));
(*currentFrame_)[ins.r2] - (*currentFrame_)[ins.r1])));
advancePc();
DO_NEXT_INS();
}
Expand Down
1 change: 1 addition & 0 deletions src/ChaiVM/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
add_library(chai_utils STATIC)
target_sources(chai_utils PRIVATE
./file-format/chai-file.cpp
./file-format/klass-info.cpp
./file-format/function-info.cpp
./file-format/constant.cpp
./instr2Raw.cpp
Expand Down
Loading

1 comment on commit 858ac6a

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 858ac6a Jun 12, 2024

Choose a reason for hiding this comment

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

Puzzle 94-179b6abd discovered in include/ChaiVM/utils/file-format/chai-file.hpp) and submitted as #98. 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.