Phasor 3.3.0
Stack VM based Programming Language
Loading...
Searching...
No Matches
BytecodeSerializer.cpp
Go to the documentation of this file.
2#include <cstring>
3#include <stdexcept>
4#include <filesystem>
5#include <fstream>
6#include "metadata.h"
7
8// Section IDs
9const uint8_t SECTION_CONSTANTS = 0x01; //< Constants Section
10const uint8_t SECTION_VARIABLES = 0x02; //< Variables Section
11const uint8_t SECTION_INSTRUCTIONS = 0x03; //< Instructions Section
12const uint8_t SECTION_FUNCTIONS = 0x04; //< Functions Section
13
14static uint32_t crc32_table[256]; //< CRC32 lookup table
15static bool crc32_table_initialized = false;
16
19{
20 for (uint32_t i = 0; i < 256; i++)
21 {
22 uint32_t crc = i;
23 for (int j = 0; j < 8; j++)
24 {
25 if ((crc & 1) != 0u)
26 {
27 crc = (crc >> 1) ^ 0xEDB88320;
28 }
29 else
30 {
31 crc >>= 1;
32 }
33 }
34 crc32_table[i] = crc;
35 }
37}
38
39namespace Phasor
40{
41
42uint32_t BytecodeSerializer::calculateCRC32(const std::vector<uint8_t> &data)
43{
45 {
47 }
48
49 uint32_t crc = 0xFFFFFFFF;
50 for (uint8_t byte : data)
51 {
52 crc = (crc >> 8) ^ crc32_table[(crc ^ byte) & 0xFF];
53 }
54 return crc ^ 0xFFFFFFFF;
55}
56
58{
59 buffer.push_back(value);
60}
61
63{
64 buffer.push_back(static_cast<uint8_t>(value & 0xFF));
65 buffer.push_back(static_cast<uint8_t>((value >> 8) & 0xFF));
66}
67
69{
70 buffer.push_back(static_cast<uint8_t>(value & 0xFF));
71 buffer.push_back(static_cast<uint8_t>((value >> 8) & 0xFF));
72 buffer.push_back(static_cast<uint8_t>((value >> 16) & 0xFF));
73 buffer.push_back(static_cast<uint8_t>((value >> 24) & 0xFF));
74}
75
77{
78 writeUInt32(static_cast<uint32_t>(value));
79}
80
82{
83 for (int i = 0; i < 8; i++)
84 {
85 buffer.push_back(static_cast<uint8_t>((value >> (i * 8)) & 0xFF));
86 }
87}
88
90{
91 uint64_t bits;
92 std::memcpy(&bits, &value, sizeof(double));
93 for (int i = 0; i < 8; i++)
94 {
95 buffer.push_back(static_cast<uint8_t>((bits >> (i * 8)) & 0xFF));
96 }
97}
98
99void BytecodeSerializer::writeString(const std::string &str)
100{
101 writeUInt16(static_cast<uint16_t>(str.length()));
102 for (char c : str)
103 {
104 buffer.push_back(static_cast<uint8_t>(c));
105 }
106}
107
108void BytecodeSerializer::writeHeader(uint32_t dataChecksum)
109{
112 writeUInt32(0); // Flags (reserved)
113 writeUInt32(dataChecksum);
114}
115
116void BytecodeSerializer::writeConstantPool(const std::vector<Value> &constants)
117{
119 writeUInt32(static_cast<uint32_t>(constants.size()));
120
121 for (const auto &constant : constants)
122 {
123 ValueType type = constant.getType();
124
125 // Write type tag
126 switch (type)
127 {
128 case ValueType::Null:
129 writeUInt8(0);
130 break;
131 case ValueType::Bool:
132 writeUInt8(1);
133 writeUInt8(constant.asBool() ? 1 : 0);
134 break;
135 case ValueType::Int:
136 writeUInt8(2);
137 writeInt64(constant.asInt());
138 break;
139 case ValueType::Float:
140 writeUInt8(3);
141 writeDouble(constant.asFloat());
142 break;
144 writeUInt8(4);
145 writeString(constant.asString());
146 break;
148#warning "Warning: PHS_01 Structs have not been implemented!"
149 throw std::runtime_error("Structs have not been implemented!");
150 break;
151 case ValueType::Array:
152#warning "Warning: PHS_02 Arrays have not been implemented!"
153 throw std::runtime_error("Arrays have not been implemented!");
154 break;
155 }
156 }
157}
158
159void BytecodeSerializer::writeVariableMapping(const std::unordered_map<std::string, int> &variables, int nextVarIndex)
160{
162 writeUInt32(static_cast<uint32_t>(variables.size()));
163 writeInt32(nextVarIndex);
164
165 for (const auto &[name, index] : variables)
166 {
167 writeString(name);
168 writeInt32(index);
169 }
170}
171
172void BytecodeSerializer::writeInstructions(const std::vector<Instruction> &instructions)
173{
175 writeUInt32(static_cast<uint32_t>(instructions.size()));
176
177 for (const auto &instr : instructions)
178 {
179 writeUInt8(static_cast<uint8_t>(instr.op));
180 writeInt32(instr.operand1);
181 writeInt32(instr.operand2);
182 writeInt32(instr.operand3);
183 }
184}
185
186void BytecodeSerializer::writeFunctionEntries(const std::unordered_map<std::string, int> &functionEntries)
187{
189 writeUInt32(static_cast<uint32_t>(functionEntries.size()));
190
191 for (const auto &[name, address] : functionEntries)
192 {
193 writeString(name);
194 writeInt32(address);
195 }
196}
197
198std::vector<uint8_t> BytecodeSerializer::serialize(const Bytecode &bytecode)
199{
200 buffer.clear();
201
202 for (int i = 0; i < 16; i++)
203 {
204 buffer.push_back(0);
205 }
206
207 // Write all sections
208 size_t dataStartPos = buffer.size();
210 writeVariableMapping(bytecode.variables, bytecode.nextVarIndex);
213
214 // Calculate checksum of data (everything after header)
215 std::vector<uint8_t> dataSection(buffer.begin() + dataStartPos, buffer.end());
216 uint32_t checksum = calculateCRC32(dataSection);
217
218 // Write header at the beginning
219 std::vector<uint8_t> tempBuffer = buffer;
220 buffer.clear();
221 writeHeader(checksum);
222
223 // Append the data sections
224 buffer.insert(buffer.end(), tempBuffer.begin() + 16, tempBuffer.end());
225
226 return buffer;
227}
228
229bool BytecodeSerializer::saveToFile(const Bytecode &bytecode, const std::filesystem::path &filename)
230{
231 try
232 {
233 std::vector<uint8_t> data = serialize(bytecode);
234
235 std::ofstream file(filename, std::ios::binary);
236 if (!file.is_open())
237 {
238 return false;
239 }
240
241 file.write(reinterpret_cast<const char *>(data.data()), data.size());
242 file.close();
243
244 return true;
245 }
246 catch (const std::exception &)
247 {
248 return false;
249 }
250}
251} // namespace Phasor
const uint8_t SECTION_CONSTANTS
const uint8_t SECTION_VARIABLES
const uint8_t SECTION_FUNCTIONS
const uint8_t SECTION_INSTRUCTIONS
static uint32_t crc32_table[256]
static bool crc32_table_initialized
void init_crc32_table()
Init CRC32 Table.
void writeUInt16(uint16_t value)
Helper method to write UInt16.
void writeInstructions(const std::vector< Instruction > &instructions)
Helper method to write Instruction Table.
void writeString(const std::string &str)
Helper method to write String.
void writeInt64(int64_t value)
Helper method to write Int64.
void writeUInt8(uint8_t value)
Helper method to write UInt8.
void writeFunctionEntries(const std::unordered_map< std::string, int > &functionEntries)
Helper method to write Function Table.
bool saveToFile(const Bytecode &bytecode, const std::filesystem::path &filename)
Save bytecode to .phsb file.
std::vector< uint8_t > buffer
void writeInt32(int32_t value)
Helper method to write Int32.
static uint32_t calculateCRC32(const std::vector< uint8_t > &data)
Calculate CRC32 checksum.
std::vector< uint8_t > serialize(const Bytecode &bytecode)
Serialize bytecode to binary buffer.
void writeHeader(uint32_t dataChecksum)
Section writers.
void writeConstantPool(const std::vector< Value > &constants)
Helper method to write Constants Table.
void writeUInt32(uint32_t value)
Helper method to write UInt32.
void writeDouble(double value)
Helper method to write Double.
void writeVariableMapping(const std::unordered_map< std::string, int > &variables, int nextVarIndex)
Helper method to write Variable Map Table.
const uint32_t VERSION
Version number.
Definition metadata.h:22
#define MAGIC_NUMBER
Magic number (little endian).
Definition metadata.h:15
The Phasor Programming Language and Runtime.
Definition AST.hpp:12
ValueType
Runtime value types for the VM.
Definition Value.hpp:42
Complete bytecode structure.
Definition CodeGen.hpp:50
std::unordered_map< std::string, int > variables
Variable name -> index mapping.
Definition CodeGen.hpp:53
std::vector< Instruction > instructions
List of instructions.
Definition CodeGen.hpp:51
std::unordered_map< std::string, int > functionEntries
Function name -> instruction index mapping.
Definition CodeGen.hpp:54
int nextVarIndex
Next available variable index.
Definition CodeGen.hpp:56
std::vector< Value > constants
Constant pool.
Definition CodeGen.hpp:52