Remove Module's finalize_function and finalize_data. (#519)
* Remove `Module`'s `finalize_function` and `finalize_data`. Remove the ability to finalize individiual functions and data objects, and instead just provide a way to finalize everything that's been defined but not yet finalized. This allows SimpleJIT to share an allocation between multiple functions without having to worry about individual functions being finalized and needing to be published without the other functions in the same allocation. Users of the return values of `Module`'s `finalize_function` and `finalize_data` should now use `get_finalized_function` and `get_finalized_data` to obtain these values.
This commit is contained in:
@@ -154,8 +154,6 @@ where
|
||||
decl: FunctionDeclaration,
|
||||
/// The compiled artifact, once it's available.
|
||||
compiled: Option<B::CompiledFunction>,
|
||||
/// A flag indicating whether the function has been finalized.
|
||||
finalized: bool,
|
||||
}
|
||||
|
||||
impl<B> ModuleFunction<B>
|
||||
@@ -187,8 +185,6 @@ where
|
||||
decl: DataDeclaration,
|
||||
/// The "compiled" artifact, once it's available.
|
||||
compiled: Option<B::CompiledData>,
|
||||
/// A flag indicating whether the data object has been finalized.
|
||||
finalized: bool,
|
||||
}
|
||||
|
||||
impl<B> ModuleData<B>
|
||||
@@ -314,6 +310,8 @@ where
|
||||
{
|
||||
names: HashMap<String, FuncOrDataId>,
|
||||
contents: ModuleContents<B>,
|
||||
functions_to_finalize: Vec<FuncId>,
|
||||
data_objects_to_finalize: Vec<DataId>,
|
||||
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::<B> {
|
||||
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::<B> {
|
||||
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::<B> {
|
||||
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::<B> {
|
||||
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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -57,13 +57,15 @@ fn define_simple_function(module: &mut Module<SimpleJITBackend>) -> FuncId {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "function can't be finalized twice")]
|
||||
fn panic_on_double_finalize() {
|
||||
fn double_finalize() {
|
||||
let mut module: Module<SimpleJITBackend> = 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<SimpleJITBackend> = 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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user