only reset string arena when it is used

This commit is contained in:
Paul Masurel
2026-08-18 14:06:38 +02:00
parent 3381b92586
commit 73eabcc7c3
5 changed files with 25 additions and 13 deletions
@@ -218,6 +218,7 @@ impl<'types, 'names> CompileFnBuilder<'types, 'names> {
let mut lowering_context = LoweringContext {
args_ptr,
string_arena_ptr,
string_arena_was_reset: false,
pointer_type,
native_functions: &native_functions,
};
-1
View File
@@ -64,7 +64,6 @@ impl CompiledFn {
{
debug_assert_eq!(args.len(), self.inputs.len());
let args: &[VariableValue<'output>] = args;
self.string_arena.clear();
let string_arena = &raw mut self.string_arena;
// SAFETY: Guaranteed by the caller. Both the input and compiled-function
// lifetimes outlive the lifetime selected for the returned value.
+14 -1
View File
@@ -45,6 +45,7 @@ pub fn compile_to_assembly(
pub(crate) struct LoweringContext<'a> {
args_ptr: CraneliftValue,
string_arena_ptr: CraneliftValue,
string_arena_was_reset: bool,
pointer_type: Type,
native_functions: &'a NativeFunctions,
}
@@ -122,7 +123,17 @@ impl LoweringContext<'_> {
self.pointer_type
}
pub(crate) fn string_arena_ptr(&self) -> CraneliftValue {
pub(crate) fn string_arena_ptr(&mut self, builder: &mut FunctionBuilder<'_>) -> CraneliftValue {
if !self.string_arena_was_reset {
let zero = builder.ins().iconst(cranelift_types::I64, 0);
builder.ins().store(
MemFlagsData::trusted(),
zero,
self.string_arena_ptr,
StringArena::CURSOR_OFFSET,
);
self.string_arena_was_reset = true;
}
self.string_arena_ptr
}
@@ -217,10 +228,12 @@ mod tests {
let untyped_expr = UntypedExpr::variable("flag");
let variable_types = HashMap::from([("flag", VarType::Bool)]);
let mut compiled_fn = compile(&untyped_expr, &variable_types).unwrap();
assert!(compiled_fn.string_arena.allocate(1).is_some());
let input = [VariableValue::some(true)];
let output = unsafe { compiled_fn.call(&input) };
assert_eq!(unsafe { output.as_bool() }, Some(true));
assert_eq!(compiled_fn.string_arena.used_bytes(), 1);
}
#[test]
+2 -4
View File
@@ -7,6 +7,8 @@ pub(crate) struct StringArena {
}
impl StringArena {
pub(crate) const CURSOR_OFFSET: i32 = std::mem::offset_of!(StringArena, cursor) as i32;
pub(crate) fn new() -> Self {
let buffer = vec![0; STRING_ARENA_CAPACITY].into_boxed_slice();
let buffer = buffer
@@ -15,10 +17,6 @@ impl StringArena {
Self { buffer, cursor: 0 }
}
pub(crate) fn clear(&mut self) {
self.cursor = 0;
}
/// Reserves `len` contiguous bytes without growing the backing allocation.
pub(crate) fn allocate(&mut self, len: usize) -> Option<*mut u8> {
let end = self.cursor.checked_add(len)?;
+8 -7
View File
@@ -78,9 +78,11 @@ impl FnCall for LowerFnCall {
let arg = context.compile_expr(&self.arg, builder)?;
let null = builder.ins().iconst(context.pointer_type(), 0);
let input_ptr = builder.ins().select(arg.is_present, arg.value, null);
let string_lowercase = context.native_functions().string_lowercase();
let string_arena_ptr = context.string_arena_ptr(builder);
let call = builder.ins().call(
context.native_functions().string_lowercase(),
&[input_ptr, arg.string_len, context.string_arena_ptr()],
string_lowercase,
&[input_ptr, arg.string_len, string_arena_ptr],
);
let value = builder.inst_results(call)[0];
let string_len = builder.inst_results(call)[1];
@@ -265,9 +267,7 @@ mod tests {
let mut compiled = compile(&expression, &variable_types).unwrap();
let input = [VariableValue::some("HeLLo")];
let output = unsafe { compiled.call(&input) };
assert_eq!(unsafe { output.as_str() }, Some("hello"));
assert_eq!(unsafe { compiled.call(&input).as_str() }, Some("hello"));
}
#[test]
@@ -275,11 +275,12 @@ mod tests {
let expression = deserialize("(EQ (LOWER left) (LOWER right))").unwrap();
let variable_types = HashMap::from([("left", VarType::Str), ("right", VarType::Str)]);
let mut compiled = compile(&expression, &variable_types).unwrap();
let input = [VariableValue::some("FiRsT"), VariableValue::some("fIrSt")];
let input = [VariableValue::some("FiRsT"), VariableValue::some("SeCoNd")];
let output = unsafe { compiled.call(&input) };
assert_eq!(unsafe { output.as_bool() }, Some(true));
assert_eq!(unsafe { output.as_bool() }, Some(false));
assert_eq!(compiled.string_arena.used_bytes(), 11);
}
#[test]