1fn emit_ir_function(
2 function: &ir::Function,
3 module: &ir::Module,
4 method: &FunctionMetadata,
5 use_callt: bool,
6) -> (Vec<u8>, Vec<CallPatch>, Vec<MethodTokenPatch>) {
7 use std::{collections::HashMap, convert::TryFrom};
8
9 let mut local = Vec::new();
10 let arg_count = method.parameters.len() as u8;
11 let local_count = u8::try_from(function.local_count).unwrap_or(u8::MAX);
12 if local_count > 0 || arg_count > 0 {
13 local.push(0x57); local.push(local_count);
15 local.push(arg_count);
16 }
17 let mut label_offsets: HashMap<usize, u32> = HashMap::new();
18 let mut jump_patches: Vec<(usize, usize)> = Vec::new();
19 let mut call_patches: Vec<CallPatch> = Vec::new();
20 let mut token_patches: Vec<MethodTokenPatch> = Vec::new();
21
22 for block in &function.basic_blocks {
23 for instruction in &block.instructions {
24 match instruction {
25 ir::Instruction::Drop(_) => local.push(0x45),
26 ir::Instruction::LoadParameter(index) => {
27 emit_load_parameter(&mut local, method, *index)
28 }
29 ir::Instruction::PushLiteral(literal) => {
30 push_literal_value(&mut local, literal);
31 }
32 ir::Instruction::BinaryOp(operator) => emit_binary_op(&mut local, *operator),
33 ir::Instruction::Return | ir::Instruction::ReturnVoid => local.push(0x40),
34 ir::Instruction::ReturnDefault(value_type) => {
35 append_default_value(&mut local, value_type);
36 local.push(0x40);
37 }
38 ir::Instruction::LoadState(index) => emit_load_state(&mut local, module, *index),
39 ir::Instruction::StoreState(index) => emit_store_state(&mut local, module, *index),
40 ir::Instruction::LoadStorageDynamic => emit_load_storage_dynamic(&mut local),
41 ir::Instruction::LoadLocal(index) => emit_load_local(&mut local, *index),
42 ir::Instruction::StoreLocal(index) => emit_store_local(&mut local, *index),
43 ir::Instruction::LoadMappingElement {
44 state_index,
45 key_types,
46 } => emit_load_mapping(
47 &mut local,
48 module,
49 *state_index,
50 key_types,
51 use_callt,
52 &mut token_patches,
53 ),
54 ir::Instruction::StoreMappingElement {
55 state_index,
56 key_types,
57 } => emit_store_mapping(
58 &mut local,
59 module,
60 *state_index,
61 key_types,
62 use_callt,
63 &mut token_patches,
64 ),
65 ir::Instruction::LoadStructField {
66 state_index,
67 key_types,
68 field_keys,
69 field_type,
70 ..
71 } => emit_load_struct_field(
72 &mut local,
73 module,
74 *state_index,
75 key_types,
76 StructFieldAccess {
77 field_keys: field_keys.as_slice(),
78 ty: field_type,
79 },
80 use_callt,
81 &mut token_patches,
82 ),
83 ir::Instruction::StoreStructField {
84 state_index,
85 key_types,
86 field_keys,
87 field_type,
88 ..
89 } => {
90 emit_store_struct_field(
91 &mut local,
92 module,
93 *state_index,
94 key_types,
95 StructFieldAccess {
96 field_keys: field_keys.as_slice(),
97 ty: field_type,
98 },
99 use_callt,
100 &mut token_patches,
101 )
102 }
103 ir::Instruction::LoadStructArrayElement {
104 state_index,
105 key_types,
106 field_keys,
107 element_type,
108 } => emit_load_struct_array_element(
109 &mut local,
110 module,
111 *state_index,
112 key_types,
113 StructArrayElementAccess {
114 field_keys: field_keys.as_slice(),
115 element_type,
116 },
117 use_callt,
118 &mut token_patches,
119 ),
120 ir::Instruction::StoreStructArrayElement {
121 state_index,
122 key_types,
123 field_keys,
124 element_type,
125 } => emit_store_struct_array_element(
126 &mut local,
127 module,
128 *state_index,
129 key_types,
130 StructArrayElementAccess {
131 field_keys: field_keys.as_slice(),
132 element_type,
133 },
134 use_callt,
135 &mut token_patches,
136 ),
137 ir::Instruction::LoadRuntimeValue(value) => {
138 emit_load_runtime_value(&mut local, value, use_callt, &mut token_patches)
139 }
140 ir::Instruction::GetSize => local.push(0xCA),
141 ir::Instruction::CallBuiltin { builtin, arg_count } => {
142 emit_builtin_call(
143 &mut local,
144 builtin,
145 *arg_count,
146 use_callt,
147 &mut token_patches,
148 );
149 }
150 ir::Instruction::CallFunction { name, arg_count } => {
151 if *arg_count > 1 {
158 push_integer_bigint(&mut local, &BigInt::from(*arg_count));
159 local.push(0x55); }
161 local.push(0x35); let patch_pos = local.len();
166 local.extend_from_slice(&[0, 0, 0, 0]);
167 call_patches.push(CallPatch {
168 position: patch_pos,
169 target: name.clone(),
170 });
171 }
172 ir::Instruction::EmitEvent {
173 event_index,
174 arg_count,
175 } => emit_event(&mut local, module, *event_index, *arg_count),
176 ir::Instruction::EmitEventByName { name, arg_count } => {
177 emit_event_by_name(&mut local, name, *arg_count)
178 }
179 ir::Instruction::Convert { target } => emit_convert(&mut local, *target),
180 ir::Instruction::IsType { target } => emit_is_type(&mut local, *target),
181 ir::Instruction::NewBuffer => emit_new_buffer(&mut local),
182 ir::Instruction::NewArray { .. } => emit_new_array(&mut local),
183 ir::Instruction::ArrayGet => emit_array_get(&mut local),
184 ir::Instruction::ArraySet => emit_array_set(&mut local),
185 ir::Instruction::MemCpy => {
186 local.push(0x89); }
188 ir::Instruction::ReverseItems => {
189 local.push(0xD1); }
191 ir::Instruction::BitwiseNot => {
192 local.push(0x90); }
194 ir::Instruction::LogicalNot => {
195 local.push(0xAA); }
197 ir::Instruction::Try { catch_target } => {
198 local.push(0x3C); let position = local.len();
203 local.extend_from_slice(&[0, 0, 0, 0]); jump_patches.push((position, *catch_target));
205 local.extend_from_slice(&[0, 0, 0, 0]); }
207 ir::Instruction::EndTry { target } => {
208 local.push(0x3E); let position = local.len();
212 local.extend_from_slice(&[0, 0, 0, 0]);
213 jump_patches.push((position, *target));
214 }
215 ir::Instruction::Jump { target } => {
216 local.push(0x23); let position = local.len();
221 local.extend_from_slice(&[0, 0, 0, 0]);
222 jump_patches.push((position, *target));
223 }
224 ir::Instruction::JumpIf { target } => {
225 local.push(0x27); let position = local.len();
230 local.extend_from_slice(&[0, 0, 0, 0]);
231 jump_patches.push((position, *target));
232 }
233 ir::Instruction::Label(label) => {
234 label_offsets.insert(*label, local.len() as u32);
235 }
236 ir::Instruction::AbortMsg => {
237 local.push(0xE0); }
239 ir::Instruction::Abort => {
240 local.push(0x38); }
242 ir::Instruction::Throw => {
243 local.push(0x3A); }
245 ir::Instruction::Dup => {
246 local.push(0x4A); }
248 ir::Instruction::Swap => {
249 local.push(0x50); }
251 }
252 }
253 }
254
255 for (position, label) in jump_patches {
256 let target_offset = label_offsets
257 .get(&label)
258 .copied()
259 .unwrap_or(local.len() as u32) as i32;
260 let opcode_pos = (position - 1) as i32;
263 let relative = target_offset
264 .checked_sub(opcode_pos)
265 .unwrap_or(0);
266 local[position..position + 4].copy_from_slice(&relative.to_le_bytes());
267 }
268
269 (local, call_patches, token_patches)
270}
271
272fn append_default_value(bytecode: &mut Vec<u8>, value_type: &ValueType) {
273 match value_type {
274 ValueType::Integer { .. } => bytecode.push(0x10),
275 ValueType::Boolean => bytecode.push(0x10), ValueType::String => push_data(bytecode, &[]),
279 ValueType::Address => push_data(bytecode, &[0u8; 20]),
280 ValueType::ByteArray { fixed_len } => {
281 if let Some(len) = fixed_len {
282 let zeros = vec![0u8; *len as usize];
283 push_data(bytecode, &zeros);
284 } else {
285 push_data(bytecode, &[]);
286 }
287 }
288 ValueType::Array(_) => bytecode.push(0xC2), ValueType::Mapping { .. } => bytecode.push(0xC8), ValueType::Struct { .. } => bytecode.push(0xC5), ValueType::Any => bytecode.push(0x0B), }
293}