Skip to content

Commit bc1619f

Browse files
committed
fix(jit): propagate replace-many bridge failures
1 parent efba561 commit bc1619f

3 files changed

Lines changed: 56 additions & 7 deletions

File tree

src/builtins/runtime/core.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,11 @@ pub(crate) fn builtin_string_replace_literal_impl(
792792
text.replace(needle, replacement)
793793
}
794794

795-
/// Apply ordered literal replacements from parallel needle/replacement arrays.
795+
/// Apply literal replacements in order from parallel `needles` and `replacements` arrays.
796+
///
797+
/// Each pair uses the same non-overlapping semantics as the scalar overload. Empty needles
798+
/// leave the current output unchanged. Both arrays must have equal length and contain strings.
799+
/// A length mismatch or a non-string element returns an error.
796800
#[pd_host_function(name = "string_replace_literal")]
797801
pub(crate) fn builtin_string_replace_literal_many_impl(
798802
text: VmStringRef<'_>,

src/vm/jit/native/lower.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1839,12 +1839,6 @@ fn lower_ssa_inst(
18391839
let text = values[text];
18401840
let needles = values[needles];
18411841
let replacements = values[replacements];
1842-
let out = owned_value_temp_slot_addr(
1843-
b,
1844-
pointer_type,
1845-
owned_value_temps,
1846-
SsaTempValueSlotKey::Output(output.id),
1847-
)?;
18481842
let out_raw = ssa_call_string_replace_literal_many(
18491843
b,
18501844
pointer_type,
@@ -1854,6 +1848,20 @@ fn lower_ssa_inst(
18541848
needles,
18551849
replacements,
18561850
)?;
1851+
let error = b.ins().icmp_imm(IntCC::Equal, out_raw, 0);
1852+
let failed = b.create_block();
1853+
let replaced = b.create_block();
1854+
b.ins().brif(error, failed, &[], replaced, &[]);
1855+
b.switch_to_block(failed);
1856+
let status = b.ins().iconst(types::I32, STATUS_ERROR as i64);
1857+
jump_with_status(b, exit_block, status);
1858+
b.switch_to_block(replaced);
1859+
let out = owned_value_temp_slot_addr(
1860+
b,
1861+
pointer_type,
1862+
owned_value_temps,
1863+
SsaTempValueSlotKey::Output(output.id),
1864+
)?;
18571865
clear_owned_value_temp_slot(b, pointer_type, helper_refs, helper_addrs, out)?;
18581866
ssa_store_heap_ptr_in_value(b, layout.value, out, layout.value.string_tag, out_raw);
18591867
out
@@ -3979,6 +3987,7 @@ fn ssa_call_regex_match(
39793987
Ok(b.inst_results(call)[0])
39803988
}
39813989

3990+
#[allow(clippy::too_many_arguments)]
39823991
fn ssa_call_regex_replace(
39833992
b: &mut FunctionBuilder,
39843993
pointer_type: cranelift_codegen::ir::Type,

tests/jit/jit_tests.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4858,3 +4858,39 @@ fn trace_jit_specializes_regex_builtins_without_call_boundary() {
48584858
assert_eq!(vm.regex_cache_compile_count(), 2);
48594859
assert!(vm.regex_cache_hit_count() >= 14);
48604860
}
4861+
4862+
#[test]
4863+
fn trace_jit_propagates_replace_many_length_mismatch() {
4864+
if !native_jit_supported() {
4865+
return;
4866+
}
4867+
let source = r#"
4868+
let needles = ["a"];
4869+
let replacement_sets: [[string]] = [["x"], ["x"], ["x"], ["x"], ["x"], []];
4870+
let mut replacements: [string] = ["x"];
4871+
let mut i = 0;
4872+
let mut out = "";
4873+
while i < 6 {
4874+
replacements = (&replacement_sets)[i];
4875+
out = string_replace_literal("a", &needles, &replacements);
4876+
i = i + 1;
4877+
}
4878+
out;
4879+
"#;
4880+
let compiled = compile_source(source).expect("replace-many mismatch fixture should compile");
4881+
let mut vm = Vm::new_with_jit_config(
4882+
compiled.program.with_local_count(compiled.locals),
4883+
JitConfig {
4884+
enabled: true,
4885+
hot_loop_threshold: 1,
4886+
max_trace_len: 512,
4887+
},
4888+
);
4889+
let error = vm
4890+
.run()
4891+
.expect_err("replace-many mismatch should propagate its host error");
4892+
assert_eq!(
4893+
error.to_string(),
4894+
"host error: string_replace_literal array lengths must match"
4895+
);
4896+
}

0 commit comments

Comments
 (0)