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#include <phsint.hpp>
8
9// Section IDs
15
17static bool crc32_table_initialized = false;
18
20{
21 for (Phasor::u32 i = 0; i < 256; i++)
22 {
23 Phasor::u32 crc = i;
24 for (int j = 0; j < 8; j++)
25 {
26 if ((crc & 1) != 0u)
27 crc = (crc >> 1) ^ 0xEDB88320;
28 else
29 crc >>= 1;
30 }
31 crc32_table[i] = crc;
32 }
34}
35
36namespace Phasor
37{
38
39u32 BytecodeSerializer::calculateCRC32(const std::vector<u8> &data)
40{
43
44 u32 crc = 0xFFFFFFFF;
45 for (u8 byte : data)
46 crc = (crc >> 8) ^ crc32_table[(crc ^ byte) & 0xFF];
47 return crc ^ 0xFFFFFFFF;
48}
49
50// ---------------------------------------------------------------------------
51// Primitive writers
52// ---------------------------------------------------------------------------
53
55{
56 buffer.push_back(value);
57}
58
60{
61 buffer.push_back(static_cast<u8>(value & 0xFF));
62 buffer.push_back(static_cast<u8>((value >> 8) & 0xFF));
63}
64
66{
67 buffer.push_back(static_cast<u8>(value & 0xFF));
68 buffer.push_back(static_cast<u8>((value >> 8) & 0xFF));
69 buffer.push_back(static_cast<u8>((value >> 16) & 0xFF));
70 buffer.push_back(static_cast<u8>((value >> 24) & 0xFF));
71}
72
74{
75 writeUInt32(static_cast<u32>(value));
76}
77
79{
80 for (int i = 0; i < 8; i++)
81 buffer.push_back(static_cast<u8>((value >> (i * 8)) & 0xFF));
82}
83
85{
86 u64 bits;
87 std::memcpy(&bits, &value, sizeof(f64));
88 for (int i = 0; i < 8; i++)
89 buffer.push_back(static_cast<u8>((bits >> (i * 8)) & 0xFF));
90}
91
92void BytecodeSerializer::writeString(const std::string &str)
93{
94 writeUInt16(static_cast<u16>(str.length()));
95 for (char c : str)
96 buffer.push_back(static_cast<u8>(c));
97}
98
99// ---------------------------------------------------------------------------
100// Recursive value writer
101//
102// Binary layout per value:
103// Null : u8(0)
104// Bool : u8(1) u8(0|1)
105// Int : u8(2) i64
106// Float : u8(3) f64
107// String : u8(4) u16(len) chars...
108// Struct : u8(5) string(structName) u32(fieldCount) [string(fieldName) value]...
109// Array : u8(6) u32(elementCount) [value]...
110// ---------------------------------------------------------------------------
112{
113 switch (val.getType())
114 {
115 case ValueType::Null:
116 writeUInt8(0);
117 break;
118
119 case ValueType::Bool:
120 writeUInt8(1);
121 writeUInt8(val.asBool() ? 1 : 0);
122 break;
123
124 case ValueType::Int:
125 writeUInt8(2);
126 writeInt64(val.asInt());
127 break;
128
129 case ValueType::Float:
130 writeUInt8(3);
131 writeDouble(val.asFloat());
132 break;
133
135 writeUInt8(4);
136 writeString(val.asString().str());
137 break;
138
140 {
141 auto s = val.asStruct();
142 writeUInt8(5);
143 writeString(s->structName.str());
144 writeUInt32(static_cast<u32>(s->fields.size()));
145 for (const auto &[fieldName, fieldVal] : s->fields)
146 {
147 writeString(fieldName.str());
148 writeValue(fieldVal); // recurse
149 }
150 break;
151 }
152
153 case ValueType::Array:
154 {
155 auto a = val.asArray();
156 writeUInt8(6);
157 writeUInt32(static_cast<u32>(a->size()));
158 for (const auto &elem : *a)
159 writeValue(elem); // recurse
160 break;
161 }
162
163 default:
164 throw std::runtime_error("BytecodeSerializer::writeValue: unknown ValueType");
165 }
166}
167
168// ---------------------------------------------------------------------------
169// Section writers
170// ---------------------------------------------------------------------------
171
173{
176 writeUInt32(0); // Flags (reserved)
177 writeUInt32(dataChecksum);
178}
179
180void BytecodeSerializer::writeConstantPool(const std::vector<Value> &constants)
181{
183 writeUInt32(static_cast<u32>(constants.size()));
184 for (const auto &val : constants)
185 writeValue(val);
186}
187
188void BytecodeSerializer::writeVariableMapping(const std::unordered_map<std::string, int> &variables,
189 int nextVarIndex)
190{
192 writeUInt32(static_cast<u32>(variables.size()));
193 writeInt32(nextVarIndex);
194 for (const auto &[name, index] : variables)
195 {
196 writeString(name);
197 writeInt32(index);
198 }
199}
200
201void BytecodeSerializer::writeInstructions(const std::vector<Instruction> &instructions)
202{
204 writeUInt32(static_cast<u32>(instructions.size()));
205 for (const auto &instr : instructions)
206 {
207 writeUInt8(static_cast<u8>(instr.op));
208 writeInt32(instr.operand1);
209 writeInt32(instr.operand2);
210 writeInt32(instr.operand3);
211 }
212}
213
214void BytecodeSerializer::writeFunctionEntries(const std::unordered_map<std::string, int> &functionEntries)
215{
217 writeUInt32(static_cast<u32>(functionEntries.size()));
218 for (const auto &[name, address] : functionEntries)
219 {
220 writeString(name);
221 writeInt32(address);
222 }
223}
224
237void BytecodeSerializer::writeStructSection(const std::vector<StructInfo> &structs)
238{
240 writeUInt32(static_cast<u32>(structs.size()));
241 for (const auto &info : structs)
242 {
243 writeString(info.name);
244 writeInt32(info.firstConstIndex);
245 writeInt32(info.fieldCount);
246 for (const auto &fieldName : info.fieldNames)
247 writeString(fieldName);
248 }
249}
250
251// ---------------------------------------------------------------------------
252// Top-level serialize / saveToFile
253// ---------------------------------------------------------------------------
254
255std::vector<u8> BytecodeSerializer::serialize(const Bytecode &bytecode)
256{
257 buffer.clear();
258
259 // Reserve 16 bytes for the header (written after checksum is known).
260 for (int i = 0; i < 16; i++)
261 buffer.push_back(0);
262
263 size_t dataStartPos = buffer.size();
265 writeVariableMapping(bytecode.variables, bytecode.nextVarIndex);
267 writeStructSection(bytecode.structs);
269
270 std::vector<u8> dataSection(buffer.begin() + dataStartPos, buffer.end());
271 u32 checksum = calculateCRC32(dataSection);
272
273 std::vector<u8> tempBuffer = buffer;
274 buffer.clear();
275 writeHeader(checksum);
276 buffer.insert(buffer.end(), tempBuffer.begin() + 16, tempBuffer.end());
277
278 return buffer;
279}
280
281bool BytecodeSerializer::saveToFile(const Bytecode &bytecode, const std::filesystem::path &filename)
282{
283 try
284 {
285 std::vector<u8> data = serialize(bytecode);
286 std::ofstream file(filename, std::ios::binary);
287 if (!file.is_open())
288 return false;
289 file.write(reinterpret_cast<const char *>(data.data()), data.size());
290 return true;
291 }
292 catch (const std::exception &)
293 {
294 return false;
295 }
296}
297
298} // namespace Phasor
const Phasor::u8 SECTION_FUNCTIONS
const Phasor::u8 SECTION_VARIABLES
const Phasor::u8 SECTION_STRUCTS
const Phasor::u8 SECTION_CONSTANTS
const Phasor::u8 SECTION_INSTRUCTIONS
static Phasor::u32 crc32_table[256]
static bool crc32_table_initialized
void init_crc32_table()
std::vector< u8 > serialize(const Bytecode &bytecode)
Serialize bytecode to binary buffer.
void writeDouble(f64 value)
Helper method to write Double.
void writeInstructions(const std::vector< Instruction > &instructions)
Helper method to write Instruction Table.
static u32 calculateCRC32(const std::vector< u8 > &data)
Calculate CRC32 checksum.
void writeString(const std::string &str)
Helper method to write String.
void writeValue(const Value &val)
Write a single Value (recursive — handles nested structs/arrays).
void writeInt64(i64 value)
Helper method to write Int64.
void writeUInt32(u32 value)
Helper method to write UInt32.
void writeInt32(i32 value)
Helper method to write Int32.
void writeStructSection(const std::vector< StructInfo > &structs)
Helper method to write Struct Section.
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.
void writeHeader(u32 dataChecksum)
Section writers.
void writeUInt8(u8 value)
Helper method to write UInt8.
void writeUInt16(u16 value)
Helper method to write UInt16.
void writeConstantPool(const std::vector< Value > &constants)
Helper method to write Constants Table.
void writeVariableMapping(const std::unordered_map< std::string, int > &variables, int nextVarIndex)
Helper method to write Variable Map Table.
std::string str() const
A value in the Phasor VM.
Definition Value.hpp:59
PhsString asString() const noexcept
Get the value as a Small String.
Definition Value.hpp:199
std::shared_ptr< StructInstance > asStruct()
Definition Value.hpp:557
std::shared_ptr< ArrayInstance > asArray()
Get the value as an array.
Definition Value.hpp:208
ValueType getType() const noexcept
Get the type of the value.
Definition Value.hpp:118
f64 asFloat() const noexcept
Get the value as a f64.
Definition Value.hpp:177
i64 asInt() const noexcept
Get the value as an integer.
Definition Value.hpp:164
bool asBool() const noexcept
Get the value as a boolean.
Definition Value.hpp:159
static Phasor::u64 s[2]
Definition random.cpp:7
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:13
int64_t i64
Definition phsint.hpp:16
uint8_t u8
Definition phsint.hpp:9
double f64
Definition phsint.hpp:7
uint64_t u64
Definition phsint.hpp:12
int32_t i32
Definition phsint.hpp:15
uint16_t u16
Definition phsint.hpp:10
uint32_t u32
Definition phsint.hpp:11
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
std::vector< StructInfo > structs
List of struct descriptors.
Definition CodeGen.hpp:59