neo_solidity/ir/statements/
assembly.rs

1fn 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}