Skip to content

Commit 2166a05

Browse files
committed
Reuse MarshalError
1 parent f2e19bd commit 2166a05

File tree

2 files changed

+29
-33
lines changed

2 files changed

+29
-33
lines changed

compiler/core/src/marshal.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,19 @@ impl<'a> ReadBorrowed<'a> for &'a [u8] {
165165
}
166166
}
167167

168+
/// Parses bytecode bytes into CodeUnit instructions.
169+
/// Each instruction is 2 bytes: opcode and argument.
170+
pub fn parse_instructions_from_bytes(bytes: &[u8]) -> Result<Box<[CodeUnit]>> {
171+
bytes
172+
.chunks_exact(2)
173+
.map(|cu| {
174+
let op = Instruction::try_from(cu[0])?;
175+
let arg = OpArgByte(cu[1]);
176+
Ok(CodeUnit { op, arg })
177+
})
178+
.collect()
179+
}
180+
168181
pub struct Cursor<B> {
169182
pub data: B,
170183
pub position: usize,
@@ -185,14 +198,7 @@ pub fn deserialize_code<R: Read, Bag: ConstantBag>(
185198
) -> Result<CodeObject<Bag::Constant>> {
186199
let len = rdr.read_u32()?;
187200
let instructions = rdr.read_slice(len * 2)?;
188-
let instructions = instructions
189-
.chunks_exact(2)
190-
.map(|cu| {
191-
let op = Instruction::try_from(cu[0])?;
192-
let arg = OpArgByte(cu[1]);
193-
Ok(CodeUnit { op, arg })
194-
})
195-
.collect::<Result<Box<[CodeUnit]>>>()?;
201+
let instructions = parse_instructions_from_bytes(instructions)?;
196202

197203
let len = rdr.read_u32()?;
198204
let locations = (0..len)

vm/src/builtins/code.rs

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@ use crate::{
1515
};
1616
use malachite_bigint::BigInt;
1717
use num_traits::Zero;
18-
use rustpython_compiler_core::OneIndexed;
19-
use rustpython_compiler_core::bytecode::PyCodeLocationInfoKind;
18+
use rustpython_compiler_core::{
19+
OneIndexed,
20+
bytecode::PyCodeLocationInfoKind,
21+
marshal::{MarshalError, parse_instructions_from_bytes},
22+
};
2023
use std::{borrow::Borrow, fmt, ops::Deref};
2124

2225
/// State for iterating through code address ranges
@@ -454,11 +457,8 @@ impl Constructor for PyCode {
454457

455458
// Parse and validate bytecode from bytes
456459
let bytecode_bytes = args.co_code.as_bytes();
457-
let instructions = parse_bytecode(bytecode_bytes).ok_or_else(|| {
458-
vm.new_value_error(
459-
"bytecode must have even length and contain only valid opcodes".to_owned(),
460-
)
461-
})?;
460+
let instructions = parse_bytecode(bytecode_bytes)
461+
.map_err(|e| vm.new_value_error(format!("invalid bytecode: {}", e)))?;
462462

463463
// Convert constants
464464
let constants: Box<[Literal]> = args
@@ -925,11 +925,8 @@ impl PyCode {
925925
let instructions = match co_code {
926926
OptionalArg::Present(code_bytes) => {
927927
// Parse and validate bytecode from bytes
928-
parse_bytecode(code_bytes.as_bytes()).ok_or_else(|| {
929-
vm.new_value_error(
930-
"bytecode must have even length and contain only valid opcodes".to_owned(),
931-
)
932-
})?
928+
parse_bytecode(code_bytes.as_bytes())
929+
.map_err(|e| vm.new_value_error(format!("invalid bytecode: {}", e)))?
933930
}
934931
OptionalArg::Missing => self.code.instructions.clone(),
935932
};
@@ -1037,23 +1034,16 @@ impl ToPyObject for bytecode::CodeObject {
10371034
}
10381035

10391036
/// Validates and parses bytecode bytes into CodeUnit instructions.
1040-
/// Returns None if bytecode is invalid (odd length or contains invalid opcodes).
1041-
fn parse_bytecode(bytecode_bytes: &[u8]) -> Option<Box<[CodeUnit]>> {
1037+
/// Returns MarshalError if bytecode is invalid (odd length or contains invalid opcodes).
1038+
/// Note: Returning MarshalError is not necessary at this point because this is not a part of marshalling API.
1039+
/// However, we (temporarily) reuse MarshalError for simplicity.
1040+
fn parse_bytecode(bytecode_bytes: &[u8]) -> Result<Box<[CodeUnit]>, MarshalError> {
10421041
// Bytecode must have even length (each instruction is 2 bytes)
10431042
if !bytecode_bytes.len().is_multiple_of(2) {
1044-
return None;
1045-
}
1046-
1047-
let mut instructions = Vec::with_capacity(bytecode_bytes.len() / 2);
1048-
1049-
for chunk in bytecode_bytes.chunks_exact(2) {
1050-
// Try to parse the opcode - if invalid, return None
1051-
let op = rustpython_compiler_core::bytecode::Instruction::try_from(chunk[0]).ok()?;
1052-
let arg = rustpython_compiler_core::bytecode::OpArgByte(chunk[1]);
1053-
instructions.push(CodeUnit { op, arg });
1043+
return Err(MarshalError::InvalidBytecode);
10541044
}
10551045

1056-
Some(instructions.into_boxed_slice())
1046+
parse_instructions_from_bytes(bytecode_bytes)
10571047
}
10581048

10591049
// Helper struct for reading linetable

0 commit comments

Comments
 (0)