1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use super::Interpreter;
use crate::consts::*;
use crate::error::RuntimeError;
use fuel_asm::PanicReason;
use fuel_types::{Immediate18, RegisterId, Word};
const IS_CALLER_EXTERNAL: Immediate18 = 0x000001;
const GET_CALLER: Immediate18 = 0x000002;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InterpreterMetadata {
IsCallerExternal = IS_CALLER_EXTERNAL as isize,
GetCaller = GET_CALLER as isize,
}
impl TryFrom<Immediate18> for InterpreterMetadata {
type Error = PanicReason;
fn try_from(imm: Immediate18) -> Result<Self, Self::Error> {
match imm {
IS_CALLER_EXTERNAL => Ok(Self::IsCallerExternal),
GET_CALLER => Ok(Self::GetCaller),
_ => Err(PanicReason::InvalidMetadataIdentifier),
}
}
}
impl From<InterpreterMetadata> for Immediate18 {
fn from(m: InterpreterMetadata) -> Immediate18 {
match m {
InterpreterMetadata::IsCallerExternal => IS_CALLER_EXTERNAL,
InterpreterMetadata::GetCaller => GET_CALLER,
}
}
}
impl<S> Interpreter<S> {
pub(crate) fn metadata(&mut self, ra: RegisterId, imm: Immediate18) -> Result<(), RuntimeError> {
Self::is_register_writable(ra)?;
if self.is_external_context() {
return Err(PanicReason::ExpectedInternalContext.into());
}
let parent = self
.frames
.last()
.map(|f| f.registers()[REG_FP])
.expect("External context will always have a frame");
match imm {
IS_CALLER_EXTERNAL => {
self.registers[ra] = (parent != 0) as Word;
}
GET_CALLER => {
if parent == 0 {
return Err(PanicReason::ExpectedInternalContext.into());
}
self.registers[ra] = parent;
}
_ => return Err(PanicReason::InvalidMetadataIdentifier.into()),
}
self.inc_pc()
}
}