neo_solidity/ir/statements/
assembly.rs1fn lower_special_assembly(ctx: &mut LoweringContext, instructions: &mut Vec<Instruction>) -> bool {
2 match ctx.function_name.as_str() {
3 "extsload" | "exttload" => {
4 lower_extsload_single(ctx, instructions)
5 || lower_extsload_range(ctx, instructions)
6 || lower_extsload_slots(ctx, instructions)
7 }
8 _ => false,
9 }
10}
11
12fn lower_extsload_single(ctx: &mut LoweringContext, instructions: &mut Vec<Instruction>) -> bool {
13 let slot_index = match ctx.param_index_map.get("slot").copied() {
14 Some(index) if ctx.param_index_map.len() == 1 => index,
15 _ => return false,
16 };
17
18 instructions.push(Instruction::LoadParameter(slot_index));
19 instructions.push(Instruction::LoadStorageDynamic);
20 instructions.push(Instruction::Return);
21 true
22}
23
24fn lower_extsload_range(ctx: &mut LoweringContext, instructions: &mut Vec<Instruction>) -> bool {
25 let start_index = match ctx.param_index_map.get("startSlot").copied() {
26 Some(index) => index,
27 None => return false,
28 };
29 let count_index = match ctx.param_index_map.get("nSlots").copied() {
30 Some(index) => index,
31 None => return false,
32 };
33
34 if ctx.param_index_map.len() != 2 {
35 return false;
36 }
37
38 let start_local = ctx.allocate_local("__extsload_start".to_string(), None);
39 instructions.push(Instruction::LoadParameter(start_index));
40 instructions.push(Instruction::StoreLocal(start_local));
41
42 let count_local = ctx.allocate_local("__extsload_count".to_string(), None);
43 instructions.push(Instruction::LoadParameter(count_index));
44 instructions.push(Instruction::StoreLocal(count_local));
45
46 let array_element_type = ValueType::ByteArray {
47 fixed_len: Some(32),
48 };
49 let array_value_type = ValueType::Array(Box::new(array_element_type.clone()));
50 let array_local = ctx.allocate_local(
51 "__extsload_array".to_string(),
52 Some(array_value_type.clone()),
53 );
54 instructions.push(Instruction::LoadLocal(count_local));
55 instructions.push(Instruction::NewArray {
56 element_type: array_element_type,
57 });
58 instructions.push(Instruction::StoreLocal(array_local));
59
60 let index_local = ctx.allocate_local("__extsload_index".to_string(), None);
61 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
62 BigInt::zero(),
63 )));
64 instructions.push(Instruction::StoreLocal(index_local));
65
66 let value_local = ctx.allocate_local("__extsload_value".to_string(), None);
67
68 let loop_label = ctx.next_label();
69 let end_label = ctx.next_label();
70
71 instructions.push(Instruction::Label(loop_label));
72 instructions.push(Instruction::LoadLocal(index_local));
73 instructions.push(Instruction::LoadLocal(count_local));
74 instructions.push(Instruction::BinaryOp(BinaryOperator::Lt));
75 instructions.push(Instruction::JumpIf { target: end_label });
76
77 instructions.push(Instruction::LoadLocal(start_local));
78 instructions.push(Instruction::LoadStorageDynamic);
79 instructions.push(Instruction::StoreLocal(value_local));
80
81 instructions.push(Instruction::LoadLocal(array_local));
82 instructions.push(Instruction::LoadLocal(index_local));
83 instructions.push(Instruction::LoadLocal(value_local));
84 instructions.push(Instruction::ArraySet);
85
86 instructions.push(Instruction::LoadLocal(index_local));
87 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
88 BigInt::from(1u8),
89 )));
90 instructions.push(Instruction::BinaryOp(BinaryOperator::Add));
91 instructions.push(Instruction::StoreLocal(index_local));
92
93 instructions.push(Instruction::LoadLocal(start_local));
94 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
95 BigInt::from(1u8),
96 )));
97 instructions.push(Instruction::BinaryOp(BinaryOperator::Add));
98 instructions.push(Instruction::StoreLocal(start_local));
99
100 instructions.push(Instruction::Jump { target: loop_label });
101 instructions.push(Instruction::Label(end_label));
102 instructions.push(Instruction::LoadLocal(array_local));
103 instructions.push(Instruction::Return);
104 true
105}
106
107fn lower_extsload_slots(ctx: &mut LoweringContext, instructions: &mut Vec<Instruction>) -> bool {
108 let slots_index = match ctx.param_index_map.get("slots").copied() {
109 Some(index) if ctx.param_index_map.len() == 1 => index,
110 _ => return false,
111 };
112
113 let slots_local = ctx.allocate_local("__extsload_slots".to_string(), None);
114 instructions.push(Instruction::LoadParameter(slots_index));
115 instructions.push(Instruction::StoreLocal(slots_local));
116
117 let count_local = ctx.allocate_local("__extsload_count".to_string(), None);
118 instructions.push(Instruction::LoadLocal(slots_local));
119 instructions.push(Instruction::GetSize);
120 instructions.push(Instruction::StoreLocal(count_local));
121
122 let slots_array_element = ValueType::ByteArray {
123 fixed_len: Some(32),
124 };
125 let slots_array_type = ValueType::Array(Box::new(slots_array_element.clone()));
126 let array_local = ctx.allocate_local(
127 "__extsload_array".to_string(),
128 Some(slots_array_type.clone()),
129 );
130 instructions.push(Instruction::LoadLocal(count_local));
131 instructions.push(Instruction::NewArray {
132 element_type: slots_array_element,
133 });
134 instructions.push(Instruction::StoreLocal(array_local));
135
136 let index_local = ctx.allocate_local("__extsload_index".to_string(), None);
137 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
138 BigInt::zero(),
139 )));
140 instructions.push(Instruction::StoreLocal(index_local));
141
142 let value_local = ctx.allocate_local("__extsload_value".to_string(), None);
143
144 let loop_label = ctx.next_label();
145 let end_label = ctx.next_label();
146
147 instructions.push(Instruction::Label(loop_label));
148 instructions.push(Instruction::LoadLocal(index_local));
149 instructions.push(Instruction::LoadLocal(count_local));
150 instructions.push(Instruction::BinaryOp(BinaryOperator::Lt));
151 instructions.push(Instruction::JumpIf { target: end_label });
152
153 instructions.push(Instruction::LoadLocal(slots_local));
154 instructions.push(Instruction::LoadLocal(index_local));
155 instructions.push(Instruction::ArrayGet);
156 instructions.push(Instruction::LoadStorageDynamic);
157 instructions.push(Instruction::StoreLocal(value_local));
158
159 instructions.push(Instruction::LoadLocal(array_local));
160 instructions.push(Instruction::LoadLocal(index_local));
161 instructions.push(Instruction::LoadLocal(value_local));
162 instructions.push(Instruction::ArraySet);
163
164 instructions.push(Instruction::LoadLocal(index_local));
165 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
166 BigInt::from(1u8),
167 )));
168 instructions.push(Instruction::BinaryOp(BinaryOperator::Add));
169 instructions.push(Instruction::StoreLocal(index_local));
170
171 instructions.push(Instruction::Jump { target: loop_label });
172 instructions.push(Instruction::Label(end_label));
173 instructions.push(Instruction::LoadLocal(array_local));
174 instructions.push(Instruction::Return);
175 true
176}