use facet_format::jit::{
AbiParam, BlockArg, FunctionBuilder, InstBuilder, IntCC,
JIT_SCRATCH_MAX_COLLECTION_ELEMENTS_OFFSET, JITBuilder, JITModule, JitCursor, JitFormat,
JitStringValue, MemFlags, StructEncoding, Value, types,
};
use super::helpers;
#[derive(Debug, Clone, Copy, Default)]
pub struct PostcardJitFormat;
pub mod error {
pub use super::helpers::error::*;
}
impl PostcardJitFormat {
fn emit_varint_decode(builder: &mut FunctionBuilder, cursor: &mut JitCursor) -> (Value, Value) {
let result_var = builder.declare_var(types::I64);
let shift_var = builder.declare_var(types::I32);
let error_var = builder.declare_var(types::I32);
let value_var = builder.declare_var(types::I64);
let zero_i64 = builder.ins().iconst(types::I64, 0);
let zero_i32 = builder.ins().iconst(types::I32, 0);
builder.def_var(result_var, zero_i64);
builder.def_var(shift_var, zero_i32);
builder.def_var(error_var, zero_i32);
builder.def_var(value_var, zero_i64);
let loop_header = builder.create_block();
let load_byte = builder.create_block();
let process_byte = builder.create_block();
let check_continue = builder.create_block();
let check_overflow = builder.create_block();
let done = builder.create_block();
let eof_error = builder.create_block();
let overflow_error = builder.create_block();
let merge = builder.create_block();
builder.ins().jump(loop_header, &[]);
builder.switch_to_block(loop_header);
let current_pos = builder.use_var(cursor.pos);
let have_byte = builder
.ins()
.icmp(IntCC::UnsignedLessThan, current_pos, cursor.len);
builder
.ins()
.brif(have_byte, load_byte, &[], eof_error, &[]);
builder.switch_to_block(load_byte);
builder.seal_block(load_byte);
let addr = builder.ins().iadd(cursor.input_ptr, current_pos);
let byte = builder.ins().load(types::I8, MemFlags::trusted(), addr, 0);
let one = builder.ins().iconst(cursor.ptr_type, 1);
let next_pos = builder.ins().iadd(current_pos, one);
builder.def_var(cursor.pos, next_pos);
builder.ins().jump(process_byte, &[]);
builder.switch_to_block(process_byte);
builder.seal_block(process_byte);
let byte_i64 = builder.ins().uextend(types::I64, byte);
let mask_7f = builder.ins().iconst(types::I64, 0x7F);
let data = builder.ins().band(byte_i64, mask_7f);
let shift = builder.use_var(shift_var);
let shift_i64 = builder.ins().uextend(types::I64, shift);
let shifted_data = builder.ins().ishl(data, shift_i64);
let result = builder.use_var(result_var);
let new_result = builder.ins().bor(result, shifted_data);
builder.def_var(result_var, new_result);
builder.ins().jump(check_continue, &[]);
builder.switch_to_block(check_continue);
builder.seal_block(check_continue);
let mask_80 = builder.ins().iconst(types::I8, 0x80u8 as i64);
let cont_bit = builder.ins().band(byte, mask_80);
let has_more = builder.ins().icmp_imm(IntCC::NotEqual, cont_bit, 0);
builder.ins().brif(has_more, check_overflow, &[], done, &[]);
builder.switch_to_block(check_overflow);
builder.seal_block(check_overflow);
let seven = builder.ins().iconst(types::I32, 7);
let new_shift = builder.ins().iadd(shift, seven);
builder.def_var(shift_var, new_shift);
let overflow_limit = builder.ins().iconst(types::I32, 64);
let is_overflow =
builder
.ins()
.icmp(IntCC::UnsignedGreaterThanOrEqual, new_shift, overflow_limit);
builder
.ins()
.brif(is_overflow, overflow_error, &[], loop_header, &[]);
builder.seal_block(loop_header);
builder.switch_to_block(eof_error);
builder.seal_block(eof_error);
let eof_err = builder
.ins()
.iconst(types::I32, error::UNEXPECTED_EOF as i64);
builder.def_var(error_var, eof_err);
builder.ins().jump(merge, &[]);
builder.switch_to_block(overflow_error);
builder.seal_block(overflow_error);
let overflow_err = builder
.ins()
.iconst(types::I32, error::VARINT_OVERFLOW as i64);
builder.def_var(error_var, overflow_err);
builder.ins().jump(merge, &[]);
builder.switch_to_block(done);
builder.seal_block(done);
let final_result = builder.use_var(result_var);
builder.def_var(value_var, final_result);
builder.ins().jump(merge, &[]);
builder.switch_to_block(merge);
builder.seal_block(merge);
let value = builder.use_var(value_var);
let err = builder.use_var(error_var);
(value, err)
}
}
impl JitFormat for PostcardJitFormat {
fn register_helpers(builder: &mut JITBuilder) {
builder.symbol(
"postcard_jit_read_varint",
helpers::postcard_jit_read_varint as *const u8,
);
builder.symbol(
"postcard_jit_seq_begin",
helpers::postcard_jit_seq_begin as *const u8,
);
builder.symbol(
"postcard_jit_seq_is_end",
helpers::postcard_jit_seq_is_end as *const u8,
);
builder.symbol(
"postcard_jit_seq_next",
helpers::postcard_jit_seq_next as *const u8,
);
builder.symbol(
"postcard_jit_parse_bool",
helpers::postcard_jit_parse_bool as *const u8,
);
builder.symbol(
"postcard_jit_bulk_copy_u8",
helpers::postcard_jit_bulk_copy_u8 as *const u8,
);
}
fn helper_seq_begin() -> Option<&'static str> {
Some("postcard_jit_seq_begin")
}
fn helper_seq_is_end() -> Option<&'static str> {
Some("postcard_jit_seq_is_end")
}
fn helper_seq_next() -> Option<&'static str> {
Some("postcard_jit_seq_next")
}
fn helper_parse_bool() -> Option<&'static str> {
Some("postcard_jit_parse_bool")
}
const SEQ_STATE_SIZE: u32 = 8; const SEQ_STATE_ALIGN: u32 = 8;
const PROVIDES_SEQ_COUNT: bool = true;
const MAP_STATE_SIZE: u32 = 8;
const MAP_STATE_ALIGN: u32 = 8;
const STRUCT_ENCODING: StructEncoding = StructEncoding::Positional;
fn emit_skip_ws(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
_cursor: &mut JitCursor,
) -> Value {
builder.ins().iconst(types::I32, 0)
}
fn emit_skip_value(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
_cursor: &mut JitCursor,
) -> Value {
builder.ins().iconst(types::I32, error::UNSUPPORTED as i64)
}
fn emit_peek_null(
&self,
builder: &mut FunctionBuilder,
_cursor: &mut JitCursor,
) -> (Value, Value) {
let zero = builder.ins().iconst(types::I8, 0);
let err = builder.ins().iconst(types::I32, error::UNSUPPORTED as i64);
(zero, err)
}
fn emit_consume_null(&self, builder: &mut FunctionBuilder, _cursor: &mut JitCursor) -> Value {
builder.ins().iconst(types::I32, error::UNSUPPORTED as i64)
}
fn emit_parse_bool(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
) -> (Value, Value) {
let pos = builder.use_var(cursor.pos);
let result_value_var = builder.declare_var(types::I8);
let result_error_var = builder.declare_var(types::I32);
let zero_i8 = builder.ins().iconst(types::I8, 0);
let zero_i32 = builder.ins().iconst(types::I32, 0);
builder.def_var(result_value_var, zero_i8);
builder.def_var(result_error_var, zero_i32);
let have_byte = builder.ins().icmp(IntCC::UnsignedLessThan, pos, cursor.len);
let check_byte = builder.create_block();
let valid_false = builder.create_block();
let check_true = builder.create_block();
let valid_true = builder.create_block();
let invalid_bool = builder.create_block();
let eof_error = builder.create_block();
let merge = builder.create_block();
builder
.ins()
.brif(have_byte, check_byte, &[], eof_error, &[]);
builder.switch_to_block(eof_error);
builder.seal_block(eof_error);
let eof_err = builder
.ins()
.iconst(types::I32, error::UNEXPECTED_EOF as i64);
builder.def_var(result_error_var, eof_err);
builder.ins().jump(merge, &[]);
builder.switch_to_block(check_byte);
builder.seal_block(check_byte);
let addr = builder.ins().iadd(cursor.input_ptr, pos);
let byte = builder.ins().load(types::I8, MemFlags::trusted(), addr, 0);
let is_zero = builder.ins().icmp_imm(IntCC::Equal, byte, 0);
builder
.ins()
.brif(is_zero, valid_false, &[], check_true, &[]);
builder.switch_to_block(valid_false);
builder.seal_block(valid_false);
let one = builder.ins().iconst(cursor.ptr_type, 1);
let new_pos = builder.ins().iadd(pos, one);
builder.def_var(cursor.pos, new_pos);
builder.def_var(result_value_var, zero_i8);
builder.def_var(result_error_var, zero_i32);
builder.ins().jump(merge, &[]);
builder.switch_to_block(check_true);
builder.seal_block(check_true);
let is_one = builder.ins().icmp_imm(IntCC::Equal, byte, 1);
builder
.ins()
.brif(is_one, valid_true, &[], invalid_bool, &[]);
builder.switch_to_block(valid_true);
builder.seal_block(valid_true);
let one_val = builder.ins().iconst(types::I8, 1);
let one_ptr = builder.ins().iconst(cursor.ptr_type, 1);
let new_pos = builder.ins().iadd(pos, one_ptr);
builder.def_var(cursor.pos, new_pos);
builder.def_var(result_value_var, one_val);
builder.def_var(result_error_var, zero_i32);
builder.ins().jump(merge, &[]);
builder.switch_to_block(invalid_bool);
builder.seal_block(invalid_bool);
let invalid_err = builder.ins().iconst(types::I32, error::INVALID_BOOL as i64);
builder.def_var(result_error_var, invalid_err);
builder.ins().jump(merge, &[]);
builder.switch_to_block(merge);
builder.seal_block(merge);
let final_value = builder.use_var(result_value_var);
let final_error = builder.use_var(result_error_var);
(final_value, final_error)
}
fn emit_parse_u8(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
) -> (Value, Value) {
let pos = builder.use_var(cursor.pos);
let result_value_var = builder.declare_var(types::I8);
let result_error_var = builder.declare_var(types::I32);
let zero_i8 = builder.ins().iconst(types::I8, 0);
let zero_i32 = builder.ins().iconst(types::I32, 0);
builder.def_var(result_value_var, zero_i8);
builder.def_var(result_error_var, zero_i32);
let have_byte = builder.ins().icmp(IntCC::UnsignedLessThan, pos, cursor.len);
let read_byte = builder.create_block();
let eof_error = builder.create_block();
let merge = builder.create_block();
builder
.ins()
.brif(have_byte, read_byte, &[], eof_error, &[]);
builder.switch_to_block(eof_error);
builder.seal_block(eof_error);
let eof_err = builder
.ins()
.iconst(types::I32, error::UNEXPECTED_EOF as i64);
builder.def_var(result_error_var, eof_err);
builder.ins().jump(merge, &[]);
builder.switch_to_block(read_byte);
builder.seal_block(read_byte);
let addr = builder.ins().iadd(cursor.input_ptr, pos);
let byte = builder.ins().load(types::I8, MemFlags::trusted(), addr, 0);
let one = builder.ins().iconst(cursor.ptr_type, 1);
let new_pos = builder.ins().iadd(pos, one);
builder.def_var(cursor.pos, new_pos);
builder.def_var(result_value_var, byte);
builder.def_var(result_error_var, zero_i32);
builder.ins().jump(merge, &[]);
builder.switch_to_block(merge);
builder.seal_block(merge);
let final_value = builder.use_var(result_value_var);
let final_error = builder.use_var(result_error_var);
(final_value, final_error)
}
fn emit_parse_i64(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
) -> (Value, Value) {
let (varint_val, err) = Self::emit_varint_decode(builder, cursor);
let one = builder.ins().iconst(types::I64, 1);
let shifted = builder.ins().ushr(varint_val, one); let sign_bit = builder.ins().band(varint_val, one); let neg_sign = builder.ins().ineg(sign_bit); let decoded = builder.ins().bxor(shifted, neg_sign);
(decoded, err)
}
fn emit_parse_u64(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
) -> (Value, Value) {
Self::emit_varint_decode(builder, cursor)
}
fn emit_parse_f32(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
) -> (Value, Value) {
let pos = builder.use_var(cursor.pos);
let result_value_var = builder.declare_var(types::F32);
let result_error_var = builder.declare_var(types::I32);
let zero_f32 = builder.ins().f32const(0.0);
let zero_i32 = builder.ins().iconst(types::I32, 0);
builder.def_var(result_value_var, zero_f32);
builder.def_var(result_error_var, zero_i32);
let four = builder.ins().iconst(cursor.ptr_type, 4);
let end_pos = builder.ins().iadd(pos, four);
let have_bytes = builder
.ins()
.icmp(IntCC::UnsignedLessThanOrEqual, end_pos, cursor.len);
let read_bytes = builder.create_block();
let eof_error = builder.create_block();
let merge = builder.create_block();
builder
.ins()
.brif(have_bytes, read_bytes, &[], eof_error, &[]);
builder.switch_to_block(eof_error);
builder.seal_block(eof_error);
let eof_err = builder
.ins()
.iconst(types::I32, error::UNEXPECTED_EOF as i64);
builder.def_var(result_error_var, eof_err);
builder.ins().jump(merge, &[]);
builder.switch_to_block(read_bytes);
builder.seal_block(read_bytes);
let addr = builder.ins().iadd(cursor.input_ptr, pos);
let value = builder.ins().load(types::F32, MemFlags::trusted(), addr, 0);
builder.def_var(cursor.pos, end_pos);
builder.def_var(result_value_var, value);
builder.def_var(result_error_var, zero_i32);
builder.ins().jump(merge, &[]);
builder.switch_to_block(merge);
builder.seal_block(merge);
let final_value = builder.use_var(result_value_var);
let final_error = builder.use_var(result_error_var);
(final_value, final_error)
}
fn emit_parse_f64(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
) -> (Value, Value) {
let pos = builder.use_var(cursor.pos);
let result_value_var = builder.declare_var(types::F64);
let result_error_var = builder.declare_var(types::I32);
let zero_f64 = builder.ins().f64const(0.0);
let zero_i32 = builder.ins().iconst(types::I32, 0);
builder.def_var(result_value_var, zero_f64);
builder.def_var(result_error_var, zero_i32);
let eight = builder.ins().iconst(cursor.ptr_type, 8);
let end_pos = builder.ins().iadd(pos, eight);
let have_bytes = builder
.ins()
.icmp(IntCC::UnsignedLessThanOrEqual, end_pos, cursor.len);
let read_bytes = builder.create_block();
let eof_error = builder.create_block();
let merge = builder.create_block();
builder
.ins()
.brif(have_bytes, read_bytes, &[], eof_error, &[]);
builder.switch_to_block(eof_error);
builder.seal_block(eof_error);
let eof_err = builder
.ins()
.iconst(types::I32, error::UNEXPECTED_EOF as i64);
builder.def_var(result_error_var, eof_err);
builder.ins().jump(merge, &[]);
builder.switch_to_block(read_bytes);
builder.seal_block(read_bytes);
let addr = builder.ins().iadd(cursor.input_ptr, pos);
let value = builder.ins().load(types::F64, MemFlags::trusted(), addr, 0);
builder.def_var(cursor.pos, end_pos);
builder.def_var(result_value_var, value);
builder.def_var(result_error_var, zero_i32);
builder.ins().jump(merge, &[]);
builder.switch_to_block(merge);
builder.seal_block(merge);
let final_value = builder.use_var(result_value_var);
let final_error = builder.use_var(result_error_var);
(final_value, final_error)
}
fn emit_parse_string(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
) -> (JitStringValue, Value) {
let (length_i64, varint_err) = Self::emit_varint_decode(builder, cursor);
let length = if cursor.ptr_type == types::I64 {
length_i64
} else {
builder.ins().ireduce(cursor.ptr_type, length_i64)
};
let result_ptr_var = builder.declare_var(cursor.ptr_type);
let result_len_var = builder.declare_var(cursor.ptr_type);
let result_error_var = builder.declare_var(types::I32);
let null = builder.ins().iconst(cursor.ptr_type, 0);
let zero_i32 = builder.ins().iconst(types::I32, 0);
builder.def_var(result_ptr_var, null);
builder.def_var(result_len_var, null);
builder.def_var(result_error_var, varint_err);
let varint_ok = builder.ins().icmp_imm(IntCC::Equal, varint_err, 0);
let check_bounds = builder.create_block();
let varint_error = builder.create_block();
let read_string = builder.create_block();
let bounds_error = builder.create_block();
let merge = builder.create_block();
builder
.ins()
.brif(varint_ok, check_bounds, &[], varint_error, &[]);
builder.switch_to_block(varint_error);
builder.seal_block(varint_error);
builder.ins().jump(merge, &[]);
builder.switch_to_block(check_bounds);
builder.seal_block(check_bounds);
let pos = builder.use_var(cursor.pos);
let end_pos = builder.ins().iadd(pos, length);
let within_bounds = builder
.ins()
.icmp(IntCC::UnsignedLessThanOrEqual, end_pos, cursor.len);
let no_overflow = builder
.ins()
.icmp(IntCC::UnsignedGreaterThanOrEqual, end_pos, pos);
let bounds_ok = builder.ins().band(within_bounds, no_overflow);
builder
.ins()
.brif(bounds_ok, read_string, &[], bounds_error, &[]);
builder.switch_to_block(bounds_error);
builder.seal_block(bounds_error);
let eof_err = builder
.ins()
.iconst(types::I32, error::UNEXPECTED_EOF as i64);
builder.def_var(result_error_var, eof_err);
builder.ins().jump(merge, &[]);
builder.switch_to_block(read_string);
builder.seal_block(read_string);
let str_ptr = builder.ins().iadd(cursor.input_ptr, pos);
builder.def_var(cursor.pos, end_pos);
builder.def_var(result_ptr_var, str_ptr);
builder.def_var(result_len_var, length);
builder.def_var(result_error_var, zero_i32);
builder.ins().jump(merge, &[]);
builder.switch_to_block(merge);
builder.seal_block(merge);
let final_ptr = builder.use_var(result_ptr_var);
let final_len = builder.use_var(result_len_var);
let final_error = builder.use_var(result_error_var);
(
JitStringValue {
ptr: final_ptr,
len: final_len,
cap: null, owned: builder.ins().iconst(types::I8, 0), },
final_error,
)
}
fn emit_seq_begin(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
state_ptr: Value,
) -> (Value, Value) {
let (count, err) = Self::emit_varint_decode(builder, cursor);
let max_count = builder.ins().load(
types::I64,
MemFlags::trusted(),
cursor.scratch_ptr,
JIT_SCRATCH_MAX_COLLECTION_ELEMENTS_OFFSET,
);
let count_ok = builder
.ins()
.icmp(IntCC::UnsignedLessThanOrEqual, count, max_count);
let zero_i32 = builder.ins().iconst(types::I32, 0);
let too_large_err = builder
.ins()
.iconst(types::I32, error::COLLECTION_TOO_LARGE as i64);
let limit_err = builder.ins().select(count_ok, zero_i32, too_large_err);
let decode_ok = builder.ins().icmp_imm(IntCC::Equal, err, 0);
let final_err = builder.ins().select(decode_ok, limit_err, err);
builder
.ins()
.store(MemFlags::trusted(), count, state_ptr, 0);
(count, final_err)
}
fn emit_seq_is_end(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
_cursor: &mut JitCursor,
state_ptr: Value,
) -> (Value, Value) {
let remaining = builder
.ins()
.load(types::I64, MemFlags::trusted(), state_ptr, 0);
let is_zero = builder.ins().icmp_imm(IntCC::Equal, remaining, 0);
let one_i8 = builder.ins().iconst(types::I8, 1);
let zero_i8 = builder.ins().iconst(types::I8, 0);
let is_end = builder.ins().select(is_zero, one_i8, zero_i8);
let no_error = builder.ins().iconst(types::I32, 0);
(is_end, no_error)
}
fn emit_seq_next(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
_cursor: &mut JitCursor,
state_ptr: Value,
) -> Value {
let remaining = builder
.ins()
.load(types::I64, MemFlags::trusted(), state_ptr, 0);
let is_zero = builder.ins().icmp_imm(IntCC::Equal, remaining, 0);
let underflow_block = builder.create_block();
let decrement_block = builder.create_block();
let merge = builder.create_block();
builder.append_block_param(merge, types::I32);
builder
.ins()
.brif(is_zero, underflow_block, &[], decrement_block, &[]);
builder.switch_to_block(underflow_block);
builder.seal_block(underflow_block);
let underflow_err = builder
.ins()
.iconst(types::I32, error::SEQ_UNDERFLOW as i64);
builder.ins().jump(merge, &[BlockArg::from(underflow_err)]);
builder.switch_to_block(decrement_block);
builder.seal_block(decrement_block);
let one = builder.ins().iconst(types::I64, 1);
let new_remaining = builder.ins().isub(remaining, one);
builder
.ins()
.store(MemFlags::trusted(), new_remaining, state_ptr, 0);
let success = builder.ins().iconst(types::I32, 0);
builder.ins().jump(merge, &[BlockArg::from(success)]);
builder.switch_to_block(merge);
builder.seal_block(merge);
builder.block_params(merge)[0]
}
fn emit_seq_bulk_copy_u8(
&self,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
count: Value,
dest_ptr: Value,
) -> Option<Value> {
let pos = builder.use_var(cursor.pos);
let bounds_ok = builder.create_block();
let bounds_fail = builder.create_block();
let merge = builder.create_block();
builder.append_block_param(merge, types::I32);
let end_pos = builder.ins().iadd(pos, count);
let within_bounds = builder
.ins()
.icmp(IntCC::UnsignedLessThanOrEqual, end_pos, cursor.len);
let no_overflow = builder
.ins()
.icmp(IntCC::UnsignedGreaterThanOrEqual, end_pos, pos);
let ok = builder.ins().band(within_bounds, no_overflow);
builder.ins().brif(ok, bounds_ok, &[], bounds_fail, &[]);
builder.switch_to_block(bounds_fail);
builder.seal_block(bounds_fail);
let eof_err = builder
.ins()
.iconst(types::I32, error::UNEXPECTED_EOF as i64);
builder.ins().jump(merge, &[BlockArg::from(eof_err)]);
builder.switch_to_block(bounds_ok);
builder.seal_block(bounds_ok);
let src_ptr = builder.ins().iadd(cursor.input_ptr, pos);
let bulk_copy_ptr = builder.ins().iconst(
cursor.ptr_type,
helpers::postcard_jit_bulk_copy_u8 as *const u8 as i64,
);
let mut sig = builder.func.signature.clone();
sig.params.clear();
sig.returns.clear();
sig.params.push(AbiParam::new(cursor.ptr_type)); sig.params.push(AbiParam::new(cursor.ptr_type)); sig.params.push(AbiParam::new(cursor.ptr_type)); let sig_ref = builder.import_signature(sig);
builder
.ins()
.call_indirect(sig_ref, bulk_copy_ptr, &[dest_ptr, src_ptr, count]);
builder.def_var(cursor.pos, end_pos);
let success = builder.ins().iconst(types::I32, 0);
builder.ins().jump(merge, &[BlockArg::from(success)]);
builder.switch_to_block(merge);
builder.seal_block(merge);
Some(builder.block_params(merge)[0])
}
fn emit_map_begin(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
state_ptr: Value,
) -> Value {
let (count, err) = Self::emit_varint_decode(builder, cursor);
let max_count = builder.ins().load(
types::I64,
MemFlags::trusted(),
cursor.scratch_ptr,
JIT_SCRATCH_MAX_COLLECTION_ELEMENTS_OFFSET,
);
let count_ok = builder
.ins()
.icmp(IntCC::UnsignedLessThanOrEqual, count, max_count);
let zero_i32 = builder.ins().iconst(types::I32, 0);
let too_large_err = builder
.ins()
.iconst(types::I32, error::COLLECTION_TOO_LARGE as i64);
let limit_err = builder.ins().select(count_ok, zero_i32, too_large_err);
let decode_ok = builder.ins().icmp_imm(IntCC::Equal, err, 0);
let final_err = builder.ins().select(decode_ok, limit_err, err);
builder
.ins()
.store(MemFlags::trusted(), count, state_ptr, 0);
final_err
}
fn emit_map_is_end(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
_cursor: &mut JitCursor,
state_ptr: Value,
) -> (Value, Value) {
let remaining = builder
.ins()
.load(types::I64, MemFlags::trusted(), state_ptr, 0);
let is_zero = builder.ins().icmp_imm(IntCC::Equal, remaining, 0);
let one_i8 = builder.ins().iconst(types::I8, 1);
let zero_i8 = builder.ins().iconst(types::I8, 0);
let is_end = builder.ins().select(is_zero, one_i8, zero_i8);
let no_error = builder.ins().iconst(types::I32, 0);
(is_end, no_error)
}
fn emit_map_read_key(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
_state_ptr: Value,
) -> (JitStringValue, Value) {
self.emit_parse_string(_module, builder, cursor)
}
fn emit_map_kv_sep(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
_cursor: &mut JitCursor,
_state_ptr: Value,
) -> Value {
builder.ins().iconst(types::I32, 0)
}
fn emit_map_next(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
_cursor: &mut JitCursor,
state_ptr: Value,
) -> Value {
let remaining = builder
.ins()
.load(types::I64, MemFlags::trusted(), state_ptr, 0);
let is_zero = builder.ins().icmp_imm(IntCC::Equal, remaining, 0);
let underflow_block = builder.create_block();
let decrement_block = builder.create_block();
let merge = builder.create_block();
builder.append_block_param(merge, types::I32);
builder
.ins()
.brif(is_zero, underflow_block, &[], decrement_block, &[]);
builder.switch_to_block(underflow_block);
builder.seal_block(underflow_block);
let underflow_err = builder
.ins()
.iconst(types::I32, error::SEQ_UNDERFLOW as i64);
builder.ins().jump(merge, &[BlockArg::from(underflow_err)]);
builder.switch_to_block(decrement_block);
builder.seal_block(decrement_block);
let one = builder.ins().iconst(types::I64, 1);
let new_remaining = builder.ins().isub(remaining, one);
builder
.ins()
.store(MemFlags::trusted(), new_remaining, state_ptr, 0);
let success = builder.ins().iconst(types::I32, 0);
builder.ins().jump(merge, &[BlockArg::from(success)]);
builder.switch_to_block(merge);
builder.seal_block(merge);
builder.block_params(merge)[0]
}
}