Phasor 2.2.0
Stack VM based Programming Language
Loading...
Searching...
No Matches
BytecodeDeserializer.cpp
Go to the documentation of this file.
2#include <cstring>
3#include <stdexcept>
4#include <filesystem>
5#include "metadata.h"
6
7// Section IDs
8const uint8_t SECTION_CONSTANTS = 0x01; //< Constants Section
9const uint8_t SECTION_VARIABLES = 0x02; //< Variables Section
10const uint8_t SECTION_INSTRUCTIONS = 0x03; //< Instructions Section
11const uint8_t SECTION_FUNCTIONS = 0x04; //< Functions Section
12
13static uint32_t crc32_table[256]; //< CRC32 lookup table
14static bool crc32_table_initialized = false;
15
18{
19 for (uint32_t i = 0; i < 256; i++)
20 {
21 uint32_t crc = i;
22 for (int j = 0; j < 8; j++)
23 {
24 if (crc & 1)
25 {
26 crc = (crc >> 1) ^ 0xEDB88320;
27 }
28 else
29 {
30 crc >>= 1;
31 }
32 }
33 crc32_table[i] = crc;
34 }
36}
37
38namespace Phasor
39{
40
41uint32_t BytecodeDeserializer::calculateCRC32(const uint8_t *data, size_t size)
42{
44 {
46 }
47
48 uint32_t crc = 0xFFFFFFFF;
49 for (size_t i = 0; i < size; i++)
50 {
51 crc = (crc >> 8) ^ crc32_table[(crc ^ data[i]) & 0xFF];
52 }
53 return crc ^ 0xFFFFFFFF;
54}
55
57{
58 if (position >= dataSize)
59 {
60 throw std::runtime_error("Unexpected end of bytecode data");
61 }
62 return _data[position++];
63}
64
66{
67 uint16_t value = 0;
68 value |= static_cast<uint16_t>(readUInt8());
69 value |= static_cast<uint16_t>(readUInt8()) << 8;
70 return value;
71}
72
74{
75 uint32_t value = 0;
76 value |= static_cast<uint32_t>(readUInt8());
77 value |= static_cast<uint32_t>(readUInt8()) << 8;
78 value |= static_cast<uint32_t>(readUInt8()) << 16;
79 value |= static_cast<uint32_t>(readUInt8()) << 24;
80 return value;
81}
82
84{
85 return static_cast<int32_t>(readUInt32());
86}
87
89{
90 int64_t value = 0;
91 for (int i = 0; i < 8; i++)
92 {
93 value |= static_cast<int64_t>(readUInt8()) << (i * 8);
94 }
95 return value;
96}
97
99{
100 uint64_t bits = 0;
101 for (int i = 0; i < 8; i++)
102 {
103 bits |= static_cast<uint64_t>(readUInt8()) << (i * 8);
104 }
105 double value;
106 std::memcpy(&value, &bits, sizeof(double));
107 return value;
108}
109
111{
112 uint16_t length = readUInt16();
113 std::string str;
114 str.reserve(length);
115 for (uint16_t i = 0; i < length; i++)
116 {
117 str.push_back(static_cast<char>(readUInt8()));
118 }
119 return str;
120}
121
122void BytecodeDeserializer::readHeader(uint32_t &checksum)
123{
124 uint32_t magic = readUInt32();
125 if (magic != MAGIC_NUMBER)
126 {
127 throw std::runtime_error("Invalid bytecode file: incorrect magic number");
128 }
129
130 uint32_t version = readUInt32();
131 if (version != VERSION)
132 {
133 throw std::runtime_error("Incompatible bytecode version");
134 }
135
136 uint32_t flags = readUInt32(); // Reserved for future use
137 (void)flags;
138
139 checksum = readUInt32();
140}
141
143{
144 uint8_t sectionId = readUInt8();
145 if (sectionId != SECTION_CONSTANTS)
146 {
147 throw std::runtime_error("Expected constant pool section");
148 }
149
150 uint32_t count = readUInt32();
151 bytecode.constants.reserve(count);
152
153 for (uint32_t i = 0; i < count; i++)
154 {
155 uint8_t typeTag = readUInt8();
156
157 switch (typeTag)
158 {
159 case 0: // Null
160 bytecode.constants.push_back(Value());
161 break;
162 case 1: // Bool
163 {
164 uint8_t boolValue = readUInt8();
165 bytecode.constants.push_back(Value(boolValue != 0));
166 break;
167 }
168 case 2: // Int
169 {
170 int64_t intValue = readInt64();
171 bytecode.constants.push_back(Value(intValue));
172 break;
173 }
174 case 3: // Float
175 {
176 double floatValue = readDouble();
177 bytecode.constants.push_back(Value(floatValue));
178 break;
179 }
180 case 4: // String
181 {
182 std::string strValue = readString();
183 bytecode.constants.push_back(Value(strValue));
184 break;
185 }
186 default:
187 throw std::runtime_error("Unknown value type in constant pool");
188 }
189 }
190}
191
193{
194 uint8_t sectionId = readUInt8();
195 if (sectionId != SECTION_VARIABLES)
196 {
197 throw std::runtime_error("Expected variable mapping section");
198 }
199
200 uint32_t count = readUInt32();
201 bytecode.nextVarIndex = readInt32();
202
203 for (uint32_t i = 0; i < count; i++)
204 {
205 std::string name = readString();
206 int32_t index = readInt32();
207 bytecode.variables[name] = index;
208 }
209}
210
212{
213 uint8_t sectionId = readUInt8();
214 if (sectionId != SECTION_INSTRUCTIONS)
215 {
216 throw std::runtime_error("Expected instructions section");
217 }
218
219 uint32_t count = readUInt32();
220 bytecode.instructions.reserve(count);
221
222 for (uint32_t i = 0; i < count; i++)
223 {
224 uint8_t opcode = readUInt8();
225 int32_t op1 = readInt32();
226 int32_t op2 = readInt32();
227 int32_t op3 = readInt32();
228 int32_t op4 = readInt32();
229 int32_t op5 = readInt32();
230 bytecode.instructions.push_back(Instruction(static_cast<OpCode>(opcode), op1, op2, op3, op4, op5));
231 }
232}
233
235{
236 uint8_t sectionId = readUInt8();
237 if (sectionId != SECTION_FUNCTIONS)
238 {
239 throw std::runtime_error("Expected function entries section");
240 }
241
242 uint32_t count = readUInt32();
243
244 for (uint32_t i = 0; i < count; i++)
245 {
246 std::string name = readString();
247 int32_t address = readInt32();
248 bytecode.functionEntries[name] = address;
249 }
250}
251
252Bytecode BytecodeDeserializer::deserialize(const std::vector<uint8_t> &buffer)
253{
254 _data = buffer.data();
255 dataSize = buffer.size();
256 position = 0;
257
258 Bytecode bytecode;
259
260 // Read header
261 uint32_t expectedChecksum;
262 readHeader(expectedChecksum);
263
264 // Calculate checksum of data section
265 size_t dataStart = position;
266 uint32_t actualChecksum = calculateCRC32(_data + dataStart, dataSize - dataStart);
267
268 if (actualChecksum != expectedChecksum)
269 {
270 throw std::runtime_error("Bytecode file corrupted: checksum mismatch");
271 }
272
273 // Read sections
274 readConstantPool(bytecode);
275 readVariableMapping(bytecode);
276 readFunctionEntries(bytecode);
277 readInstructions(bytecode);
278
279 return bytecode;
280}
281
282Bytecode BytecodeDeserializer::loadFromFile(const std::filesystem::path &filename)
283{
284 std::ifstream file(filename, std::ios::binary | std::ios::ate);
285 if (!file.is_open())
286 {
287 throw std::runtime_error("Failed to open bytecode file: " + filename.string());
288 }
289
290 std::streamsize size = file.tellg();
291 file.seekg(0, std::ios::beg);
292
293 std::vector<uint8_t> buffer(size);
294 if (!file.read(reinterpret_cast<char *>(buffer.data()), size))
295 {
296 throw std::runtime_error("Failed to read bytecode file: " + filename.string());
297 }
298
299 file.close();
300
301 return deserialize(buffer);
302}
303} // namespace Phasor
const uint8_t SECTION_CONSTANTS
const uint8_t SECTION_VARIABLES
void init_crc32_table_deserializer()
Deserialize CRC32 Table.
const uint8_t SECTION_FUNCTIONS
const uint8_t SECTION_INSTRUCTIONS
static uint32_t crc32_table[256]
static bool crc32_table_initialized
uint32_t readUInt32()
Helper method to read UInt32.
void readInstructions(Bytecode &bytecode)
Helper method to read Instuctions Table.
uint32_t calculateCRC32(const uint8_t *data, size_t size)
Calculate CRC32 checksum.
void readHeader(uint32_t &checksum)
Helper method to read Header.
void readConstantPool(Bytecode &bytecode)
Helper method to read Constants Table.
Bytecode loadFromFile(const std::filesystem::path &filename)
Load bytecode from .phsb file.
void readFunctionEntries(Bytecode &bytecode)
Helper method to read Function Entries.
uint16_t readUInt16()
Helper method to read UInt16.
Bytecode deserialize(const std::vector< uint8_t > &data)
Deserialize bytecode from binary buffer.
void readVariableMapping(Bytecode &bytecode)
Helper method to read Variable Table.
uint8_t readUInt8()
Helper method to read UInt8.
int32_t readInt32()
Helper method to read Int32.
A value in the Phasor VM.
Definition Value.hpp:33
const uint32_t VERSION
Version number.
Definition metadata.h:24
#define MAGIC_NUMBER
Magic number (little endian).
Definition metadata.h:17
The Phasor Programming Language and Runtime.
Definition AST.hpp:8
Complete bytecode structure.
Definition CodeGen.hpp:201
std::vector< Value > constants
Constant pool.
Definition CodeGen.hpp:203
std::map< std::string, int > functionEntries
Function name -> instruction index mapping.
Definition CodeGen.hpp:205
int nextVarIndex
Next available variable index.
Definition CodeGen.hpp:206
std::map< std::string, int > variables
Variable name -> index mapping.
Definition CodeGen.hpp:204
std::vector< Instruction > instructions
List of instructions.
Definition CodeGen.hpp:202
Instruction with up to 5 operands Format: instruction operand1, operand2, operand3,...
Definition CodeGen.hpp:170