use facet_format::jit::{
AbiParam, FunctionBuilder, InstBuilder, IntCC, JITBuilder, JITModule, JitCursor, JitFormat,
JitStringValue, MemFlags, Module, Value, c_call_conv, types,
};
use super::helpers;
#[derive(Debug, Clone, Copy, Default)]
pub struct JsonJitFormat;
pub mod error {
pub use super::helpers::error::*;
}
impl JitFormat for JsonJitFormat {
fn register_helpers(builder: &mut JITBuilder) {
builder.symbol("json_jit_skip_ws", helpers::json_jit_skip_ws as *const u8);
builder.symbol(
"json_jit_seq_begin",
helpers::json_jit_seq_begin as *const u8,
);
builder.symbol(
"json_jit_seq_is_end",
helpers::json_jit_seq_is_end as *const u8,
);
builder.symbol("json_jit_seq_next", helpers::json_jit_seq_next as *const u8);
builder.symbol(
"json_jit_parse_bool",
helpers::json_jit_parse_bool as *const u8,
);
builder.symbol(
"json_jit_parse_i64",
helpers::json_jit_parse_i64 as *const u8,
);
builder.symbol(
"json_jit_parse_u64",
helpers::json_jit_parse_u64 as *const u8,
);
builder.symbol(
"json_jit_parse_f64",
helpers::json_jit_parse_f64 as *const u8,
);
builder.symbol(
"json_jit_parse_f64_out",
helpers::json_jit_parse_f64_out as *const u8,
);
builder.symbol(
"json_jit_parse_string",
helpers::json_jit_parse_string as *const u8,
);
builder.symbol(
"json_jit_skip_value",
helpers::json_jit_skip_value as *const u8,
);
builder.symbol(
"json_jit_memchr2_quote_backslash",
helpers::json_jit_memchr2_quote_backslash as *const u8,
);
builder.symbol(
"json_jit_scratch_take",
helpers::json_jit_scratch_take as *const u8,
);
builder.symbol(
"json_jit_scratch_extend",
helpers::json_jit_scratch_extend as *const u8,
);
builder.symbol(
"json_jit_scratch_push_byte",
helpers::json_jit_scratch_push_byte as *const u8,
);
builder.symbol(
"json_jit_decode_unicode_escape",
helpers::json_jit_decode_unicode_escape as *const u8,
);
builder.symbol(
"json_jit_scratch_finalize_string",
helpers::json_jit_scratch_finalize_string as *const u8,
);
builder.symbol("json_jit_is_ascii", helpers::json_jit_is_ascii as *const u8);
}
fn helper_seq_begin() -> Option<&'static str> {
Some("json_jit_seq_begin")
}
fn helper_seq_is_end() -> Option<&'static str> {
Some("json_jit_seq_is_end")
}
fn helper_seq_next() -> Option<&'static str> {
Some("json_jit_seq_next")
}
fn helper_parse_bool() -> Option<&'static str> {
Some("json_jit_parse_bool")
}
const SEQ_STATE_SIZE: u32 = 0;
const SEQ_STATE_ALIGN: u32 = 1;
const MAP_STATE_SIZE: u32 = 0;
const MAP_STATE_ALIGN: u32 = 1;
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 {
let pos = builder.use_var(cursor.pos);
let helper_sig = {
let mut sig = module.make_signature();
sig.call_conv = c_call_conv();
sig.params.push(AbiParam::new(cursor.ptr_type)); sig.params.push(AbiParam::new(cursor.ptr_type)); sig.params.push(AbiParam::new(cursor.ptr_type)); sig.returns.push(AbiParam::new(cursor.ptr_type));
sig
};
let helper_sig_ref = builder.import_signature(helper_sig);
let helper_ptr = builder.ins().iconst(
cursor.ptr_type,
helpers::json_jit_skip_value as *const u8 as i64,
);
let call = builder.ins().call_indirect(
helper_sig_ref,
helper_ptr,
&[cursor.input_ptr, cursor.len, pos],
);
let result = builder.inst_results(call)[0];
let zero = builder.ins().iconst(cursor.ptr_type, 0);
let is_success = builder
.ins()
.icmp(IntCC::SignedGreaterThanOrEqual, result, zero);
let update_pos = builder.create_block();
let merge = builder.create_block();
builder.ins().brif(is_success, update_pos, &[], merge, &[]);
builder.switch_to_block(update_pos);
builder.seal_block(update_pos);
builder.def_var(cursor.pos, result); builder.ins().jump(merge, &[]);
builder.switch_to_block(merge);
builder.seal_block(merge);
let error = builder.ins().select(is_success, zero, result);
builder.ins().ireduce(types::I32, error)
}
fn emit_peek_null(
&self,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
) -> (Value, Value) {
let pos = builder.use_var(cursor.pos);
let result_is_null_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_is_null_var, zero_i8);
builder.def_var(result_error_var, zero_i32);
let four = builder.ins().iconst(cursor.ptr_type, 4);
let pos_plus_4 = builder.ins().iadd(pos, four);
let have_4_bytes =
builder
.ins()
.icmp(IntCC::UnsignedLessThanOrEqual, pos_plus_4, cursor.len);
let check_null = builder.create_block();
let not_enough_bytes = builder.create_block();
let merge = builder.create_block();
builder
.ins()
.brif(have_4_bytes, check_null, &[], not_enough_bytes, &[]);
builder.switch_to_block(check_null);
builder.seal_block(check_null);
let addr = builder.ins().iadd(cursor.input_ptr, pos);
let word = builder.ins().load(types::I32, MemFlags::trusted(), addr, 0);
let null_const = builder.ins().iconst(types::I32, 0x6c6c756ei64); let is_null = builder.ins().icmp(IntCC::Equal, word, null_const);
let one_i8 = builder.ins().iconst(types::I8, 1);
let is_null_val = builder.ins().select(is_null, one_i8, zero_i8);
builder.def_var(result_is_null_var, is_null_val);
builder.ins().jump(merge, &[]);
builder.switch_to_block(not_enough_bytes);
builder.seal_block(not_enough_bytes);
builder.ins().jump(merge, &[]);
builder.switch_to_block(merge);
builder.seal_block(merge);
let result_is_null = builder.use_var(result_is_null_var);
let result_error = builder.use_var(result_error_var);
(result_is_null, result_error)
}
fn emit_consume_null(&self, builder: &mut FunctionBuilder, cursor: &mut JitCursor) -> Value {
let pos = builder.use_var(cursor.pos);
let four = builder.ins().iconst(cursor.ptr_type, 4);
let new_pos = builder.ins().iadd(pos, four);
builder.def_var(cursor.pos, new_pos);
builder.ins().iconst(types::I32, 0)
}
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 four = builder.ins().iconst(cursor.ptr_type, 4);
let pos_plus_4 = builder.ins().iadd(pos, four);
let have_4_bytes =
builder
.ins()
.icmp(IntCC::UnsignedLessThanOrEqual, pos_plus_4, cursor.len);
let check_true = builder.create_block();
let check_false = builder.create_block();
let found_true = builder.create_block();
let found_false = builder.create_block();
let error_block = builder.create_block();
let merge = builder.create_block();
builder
.ins()
.brif(have_4_bytes, check_true, &[], error_block, &[]);
builder.switch_to_block(check_true);
builder.seal_block(check_true);
let addr = builder.ins().iadd(cursor.input_ptr, pos);
let word = builder.ins().load(types::I32, MemFlags::trusted(), addr, 0);
let true_const = builder.ins().iconst(types::I32, 0x65757274u32 as i64); let is_true = builder.ins().icmp(IntCC::Equal, word, true_const);
builder
.ins()
.brif(is_true, found_true, &[], check_false, &[]);
builder.switch_to_block(found_true);
builder.seal_block(found_true);
let one_i8 = builder.ins().iconst(types::I8, 1);
let zero_err = builder.ins().iconst(types::I32, 0);
builder.def_var(result_value_var, one_i8);
builder.def_var(result_error_var, zero_err);
builder.def_var(cursor.pos, pos_plus_4);
builder.ins().jump(merge, &[]);
builder.switch_to_block(check_false);
builder.seal_block(check_false);
let five = builder.ins().iconst(cursor.ptr_type, 5);
let pos_plus_5 = builder.ins().iadd(pos, five);
let have_5_bytes =
builder
.ins()
.icmp(IntCC::UnsignedLessThanOrEqual, pos_plus_5, cursor.len);
let check_false_content = builder.create_block();
builder
.ins()
.brif(have_5_bytes, check_false_content, &[], error_block, &[]);
builder.switch_to_block(check_false_content);
builder.seal_block(check_false_content);
let fals_word = builder.ins().load(types::I32, MemFlags::trusted(), addr, 0);
let fals_const = builder.ins().iconst(types::I32, 0x736c6166u32 as i64); let is_fals = builder.ins().icmp(IntCC::Equal, fals_word, fals_const);
let check_e = builder.create_block();
builder.ins().brif(is_fals, check_e, &[], error_block, &[]);
builder.switch_to_block(check_e);
builder.seal_block(check_e);
let e_byte = builder.ins().load(types::I8, MemFlags::trusted(), addr, 4);
let e_const = builder.ins().iconst(types::I8, 0x65); let is_e = builder.ins().icmp(IntCC::Equal, e_byte, e_const);
builder.ins().brif(is_e, found_false, &[], error_block, &[]);
builder.switch_to_block(found_false);
builder.seal_block(found_false);
let zero_val = builder.ins().iconst(types::I8, 0);
let zero_err2 = builder.ins().iconst(types::I32, 0);
builder.def_var(result_value_var, zero_val);
builder.def_var(result_error_var, zero_err2);
builder.def_var(cursor.pos, pos_plus_5);
builder.ins().jump(merge, &[]);
builder.switch_to_block(error_block);
builder.seal_block(error_block);
let err_val = builder.ins().iconst(types::I8, 0);
let err_code = builder
.ins()
.iconst(types::I32, error::EXPECTED_BOOL as i64);
builder.def_var(result_value_var, err_val);
builder.def_var(result_error_var, err_code);
builder.ins().jump(merge, &[]);
builder.switch_to_block(merge);
builder.seal_block(merge);
let result_value = builder.use_var(result_value_var);
let result_error = builder.use_var(result_error_var);
(result_value, result_error)
}
fn emit_parse_u8(
&self,
_module: &mut JITModule,
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_parse_i64(
&self,
module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
) -> (Value, Value) {
use facet_format::jit::{StackSlotData, StackSlotKind};
let sig = {
let mut s = module.make_signature();
s.call_conv = c_call_conv();
s.params.push(AbiParam::new(cursor.ptr_type)); s.params.push(AbiParam::new(cursor.ptr_type)); s.params.push(AbiParam::new(cursor.ptr_type)); s.params.push(AbiParam::new(cursor.ptr_type)); s
};
let sig_ref = builder.import_signature(sig);
let callee_ptr = builder.ins().iconst(
cursor.ptr_type,
helpers::json_jit_parse_i64 as *const u8 as i64,
);
let result_slot =
builder.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 24, 8));
let result_ptr = builder.ins().stack_addr(cursor.ptr_type, result_slot, 0);
let pos = builder.use_var(cursor.pos);
builder.ins().call_indirect(
sig_ref,
callee_ptr,
&[result_ptr, cursor.input_ptr, cursor.len, pos],
);
let new_pos = builder
.ins()
.load(cursor.ptr_type, MemFlags::trusted(), result_ptr, 0);
let value = builder
.ins()
.load(types::I64, MemFlags::trusted(), result_ptr, 8);
let error = builder
.ins()
.load(types::I32, MemFlags::trusted(), result_ptr, 16);
builder.def_var(cursor.pos, new_pos);
(value, error)
}
fn emit_parse_u64(
&self,
module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
) -> (Value, Value) {
use facet_format::jit::{StackSlotData, StackSlotKind};
let sig = {
let mut s = module.make_signature();
s.call_conv = c_call_conv();
s.params.push(AbiParam::new(cursor.ptr_type)); s.params.push(AbiParam::new(cursor.ptr_type)); s.params.push(AbiParam::new(cursor.ptr_type)); s.params.push(AbiParam::new(cursor.ptr_type)); s
};
let sig_ref = builder.import_signature(sig);
let callee_ptr = builder.ins().iconst(
cursor.ptr_type,
helpers::json_jit_parse_u64 as *const u8 as i64,
);
let result_slot =
builder.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 24, 8));
let result_ptr = builder.ins().stack_addr(cursor.ptr_type, result_slot, 0);
let pos = builder.use_var(cursor.pos);
builder.ins().call_indirect(
sig_ref,
callee_ptr,
&[result_ptr, cursor.input_ptr, cursor.len, pos],
);
let new_pos = builder
.ins()
.load(cursor.ptr_type, MemFlags::trusted(), result_ptr, 0);
let value = builder
.ins()
.load(types::I64, MemFlags::trusted(), result_ptr, 8);
let error = builder
.ins()
.load(types::I32, MemFlags::trusted(), result_ptr, 16);
builder.def_var(cursor.pos, new_pos);
(value, error)
}
fn emit_parse_f64(
&self,
module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
) -> (Value, Value) {
use facet_format::jit::{StackSlotData, StackSlotKind};
let pos = builder.use_var(cursor.pos);
let result_slot =
builder.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 24, 8));
let result_ptr = builder.ins().stack_addr(cursor.ptr_type, result_slot, 0);
let helper_sig = {
let mut sig = module.make_signature();
sig.call_conv = c_call_conv();
sig.params.push(AbiParam::new(cursor.ptr_type)); sig.params.push(AbiParam::new(cursor.ptr_type)); sig.params.push(AbiParam::new(cursor.ptr_type)); sig.params.push(AbiParam::new(cursor.ptr_type)); sig
};
let helper_sig_ref = builder.import_signature(helper_sig);
let helper_ptr = builder.ins().iconst(
cursor.ptr_type,
helpers::json_jit_parse_f64_out as *const u8 as i64,
);
builder.ins().call_indirect(
helper_sig_ref,
helper_ptr,
&[result_ptr, cursor.input_ptr, cursor.len, pos],
);
let new_pos = builder
.ins()
.load(cursor.ptr_type, MemFlags::trusted(), result_ptr, 0);
let value = builder
.ins()
.load(types::F64, MemFlags::trusted(), result_ptr, 8);
let error = builder
.ins()
.load(types::I32, MemFlags::trusted(), result_ptr, 16);
let zero_i32 = builder.ins().iconst(types::I32, 0);
let is_success = builder.ins().icmp(IntCC::Equal, error, zero_i32);
let update_pos = builder.create_block();
let merge = builder.create_block();
builder.ins().brif(is_success, update_pos, &[], merge, &[]);
builder.switch_to_block(update_pos);
builder.seal_block(update_pos);
builder.def_var(cursor.pos, new_pos);
builder.ins().jump(merge, &[]);
builder.switch_to_block(merge);
builder.seal_block(merge);
(value, error)
}
fn emit_parse_string(
&self,
module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
) -> (JitStringValue, Value) {
use facet_format::jit::{StackSlotData, StackSlotKind};
let sig = {
let mut s = module.make_signature();
s.call_conv = c_call_conv();
s.params.push(AbiParam::new(cursor.ptr_type)); s.params.push(AbiParam::new(cursor.ptr_type)); s.params.push(AbiParam::new(cursor.ptr_type)); s.params.push(AbiParam::new(cursor.ptr_type)); s.params.push(AbiParam::new(cursor.ptr_type)); s
};
let sig_ref = builder.import_signature(sig);
let callee_ptr = builder.ins().iconst(
cursor.ptr_type,
helpers::json_jit_parse_string as *const u8 as i64,
);
let result_slot =
builder.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 40, 8));
let result_ptr = builder.ins().stack_addr(cursor.ptr_type, result_slot, 0);
let pos = builder.use_var(cursor.pos);
builder.ins().call_indirect(
sig_ref,
callee_ptr,
&[
result_ptr,
cursor.input_ptr,
cursor.len,
pos,
cursor.scratch_ptr,
],
);
let new_pos = builder
.ins()
.load(cursor.ptr_type, MemFlags::trusted(), result_ptr, 0);
let str_ptr = builder
.ins()
.load(cursor.ptr_type, MemFlags::trusted(), result_ptr, 8);
let str_len = builder
.ins()
.load(cursor.ptr_type, MemFlags::trusted(), result_ptr, 16);
let str_cap = builder
.ins()
.load(cursor.ptr_type, MemFlags::trusted(), result_ptr, 24);
let str_owned = builder
.ins()
.load(types::I8, MemFlags::trusted(), result_ptr, 32);
let error = builder
.ins()
.load(types::I32, MemFlags::trusted(), result_ptr, 36);
builder.def_var(cursor.pos, new_pos);
(
JitStringValue {
ptr: str_ptr,
len: str_len,
cap: str_cap,
owned: str_owned,
},
error,
)
}
fn emit_seq_begin(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
_state_ptr: Value,
) -> (Value, Value) {
let result_error_var = builder.declare_var(types::I32);
let zero_i32 = builder.ins().iconst(types::I32, 0);
let zero_count = builder.ins().iconst(cursor.ptr_type, 0);
builder.def_var(result_error_var, zero_i32);
let one = builder.ins().iconst(cursor.ptr_type, 1);
let space = builder.ins().iconst(types::I8, b' ' as i64);
let tab = builder.ins().iconst(types::I8, b'\t' as i64);
let newline = builder.ins().iconst(types::I8, b'\n' as i64);
let cr = builder.ins().iconst(types::I8, b'\r' as i64);
let const_32 = builder.ins().iconst(types::I8, 32);
let skip_leading_ws_loop = builder.create_block();
let check_leading_ws = builder.create_block();
let maybe_leading_ws = builder.create_block();
let check_leading_low_ws = builder.create_block();
let skip_leading_ws_advance = builder.create_block();
let check_bracket = builder.create_block();
let skip_trailing_ws_loop = builder.create_block();
let check_trailing_ws = builder.create_block();
let skip_trailing_ws_advance = builder.create_block();
let not_bracket_error = builder.create_block();
let eof_error = builder.create_block();
let merge = builder.create_block();
builder.ins().jump(skip_leading_ws_loop, &[]);
builder.switch_to_block(skip_leading_ws_loop);
let pos = builder.use_var(cursor.pos);
let have_bytes = builder.ins().icmp(IntCC::UnsignedLessThan, pos, cursor.len);
builder
.ins()
.brif(have_bytes, check_leading_ws, &[], eof_error, &[]);
builder.switch_to_block(check_leading_ws);
builder.seal_block(check_leading_ws);
let addr = builder.ins().iadd(cursor.input_ptr, pos);
let byte = builder.ins().load(types::I8, MemFlags::trusted(), addr, 0);
let gt_32 = builder
.ins()
.icmp(IntCC::UnsignedGreaterThan, byte, const_32);
builder
.ins()
.brif(gt_32, check_bracket, &[], maybe_leading_ws, &[]);
builder.switch_to_block(maybe_leading_ws);
builder.seal_block(maybe_leading_ws);
let is_space = builder.ins().icmp(IntCC::Equal, byte, space);
builder.ins().brif(
is_space,
skip_leading_ws_advance,
&[],
check_leading_low_ws,
&[],
);
builder.switch_to_block(check_leading_low_ws);
builder.seal_block(check_leading_low_ws);
let is_tab = builder.ins().icmp(IntCC::Equal, byte, tab);
let is_newline = builder.ins().icmp(IntCC::Equal, byte, newline);
let is_cr = builder.ins().icmp(IntCC::Equal, byte, cr);
let is_ws_1 = builder.ins().bor(is_tab, is_newline);
let is_ws = builder.ins().bor(is_ws_1, is_cr);
builder
.ins()
.brif(is_ws, skip_leading_ws_advance, &[], check_bracket, &[]);
builder.switch_to_block(skip_leading_ws_advance);
builder.seal_block(skip_leading_ws_advance);
let next_pos = builder.ins().iadd(pos, one);
builder.def_var(cursor.pos, next_pos);
builder.ins().jump(skip_leading_ws_loop, &[]);
builder.seal_block(skip_leading_ws_loop);
builder.switch_to_block(check_bracket);
builder.seal_block(check_bracket);
let open_bracket = builder.ins().iconst(types::I8, b'[' as i64);
let is_bracket = builder.ins().icmp(IntCC::Equal, byte, open_bracket);
builder.ins().brif(
is_bracket,
skip_trailing_ws_loop,
&[],
not_bracket_error,
&[],
);
builder.switch_to_block(skip_trailing_ws_loop);
builder.seal_block(skip_trailing_ws_loop);
let pos2 = builder.use_var(cursor.pos);
let pos_after_bracket = builder.ins().iadd(pos2, one);
builder.def_var(cursor.pos, pos_after_bracket);
let trailing_ws_check_bounds = builder.create_block();
builder.ins().jump(trailing_ws_check_bounds, &[]);
builder.switch_to_block(trailing_ws_check_bounds);
let pos3 = builder.use_var(cursor.pos);
let have_bytes3 = builder
.ins()
.icmp(IntCC::UnsignedLessThan, pos3, cursor.len);
builder
.ins()
.brif(have_bytes3, check_trailing_ws, &[], merge, &[]);
let maybe_trailing_ws = builder.create_block();
let check_trailing_low_ws = builder.create_block();
builder.switch_to_block(check_trailing_ws);
builder.seal_block(check_trailing_ws);
let addr3 = builder.ins().iadd(cursor.input_ptr, pos3);
let byte3 = builder.ins().load(types::I8, MemFlags::trusted(), addr3, 0);
let gt_32_3 = builder
.ins()
.icmp(IntCC::UnsignedGreaterThan, byte3, const_32);
builder
.ins()
.brif(gt_32_3, merge, &[], maybe_trailing_ws, &[]);
builder.switch_to_block(maybe_trailing_ws);
builder.seal_block(maybe_trailing_ws);
let is_space3 = builder.ins().icmp(IntCC::Equal, byte3, space);
builder.ins().brif(
is_space3,
skip_trailing_ws_advance,
&[],
check_trailing_low_ws,
&[],
);
builder.switch_to_block(check_trailing_low_ws);
builder.seal_block(check_trailing_low_ws);
let is_tab3 = builder.ins().icmp(IntCC::Equal, byte3, tab);
let is_newline3 = builder.ins().icmp(IntCC::Equal, byte3, newline);
let is_cr3 = builder.ins().icmp(IntCC::Equal, byte3, cr);
let is_ws3_1 = builder.ins().bor(is_tab3, is_newline3);
let is_ws3 = builder.ins().bor(is_ws3_1, is_cr3);
builder
.ins()
.brif(is_ws3, skip_trailing_ws_advance, &[], merge, &[]);
builder.switch_to_block(skip_trailing_ws_advance);
builder.seal_block(skip_trailing_ws_advance);
let next_pos3 = builder.ins().iadd(pos3, one);
builder.def_var(cursor.pos, next_pos3);
builder.ins().jump(trailing_ws_check_bounds, &[]);
builder.seal_block(trailing_ws_check_bounds);
builder.switch_to_block(not_bracket_error);
builder.seal_block(not_bracket_error);
let err_not_bracket = builder
.ins()
.iconst(types::I32, error::EXPECTED_ARRAY_START as i64);
builder.def_var(result_error_var, err_not_bracket);
builder.ins().jump(merge, &[]);
builder.switch_to_block(eof_error);
builder.seal_block(eof_error);
let err_eof = builder
.ins()
.iconst(types::I32, error::UNEXPECTED_EOF as i64);
builder.def_var(result_error_var, err_eof);
builder.ins().jump(merge, &[]);
builder.switch_to_block(merge);
builder.seal_block(merge);
let result_error = builder.use_var(result_error_var);
(zero_count, result_error)
}
fn emit_seq_is_end(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
_state_ptr: Value,
) -> (Value, Value) {
let pos = builder.use_var(cursor.pos);
let result_is_end_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_is_end_var, zero_i8);
builder.def_var(result_error_var, zero_i32);
let check_byte = builder.create_block();
let found_end = builder.create_block();
let skip_ws_loop = builder.create_block();
let skip_ws_check = builder.create_block();
let not_end = builder.create_block();
let eof_error = builder.create_block();
let merge = builder.create_block();
let have_bytes = builder.ins().icmp(IntCC::UnsignedLessThan, pos, cursor.len);
builder
.ins()
.brif(have_bytes, check_byte, &[], eof_error, &[]);
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 close_bracket = builder.ins().iconst(types::I8, b']' as i64);
let is_close = builder.ins().icmp(IntCC::Equal, byte, close_bracket);
builder.ins().brif(is_close, found_end, &[], not_end, &[]);
builder.switch_to_block(found_end);
builder.seal_block(found_end);
let one = builder.ins().iconst(cursor.ptr_type, 1);
let pos_after_bracket = builder.ins().iadd(pos, one);
builder.def_var(cursor.pos, pos_after_bracket);
builder.ins().jump(skip_ws_loop, &[]);
builder.switch_to_block(skip_ws_loop);
let ws_pos = builder.use_var(cursor.pos);
let ws_have_bytes = builder
.ins()
.icmp(IntCC::UnsignedLessThan, ws_pos, cursor.len);
let ws_check_char = builder.create_block();
let ws_done = builder.create_block();
builder
.ins()
.brif(ws_have_bytes, ws_check_char, &[], ws_done, &[]);
let maybe_ws = builder.create_block();
let check_low_ws = builder.create_block();
builder.switch_to_block(ws_check_char);
builder.seal_block(ws_check_char);
let ws_addr = builder.ins().iadd(cursor.input_ptr, ws_pos);
let ws_byte = builder
.ins()
.load(types::I8, MemFlags::trusted(), ws_addr, 0);
let const_32 = builder.ins().iconst(types::I8, 32);
let gt_32 = builder
.ins()
.icmp(IntCC::UnsignedGreaterThan, ws_byte, const_32);
builder.ins().brif(gt_32, ws_done, &[], maybe_ws, &[]);
builder.switch_to_block(maybe_ws);
builder.seal_block(maybe_ws);
let space = builder.ins().iconst(types::I8, b' ' as i64);
let is_space = builder.ins().icmp(IntCC::Equal, ws_byte, space);
builder
.ins()
.brif(is_space, skip_ws_check, &[], check_low_ws, &[]);
builder.switch_to_block(check_low_ws);
builder.seal_block(check_low_ws);
let tab = builder.ins().iconst(types::I8, b'\t' as i64);
let newline = builder.ins().iconst(types::I8, b'\n' as i64);
let cr = builder.ins().iconst(types::I8, b'\r' as i64);
let is_tab = builder.ins().icmp(IntCC::Equal, ws_byte, tab);
let is_newline = builder.ins().icmp(IntCC::Equal, ws_byte, newline);
let is_cr = builder.ins().icmp(IntCC::Equal, ws_byte, cr);
let is_ws_1 = builder.ins().bor(is_tab, is_newline);
let is_ws = builder.ins().bor(is_ws_1, is_cr);
builder.ins().brif(is_ws, skip_ws_check, &[], ws_done, &[]);
builder.switch_to_block(skip_ws_check);
builder.seal_block(skip_ws_check);
let ws_next = builder.ins().iadd(ws_pos, one);
builder.def_var(cursor.pos, ws_next);
builder.ins().jump(skip_ws_loop, &[]);
builder.seal_block(skip_ws_loop);
builder.switch_to_block(ws_done);
builder.seal_block(ws_done);
let one_i8 = builder.ins().iconst(types::I8, 1);
builder.def_var(result_is_end_var, one_i8);
builder.def_var(result_error_var, zero_i32);
builder.ins().jump(merge, &[]);
builder.switch_to_block(not_end);
builder.seal_block(not_end);
builder.ins().jump(merge, &[]);
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(merge);
builder.seal_block(merge);
let result_is_end = builder.use_var(result_is_end_var);
let result_error = builder.use_var(result_error_var);
(result_is_end, result_error)
}
fn emit_seq_next(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
_state_ptr: Value,
) -> Value {
let result_error_var = builder.declare_var(types::I32);
let zero_i32 = builder.ins().iconst(types::I32, 0);
builder.def_var(result_error_var, zero_i32);
let one = builder.ins().iconst(cursor.ptr_type, 1);
let space = builder.ins().iconst(types::I8, b' ' as i64);
let tab = builder.ins().iconst(types::I8, b'\t' as i64);
let newline = builder.ins().iconst(types::I8, b'\n' as i64);
let cr = builder.ins().iconst(types::I8, b'\r' as i64);
let skip_leading_ws_loop = builder.create_block();
let check_leading_ws = builder.create_block();
let skip_leading_ws_advance = builder.create_block();
let check_separator = builder.create_block();
let not_comma = builder.create_block();
let handle_comma = builder.create_block();
let skip_trailing_ws_loop = builder.create_block();
let check_trailing_ws = builder.create_block();
let skip_trailing_ws_advance = builder.create_block();
let handle_close_bracket = builder.create_block();
let unexpected_char = builder.create_block();
let eof_error = builder.create_block();
let merge = builder.create_block();
builder.ins().jump(skip_leading_ws_loop, &[]);
builder.switch_to_block(skip_leading_ws_loop);
let pos = builder.use_var(cursor.pos);
let have_bytes = builder.ins().icmp(IntCC::UnsignedLessThan, pos, cursor.len);
builder
.ins()
.brif(have_bytes, check_leading_ws, &[], eof_error, &[]);
builder.switch_to_block(check_leading_ws);
builder.seal_block(check_leading_ws);
let addr = builder.ins().iadd(cursor.input_ptr, pos);
let byte = builder.ins().load(types::I8, MemFlags::trusted(), addr, 0);
let is_space = builder.ins().icmp(IntCC::Equal, byte, space);
let is_tab = builder.ins().icmp(IntCC::Equal, byte, tab);
let is_newline = builder.ins().icmp(IntCC::Equal, byte, newline);
let is_cr = builder.ins().icmp(IntCC::Equal, byte, cr);
let is_ws_1 = builder.ins().bor(is_space, is_tab);
let is_ws_2 = builder.ins().bor(is_newline, is_cr);
let is_ws = builder.ins().bor(is_ws_1, is_ws_2);
builder
.ins()
.brif(is_ws, skip_leading_ws_advance, &[], check_separator, &[]);
builder.switch_to_block(skip_leading_ws_advance);
builder.seal_block(skip_leading_ws_advance);
let next_pos = builder.ins().iadd(pos, one);
builder.def_var(cursor.pos, next_pos);
builder.ins().jump(skip_leading_ws_loop, &[]);
builder.seal_block(skip_leading_ws_loop);
builder.switch_to_block(check_separator);
builder.seal_block(check_separator);
let comma = builder.ins().iconst(types::I8, b',' as i64);
let close_bracket = builder.ins().iconst(types::I8, b']' as i64);
let is_comma = builder.ins().icmp(IntCC::Equal, byte, comma);
builder
.ins()
.brif(is_comma, handle_comma, &[], not_comma, &[]);
builder.switch_to_block(not_comma);
builder.seal_block(not_comma);
let is_close = builder.ins().icmp(IntCC::Equal, byte, close_bracket);
builder
.ins()
.brif(is_close, handle_close_bracket, &[], unexpected_char, &[]);
builder.switch_to_block(handle_comma);
builder.seal_block(handle_comma);
let pos_after_comma = builder.ins().iadd(pos, one);
builder.def_var(cursor.pos, pos_after_comma);
builder.ins().jump(skip_trailing_ws_loop, &[]);
builder.switch_to_block(skip_trailing_ws_loop);
let pos2 = builder.use_var(cursor.pos);
let have_bytes2 = builder
.ins()
.icmp(IntCC::UnsignedLessThan, pos2, cursor.len);
builder
.ins()
.brif(have_bytes2, check_trailing_ws, &[], merge, &[]);
builder.switch_to_block(check_trailing_ws);
builder.seal_block(check_trailing_ws);
let addr2 = builder.ins().iadd(cursor.input_ptr, pos2);
let byte2 = builder.ins().load(types::I8, MemFlags::trusted(), addr2, 0);
let is_space2 = builder.ins().icmp(IntCC::Equal, byte2, space);
let is_tab2 = builder.ins().icmp(IntCC::Equal, byte2, tab);
let is_newline2 = builder.ins().icmp(IntCC::Equal, byte2, newline);
let is_cr2 = builder.ins().icmp(IntCC::Equal, byte2, cr);
let is_ws2_1 = builder.ins().bor(is_space2, is_tab2);
let is_ws2_2 = builder.ins().bor(is_newline2, is_cr2);
let is_ws2 = builder.ins().bor(is_ws2_1, is_ws2_2);
builder
.ins()
.brif(is_ws2, skip_trailing_ws_advance, &[], merge, &[]);
builder.switch_to_block(skip_trailing_ws_advance);
builder.seal_block(skip_trailing_ws_advance);
let next_pos2 = builder.ins().iadd(pos2, one);
builder.def_var(cursor.pos, next_pos2);
builder.ins().jump(skip_trailing_ws_loop, &[]);
builder.seal_block(skip_trailing_ws_loop);
builder.switch_to_block(handle_close_bracket);
builder.seal_block(handle_close_bracket);
builder.ins().jump(merge, &[]);
builder.switch_to_block(unexpected_char);
builder.seal_block(unexpected_char);
let err_unexpected = builder
.ins()
.iconst(types::I32, error::EXPECTED_COMMA_OR_END as i64);
builder.def_var(result_error_var, err_unexpected);
builder.ins().jump(merge, &[]);
builder.switch_to_block(eof_error);
builder.seal_block(eof_error);
let err_eof = builder
.ins()
.iconst(types::I32, error::UNEXPECTED_EOF as i64);
builder.def_var(result_error_var, err_eof);
builder.ins().jump(merge, &[]);
builder.switch_to_block(merge);
builder.seal_block(merge);
builder.use_var(result_error_var)
}
fn emit_try_empty_seq(
&self,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
) -> Option<(Value, Value)> {
let result_is_empty_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 one_i8 = builder.ins().iconst(types::I8, 1);
let zero_i32 = builder.ins().iconst(types::I32, 0);
builder.def_var(result_is_empty_var, zero_i8);
builder.def_var(result_error_var, zero_i32);
let orig_pos = builder.use_var(cursor.pos);
let orig_pos_var = builder.declare_var(cursor.ptr_type);
builder.def_var(orig_pos_var, orig_pos);
let one = builder.ins().iconst(cursor.ptr_type, 1);
let two = builder.ins().iconst(cursor.ptr_type, 2);
let space = builder.ins().iconst(types::I8, b' ' as i64);
let tab = builder.ins().iconst(types::I8, b'\t' as i64);
let newline = builder.ins().iconst(types::I8, b'\n' as i64);
let cr = builder.ins().iconst(types::I8, b'\r' as i64);
let skip_ws_loop = builder.create_block();
let check_ws = builder.create_block();
let skip_ws_advance = builder.create_block();
let check_pattern = builder.create_block();
let found_empty = builder.create_block();
let skip_trailing_ws_loop = builder.create_block();
let check_trailing_ws = builder.create_block();
let skip_trailing_ws_advance = builder.create_block();
let not_empty = builder.create_block();
let merge = builder.create_block();
builder.ins().jump(skip_ws_loop, &[]);
builder.switch_to_block(skip_ws_loop);
let pos = builder.use_var(cursor.pos);
let have_bytes = builder.ins().icmp(IntCC::UnsignedLessThan, pos, cursor.len);
builder
.ins()
.brif(have_bytes, check_ws, &[], not_empty, &[]);
builder.switch_to_block(check_ws);
builder.seal_block(check_ws);
let addr = builder.ins().iadd(cursor.input_ptr, pos);
let byte = builder.ins().load(types::I8, MemFlags::trusted(), addr, 0);
let is_space = builder.ins().icmp(IntCC::Equal, byte, space);
let is_tab = builder.ins().icmp(IntCC::Equal, byte, tab);
let is_newline = builder.ins().icmp(IntCC::Equal, byte, newline);
let is_cr = builder.ins().icmp(IntCC::Equal, byte, cr);
let is_ws1 = builder.ins().bor(is_space, is_tab);
let is_ws2 = builder.ins().bor(is_newline, is_cr);
let is_ws = builder.ins().bor(is_ws1, is_ws2);
builder
.ins()
.brif(is_ws, skip_ws_advance, &[], check_pattern, &[]);
builder.switch_to_block(skip_ws_advance);
builder.seal_block(skip_ws_advance);
let next_pos = builder.ins().iadd(pos, one);
builder.def_var(cursor.pos, next_pos);
builder.ins().jump(skip_ws_loop, &[]);
builder.seal_block(skip_ws_loop);
builder.switch_to_block(check_pattern);
builder.seal_block(check_pattern);
let pos2 = builder.use_var(cursor.pos);
let end_pos = builder.ins().iadd(pos2, two);
let have_two = builder
.ins()
.icmp(IntCC::UnsignedLessThanOrEqual, end_pos, cursor.len);
let check_bytes = builder.create_block();
builder
.ins()
.brif(have_two, check_bytes, &[], not_empty, &[]);
builder.switch_to_block(check_bytes);
builder.seal_block(check_bytes);
let addr2 = builder.ins().iadd(cursor.input_ptr, pos2);
let two_bytes = builder
.ins()
.load(types::I16, MemFlags::trusted(), addr2, 0);
let empty_pattern = builder.ins().iconst(types::I16, 0x5D5B); let is_empty = builder.ins().icmp(IntCC::Equal, two_bytes, empty_pattern);
builder
.ins()
.brif(is_empty, found_empty, &[], not_empty, &[]);
builder.switch_to_block(found_empty);
builder.seal_block(found_empty);
let pos_after_empty = builder.ins().iadd(pos2, two);
builder.def_var(cursor.pos, pos_after_empty);
builder.def_var(result_is_empty_var, one_i8);
builder.ins().jump(skip_trailing_ws_loop, &[]);
builder.switch_to_block(skip_trailing_ws_loop);
let pos3 = builder.use_var(cursor.pos);
let have_bytes3 = builder
.ins()
.icmp(IntCC::UnsignedLessThan, pos3, cursor.len);
builder
.ins()
.brif(have_bytes3, check_trailing_ws, &[], merge, &[]);
builder.switch_to_block(check_trailing_ws);
builder.seal_block(check_trailing_ws);
let addr3 = builder.ins().iadd(cursor.input_ptr, pos3);
let byte3 = builder.ins().load(types::I8, MemFlags::trusted(), addr3, 0);
let is_space3 = builder.ins().icmp(IntCC::Equal, byte3, space);
let is_tab3 = builder.ins().icmp(IntCC::Equal, byte3, tab);
let is_newline3 = builder.ins().icmp(IntCC::Equal, byte3, newline);
let is_cr3 = builder.ins().icmp(IntCC::Equal, byte3, cr);
let is_ws3_1 = builder.ins().bor(is_space3, is_tab3);
let is_ws3_2 = builder.ins().bor(is_newline3, is_cr3);
let is_ws3 = builder.ins().bor(is_ws3_1, is_ws3_2);
builder
.ins()
.brif(is_ws3, skip_trailing_ws_advance, &[], merge, &[]);
builder.switch_to_block(skip_trailing_ws_advance);
builder.seal_block(skip_trailing_ws_advance);
let next_pos3 = builder.ins().iadd(pos3, one);
builder.def_var(cursor.pos, next_pos3);
builder.ins().jump(skip_trailing_ws_loop, &[]);
builder.seal_block(skip_trailing_ws_loop);
builder.switch_to_block(not_empty);
builder.seal_block(not_empty);
let orig = builder.use_var(orig_pos_var);
builder.def_var(cursor.pos, orig);
builder.ins().jump(merge, &[]);
builder.switch_to_block(merge);
builder.seal_block(merge);
let is_empty_result = builder.use_var(result_is_empty_var);
let error_result = builder.use_var(result_error_var);
Some((is_empty_result, error_result))
}
fn emit_try_empty_map(
&self,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
) -> Option<(Value, Value)> {
let result_is_empty_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 one_i8 = builder.ins().iconst(types::I8, 1);
let zero_i32 = builder.ins().iconst(types::I32, 0);
builder.def_var(result_is_empty_var, zero_i8);
builder.def_var(result_error_var, zero_i32);
let orig_pos = builder.use_var(cursor.pos);
let orig_pos_var = builder.declare_var(cursor.ptr_type);
builder.def_var(orig_pos_var, orig_pos);
let one = builder.ins().iconst(cursor.ptr_type, 1);
let two = builder.ins().iconst(cursor.ptr_type, 2);
let space = builder.ins().iconst(types::I8, b' ' as i64);
let tab = builder.ins().iconst(types::I8, b'\t' as i64);
let newline = builder.ins().iconst(types::I8, b'\n' as i64);
let cr = builder.ins().iconst(types::I8, b'\r' as i64);
let skip_ws_loop = builder.create_block();
let check_ws = builder.create_block();
let skip_ws_advance = builder.create_block();
let check_pattern = builder.create_block();
let found_empty = builder.create_block();
let skip_trailing_ws_loop = builder.create_block();
let check_trailing_ws = builder.create_block();
let skip_trailing_ws_advance = builder.create_block();
let not_empty = builder.create_block();
let merge = builder.create_block();
builder.ins().jump(skip_ws_loop, &[]);
builder.switch_to_block(skip_ws_loop);
let pos = builder.use_var(cursor.pos);
let have_bytes = builder.ins().icmp(IntCC::UnsignedLessThan, pos, cursor.len);
builder
.ins()
.brif(have_bytes, check_ws, &[], not_empty, &[]);
builder.switch_to_block(check_ws);
builder.seal_block(check_ws);
let addr = builder.ins().iadd(cursor.input_ptr, pos);
let byte = builder.ins().load(types::I8, MemFlags::trusted(), addr, 0);
let is_space = builder.ins().icmp(IntCC::Equal, byte, space);
let is_tab = builder.ins().icmp(IntCC::Equal, byte, tab);
let is_newline = builder.ins().icmp(IntCC::Equal, byte, newline);
let is_cr = builder.ins().icmp(IntCC::Equal, byte, cr);
let is_ws1 = builder.ins().bor(is_space, is_tab);
let is_ws2 = builder.ins().bor(is_newline, is_cr);
let is_ws = builder.ins().bor(is_ws1, is_ws2);
builder
.ins()
.brif(is_ws, skip_ws_advance, &[], check_pattern, &[]);
builder.switch_to_block(skip_ws_advance);
builder.seal_block(skip_ws_advance);
let next_pos = builder.ins().iadd(pos, one);
builder.def_var(cursor.pos, next_pos);
builder.ins().jump(skip_ws_loop, &[]);
builder.seal_block(skip_ws_loop);
builder.switch_to_block(check_pattern);
builder.seal_block(check_pattern);
let pos2 = builder.use_var(cursor.pos);
let end_pos = builder.ins().iadd(pos2, two);
let have_two = builder
.ins()
.icmp(IntCC::UnsignedLessThanOrEqual, end_pos, cursor.len);
let check_bytes = builder.create_block();
builder
.ins()
.brif(have_two, check_bytes, &[], not_empty, &[]);
builder.switch_to_block(check_bytes);
builder.seal_block(check_bytes);
let addr2 = builder.ins().iadd(cursor.input_ptr, pos2);
let two_bytes = builder
.ins()
.load(types::I16, MemFlags::trusted(), addr2, 0);
let empty_pattern = builder.ins().iconst(types::I16, 0x7D7B); let is_empty = builder.ins().icmp(IntCC::Equal, two_bytes, empty_pattern);
builder
.ins()
.brif(is_empty, found_empty, &[], not_empty, &[]);
builder.switch_to_block(found_empty);
builder.seal_block(found_empty);
let pos_after_empty = builder.ins().iadd(pos2, two);
builder.def_var(cursor.pos, pos_after_empty);
builder.def_var(result_is_empty_var, one_i8);
builder.ins().jump(skip_trailing_ws_loop, &[]);
builder.switch_to_block(skip_trailing_ws_loop);
let pos3 = builder.use_var(cursor.pos);
let have_bytes3 = builder
.ins()
.icmp(IntCC::UnsignedLessThan, pos3, cursor.len);
builder
.ins()
.brif(have_bytes3, check_trailing_ws, &[], merge, &[]);
builder.switch_to_block(check_trailing_ws);
builder.seal_block(check_trailing_ws);
let addr3 = builder.ins().iadd(cursor.input_ptr, pos3);
let byte3 = builder.ins().load(types::I8, MemFlags::trusted(), addr3, 0);
let is_space3 = builder.ins().icmp(IntCC::Equal, byte3, space);
let is_tab3 = builder.ins().icmp(IntCC::Equal, byte3, tab);
let is_newline3 = builder.ins().icmp(IntCC::Equal, byte3, newline);
let is_cr3 = builder.ins().icmp(IntCC::Equal, byte3, cr);
let is_ws3_1 = builder.ins().bor(is_space3, is_tab3);
let is_ws3_2 = builder.ins().bor(is_newline3, is_cr3);
let is_ws3 = builder.ins().bor(is_ws3_1, is_ws3_2);
builder
.ins()
.brif(is_ws3, skip_trailing_ws_advance, &[], merge, &[]);
builder.switch_to_block(skip_trailing_ws_advance);
builder.seal_block(skip_trailing_ws_advance);
let next_pos3 = builder.ins().iadd(pos3, one);
builder.def_var(cursor.pos, next_pos3);
builder.ins().jump(skip_trailing_ws_loop, &[]);
builder.seal_block(skip_trailing_ws_loop);
builder.switch_to_block(not_empty);
builder.seal_block(not_empty);
let orig = builder.use_var(orig_pos_var);
builder.def_var(cursor.pos, orig);
builder.ins().jump(merge, &[]);
builder.switch_to_block(merge);
builder.seal_block(merge);
let is_empty_result = builder.use_var(result_is_empty_var);
let error_result = builder.use_var(result_error_var);
Some((is_empty_result, error_result))
}
fn emit_map_begin(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
_state_ptr: Value,
) -> Value {
let result_error_var = builder.declare_var(types::I32);
let zero_i32 = builder.ins().iconst(types::I32, 0);
builder.def_var(result_error_var, zero_i32);
let one = builder.ins().iconst(cursor.ptr_type, 1);
let space = builder.ins().iconst(types::I8, b' ' as i64);
let tab = builder.ins().iconst(types::I8, b'\t' as i64);
let newline = builder.ins().iconst(types::I8, b'\n' as i64);
let cr = builder.ins().iconst(types::I8, b'\r' as i64);
let const_32 = builder.ins().iconst(types::I8, 32);
let skip_leading_ws_loop = builder.create_block();
let check_leading_ws = builder.create_block();
let maybe_leading_ws = builder.create_block();
let check_leading_low_ws = builder.create_block();
let skip_leading_ws_advance = builder.create_block();
let check_brace = builder.create_block();
let skip_trailing_ws_loop = builder.create_block();
let check_trailing_ws = builder.create_block();
let skip_trailing_ws_advance = builder.create_block();
let not_brace_error = builder.create_block();
let eof_error = builder.create_block();
let merge = builder.create_block();
builder.ins().jump(skip_leading_ws_loop, &[]);
builder.switch_to_block(skip_leading_ws_loop);
let pos = builder.use_var(cursor.pos);
let have_bytes = builder.ins().icmp(IntCC::UnsignedLessThan, pos, cursor.len);
builder
.ins()
.brif(have_bytes, check_leading_ws, &[], eof_error, &[]);
builder.switch_to_block(check_leading_ws);
builder.seal_block(check_leading_ws);
let addr = builder.ins().iadd(cursor.input_ptr, pos);
let byte = builder.ins().load(types::I8, MemFlags::trusted(), addr, 0);
let gt_32 = builder
.ins()
.icmp(IntCC::UnsignedGreaterThan, byte, const_32);
builder
.ins()
.brif(gt_32, check_brace, &[], maybe_leading_ws, &[]);
builder.switch_to_block(maybe_leading_ws);
builder.seal_block(maybe_leading_ws);
let is_space = builder.ins().icmp(IntCC::Equal, byte, space);
builder.ins().brif(
is_space,
skip_leading_ws_advance,
&[],
check_leading_low_ws,
&[],
);
builder.switch_to_block(check_leading_low_ws);
builder.seal_block(check_leading_low_ws);
let is_tab = builder.ins().icmp(IntCC::Equal, byte, tab);
let is_newline = builder.ins().icmp(IntCC::Equal, byte, newline);
let is_cr = builder.ins().icmp(IntCC::Equal, byte, cr);
let is_ws_1 = builder.ins().bor(is_tab, is_newline);
let is_ws = builder.ins().bor(is_ws_1, is_cr);
builder
.ins()
.brif(is_ws, skip_leading_ws_advance, &[], check_brace, &[]);
builder.switch_to_block(skip_leading_ws_advance);
builder.seal_block(skip_leading_ws_advance);
let next_pos = builder.ins().iadd(pos, one);
builder.def_var(cursor.pos, next_pos);
builder.ins().jump(skip_leading_ws_loop, &[]);
builder.seal_block(skip_leading_ws_loop);
builder.switch_to_block(check_brace);
builder.seal_block(check_brace);
let open_brace = builder.ins().iconst(types::I8, b'{' as i64);
let is_brace = builder.ins().icmp(IntCC::Equal, byte, open_brace);
builder
.ins()
.brif(is_brace, skip_trailing_ws_loop, &[], not_brace_error, &[]);
builder.switch_to_block(skip_trailing_ws_loop);
builder.seal_block(skip_trailing_ws_loop);
let pos2 = builder.use_var(cursor.pos);
let pos_after_brace = builder.ins().iadd(pos2, one);
builder.def_var(cursor.pos, pos_after_brace);
let trailing_ws_check_bounds = builder.create_block();
builder.ins().jump(trailing_ws_check_bounds, &[]);
builder.switch_to_block(trailing_ws_check_bounds);
let pos3 = builder.use_var(cursor.pos);
let have_bytes3 = builder
.ins()
.icmp(IntCC::UnsignedLessThan, pos3, cursor.len);
builder
.ins()
.brif(have_bytes3, check_trailing_ws, &[], merge, &[]);
let maybe_trailing_ws = builder.create_block();
let check_trailing_low_ws = builder.create_block();
builder.switch_to_block(check_trailing_ws);
builder.seal_block(check_trailing_ws);
let addr3 = builder.ins().iadd(cursor.input_ptr, pos3);
let byte3 = builder.ins().load(types::I8, MemFlags::trusted(), addr3, 0);
let gt_32_3 = builder
.ins()
.icmp(IntCC::UnsignedGreaterThan, byte3, const_32);
builder
.ins()
.brif(gt_32_3, merge, &[], maybe_trailing_ws, &[]);
builder.switch_to_block(maybe_trailing_ws);
builder.seal_block(maybe_trailing_ws);
let is_space3 = builder.ins().icmp(IntCC::Equal, byte3, space);
builder.ins().brif(
is_space3,
skip_trailing_ws_advance,
&[],
check_trailing_low_ws,
&[],
);
builder.switch_to_block(check_trailing_low_ws);
builder.seal_block(check_trailing_low_ws);
let is_tab3 = builder.ins().icmp(IntCC::Equal, byte3, tab);
let is_newline3 = builder.ins().icmp(IntCC::Equal, byte3, newline);
let is_cr3 = builder.ins().icmp(IntCC::Equal, byte3, cr);
let is_ws3_1 = builder.ins().bor(is_tab3, is_newline3);
let is_ws3 = builder.ins().bor(is_ws3_1, is_cr3);
builder
.ins()
.brif(is_ws3, skip_trailing_ws_advance, &[], merge, &[]);
builder.switch_to_block(skip_trailing_ws_advance);
builder.seal_block(skip_trailing_ws_advance);
let next_pos3 = builder.ins().iadd(pos3, one);
builder.def_var(cursor.pos, next_pos3);
builder.ins().jump(trailing_ws_check_bounds, &[]);
builder.seal_block(trailing_ws_check_bounds);
builder.switch_to_block(not_brace_error);
builder.seal_block(not_brace_error);
let err_not_brace = builder
.ins()
.iconst(types::I32, error::EXPECTED_OBJECT_START as i64);
builder.def_var(result_error_var, err_not_brace);
builder.ins().jump(merge, &[]);
builder.switch_to_block(eof_error);
builder.seal_block(eof_error);
let err_eof = builder
.ins()
.iconst(types::I32, error::UNEXPECTED_EOF as i64);
builder.def_var(result_error_var, err_eof);
builder.ins().jump(merge, &[]);
builder.switch_to_block(merge);
builder.seal_block(merge);
builder.use_var(result_error_var)
}
fn emit_map_is_end(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
_state_ptr: Value,
) -> (Value, Value) {
let pos = builder.use_var(cursor.pos);
let result_is_end_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_is_end_var, zero_i8);
builder.def_var(result_error_var, zero_i32);
let check_byte = builder.create_block();
let found_end = builder.create_block();
let skip_ws_loop = builder.create_block();
let skip_ws_check = builder.create_block();
let not_end = builder.create_block();
let eof_error = builder.create_block();
let merge = builder.create_block();
let have_bytes = builder.ins().icmp(IntCC::UnsignedLessThan, pos, cursor.len);
builder
.ins()
.brif(have_bytes, check_byte, &[], eof_error, &[]);
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 close_brace = builder.ins().iconst(types::I8, b'}' as i64);
let is_close = builder.ins().icmp(IntCC::Equal, byte, close_brace);
builder.ins().brif(is_close, found_end, &[], not_end, &[]);
builder.switch_to_block(found_end);
builder.seal_block(found_end);
let one = builder.ins().iconst(cursor.ptr_type, 1);
let pos_after_brace = builder.ins().iadd(pos, one);
builder.def_var(cursor.pos, pos_after_brace);
builder.ins().jump(skip_ws_loop, &[]);
builder.switch_to_block(skip_ws_loop);
let ws_pos = builder.use_var(cursor.pos);
let ws_have_bytes = builder
.ins()
.icmp(IntCC::UnsignedLessThan, ws_pos, cursor.len);
let ws_check_char = builder.create_block();
let ws_done = builder.create_block();
builder
.ins()
.brif(ws_have_bytes, ws_check_char, &[], ws_done, &[]);
let maybe_ws = builder.create_block();
let check_low_ws = builder.create_block();
builder.switch_to_block(ws_check_char);
builder.seal_block(ws_check_char);
let ws_addr = builder.ins().iadd(cursor.input_ptr, ws_pos);
let ws_byte = builder
.ins()
.load(types::I8, MemFlags::trusted(), ws_addr, 0);
let const_32 = builder.ins().iconst(types::I8, 32);
let gt_32 = builder
.ins()
.icmp(IntCC::UnsignedGreaterThan, ws_byte, const_32);
builder.ins().brif(gt_32, ws_done, &[], maybe_ws, &[]);
builder.switch_to_block(maybe_ws);
builder.seal_block(maybe_ws);
let space = builder.ins().iconst(types::I8, b' ' as i64);
let is_space = builder.ins().icmp(IntCC::Equal, ws_byte, space);
builder
.ins()
.brif(is_space, skip_ws_check, &[], check_low_ws, &[]);
builder.switch_to_block(check_low_ws);
builder.seal_block(check_low_ws);
let tab = builder.ins().iconst(types::I8, b'\t' as i64);
let newline = builder.ins().iconst(types::I8, b'\n' as i64);
let cr = builder.ins().iconst(types::I8, b'\r' as i64);
let is_tab = builder.ins().icmp(IntCC::Equal, ws_byte, tab);
let is_newline = builder.ins().icmp(IntCC::Equal, ws_byte, newline);
let is_cr = builder.ins().icmp(IntCC::Equal, ws_byte, cr);
let is_ws_1 = builder.ins().bor(is_tab, is_newline);
let is_ws = builder.ins().bor(is_ws_1, is_cr);
builder.ins().brif(is_ws, skip_ws_check, &[], ws_done, &[]);
builder.switch_to_block(skip_ws_check);
builder.seal_block(skip_ws_check);
let ws_next = builder.ins().iadd(ws_pos, one);
builder.def_var(cursor.pos, ws_next);
builder.ins().jump(skip_ws_loop, &[]);
builder.seal_block(skip_ws_loop);
builder.switch_to_block(ws_done);
builder.seal_block(ws_done);
let one_i8 = builder.ins().iconst(types::I8, 1);
builder.def_var(result_is_end_var, one_i8);
builder.def_var(result_error_var, zero_i32);
builder.ins().jump(merge, &[]);
builder.switch_to_block(not_end);
builder.seal_block(not_end);
builder.ins().jump(merge, &[]);
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(merge);
builder.seal_block(merge);
let result_is_end = builder.use_var(result_is_end_var);
let result_error = builder.use_var(result_error_var);
(result_is_end, result_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 {
let result_error_var = builder.declare_var(types::I32);
let zero_i32 = builder.ins().iconst(types::I32, 0);
builder.def_var(result_error_var, zero_i32);
let one = builder.ins().iconst(cursor.ptr_type, 1);
let space = builder.ins().iconst(types::I8, b' ' as i64);
let tab = builder.ins().iconst(types::I8, b'\t' as i64);
let newline = builder.ins().iconst(types::I8, b'\n' as i64);
let cr = builder.ins().iconst(types::I8, b'\r' as i64);
let const_32 = builder.ins().iconst(types::I8, 32);
let skip_leading_ws_loop = builder.create_block();
let check_leading_ws = builder.create_block();
let maybe_leading_ws = builder.create_block();
let check_leading_low_ws = builder.create_block();
let skip_leading_ws_advance = builder.create_block();
let check_colon = builder.create_block();
let skip_trailing_ws_loop = builder.create_block();
let check_trailing_ws = builder.create_block();
let skip_trailing_ws_advance = builder.create_block();
let not_colon_error = builder.create_block();
let eof_error = builder.create_block();
let merge = builder.create_block();
builder.ins().jump(skip_leading_ws_loop, &[]);
builder.switch_to_block(skip_leading_ws_loop);
let pos = builder.use_var(cursor.pos);
let have_bytes = builder.ins().icmp(IntCC::UnsignedLessThan, pos, cursor.len);
builder
.ins()
.brif(have_bytes, check_leading_ws, &[], eof_error, &[]);
builder.switch_to_block(check_leading_ws);
builder.seal_block(check_leading_ws);
let addr = builder.ins().iadd(cursor.input_ptr, pos);
let byte = builder.ins().load(types::I8, MemFlags::trusted(), addr, 0);
let gt_32 = builder
.ins()
.icmp(IntCC::UnsignedGreaterThan, byte, const_32);
builder
.ins()
.brif(gt_32, check_colon, &[], maybe_leading_ws, &[]);
builder.switch_to_block(maybe_leading_ws);
builder.seal_block(maybe_leading_ws);
let is_space = builder.ins().icmp(IntCC::Equal, byte, space);
builder.ins().brif(
is_space,
skip_leading_ws_advance,
&[],
check_leading_low_ws,
&[],
);
builder.switch_to_block(check_leading_low_ws);
builder.seal_block(check_leading_low_ws);
let is_tab = builder.ins().icmp(IntCC::Equal, byte, tab);
let is_newline = builder.ins().icmp(IntCC::Equal, byte, newline);
let is_cr = builder.ins().icmp(IntCC::Equal, byte, cr);
let is_ws_1 = builder.ins().bor(is_tab, is_newline);
let is_ws = builder.ins().bor(is_ws_1, is_cr);
builder
.ins()
.brif(is_ws, skip_leading_ws_advance, &[], check_colon, &[]);
builder.switch_to_block(skip_leading_ws_advance);
builder.seal_block(skip_leading_ws_advance);
let next_pos = builder.ins().iadd(pos, one);
builder.def_var(cursor.pos, next_pos);
builder.ins().jump(skip_leading_ws_loop, &[]);
builder.seal_block(skip_leading_ws_loop);
builder.switch_to_block(check_colon);
builder.seal_block(check_colon);
let colon = builder.ins().iconst(types::I8, b':' as i64);
let is_colon = builder.ins().icmp(IntCC::Equal, byte, colon);
builder
.ins()
.brif(is_colon, skip_trailing_ws_loop, &[], not_colon_error, &[]);
builder.switch_to_block(skip_trailing_ws_loop);
builder.seal_block(skip_trailing_ws_loop);
let pos2 = builder.use_var(cursor.pos);
let pos_after_colon = builder.ins().iadd(pos2, one);
builder.def_var(cursor.pos, pos_after_colon);
let trailing_ws_check_bounds = builder.create_block();
builder.ins().jump(trailing_ws_check_bounds, &[]);
builder.switch_to_block(trailing_ws_check_bounds);
let pos3 = builder.use_var(cursor.pos);
let have_bytes3 = builder
.ins()
.icmp(IntCC::UnsignedLessThan, pos3, cursor.len);
builder
.ins()
.brif(have_bytes3, check_trailing_ws, &[], merge, &[]);
let maybe_trailing_ws = builder.create_block();
let check_trailing_low_ws = builder.create_block();
builder.switch_to_block(check_trailing_ws);
builder.seal_block(check_trailing_ws);
let addr3 = builder.ins().iadd(cursor.input_ptr, pos3);
let byte3 = builder.ins().load(types::I8, MemFlags::trusted(), addr3, 0);
let gt_32_3 = builder
.ins()
.icmp(IntCC::UnsignedGreaterThan, byte3, const_32);
builder
.ins()
.brif(gt_32_3, merge, &[], maybe_trailing_ws, &[]);
builder.switch_to_block(maybe_trailing_ws);
builder.seal_block(maybe_trailing_ws);
let is_space3 = builder.ins().icmp(IntCC::Equal, byte3, space);
builder.ins().brif(
is_space3,
skip_trailing_ws_advance,
&[],
check_trailing_low_ws,
&[],
);
builder.switch_to_block(check_trailing_low_ws);
builder.seal_block(check_trailing_low_ws);
let is_tab3 = builder.ins().icmp(IntCC::Equal, byte3, tab);
let is_newline3 = builder.ins().icmp(IntCC::Equal, byte3, newline);
let is_cr3 = builder.ins().icmp(IntCC::Equal, byte3, cr);
let is_ws3_1 = builder.ins().bor(is_tab3, is_newline3);
let is_ws3 = builder.ins().bor(is_ws3_1, is_cr3);
builder
.ins()
.brif(is_ws3, skip_trailing_ws_advance, &[], merge, &[]);
builder.switch_to_block(skip_trailing_ws_advance);
builder.seal_block(skip_trailing_ws_advance);
let next_pos3 = builder.ins().iadd(pos3, one);
builder.def_var(cursor.pos, next_pos3);
builder.ins().jump(trailing_ws_check_bounds, &[]);
builder.seal_block(trailing_ws_check_bounds);
builder.switch_to_block(not_colon_error);
builder.seal_block(not_colon_error);
let err_not_colon = builder
.ins()
.iconst(types::I32, error::EXPECTED_COLON as i64);
builder.def_var(result_error_var, err_not_colon);
builder.ins().jump(merge, &[]);
builder.switch_to_block(eof_error);
builder.seal_block(eof_error);
let err_eof = builder
.ins()
.iconst(types::I32, error::UNEXPECTED_EOF as i64);
builder.def_var(result_error_var, err_eof);
builder.ins().jump(merge, &[]);
builder.switch_to_block(merge);
builder.seal_block(merge);
builder.use_var(result_error_var)
}
fn emit_map_next(
&self,
_module: &mut JITModule,
builder: &mut FunctionBuilder,
cursor: &mut JitCursor,
_state_ptr: Value,
) -> Value {
let result_error_var = builder.declare_var(types::I32);
let zero_i32 = builder.ins().iconst(types::I32, 0);
builder.def_var(result_error_var, zero_i32);
let one = builder.ins().iconst(cursor.ptr_type, 1);
let space = builder.ins().iconst(types::I8, b' ' as i64);
let tab = builder.ins().iconst(types::I8, b'\t' as i64);
let newline = builder.ins().iconst(types::I8, b'\n' as i64);
let cr = builder.ins().iconst(types::I8, b'\r' as i64);
let const_32 = builder.ins().iconst(types::I8, 32);
let skip_leading_ws_loop = builder.create_block();
let check_leading_ws = builder.create_block();
let maybe_leading_ws = builder.create_block();
let check_leading_low_ws = builder.create_block();
let skip_leading_ws_advance = builder.create_block();
let check_separator = builder.create_block();
let not_comma = builder.create_block();
let handle_comma = builder.create_block();
let skip_trailing_ws_loop = builder.create_block();
let check_trailing_ws = builder.create_block();
let skip_trailing_ws_advance = builder.create_block();
let handle_close_brace = builder.create_block();
let unexpected_char = builder.create_block();
let eof_error = builder.create_block();
let merge = builder.create_block();
builder.ins().jump(skip_leading_ws_loop, &[]);
builder.switch_to_block(skip_leading_ws_loop);
let pos = builder.use_var(cursor.pos);
let have_bytes = builder.ins().icmp(IntCC::UnsignedLessThan, pos, cursor.len);
builder
.ins()
.brif(have_bytes, check_leading_ws, &[], eof_error, &[]);
builder.switch_to_block(check_leading_ws);
builder.seal_block(check_leading_ws);
let addr = builder.ins().iadd(cursor.input_ptr, pos);
let byte = builder.ins().load(types::I8, MemFlags::trusted(), addr, 0);
let gt_32 = builder
.ins()
.icmp(IntCC::UnsignedGreaterThan, byte, const_32);
builder
.ins()
.brif(gt_32, check_separator, &[], maybe_leading_ws, &[]);
builder.switch_to_block(maybe_leading_ws);
builder.seal_block(maybe_leading_ws);
let is_space = builder.ins().icmp(IntCC::Equal, byte, space);
builder.ins().brif(
is_space,
skip_leading_ws_advance,
&[],
check_leading_low_ws,
&[],
);
builder.switch_to_block(check_leading_low_ws);
builder.seal_block(check_leading_low_ws);
let is_tab = builder.ins().icmp(IntCC::Equal, byte, tab);
let is_newline = builder.ins().icmp(IntCC::Equal, byte, newline);
let is_cr = builder.ins().icmp(IntCC::Equal, byte, cr);
let is_ws_1 = builder.ins().bor(is_tab, is_newline);
let is_ws = builder.ins().bor(is_ws_1, is_cr);
builder
.ins()
.brif(is_ws, skip_leading_ws_advance, &[], check_separator, &[]);
builder.switch_to_block(skip_leading_ws_advance);
builder.seal_block(skip_leading_ws_advance);
let next_pos = builder.ins().iadd(pos, one);
builder.def_var(cursor.pos, next_pos);
builder.ins().jump(skip_leading_ws_loop, &[]);
builder.seal_block(skip_leading_ws_loop);
builder.switch_to_block(check_separator);
builder.seal_block(check_separator);
let comma = builder.ins().iconst(types::I8, b',' as i64);
let close_brace = builder.ins().iconst(types::I8, b'}' as i64);
let is_comma = builder.ins().icmp(IntCC::Equal, byte, comma);
builder
.ins()
.brif(is_comma, handle_comma, &[], not_comma, &[]);
builder.switch_to_block(not_comma);
builder.seal_block(not_comma);
let is_close = builder.ins().icmp(IntCC::Equal, byte, close_brace);
builder
.ins()
.brif(is_close, handle_close_brace, &[], unexpected_char, &[]);
builder.switch_to_block(handle_comma);
builder.seal_block(handle_comma);
let pos_after_comma = builder.ins().iadd(pos, one);
builder.def_var(cursor.pos, pos_after_comma);
builder.ins().jump(skip_trailing_ws_loop, &[]);
builder.switch_to_block(skip_trailing_ws_loop);
let pos2 = builder.use_var(cursor.pos);
let have_bytes2 = builder
.ins()
.icmp(IntCC::UnsignedLessThan, pos2, cursor.len);
builder
.ins()
.brif(have_bytes2, check_trailing_ws, &[], merge, &[]);
let maybe_trailing_ws = builder.create_block();
let check_trailing_low_ws = builder.create_block();
builder.switch_to_block(check_trailing_ws);
builder.seal_block(check_trailing_ws);
let addr2 = builder.ins().iadd(cursor.input_ptr, pos2);
let byte2 = builder.ins().load(types::I8, MemFlags::trusted(), addr2, 0);
let gt_32_2 = builder
.ins()
.icmp(IntCC::UnsignedGreaterThan, byte2, const_32);
builder
.ins()
.brif(gt_32_2, merge, &[], maybe_trailing_ws, &[]);
builder.switch_to_block(maybe_trailing_ws);
builder.seal_block(maybe_trailing_ws);
let is_space2 = builder.ins().icmp(IntCC::Equal, byte2, space);
builder.ins().brif(
is_space2,
skip_trailing_ws_advance,
&[],
check_trailing_low_ws,
&[],
);
builder.switch_to_block(check_trailing_low_ws);
builder.seal_block(check_trailing_low_ws);
let is_tab2 = builder.ins().icmp(IntCC::Equal, byte2, tab);
let is_newline2 = builder.ins().icmp(IntCC::Equal, byte2, newline);
let is_cr2 = builder.ins().icmp(IntCC::Equal, byte2, cr);
let is_ws2_1 = builder.ins().bor(is_tab2, is_newline2);
let is_ws2 = builder.ins().bor(is_ws2_1, is_cr2);
builder
.ins()
.brif(is_ws2, skip_trailing_ws_advance, &[], merge, &[]);
builder.switch_to_block(skip_trailing_ws_advance);
builder.seal_block(skip_trailing_ws_advance);
let next_pos2 = builder.ins().iadd(pos2, one);
builder.def_var(cursor.pos, next_pos2);
builder.ins().jump(skip_trailing_ws_loop, &[]);
builder.seal_block(skip_trailing_ws_loop);
builder.switch_to_block(handle_close_brace);
builder.seal_block(handle_close_brace);
builder.ins().jump(merge, &[]);
builder.switch_to_block(unexpected_char);
builder.seal_block(unexpected_char);
let err_unexpected = builder
.ins()
.iconst(types::I32, error::EXPECTED_COMMA_OR_BRACE as i64);
builder.def_var(result_error_var, err_unexpected);
builder.ins().jump(merge, &[]);
builder.switch_to_block(eof_error);
builder.seal_block(eof_error);
let err_eof = builder
.ins()
.iconst(types::I32, error::UNEXPECTED_EOF as i64);
builder.def_var(result_error_var, err_eof);
builder.ins().jump(merge, &[]);
builder.switch_to_block(merge);
builder.seal_block(merge);
builder.use_var(result_error_var)
}
}