diff --git a/lib/module/src/module.rs b/lib/module/src/module.rs index bdeb90c627..bcfa7491b2 100644 --- a/lib/module/src/module.rs +++ b/lib/module/src/module.rs @@ -154,8 +154,6 @@ where decl: FunctionDeclaration, /// The compiled artifact, once it's available. compiled: Option, - /// A flag indicating whether the function has been finalized. - finalized: bool, } impl ModuleFunction @@ -187,8 +185,6 @@ where decl: DataDeclaration, /// The "compiled" artifact, once it's available. compiled: Option, - /// A flag indicating whether the data object has been finalized. - finalized: bool, } impl ModuleData @@ -314,6 +310,8 @@ where { names: HashMap, contents: ModuleContents, + functions_to_finalize: Vec, + data_objects_to_finalize: Vec, backend: B, } @@ -329,6 +327,8 @@ where functions: PrimaryMap::new(), data_objects: PrimaryMap::new(), }, + functions_to_finalize: Vec::new(), + data_objects_to_finalize: Vec::new(), backend: B::new(backend_builder), } } @@ -407,7 +407,6 @@ where signature: signature.clone(), }, compiled: None, - finalized: false, }); entry.insert(FuncOrDataId::Func(id)); self.backend.declare_function(name, linkage); @@ -447,7 +446,6 @@ where writable, }, compiled: None, - finalized: false, }); entry.insert(FuncOrDataId::Data(id)); self.backend.declare_data(name, linkage, writable); @@ -523,6 +521,7 @@ where )?) }; self.contents.functions[func].compiled = compiled; + self.functions_to_finalize.push(func); Ok(()) } @@ -546,6 +545,7 @@ where )?) }; self.contents.data_objects[data].compiled = compiled; + self.data_objects_to_finalize.push(data); Ok(()) } @@ -592,20 +592,16 @@ where ); } - /// Perform all outstanding relocations on the given function. This requires all `Local` - /// and `Export` entities referenced to be defined. + /// Finalize all functions and data objects that are defined but not yet finalized. + /// All symbols referenced in their bodies that are declared as needing a definition + /// must be defined by this point. /// - /// # Panics - /// - /// When the function has already been finalized this panics. - pub fn finalize_function(&mut self, func: FuncId) -> B::FinalizedFunction { - let output = { + /// Use `get_finalized_function` and `get_finalized_data` to obtain the final + /// artifacts. + pub fn finalize_definitions(&mut self) { + for func in self.functions_to_finalize.drain(..) { let info = &self.contents.functions[func]; - debug_assert!( - info.decl.linkage.is_definable(), - "imported function cannot be finalized" - ); - assert!(!info.finalized, "function can't be finalized twice"); + debug_assert!(info.decl.linkage.is_definable()); self.backend.finalize_function( info.compiled .as_ref() @@ -613,38 +609,11 @@ where &ModuleNamespace:: { contents: &self.contents, }, - ) - }; - self.contents.functions[func].finalized = true; - self.backend.publish(); - output - } - - /// Return the finalized artifact from the backend, if it provides one. - pub fn get_finalized_function(&mut self, func: FuncId) -> B::FinalizedFunction { - let info = &self.contents.functions[func]; - debug_assert!(info.finalized, "data object not yet finalized"); - self.backend.get_finalized_function( - info.compiled - .as_ref() - .expect("function must be compiled before it can be finalized"), - ) - } - - /// Perform all outstanding relocations on the given data object. This requires all - /// `Local` and `Export` entities referenced to be defined. - /// - /// # Panics - /// - /// When the data object has already been finalized this panics. - pub fn finalize_data(&mut self, data: DataId) -> B::FinalizedData { - let output = { - let info = &self.contents.data_objects[data]; - debug_assert!( - info.decl.linkage.is_definable(), - "imported data cannot be finalized" ); - assert!(!info.finalized, "data object can't be finalized twice"); + } + for data in self.data_objects_to_finalize.drain(..) { + let info = &self.contents.data_objects[data]; + debug_assert!(info.decl.linkage.is_definable()); self.backend.finalize_data( info.compiled .as_ref() @@ -652,17 +621,32 @@ where &ModuleNamespace:: { contents: &self.contents, }, - ) - }; - self.contents.data_objects[data].finalized = true; + ); + } self.backend.publish(); - output + } + + /// Return the finalized artifact from the backend, if it provides one. + pub fn get_finalized_function(&mut self, func: FuncId) -> B::FinalizedFunction { + let info = &self.contents.functions[func]; + debug_assert!( + !self.functions_to_finalize.iter().any(|x| *x == func), + "function not yet finalized" + ); + self.backend.get_finalized_function( + info.compiled + .as_ref() + .expect("function must be compiled before it can be finalized"), + ) } /// Return the finalized artifact from the backend, if it provides one. pub fn get_finalized_data(&mut self, data: DataId) -> B::FinalizedData { let info = &self.contents.data_objects[data]; - debug_assert!(info.finalized, "data object not yet finalized"); + debug_assert!( + !self.data_objects_to_finalize.iter().any(|x| *x == data), + "data object not yet finalized" + ); self.backend.get_finalized_data( info.compiled .as_ref() @@ -670,45 +654,6 @@ where ) } - /// Finalize all functions and data objects. Note that this doesn't return the - /// final artifacts returned from `finalize_function` or `finalize_data`. Use - /// `get_finalized_function` and `get_finalized_data` to obtain the final - /// artifacts. - pub fn finalize_all(&mut self) { - // TODO: Could we use something like `into_iter()` here? - for info in self.contents.functions.values() { - if info.decl.linkage.is_definable() && !info.finalized { - self.backend.finalize_function( - info.compiled - .as_ref() - .expect("function must be compiled before it can be finalized"), - &ModuleNamespace:: { - contents: &self.contents, - }, - ); - } - } - for info in self.contents.functions.values_mut() { - info.finalized = true; - } - for info in self.contents.data_objects.values() { - if info.decl.linkage.is_definable() && !info.finalized { - self.backend.finalize_data( - info.compiled - .as_ref() - .expect("data object must be compiled before it can be finalized"), - &ModuleNamespace:: { - contents: &self.contents, - }, - ); - } - } - for info in self.contents.data_objects.values_mut() { - info.finalized = true; - } - self.backend.publish(); - } - /// Consume the module and return the resulting `Product`. Some `Backend` /// implementations may provide additional functionality available after /// a `Module` is complete. diff --git a/lib/simplejit/examples/simplejit-minimal.rs b/lib/simplejit/examples/simplejit-minimal.rs index e393363768..0a736a8746 100644 --- a/lib/simplejit/examples/simplejit-minimal.rs +++ b/lib/simplejit/examples/simplejit-minimal.rs @@ -67,7 +67,7 @@ fn main() { module.clear_context(&mut ctx); // Perform linking. - module.finalize_all(); + module.finalize_definitions(); // Get a raw pointer to the generated code. let code_b = module.get_finalized_function(func_b); diff --git a/lib/simplejit/tests/basic.rs b/lib/simplejit/tests/basic.rs index a4aea4b389..7363fee4e9 100644 --- a/lib/simplejit/tests/basic.rs +++ b/lib/simplejit/tests/basic.rs @@ -57,13 +57,15 @@ fn define_simple_function(module: &mut Module) -> FuncId { } #[test] -#[should_panic(expected = "function can't be finalized twice")] -fn panic_on_double_finalize() { +fn double_finalize() { let mut module: Module = Module::new(SimpleJITBuilder::new()); let func_id = define_simple_function(&mut module); - module.finalize_function(func_id); - module.finalize_function(func_id); + module.finalize_definitions(); + + // Calling `finalize_definitions` a second time without any new definitions + // should have no effect. + module.finalize_definitions(); } #[test] @@ -72,6 +74,6 @@ fn panic_on_define_after_finalize() { let mut module: Module = Module::new(SimpleJITBuilder::new()); let func_id = define_simple_function(&mut module); - module.finalize_function(func_id); + module.finalize_definitions(); define_simple_function(&mut module); }