fn emit_load_state(bytecode: &mut Vec<u8>, module: &ir::Module, index: usize) {
let key = module
.state_variables
.get(index)
.map(|state| state.storage_key.as_slice())
.unwrap_or(&[]);
let value_type = module.state_variables.get(index).map(|state| &state.ty);
push_data(bytecode, key);
emit_syscall(bytecode, "System.Storage.GetContext");
emit_syscall(bytecode, "System.Storage.Get");
if let Some(ty) = value_type {
emit_coerce_storage_value(bytecode, ty);
}
}
fn emit_store_state(bytecode: &mut Vec<u8>, module: &ir::Module, index: usize) {
let key = module
.state_variables
.get(index)
.map(|state| state.storage_key.as_slice())
.unwrap_or(&[]);
push_data(bytecode, key);
emit_syscall(bytecode, "System.Storage.GetContext");
emit_syscall(bytecode, "System.Storage.Put");
}
fn emit_coerce_storage_value(bytecode: &mut Vec<u8>, ty: &ValueType) {
fn with_null_default(
bytecode: &mut Vec<u8>,
default_value: impl Fn(&mut Vec<u8>),
not_null: impl FnOnce(&mut Vec<u8>),
) {
bytecode.push(0x4A); bytecode.push(0xD8);
let jmp_not_null_pos = bytecode.len();
bytecode.push(0x27); let jmp_not_null_operand = bytecode.len();
bytecode.extend_from_slice(&[0, 0, 0, 0]);
bytecode.push(0x45); default_value(bytecode);
let jmp_end_pos = bytecode.len();
bytecode.push(0x23); let jmp_end_operand = bytecode.len();
bytecode.extend_from_slice(&[0, 0, 0, 0]);
let not_null_pos = bytecode.len();
bytecode.push(0x4A); bytecode.push(0xCA); bytecode.push(0x10); bytecode.push(0x97);
let jmp_not_missing_pos = bytecode.len();
bytecode.push(0x27); let jmp_not_missing_operand = bytecode.len();
bytecode.extend_from_slice(&[0, 0, 0, 0]);
bytecode.push(0x45); default_value(bytecode);
let jmp_end2_pos = bytecode.len();
bytecode.push(0x23); let jmp_end2_operand = bytecode.len();
bytecode.extend_from_slice(&[0, 0, 0, 0]);
let not_missing_pos = bytecode.len();
not_null(bytecode);
let end_pos = bytecode.len();
let rel_not_null = (not_null_pos as i32)
.checked_sub(jmp_not_null_pos as i32)
.unwrap_or(0);
bytecode[jmp_not_null_operand..jmp_not_null_operand + 4]
.copy_from_slice(&rel_not_null.to_le_bytes());
let rel_not_missing = (not_missing_pos as i32)
.checked_sub(jmp_not_missing_pos as i32)
.unwrap_or(0);
bytecode[jmp_not_missing_operand..jmp_not_missing_operand + 4]
.copy_from_slice(&rel_not_missing.to_le_bytes());
let rel_end = (end_pos as i32).checked_sub(jmp_end_pos as i32).unwrap_or(0);
bytecode[jmp_end_operand..jmp_end_operand + 4].copy_from_slice(&rel_end.to_le_bytes());
let rel_end2 = (end_pos as i32).checked_sub(jmp_end2_pos as i32).unwrap_or(0);
bytecode[jmp_end2_operand..jmp_end2_operand + 4].copy_from_slice(&rel_end2.to_le_bytes());
}
match ty {
ValueType::Integer { .. } => {
with_null_default(
bytecode,
|bytecode| bytecode.push(0x10), |bytecode| {
bytecode.push(0xDB); bytecode.push(0x21); },
);
}
ValueType::Boolean => {
with_null_default(
bytecode,
|bytecode| bytecode.push(0x09), |bytecode| {
bytecode.push(0xB1); },
);
}
ValueType::String => {
with_null_default(bytecode, |bytecode| push_data(bytecode, &[]), |_bytecode| {});
}
ValueType::Address => {
with_null_default(bytecode, |bytecode| push_data(bytecode, &[0u8; 20]), |_bytecode| {});
}
ValueType::ByteArray { fixed_len } => {
let default_bytes = fixed_len
.map(|len| vec![0u8; len as usize])
.unwrap_or_default();
with_null_default(bytecode, |bytecode| push_data(bytecode, &default_bytes), |_bytecode| {});
}
ValueType::Array(_) => {
with_null_default(
bytecode,
|bytecode| bytecode.push(0x10), |bytecode| {
bytecode.push(0x10); bytecode.push(0x9E); },
);
}
_ => {}
}
}