Skip to content

Commit 5380c19

Browse files
committed
Preserve VMBC local count in embedded decoder
1 parent 3d9691a commit 5380c19

3 files changed

Lines changed: 44 additions & 6 deletions

File tree

pd-vm-nostd/src/program.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ impl Program {
6262
}
6363
}
6464

65+
pub(crate) fn with_local_count(mut self, local_count: usize) -> Self {
66+
self.local_count = local_count;
67+
self
68+
}
69+
6570
pub fn constants(&self) -> &[Value] {
6671
&self.constants
6772
}

pd-vm-nostd/src/vmbc.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,17 @@ pub fn decode_program(bytes: &[u8]) -> Result<Program, WireError> {
5252
});
5353
}
5454

55-
skip_type_map(&mut cursor)?;
55+
let encoded_local_count = skip_type_map(&mut cursor)?;
5656
skip_debug_info(&mut cursor)?;
5757
if !cursor.is_empty() {
5858
return Err(WireError::TrailingBytes);
5959
}
6060

61-
Ok(Program::new(constants, code, imports))
61+
let program = Program::new(constants, code, imports);
62+
Ok(match encoded_local_count {
63+
Some(local_count) => program.with_local_count(local_count),
64+
None => program,
65+
})
6266
}
6367

6468
fn reserve<T>(items: &mut Vec<T>, field: &'static str, count: usize) -> Result<(), WireError> {
@@ -71,9 +75,9 @@ fn read_value_type(raw: u8) -> Result<ValueType, WireError> {
7175
ValueType::try_from(raw).map_err(|()| WireError::InvalidValueType(raw))
7276
}
7377

74-
fn skip_type_map(cursor: &mut Cursor<'_>) -> Result<(), WireError> {
78+
fn skip_type_map(cursor: &mut Cursor<'_>) -> Result<Option<usize>, WireError> {
7579
match cursor.read_u8()? {
76-
0 => Ok(()),
80+
0 => Ok(None),
7781
1 => {
7882
cursor.read_bool()?;
7983
let local_count = cursor.read_u32()? as usize;
@@ -96,7 +100,7 @@ fn skip_type_map(cursor: &mut Cursor<'_>) -> Result<(), WireError> {
96100
read_value_type(cursor.read_u8()?)?;
97101
read_value_type(cursor.read_u8()?)?;
98102
}
99-
Ok(())
103+
Ok(Some(local_count))
100104
}
101105
value => Err(WireError::InvalidTypeMapFlag(value)),
102106
}

pd-vm-nostd/tests/embedded_vmbc.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
use pd_vm_nostd::{Value as EmbeddedValue, WireError, decode_program};
2-
use vm::{HostImport, OpCode, Program, Value, ValueType, compile_source, encode_program};
2+
use vm::compiler::TypeSchema;
3+
use vm::{
4+
HostImport, OpCode, Program, ReplLocalBinding, Value, ValueType, compile_source,
5+
compile_source_for_repl_with_locals, encode_program,
6+
};
37

48
fn encoded_scalar_program() -> Vec<u8> {
59
let mut program = Program::new(
@@ -57,6 +61,31 @@ fn embedded_decoder_accepts_compiler_type_and_debug_metadata() {
5761
assert_eq!(program.local_count(), compiled.locals);
5862
}
5963

64+
#[test]
65+
fn embedded_decoder_preserves_metadata_only_repl_locals() {
66+
let compiled = compile_source_for_repl_with_locals(
67+
"print(42);",
68+
&[ReplLocalBinding {
69+
name: "saved".to_string(),
70+
mutable: false,
71+
schema: Some(TypeSchema::Int),
72+
optional: false,
73+
}],
74+
)
75+
.expect("REPL source should compile");
76+
let bytes = encode_program(
77+
&compiled
78+
.compiled
79+
.program
80+
.with_local_count(compiled.compiled.locals),
81+
)
82+
.expect("REPL output should encode");
83+
84+
let program = decode_program(&bytes).expect("embedded decoder should accept REPL VMBC");
85+
assert_eq!(program.local_count(), compiled.compiled.locals);
86+
assert_eq!(program.local_count(), 1);
87+
}
88+
6089
#[test]
6190
fn embedded_decoder_rejects_trailing_bytes() {
6291
let mut bytes = encoded_scalar_program();

0 commit comments

Comments
 (0)