Lines
100 %
Functions
63.64 %
Branches
use std::mem::offset_of;
use scripting_format::{
DEBUG_VALUE_DATA_SIZE, DebugValueData, ENTITY_HEADER_SIZE, EntityHeader, EntityType,
MAGIC_OUTP, OUTPUT_HEADER_SIZE, Operation, OutputHeader, TAG_DATA_SIZE, TagData, ValueType,
};
use tracing::debug;
use super::emit::FunctionEmitter;
pub struct GcLocals {
pub type_idx: u32,
pub arr: u32,
pub idx: u32,
}
pub struct OutputSerializer {
cursor: u32,
entity_count: u32,
output_start_idx: u32,
output_base_local: u32,
impl OutputSerializer {
pub fn new(output_base_local: u32) -> Self {
Self {
cursor: 0,
entity_count: 0,
output_start_idx: 0,
output_base_local,
pub fn begin_output(&mut self, emit: &mut FunctionEmitter) {
debug!(cursor = self.cursor, "writing output header");
let local = self.output_base_local;
emit.store_i32_dynamic(
local,
self.cursor + offset_of!(OutputHeader, magic) as u32,
MAGIC_OUTP as i32,
);
self.cursor + offset_of!(OutputHeader, output_entity_count) as u32,
0,
self.cursor + offset_of!(OutputHeader, output_start_idx) as u32,
self.output_start_idx as i32,
self.cursor += OUTPUT_HEADER_SIZE as u32;
fn append_entity_header(
&mut self,
emit: &mut FunctionEmitter,
entity_type: EntityType,
operation: Operation,
flags: u8,
parent_idx: i32,
data_size: u32,
) -> u32 {
debug!(
cursor = self.cursor,
?entity_type,
"appending entity header"
let data_offset = self.cursor + ENTITY_HEADER_SIZE as u32;
emit.store_u8_dynamic(
self.cursor + offset_of!(EntityHeader, entity_type) as u32,
entity_type as u8,
self.cursor + offset_of!(EntityHeader, operation) as u32,
operation as u8,
self.cursor + offset_of!(EntityHeader, flags) as u32,
flags,
self.cursor + offset_of!(EntityHeader, parent_idx) as u32,
parent_idx,
// data_offset is relative — the runtime adds output_base
self.cursor + offset_of!(EntityHeader, data_offset) as u32,
data_offset as i32,
self.cursor + offset_of!(EntityHeader, data_size) as u32,
data_size as i32,
self.cursor += ENTITY_HEADER_SIZE as u32;
self.entity_count += 1;
offset_of!(OutputHeader, output_entity_count) as u32,
self.entity_count as i32,
data_offset
fn begin_debug_value_entity(&mut self, emit: &mut FunctionEmitter) -> u32 {
self.append_entity_header(
emit,
EntityType::DebugValue,
Operation::Nop,
-1,
DEBUG_VALUE_DATA_SIZE as u32,
)
pub fn write_debug_nil(&mut self, emit: &mut FunctionEmitter) {
let data_start = self.begin_debug_value_entity(emit);
debug!(data_start, "writing nil value");
data_start + offset_of!(DebugValueData, value_type) as u32,
ValueType::Nil as u8,
self.cursor = data_start + DEBUG_VALUE_DATA_SIZE as u32;
self.finalize_cursor(emit);
pub fn write_debug_bool(&mut self, emit: &mut FunctionEmitter, value: bool) {
debug!(data_start, value, "writing bool value");
ValueType::Bool as u8,
emit.store_i64_dynamic(
data_start + offset_of!(DebugValueData, data1) as u32,
i64::from(value),
pub fn write_debug_number(&mut self, emit: &mut FunctionEmitter, numer: i64, denom: i64) {
debug!(data_start, numer, denom, "writing number value");
ValueType::Number as u8,
numer,
data_start + offset_of!(DebugValueData, data2) as u32,
denom,
pub fn write_debug_string_gc(
value_type: ValueType,
data_idx: u32,
len: u32,
gc: &GcLocals,
) {
?value_type,
data_idx,
len,
"writing string value with GC"
let strings_pool = data_start + DEBUG_VALUE_DATA_SIZE as u32;
value_type as u8,
i64::from(len),
self.copy_data_gc(emit, data_idx, len, strings_pool, gc);
offset_of!(OutputHeader, strings_offset) as u32,
strings_pool as i32,
self.cursor += len;
offset_of!(OutputHeader, next_write_pos) as u32,
self.cursor as i32,
pub fn write_tag_gc(
name_data_idx: u32,
name_len: u32,
value_data_idx: u32,
value_len: u32,
let data_start = self.append_entity_header(
EntityType::Tag,
Operation::Create,
TAG_DATA_SIZE as u32,
let strings_start = data_start + TAG_DATA_SIZE as u32;
let name_start = strings_start;
let value_start = name_start + name_len;
let strings_end = value_start + value_len;
let name_offset = strings_end - name_start;
let value_offset = strings_end - value_start;
data_start + offset_of!(TagData, name_offset) as u32,
name_offset as i32,
data_start + offset_of!(TagData, value_offset) as u32,
value_offset as i32,
data_start + offset_of!(TagData, name_len) as u32,
((value_len as i32) << 16) | (name_len as i32),
emit.store_i32_dynamic(local, data_start + offset_of!(TagData, reserved) as u32, 0);
self.copy_data_gc(emit, name_data_idx, name_len, name_start, gc);
self.copy_data_gc(emit, value_data_idx, value_len, value_start, gc);
self.cursor = strings_end;
strings_end as i32,
fn copy_data_gc(
&self,
dst_offset: u32,
emit.i32_const(0);
emit.i32_const(len as i32);
emit.array_new_data(gc.type_idx, data_idx);
emit.local_set(gc.arr);
emit.local_set(gc.idx);
emit.block_start();
emit.loop_start();
emit.local_get(gc.idx);
emit.i32_ge_u();
emit.br_if(1);
emit.local_get(local);
emit.i32_const(dst_offset as i32);
emit.i32_add();
emit.local_get(gc.arr);
emit.array_get_u(gc.type_idx);
emit.i32_store8_raw();
emit.i32_const(1);
emit.br(0);
emit.block_end();
fn finalize_cursor(&self, emit: &mut FunctionEmitter) {