1use crate::{
9 data_store::{
10 PackageStore, cached_package_store::CachedPackageStore, linked_data_store::LinkedDataStore,
11 },
12 execution_value::ExecutionState,
13 programmable_transactions::execution::subst_signature,
14 static_programmable_transactions::{
15 linkage::{
16 analysis::LinkageAnalyzer,
17 resolved_linkage::{ResolvedLinkage, RootedLinkage},
18 },
19 loading::ast::{
20 self as L, Datatype, LoadedFunction, LoadedFunctionInstantiation, Type, Vector,
21 },
22 },
23};
24use move_binary_format::{
25 CompiledModule,
26 errors::{Location, PartialVMError, VMError},
27 file_format::{Ability, AbilitySet, TypeParameterIndex},
28};
29use move_core_types::{
30 annotated_value,
31 language_storage::{ModuleId, StructTag},
32 runtime_value::{self, MoveTypeLayout},
33 vm_status::StatusCode,
34};
35use move_vm_runtime::move_vm::MoveVM;
36use move_vm_types::{data_store::DataStore, loaded_data::runtime_types as vm_runtime_type};
37use std::{cell::OnceCell, rc::Rc, sync::Arc};
38use sui_protocol_config::ProtocolConfig;
39use sui_types::{
40 Identifier, TypeTag,
41 balance::RESOLVED_BALANCE_STRUCT,
42 base_types::{ObjectID, TxContext},
43 error::{ExecutionError, ExecutionErrorKind},
44 execution_status::TypeArgumentError,
45 funds_accumulator::RESOLVED_WITHDRAWAL_STRUCT,
46 gas_coin::GasCoin,
47 move_package::{UpgradeCap, UpgradeReceipt, UpgradeTicket},
48 object::Object,
49 type_input::{StructInput, TypeInput},
50};
51
52pub struct Env<'pc, 'vm, 'state, 'linkage> {
53 pub protocol_config: &'pc ProtocolConfig,
54 pub vm: &'vm MoveVM,
55 pub state_view: &'state mut dyn ExecutionState,
56 pub linkable_store: &'linkage CachedPackageStore<'state>,
57 pub linkage_analysis: &'linkage LinkageAnalyzer,
58 gas_coin_type: OnceCell<Type>,
59 upgrade_ticket_type: OnceCell<Type>,
60 upgrade_receipt_type: OnceCell<Type>,
61 upgrade_cap_type: OnceCell<Type>,
62 tx_context_type: OnceCell<Type>,
63}
64
65macro_rules! get_or_init_ty {
66 ($env:expr, $ident:ident, $tag:expr) => {{
67 let env = $env;
68 if env.$ident.get().is_none() {
69 let tag = $tag;
70 let ty = env.load_type_from_struct(&tag)?;
71 env.$ident.set(ty.clone()).unwrap();
72 }
73 Ok(env.$ident.get().unwrap().clone())
74 }};
75}
76
77impl<'pc, 'vm, 'state, 'linkage> Env<'pc, 'vm, 'state, 'linkage> {
78 pub fn new(
79 protocol_config: &'pc ProtocolConfig,
80 vm: &'vm MoveVM,
81 state_view: &'state mut dyn ExecutionState,
82 linkable_store: &'linkage CachedPackageStore<'state>,
83 linkage_analysis: &'linkage LinkageAnalyzer,
84 ) -> Self {
85 Self {
86 protocol_config,
87 vm,
88 state_view,
89 linkable_store,
90 linkage_analysis,
91 gas_coin_type: OnceCell::new(),
92 upgrade_ticket_type: OnceCell::new(),
93 upgrade_receipt_type: OnceCell::new(),
94 upgrade_cap_type: OnceCell::new(),
95 tx_context_type: OnceCell::new(),
96 }
97 }
98
99 pub fn convert_linked_vm_error(&self, e: VMError, linkage: &RootedLinkage) -> ExecutionError {
100 convert_vm_error(e, self.vm, self.linkable_store, Some(linkage))
101 }
102
103 pub fn convert_vm_error(&self, e: VMError) -> ExecutionError {
104 convert_vm_error(e, self.vm, self.linkable_store, None)
105 }
106
107 pub fn convert_type_argument_error(
108 &self,
109 idx: usize,
110 e: VMError,
111 linkage: &RootedLinkage,
112 ) -> ExecutionError {
113 use move_core_types::vm_status::StatusCode;
114 match e.major_status() {
115 StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH => {
116 ExecutionErrorKind::TypeArityMismatch.into()
117 }
118 StatusCode::TYPE_RESOLUTION_FAILURE => ExecutionErrorKind::TypeArgumentError {
119 argument_idx: idx as TypeParameterIndex,
120 kind: TypeArgumentError::TypeNotFound,
121 }
122 .into(),
123 StatusCode::CONSTRAINT_NOT_SATISFIED => ExecutionErrorKind::TypeArgumentError {
124 argument_idx: idx as TypeParameterIndex,
125 kind: TypeArgumentError::ConstraintNotSatisfied,
126 }
127 .into(),
128 _ => self.convert_linked_vm_error(e, linkage),
129 }
130 }
131
132 pub fn module_definition(
133 &self,
134 module_id: &ModuleId,
135 linkage: &RootedLinkage,
136 ) -> Result<Arc<CompiledModule>, ExecutionError> {
137 let linked_data_store = LinkedDataStore::new(linkage, self.linkable_store);
138 self.vm
139 .get_runtime()
140 .load_module(module_id, &linked_data_store)
141 .map_err(|e| self.convert_linked_vm_error(e, linkage))
142 }
143
144 pub fn fully_annotated_layout(
145 &self,
146 ty: &Type,
147 ) -> Result<annotated_value::MoveTypeLayout, ExecutionError> {
148 let ty = self.load_vm_type_from_adapter_type(None, ty)?;
149 self.vm
150 .get_runtime()
151 .type_to_fully_annotated_layout(&ty)
152 .map_err(|e| self.convert_vm_error(e))
153 }
154
155 pub fn runtime_layout(
156 &self,
157 ty: &Type,
158 ) -> Result<runtime_value::MoveTypeLayout, ExecutionError> {
159 let ty = self.load_vm_type_from_adapter_type(None, ty)?;
160 self.vm
161 .get_runtime()
162 .type_to_type_layout(&ty)
163 .map_err(|e| self.convert_vm_error(e))
164 }
165
166 pub fn load_function(
167 &self,
168 package: ObjectID,
169 module: String,
170 function: String,
171 type_arguments: Vec<Type>,
172 linkage: RootedLinkage,
173 ) -> Result<LoadedFunction, ExecutionError> {
174 let Some(original_id) = linkage.resolved_linkage.resolve_to_original_id(&package) else {
175 invariant_violation!(
176 "Package ID {:?} is not found in linkage generated for that package",
177 package
178 );
179 };
180 let module = to_identifier(module)?;
181 let name = to_identifier(function)?;
182 let storage_id = ModuleId::new(package.into(), module.clone());
183 let runtime_id = ModuleId::new(original_id.into(), module);
184 let mut data_store = LinkedDataStore::new(&linkage, self.linkable_store);
185 let loaded_type_arguments = type_arguments
186 .iter()
187 .enumerate()
188 .map(|(idx, ty)| self.load_vm_type_argument_from_adapter_type(idx, ty))
189 .collect::<Result<Vec<_>, _>>()?;
190 let runtime_signature = self
191 .vm
192 .get_runtime()
193 .load_function(
194 &runtime_id,
195 name.as_ident_str(),
196 &loaded_type_arguments,
197 &mut data_store,
198 )
199 .map_err(|e| {
200 if e.major_status() == StatusCode::FUNCTION_RESOLUTION_FAILURE {
201 ExecutionError::new_with_source(
202 ExecutionErrorKind::FunctionNotFound,
203 format!(
204 "Could not resolve function '{}' in module {}",
205 name, &storage_id,
206 ),
207 )
208 } else {
209 self.convert_linked_vm_error(e, &linkage)
210 }
211 })?;
212 let runtime_signature = subst_signature(runtime_signature, &loaded_type_arguments)
213 .map_err(|e| self.convert_linked_vm_error(e, &linkage))?;
214 let parameters = runtime_signature
215 .parameters
216 .into_iter()
217 .map(|ty| self.adapter_type_from_vm_type(&ty))
218 .collect::<Result<Vec<_>, _>>()?;
219 let return_ = runtime_signature
220 .return_
221 .into_iter()
222 .map(|ty| self.adapter_type_from_vm_type(&ty))
223 .collect::<Result<Vec<_>, _>>()?;
224 let signature = LoadedFunctionInstantiation {
225 parameters,
226 return_,
227 };
228 Ok(LoadedFunction {
229 storage_id,
230 runtime_id,
231 name,
232 type_arguments,
233 signature,
234 linkage,
235 instruction_length: runtime_signature.instruction_length,
236 definition_index: runtime_signature.definition_index,
237 })
238 }
239
240 pub fn load_type_input(&self, idx: usize, ty: TypeInput) -> Result<Type, ExecutionError> {
241 let runtime_type = self.load_vm_type_from_type_input(idx, ty)?;
242 self.adapter_type_from_vm_type(&runtime_type)
243 }
244
245 pub fn load_type_from_struct(&self, tag: &StructTag) -> Result<Type, ExecutionError> {
247 let vm_type =
248 self.load_vm_type_from_type_tag(None, &TypeTag::Struct(Box::new(tag.clone())))?;
249 self.adapter_type_from_vm_type(&vm_type)
250 }
251
252 pub fn load_type_and_layout_from_struct(
256 &self,
257 tag: &StructTag,
258 ) -> Result<(Type, MoveTypeLayout), ExecutionError> {
259 let vm_type =
260 self.load_vm_type_from_type_tag(None, &TypeTag::Struct(Box::new(tag.clone())))?;
261 let type_layout = self
262 .vm
263 .get_runtime()
264 .type_to_type_layout(&vm_type)
265 .map_err(|e| self.convert_vm_error(e))?;
266 self.adapter_type_from_vm_type(&vm_type)
267 .map(|ty| (ty, type_layout))
268 }
269
270 pub fn type_layout_for_struct(
271 &self,
272 tag: &StructTag,
273 ) -> Result<MoveTypeLayout, ExecutionError> {
274 let ty: Type = self.load_type_from_struct(tag)?;
275 self.runtime_layout(&ty)
276 }
277
278 pub fn gas_coin_type(&self) -> Result<Type, ExecutionError> {
279 get_or_init_ty!(self, gas_coin_type, GasCoin::type_())
280 }
281
282 pub fn upgrade_ticket_type(&self) -> Result<Type, ExecutionError> {
283 get_or_init_ty!(self, upgrade_ticket_type, UpgradeTicket::type_())
284 }
285
286 pub fn upgrade_receipt_type(&self) -> Result<Type, ExecutionError> {
287 get_or_init_ty!(self, upgrade_receipt_type, UpgradeReceipt::type_())
288 }
289
290 pub fn upgrade_cap_type(&self) -> Result<Type, ExecutionError> {
291 get_or_init_ty!(self, upgrade_cap_type, UpgradeCap::type_())
292 }
293
294 pub fn tx_context_type(&self) -> Result<Type, ExecutionError> {
295 get_or_init_ty!(self, tx_context_type, TxContext::type_())
296 }
297
298 pub fn balance_type(&self, inner_type: Type) -> Result<Type, ExecutionError> {
299 let Some(abilities) = AbilitySet::from_u8(Ability::Store as u8) else {
300 invariant_violation!("Unable to create balance abilities");
301 };
302 let (a, m, n) = RESOLVED_BALANCE_STRUCT;
303 let module = ModuleId::new(*a, m.to_owned());
304 Ok(Type::Datatype(Rc::new(Datatype {
305 abilities,
306 module,
307 name: n.to_owned(),
308 type_arguments: vec![inner_type],
309 })))
310 }
311
312 pub fn withdrawal_type(&self, inner_type: Type) -> Result<Type, ExecutionError> {
313 let Some(abilities) = AbilitySet::from_u8(Ability::Drop as u8) else {
314 invariant_violation!("Unable to create withdrawal abilities");
315 };
316 let (a, m, n) = RESOLVED_WITHDRAWAL_STRUCT;
317 let module = ModuleId::new(*a, m.to_owned());
318 Ok(Type::Datatype(Rc::new(Datatype {
319 abilities,
320 module,
321 name: n.to_owned(),
322 type_arguments: vec![inner_type],
323 })))
324 }
325
326 pub fn vector_type(&self, element_type: Type) -> Result<Type, ExecutionError> {
327 let abilities = AbilitySet::polymorphic_abilities(
328 AbilitySet::VECTOR,
329 [false],
330 [element_type.abilities()],
331 )
332 .map_err(|e| {
333 ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, e.to_string())
334 })?;
335 Ok(Type::Vector(Rc::new(L::Vector {
336 abilities,
337 element_type,
338 })))
339 }
340
341 pub fn read_object(&self, id: &ObjectID) -> Result<&Object, ExecutionError> {
342 let Some(obj) = self.state_view.read_object(id) else {
343 invariant_violation!("Object {:?} does not exist", id);
345 };
346 Ok(obj)
347 }
348
349 pub fn load_vm_type_argument_from_adapter_type(
351 &self,
352 idx: usize,
353 ty: &Type,
354 ) -> Result<vm_runtime_type::Type, ExecutionError> {
355 self.load_vm_type_from_adapter_type(Some(idx), ty)
356 }
357
358 fn load_vm_type_from_adapter_type(
359 &self,
360 type_arg_idx: Option<usize>,
361 ty: &Type,
362 ) -> Result<vm_runtime_type::Type, ExecutionError> {
363 let tag: TypeTag = ty.clone().try_into().map_err(|s| {
364 ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, s)
365 })?;
366 self.load_vm_type_from_type_tag(type_arg_idx, &tag)
367 }
368
369 fn load_vm_type_from_type_tag(
371 &self,
372 type_arg_idx: Option<usize>,
373 tag: &TypeTag,
374 ) -> Result<vm_runtime_type::Type, ExecutionError> {
375 use vm_runtime_type as VMR;
376
377 fn load_type_tag(
378 env: &Env,
379 type_arg_idx: Option<usize>,
380 tag: &TypeTag,
381 ) -> Result<VMR::Type, ExecutionError> {
382 Ok(match tag {
383 TypeTag::Bool => VMR::Type::Bool,
384 TypeTag::U8 => VMR::Type::U8,
385 TypeTag::U16 => VMR::Type::U16,
386 TypeTag::U32 => VMR::Type::U32,
387 TypeTag::U64 => VMR::Type::U64,
388 TypeTag::U128 => VMR::Type::U128,
389 TypeTag::U256 => VMR::Type::U256,
390 TypeTag::Address => VMR::Type::Address,
391 TypeTag::Signer => VMR::Type::Signer,
392
393 TypeTag::Vector(inner) => {
394 VMR::Type::Vector(Box::new(load_type_tag(env, type_arg_idx, inner)?))
395 }
396 TypeTag::Struct(tag) => load_struct_tag(env, type_arg_idx, tag)?,
397 })
398 }
399
400 fn load_struct_tag(
401 env: &Env,
402 type_arg_idx: Option<usize>,
403 struct_tag: &StructTag,
404 ) -> Result<vm_runtime_type::Type, ExecutionError> {
405 fn execution_error(
406 env: &Env,
407 type_arg_idx: Option<usize>,
408 e: VMError,
409 linkage: &RootedLinkage,
410 ) -> ExecutionError {
411 if let Some(idx) = type_arg_idx {
412 env.convert_type_argument_error(idx, e, linkage)
413 } else {
414 env.convert_linked_vm_error(e, linkage)
415 }
416 }
417
418 fn verification_error(code: StatusCode) -> VMError {
419 PartialVMError::new(code).finish(Location::Undefined)
420 }
421
422 let StructTag {
423 address,
424 module,
425 name,
426 type_params,
427 } = struct_tag;
428
429 let tag_linkage =
430 ResolvedLinkage::type_linkage(&[(*address).into()], env.linkable_store)?;
431 let linkage = RootedLinkage::new(*address, tag_linkage);
432 let linked_store = LinkedDataStore::new(&linkage, env.linkable_store);
433
434 let original_id = linkage
435 .resolved_linkage
436 .resolve_to_original_id(&(*address).into())
437 .ok_or_else(|| {
438 make_invariant_violation!(
439 "StructTag {:?} is not found in linkage generated for that struct tag -- this shouldn't happen.",
440 struct_tag
441 )
442 })?;
443 let runtime_id = ModuleId::new(*original_id, module.clone());
444
445 let (idx, struct_type) = env
446 .vm
447 .get_runtime()
448 .load_type(&runtime_id, name, &linked_store)
449 .map_err(|e| execution_error(env, type_arg_idx, e, &linkage))?;
450
451 let type_param_constraints = struct_type.type_param_constraints();
452 if type_param_constraints.len() != type_params.len() {
453 return Err(execution_error(
454 env,
455 type_arg_idx,
456 verification_error(StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH),
457 &linkage,
458 ));
459 }
460
461 if type_params.is_empty() {
462 Ok(VMR::Type::Datatype(idx))
463 } else {
464 let loaded_type_params = type_params
465 .iter()
466 .map(|type_param| load_type_tag(env, type_arg_idx, type_param))
467 .collect::<Result<Vec<_>, _>>()?;
468
469 for (constraint, param) in type_param_constraints.zip(&loaded_type_params) {
471 let abilities = env
472 .vm
473 .get_runtime()
474 .get_type_abilities(param)
475 .map_err(|e| execution_error(env, type_arg_idx, e, &linkage))?;
476 if !constraint.is_subset(abilities) {
477 return Err(execution_error(
478 env,
479 type_arg_idx,
480 verification_error(StatusCode::CONSTRAINT_NOT_SATISFIED),
481 &linkage,
482 ));
483 }
484 }
485
486 Ok(VMR::Type::DatatypeInstantiation(Box::new((
487 idx,
488 loaded_type_params,
489 ))))
490 }
491 }
492
493 load_type_tag(self, type_arg_idx, tag)
494 }
495
496 fn adapter_type_from_vm_type(
498 &self,
499 vm_type: &vm_runtime_type::Type,
500 ) -> Result<Type, ExecutionError> {
501 use vm_runtime_type as VRT;
502
503 Ok(match vm_type {
504 VRT::Type::Bool => Type::Bool,
505 VRT::Type::U8 => Type::U8,
506 VRT::Type::U16 => Type::U16,
507 VRT::Type::U32 => Type::U32,
508 VRT::Type::U64 => Type::U64,
509 VRT::Type::U128 => Type::U128,
510 VRT::Type::U256 => Type::U256,
511 VRT::Type::Address => Type::Address,
512 VRT::Type::Signer => Type::Signer,
513
514 VRT::Type::Reference(ref_ty) => {
515 let inner_ty = self.adapter_type_from_vm_type(ref_ty)?;
516 Type::Reference(false, Rc::new(inner_ty))
517 }
518 VRT::Type::MutableReference(ref_ty) => {
519 let inner_ty = self.adapter_type_from_vm_type(ref_ty)?;
520 Type::Reference(true, Rc::new(inner_ty))
521 }
522
523 VRT::Type::Vector(inner) => {
524 let element_type = self.adapter_type_from_vm_type(inner)?;
525 let abilities = self
526 .vm
527 .get_runtime()
528 .get_type_abilities(vm_type)
529 .map_err(|e| self.convert_vm_error(e))?;
530 let vector_ty = Vector {
531 abilities,
532 element_type,
533 };
534 Type::Vector(Rc::new(vector_ty))
535 }
536 VRT::Type::Datatype(cached_type_index) => {
537 let runtime = self.vm.get_runtime();
538 let Some(cached_info) = runtime.get_type(*cached_type_index) else {
539 invariant_violation!(
540 "Unable to find cached type info for {:?}. This should not happen as we have \
541 a loaded VM type in-hand.",
542 vm_type
543 )
544 };
545 let datatype = Datatype {
546 abilities: cached_info.abilities,
547 module: cached_info.defining_id.clone(),
548 name: cached_info.name.clone(),
549 type_arguments: vec![],
550 };
551 Type::Datatype(Rc::new(datatype))
552 }
553 ty @ VRT::Type::DatatypeInstantiation(inst) => {
554 let (cached_type_index, type_arguments) = &**inst;
555 let runtime = self.vm.get_runtime();
556 let Some(cached_info) = runtime.get_type(*cached_type_index) else {
557 invariant_violation!(
558 "Unable to find cached type info for {:?}. This should not happen as we have \
559 a loaded VM type in-hand.",
560 vm_type
561 )
562 };
563
564 let abilities = runtime
565 .get_type_abilities(ty)
566 .map_err(|e| self.convert_vm_error(e))?;
567 let module = cached_info.defining_id.clone();
568 let name = cached_info.name.clone();
569 let type_arguments = type_arguments
570 .iter()
571 .map(|t| self.adapter_type_from_vm_type(t))
572 .collect::<Result<Vec<_>, _>>()?;
573
574 Type::Datatype(Rc::new(Datatype {
575 abilities,
576 module,
577 name,
578 type_arguments,
579 }))
580 }
581
582 VRT::Type::TyParam(_) => {
583 invariant_violation!(
584 "Unexpected type parameter in VM type: {:?}. This should not happen as we should \
585 have resolved all type parameters before this point.",
586 vm_type
587 );
588 }
589 })
590 }
591
592 fn load_vm_type_from_type_input(
596 &self,
597 type_arg_idx: usize,
598 ty: TypeInput,
599 ) -> Result<vm_runtime_type::Type, ExecutionError> {
600 fn to_type_tag_internal(
601 env: &Env,
602 type_arg_idx: usize,
603 ty: TypeInput,
604 ) -> Result<TypeTag, ExecutionError> {
605 Ok(match ty {
606 TypeInput::Bool => TypeTag::Bool,
607 TypeInput::U8 => TypeTag::U8,
608 TypeInput::U16 => TypeTag::U16,
609 TypeInput::U32 => TypeTag::U32,
610 TypeInput::U64 => TypeTag::U64,
611 TypeInput::U128 => TypeTag::U128,
612 TypeInput::U256 => TypeTag::U256,
613 TypeInput::Address => TypeTag::Address,
614 TypeInput::Signer => TypeTag::Signer,
615 TypeInput::Vector(type_input) => {
616 let inner = to_type_tag_internal(env, type_arg_idx, *type_input)?;
617 TypeTag::Vector(Box::new(inner))
618 }
619 TypeInput::Struct(struct_input) => {
620 let StructInput {
621 address,
622 module,
623 name,
624 type_params,
625 } = *struct_input;
626
627 let pkg = env
628 .linkable_store
629 .get_package(&address.into())
630 .ok()
631 .flatten()
632 .ok_or_else(|| {
633 ExecutionError::from_kind(ExecutionErrorKind::TypeArgumentError {
634 argument_idx: type_arg_idx as u16,
635 kind: TypeArgumentError::TypeNotFound,
636 })
637 })?;
638 let Some(resolved_address) = pkg
639 .type_origin_map()
640 .get(&(module.clone(), name.clone()))
641 .cloned()
642 else {
643 return Err(ExecutionError::from_kind(
644 ExecutionErrorKind::TypeArgumentError {
645 argument_idx: type_arg_idx as u16,
646 kind: TypeArgumentError::TypeNotFound,
647 },
648 ));
649 };
650
651 let module = to_identifier(module)?;
652 let name = to_identifier(name)?;
653 let tys = type_params
654 .into_iter()
655 .map(|tp| to_type_tag_internal(env, type_arg_idx, tp))
656 .collect::<Result<Vec<_>, _>>()?;
657 TypeTag::Struct(Box::new(StructTag {
658 address: *resolved_address,
659 module,
660 name,
661 type_params: tys,
662 }))
663 }
664 })
665 }
666 let tag = to_type_tag_internal(self, type_arg_idx, ty)?;
667 self.load_vm_type_from_type_tag(Some(type_arg_idx), &tag)
668 }
669}
670
671fn to_identifier(name: String) -> Result<Identifier, ExecutionError> {
672 Identifier::new(name).map_err(|e| {
673 ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, e.to_string())
674 })
675}
676
677fn convert_vm_error(
678 error: VMError,
679 vm: &MoveVM,
680 store: &dyn PackageStore,
681 linkage: Option<&RootedLinkage>,
682) -> ExecutionError {
683 use crate::error::convert_vm_error_impl;
684 convert_vm_error_impl(
685 error,
686 &|id| {
687 debug_assert!(
688 linkage.is_some(),
689 "Linkage should be set anywhere where runtime errors may occur in order to resolve abort locations to package IDs"
690 );
691 linkage
692 .and_then(|linkage| LinkedDataStore::new(linkage, store).relocate(id).ok())
693 .unwrap_or_else(|| id.clone())
694 },
695 &|id, function| {
697 debug_assert!(
698 linkage.is_some(),
699 "Linkage should be set anywhere where runtime errors may occur in order to resolve abort locations to package IDs"
700 );
701 linkage.and_then(|linkage| {
702 let state_view = LinkedDataStore::new(linkage, store);
703 vm.load_module(id, state_view).ok().map(|module| {
704 let fdef = module.function_def_at(function);
705 let fhandle = module.function_handle_at(fdef.function);
706 module.identifier_at(fhandle.name).to_string()
707 })
708 })
709 },
710 )
711}