1use anyhow::Result;
10use javm_cap::cap::Cap;
11use javm_cap::cap::image::ImageCap;
12use javm_cap::cap::instance::InstanceCap;
13use javm_cap::{CacheDirectory, CapHashOrRef};
14use nub::{CapHash, InvocationResult, LocalKernel, ObjHash};
15use nub_arch_local::{ExitingEcallHandler, ProgramSpec, RoOverlay, run_program};
16use nub_exec::Regs;
17
18pub struct JavmLocal {
20 cache: CacheDirectory,
21 state_root: CapHash,
24}
25
26impl Default for JavmLocal {
27 fn default() -> Self {
28 Self {
29 cache: CacheDirectory::new(),
30 state_root: [0; 32],
31 }
32 }
33}
34
35impl JavmLocal {
36 pub fn put_cap(&mut self, cap: &Cap) -> Result<CapHash> {
39 self.cache
40 .put_cap(cap)
41 .map_err(|e| anyhow::anyhow!("put_cap (local): {e}"))
42 }
43
44 pub fn put_cap_with_hash(&mut self, hash: CapHash, cap: &Cap) -> Result<()> {
47 self.cache
48 .put_cap_with_hash(hash, cap)
49 .map_err(|e| anyhow::anyhow!("put_cap_with_hash (local): {e}"))
50 }
51
52 fn decode(bytes: &[u8]) -> Result<Cap> {
56 let mut aligned = rkyv::util::AlignedVec::<16>::with_capacity(bytes.len());
57 aligned.extend_from_slice(bytes);
58 let archived = rkyv::access::<rkyv::Archived<Cap>, rkyv::rancor::Error>(aligned.as_slice())
59 .map_err(|e| anyhow::anyhow!("rkyv access: {e}"))?;
60 rkyv::deserialize::<Cap, rkyv::rancor::Error>(archived)
61 .map_err(|e| anyhow::anyhow!("rkyv deserialize: {e}"))
62 }
63}
64
65impl LocalKernel for JavmLocal {
66 fn put_object(&mut self, bytes: &[u8]) -> Result<ObjHash> {
67 let cap = Self::decode(bytes).map_err(|e| anyhow::anyhow!("put_object: {e}"))?;
68 self.cache
69 .put_cap(&cap)
70 .map_err(|e| anyhow::anyhow!("put_object: {e}"))
71 }
72
73 fn put_object_with_hash(&mut self, hash: ObjHash, bytes: &[u8]) -> Result<()> {
74 let cap = Self::decode(bytes).map_err(|e| anyhow::anyhow!("put_object_with_hash: {e}"))?;
75 self.cache
76 .put_cap_with_hash(hash, &cap)
77 .map_err(|e| anyhow::anyhow!("put_object_with_hash: {e}"))
78 }
79
80 fn invoke(
81 &mut self,
82 root: ObjHash,
83 endpoint: u32,
84 args: [u64; 4],
85 initial_gas: u64,
86 ) -> Result<InvocationResult> {
87 let instance_cap = self
90 .cache
91 .get(CapHashOrRef::Hash(root))
92 .ok_or_else(|| anyhow::anyhow!("invoke_cached: instance not published"))?;
93 let inst = match &*instance_cap {
94 Cap::Instance(i) => i.clone(),
95 _ => {
96 return Err(anyhow::anyhow!(
97 "invoke_cached: cap at hash is not an Instance"
98 ));
99 }
100 };
101 let image_cap = self
102 .cache
103 .get(CapHashOrRef::Hash(inst.image_hash))
104 .ok_or_else(|| anyhow::anyhow!("invoke_cached: image not in cache"))?;
105 let img = match &*image_cap {
106 Cap::Image(i) => i.clone(),
107 _ => {
108 return Err(anyhow::anyhow!(
109 "invoke_cached: cap at image_hash is not an Image"
110 ));
111 }
112 };
113
114 Ok(run_instance(
118 &inst,
119 &img,
120 (endpoint & 0xFF) as u8,
121 args,
122 initial_gas,
123 ))
124 }
125
126 fn state_root(&self) -> ObjHash {
127 self.state_root
128 }
129}
130
131fn run_instance(
141 instance: &InstanceCap,
142 image: &ImageCap,
143 endpoint_idx: u8,
144 args: [u64; 4],
145 initial_gas: u64,
146) -> InvocationResult {
147 let data_base = javm_cap::layout::DATA_BASE;
148 let data_extent = instance.mem.content_len();
149 let mut mem_image = vec![0u8; data_extent as usize];
150 if data_extent > 0 {
151 instance.mem.copy_into(0, &mut mem_image);
154 }
155 let mut ro_overlays = Vec::new();
159 for m in image.mappings.iter() {
160 if m.path().is_empty() || !image.mapping_is_pinned(m.start as u32) {
161 continue;
162 }
163 let off = (m.start.saturating_sub(data_base as u64)) as usize;
164 let len = (m.size as usize).min(mem_image.len().saturating_sub(off));
165 if len > 0 {
166 ro_overlays.push(RoOverlay {
167 start: m.start as u32,
168 image_off: off,
169 len,
170 });
171 }
172 }
173
174 let target = javm_cap::Key::from(endpoint_idx);
177 let (_, endpoint) = image
178 .endpoints
179 .iter()
180 .find(|(k, _)| *k == target)
181 .expect("endpoint key not defined");
182
183 let mut regs = Regs::new();
184 regs.pc = endpoint.entry_pc;
185 regs.gpr[..javm_cap::NUM_REGS].copy_from_slice(&endpoint.initial_regs);
191 for (i, v) in instance.regs.iter().enumerate() {
192 if *v != 0 {
193 regs.gpr[i] = *v;
194 }
195 }
196 for (i, v) in args.iter().enumerate() {
197 regs.gpr[7 + i] = *v;
198 }
199
200 let (code_base, code_bytes) = image
203 .code_mapping()
204 .expect("image has no executable code mapping");
205
206 let spec = ProgramSpec {
207 code_base,
208 code: code_bytes,
209 data_base,
210 mem_image: &mem_image,
211 ro_overlays: &ro_overlays,
212 declared_mem_size: instance.mem_size(),
213 regs,
214 };
215 let mut handler = ExitingEcallHandler;
216 run_program(&spec, &mut handler, initial_gas)
217}