1#![allow(non_camel_case_types)]
6
7#[cfg(feature = "serde_borsh")]
8use borsh::{
9 maybestd::io::Result as BorshResult, maybestd::io::Write as BorshWrite, BorshDeserialize,
10 BorshSerialize,
11};
12use std::fmt;
13use std::fmt::Debug;
14
15pub type OpIndex = i32;
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
18#[repr(u8)]
19pub enum Opcode {
20 VOID,
21
22 DUPLICATE,
23 LOAD_SLICE,
24 STORE_SLICE,
25 LOAD_ARRAY,
26 STORE_ARRAY,
27 LOAD_MAP,
28 STORE_MAP,
29 LOAD_STRUCT,
30 STORE_STRUCT,
31 LOAD_EMBEDDED,
32 STORE_EMBEDDED,
33 LOAD_PKG,
34 STORE_PKG,
35 LOAD_POINTER,
36 STORE_POINTER,
37 LOAD_UP_VALUE,
38 STORE_UP_VALUE,
39
40 ADD, SUB, MUL, QUO, REM, AND, OR, XOR, AND_NOT, SHL, SHR, ADD_ASSIGN, SUB_ASSIGN, MUL_ASSIGN, QUO_ASSIGN, REM_ASSIGN, AND_ASSIGN, OR_ASSIGN, XOR_ASSIGN, AND_NOT_ASSIGN, SHL_ASSIGN, SHR_ASSIGN, INC, DEC, UNARY_SUB, UNARY_XOR, NOT, EQL, NEQ, LSS, GTR, LEQ, GEQ, REF, REF_UPVALUE,
76 REF_SLICE_MEMBER,
77 REF_STRUCT_FIELD,
78 REF_EMBEDDED,
79 REF_PKG_MEMBER,
80 SEND, RECV, PACK_VARIADIC,
85 CALL,
86 RETURN,
87
88 JUMP,
90 JUMP_IF,
91 JUMP_IF_NOT,
92 SWITCH,
93 SELECT,
94 RANGE_INIT,
95 RANGE,
96
97 LOAD_INIT_FUNC,
99 BIND_METHOD,
100 BIND_I_METHOD,
101 CAST,
102 TYPE_ASSERT,
103 TYPE,
104
105 IMPORT, SLICE, CLOSURE, LITERAL, NEW, MAKE, COMPLEX, REAL, IMAG, LEN, CAP, APPEND, COPY, DELETE, CLOSE, PANIC, RECOVER, ASSERT, FFI, }
126
127impl fmt::Display for Opcode {
128 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129 fmt::Debug::fmt(&self, f)
130 }
131}
132
133#[cfg(feature = "serde_borsh")]
134impl BorshSerialize for Opcode {
135 #[inline]
136 fn serialize<W: BorshWrite>(&self, writer: &mut W) -> BorshResult<()> {
137 let val: u8 = unsafe { std::mem::transmute(*self) };
138 val.serialize(writer)
139 }
140}
141
142#[cfg(feature = "serde_borsh")]
143impl BorshDeserialize for Opcode {
144 #[inline]
145 fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> BorshResult<Self> {
146 let val = u8::deserialize_reader(reader)?;
147 Ok(unsafe { std::mem::transmute(val) })
148 }
149}
150
151#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Ord, PartialOrd)]
152#[repr(u8)]
153pub enum ValueType {
154 Void,
155 Bool,
156 Int,
157 Int8,
158 Int16,
159 Int32,
160 Int64,
161 Uint,
162 UintPtr,
163 Uint8,
164 Uint16,
165 Uint32,
166 Uint64,
167 Float32,
168 Float64,
169 Complex64,
170 Function,
171 Package, Metadata,
173 Complex128,
174 String,
175 Array,
176 Struct,
177 Pointer, UnsafePtr,
179 Closure,
180 Slice,
181 Map,
182 Interface,
183 Channel,
184
185 FlagA, FlagB,
187 FlagC,
188 FlagD,
189 FlagE,
190}
191
192impl ValueType {
193 #[inline]
194 pub fn copyable(&self) -> bool {
195 self <= &Self::Package
196 }
197
198 #[inline]
199 pub fn comparable(&self) -> bool {
200 self <= &Self::Pointer
201 }
202
203 #[inline]
204 pub fn nilable(&self) -> bool {
205 self >= &Self::Pointer && self <= &Self::Channel
206 }
207}
208
209#[cfg(feature = "serde_borsh")]
210impl BorshSerialize for ValueType {
211 #[inline]
212 fn serialize<W: BorshWrite>(&self, writer: &mut W) -> BorshResult<()> {
213 let val: u8 = unsafe { std::mem::transmute(*self) };
214 val.serialize(writer)
215 }
216}
217
218#[cfg(feature = "serde_borsh")]
219impl BorshDeserialize for ValueType {
220 #[inline]
221 fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> BorshResult<Self> {
222 let val = u8::deserialize_reader(reader)?;
223 Ok(unsafe { std::mem::transmute(val) })
224 }
225}
226
227impl fmt::Display for ValueType {
228 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
229 fmt::Debug::fmt(&self, f)
230 }
231}
232
233#[derive(Clone, Copy)]
234pub struct Instruction {
235 pub op0: Opcode,
236 pub op1: Opcode,
237 pub t0: ValueType,
238 pub t1: ValueType,
239 pub d: OpIndex,
240 pub s0: OpIndex,
241 pub s1: OpIndex,
242}
243
244impl Instruction {
245 pub fn op1_as_t(&self) -> ValueType {
246 unsafe { std::mem::transmute(self.op1) }
247 }
248
249 pub fn max_write_index(instructions: &[Instruction]) -> OpIndex {
251 let mut i = 0;
252 let mut result = 0;
253 loop {
254 let cur = &instructions[i];
255 let index = match cur.op0 {
256 Opcode::VOID => 0,
257 Opcode::DUPLICATE => cur.d,
258 Opcode::LOAD_SLICE => cur.d,
259 Opcode::STORE_SLICE => 0,
260 Opcode::LOAD_ARRAY => cur.d,
261 Opcode::STORE_ARRAY => 0,
262 Opcode::LOAD_MAP => {
263 i += 1;
264 match cur.t1 {
265 ValueType::FlagB => instructions[i].d,
266 _ => cur.d,
267 }
268 }
269 Opcode::STORE_MAP => {
270 i += 1;
271 0
272 }
273 Opcode::LOAD_STRUCT => cur.d,
274 Opcode::STORE_STRUCT => 0,
275 Opcode::LOAD_EMBEDDED => cur.d,
276 Opcode::STORE_EMBEDDED => 0,
277 Opcode::LOAD_PKG => cur.d,
278 Opcode::STORE_PKG => 0,
279 Opcode::LOAD_POINTER => cur.d,
280 Opcode::STORE_POINTER => 0,
281 Opcode::LOAD_UP_VALUE => cur.d,
282 Opcode::STORE_UP_VALUE => 0,
283 Opcode::ADD => cur.d,
284 Opcode::SUB => cur.d,
285 Opcode::MUL => cur.d,
286 Opcode::QUO => cur.d,
287 Opcode::REM => cur.d,
288 Opcode::AND => cur.d,
289 Opcode::OR => cur.d,
290 Opcode::XOR => cur.d,
291 Opcode::AND_NOT => cur.d,
292 Opcode::SHL => cur.d,
293 Opcode::SHR => cur.d,
294 Opcode::ADD_ASSIGN => 0,
295 Opcode::SUB_ASSIGN => 0,
296 Opcode::MUL_ASSIGN => 0,
297 Opcode::QUO_ASSIGN => 0,
298 Opcode::REM_ASSIGN => 0,
299 Opcode::AND_ASSIGN => 0,
300 Opcode::OR_ASSIGN => 0,
301 Opcode::XOR_ASSIGN => 0,
302 Opcode::AND_NOT_ASSIGN => 0,
303 Opcode::SHL_ASSIGN => 0,
304 Opcode::SHR_ASSIGN => 0,
305 Opcode::INC => 0,
306 Opcode::DEC => 0,
307 Opcode::UNARY_SUB => cur.d,
308 Opcode::UNARY_XOR => cur.d,
309 Opcode::NOT => cur.d,
310 Opcode::EQL => cur.d,
311 Opcode::NEQ => cur.d,
312 Opcode::LSS => cur.d,
313 Opcode::GTR => cur.d,
314 Opcode::LEQ => cur.d,
315 Opcode::GEQ => cur.d,
316 Opcode::REF => cur.d,
317 Opcode::REF_UPVALUE => cur.d,
318 Opcode::REF_SLICE_MEMBER => cur.d,
319 Opcode::REF_STRUCT_FIELD => cur.d,
320 Opcode::REF_EMBEDDED => cur.d,
321 Opcode::REF_PKG_MEMBER => cur.d,
322 Opcode::SEND => 0,
323 Opcode::RECV => match cur.t1 {
324 ValueType::FlagB => std::cmp::max(cur.d, cur.s1),
325 _ => cur.d,
326 },
327 Opcode::PACK_VARIADIC => cur.d,
328 Opcode::CALL => 0,
329 Opcode::RETURN => 0,
330 Opcode::JUMP => 0,
331 Opcode::JUMP_IF => 0,
332 Opcode::JUMP_IF_NOT => 0,
333 Opcode::SWITCH => 0,
334 Opcode::SELECT => {
335 let begin = i + 1;
336 i += cur.s0 as usize;
337 instructions[begin..i].iter().fold(0, |acc, x| {
338 let val = match x.t0 {
339 ValueType::FlagC => x.s1,
340 ValueType::FlagD => x.s1 + 1,
341 _ => 0,
342 };
343 std::cmp::max(acc, val)
344 })
345 }
346 Opcode::RANGE_INIT => 0,
347 Opcode::RANGE => 0,
348 Opcode::LOAD_INIT_FUNC => {
349 i += 2;
350 std::cmp::max(cur.d, cur.s1)
351 }
352 Opcode::BIND_METHOD => cur.d,
353 Opcode::BIND_I_METHOD => cur.d,
354 Opcode::CAST => cur.d,
355 Opcode::TYPE_ASSERT => match cur.t1 {
356 ValueType::FlagB => {
357 i += 1;
358 instructions[i].d
359 }
360 _ => cur.d,
361 },
362 Opcode::TYPE => match cur.t0 {
363 ValueType::FlagA => std::cmp::max(cur.d, cur.s1),
364 _ => cur.d,
365 },
366 Opcode::IMPORT => 0,
367 Opcode::SLICE => {
368 i += 1;
369 cur.d
370 }
371 Opcode::CLOSURE => cur.d,
372 Opcode::LITERAL => {
373 i += 1 + cur.s1 as usize;
374 cur.d
375 }
376 Opcode::NEW => cur.d,
377 Opcode::MAKE => {
378 if cur.t0 == ValueType::FlagC {
379 i += 1;
380 }
381 cur.d
382 }
383 Opcode::COMPLEX => cur.d,
384 Opcode::REAL => cur.d,
385 Opcode::IMAG => cur.d,
386 Opcode::LEN => cur.d,
387 Opcode::CAP => cur.d,
388 Opcode::APPEND => cur.d,
389 Opcode::COPY => cur.d,
390 Opcode::DELETE => 0,
391 Opcode::CLOSE => 0,
392 Opcode::PANIC => 0,
393 Opcode::RECOVER => cur.d,
394 Opcode::ASSERT => 0,
395 Opcode::FFI => cur.d,
396 };
397 result = std::cmp::max(result, index);
398 i += 1;
399 if i >= instructions.len() {
400 break;
401 }
402 }
403 result
404 }
405}
406
407#[cfg(feature = "serde_borsh")]
408impl BorshSerialize for Instruction {
409 fn serialize<W: BorshWrite>(&self, writer: &mut W) -> BorshResult<()> {
410 self.op0.serialize(writer)?;
411 self.op1.serialize(writer)?;
412 self.t0.serialize(writer)?;
413 self.t1.serialize(writer)?;
414 self.d.serialize(writer)?;
415 self.s0.serialize(writer)?;
416 self.s1.serialize(writer)
417 }
418}
419
420#[cfg(feature = "serde_borsh")]
421impl BorshDeserialize for Instruction {
422 fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> BorshResult<Self> {
423 const BYTE_COUNT: usize = 4;
425 const OP_INDEX_SIZE: usize = core::mem::size_of::<OpIndex>();
426 let data = <[u8; BYTE_COUNT + OP_INDEX_SIZE * 3]>::deserialize_reader(reader)?;
427 let op0 = unsafe { std::mem::transmute(data[0]) };
428 let op1 = unsafe { std::mem::transmute(data[1]) };
429 let t0 = unsafe { std::mem::transmute(data[2]) };
430 let t1 = unsafe { std::mem::transmute(data[3]) };
431 let mut begin = BYTE_COUNT;
432 let d = OpIndex::from_le_bytes(data[begin..begin + OP_INDEX_SIZE].try_into().unwrap());
433 begin += OP_INDEX_SIZE;
434 let s0 = OpIndex::from_le_bytes(data[begin..begin + OP_INDEX_SIZE].try_into().unwrap());
435 begin += OP_INDEX_SIZE;
436 let s1 = OpIndex::from_le_bytes(data[begin..begin + OP_INDEX_SIZE].try_into().unwrap());
437 Ok(Instruction {
438 op0,
439 op1,
440 t0,
441 t1,
442 d,
443 s0,
444 s1,
445 })
446 }
447}
448
449impl std::fmt::Debug for Instruction {
450 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
451 let ops = if self.op1 == Opcode::VOID {
452 self.op0.to_string()
453 } else {
454 format!("{}.{}", self.op0, self.op1)
455 };
456 write!(f, "{: <16}|", ops)?;
457 fmt_index(self.d, f)?;
458 f.write_str("\t|")?;
459 fmt_index(self.s0, f)?;
460 f.write_str("\t|")?;
461 fmt_index(self.s1, f)?;
462 f.write_str("\t|")?;
463 fmt_type(self.t0, f)?;
464 f.write_str("\t|")?;
465 fmt_type(self.t1, f)?;
466 Ok(())
467 }
468}
469
470fn fmt_type(t: ValueType, f: &mut std::fmt::Formatter) -> std::fmt::Result {
471 if t == ValueType::Void {
472 f.write_str("...")
473 } else {
474 t.fmt(f)
475 }
476}
477
478fn fmt_index(index: OpIndex, f: &mut std::fmt::Formatter) -> std::fmt::Result {
479 if index == OpIndex::MAX {
480 f.write_str("...")
481 } else {
482 index.fmt(f)
483 }
484}
485
486#[cfg(test)]
487mod test {
488 use super::*;
489
490 #[test]
491 fn test_inst_size() {
492 println!("size {} \n", std::mem::size_of::<Instruction>());
493 }
494}