Skip to content

Commit 7fc242f

Browse files
hanslclaude
andauthored
Introduce Address newtype for bytecode addresses (boa-dev#4862)
Replace raw `u32` with a typed `Address` wrapper for all bytecode address fields in opcodes, handlers, labels, and the compiler. This provides type safety to distinguish addresses from other u32 values (register indices, counts, etc.) and displays addresses as hexadecimal in bytecode dumps. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 701bebe commit 7fc242f

12 files changed

Lines changed: 219 additions & 143 deletions

File tree

core/engine/src/bytecompiler/jump_control.rs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
use super::Register;
1313
use crate::{
1414
bytecompiler::{ByteCompiler, Label},
15-
vm::{CallFrame, Handler},
15+
vm::{CallFrame, Handler, opcode::Address},
1616
};
1717
use bitflags::bitflags;
1818
use boa_interner::Sym;
@@ -93,7 +93,11 @@ impl JumpRecord {
9393
}
9494

9595
/// Performs the [`JumpRecordAction`]s.
96-
pub(crate) fn perform_actions(mut self, start_address: u32, compiler: &mut ByteCompiler<'_>) {
96+
pub(crate) fn perform_actions(
97+
mut self,
98+
start_address: Address,
99+
compiler: &mut ByteCompiler<'_>,
100+
) {
97101
while let Some(action) = self.actions.pop() {
98102
match action {
99103
JumpRecordAction::Transfer { index } => {
@@ -216,7 +220,7 @@ impl JumpRecord {
216220
#[derive(Debug)]
217221
pub(crate) struct JumpControlInfo {
218222
label: Option<Sym>,
219-
start_address: u32,
223+
start_address: Address,
220224
pub(crate) flags: JumpControlInfoFlags,
221225
pub(crate) jumps: Vec<JumpRecord>,
222226
current_open_environments_count: u32,
@@ -267,7 +271,7 @@ impl JumpControlInfo {
267271
self
268272
}
269273

270-
pub(crate) const fn with_start_address(mut self, address: u32) -> Self {
274+
pub(crate) const fn with_start_address(mut self, address: Address) -> Self {
271275
self.start_address = address;
272276
self
273277
}
@@ -310,7 +314,7 @@ impl JumpControlInfo {
310314
self.label
311315
}
312316

313-
pub(crate) const fn start_address(&self) -> u32 {
317+
pub(crate) const fn start_address(&self) -> Address {
314318
self.start_address
315319
}
316320

@@ -356,7 +360,7 @@ impl JumpControlInfo {
356360
}
357361

358362
/// Sets the `start_address` field of `JumpControlInfo`.
359-
pub(crate) fn set_start_address(&mut self, start_address: u32) {
363+
pub(crate) fn set_start_address(&mut self, start_address: Address) {
360364
self.start_address = start_address;
361365
}
362366
}
@@ -439,7 +443,7 @@ impl ByteCompiler<'_> {
439443
pub(crate) fn push_labelled_control_info(
440444
&mut self,
441445
label: Sym,
442-
start_address: u32,
446+
start_address: Address,
443447
use_expr: bool,
444448
) {
445449
let new_info = JumpControlInfo::new(self.current_open_environments_count)
@@ -473,7 +477,7 @@ impl ByteCompiler<'_> {
473477
pub(crate) fn push_loop_control_info(
474478
&mut self,
475479
label: Option<Sym>,
476-
start_address: u32,
480+
start_address: Address,
477481
use_expr: bool,
478482
) {
479483
let new_info = JumpControlInfo::new(self.current_open_environments_count)
@@ -488,7 +492,7 @@ impl ByteCompiler<'_> {
488492
pub(crate) fn push_loop_control_info_for_of_in_loop(
489493
&mut self,
490494
label: Option<Sym>,
491-
start_address: u32,
495+
start_address: Address,
492496
use_expr: bool,
493497
) {
494498
let new_info = JumpControlInfo::new(self.current_open_environments_count)
@@ -503,7 +507,7 @@ impl ByteCompiler<'_> {
503507
pub(crate) fn push_loop_control_info_for_await_of_loop(
504508
&mut self,
505509
label: Option<Sym>,
506-
start_address: u32,
510+
start_address: Address,
507511
use_expr: bool,
508512
) {
509513
let new_info = JumpControlInfo::new(self.current_open_environments_count)
@@ -539,7 +543,7 @@ impl ByteCompiler<'_> {
539543
pub(crate) fn push_switch_control_info(
540544
&mut self,
541545
label: Option<Sym>,
542-
start_address: u32,
546+
start_address: Address,
543547
use_expr: bool,
544548
) {
545549
let new_info = JumpControlInfo::new(self.current_open_environments_count)
@@ -586,7 +590,7 @@ impl ByteCompiler<'_> {
586590
///
587591
/// # Panic
588592
/// - Will panic if popped `JumpControlInfo` is not for a try block.
589-
pub(crate) fn pop_try_with_finally_control_info(&mut self, finally_start: u32) {
593+
pub(crate) fn pop_try_with_finally_control_info(&mut self, finally_start: Address) {
590594
assert!(!self.jump_info.is_empty());
591595
let info = self.jump_info.pop().expect("no jump information found");
592596

core/engine/src/bytecompiler/mod.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::{
2424
js_string,
2525
vm::{
2626
CallFrame, CodeBlock, CodeBlockFlags, Constant, GeneratorResumeKind, Handler, InlineCache,
27-
opcode::{BindingOpcode, ByteCodeEmitter, VaryingOperand},
27+
opcode::{Address, BindingOpcode, ByteCodeEmitter, VaryingOperand},
2828
source_info::{SourceInfo, SourceMap, SourceMapBuilder, SourcePath},
2929
},
3030
};
@@ -366,7 +366,7 @@ enum Literal {
366366
#[must_use]
367367
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
368368
pub(crate) struct Label {
369-
index: u32,
369+
index: Address,
370370
}
371371

372372
#[derive(Debug, Clone, Copy)]
@@ -536,8 +536,10 @@ pub(crate) enum BindingKind {
536536

537537
impl<'ctx> ByteCompiler<'ctx> {
538538
/// Represents a placeholder address that will be patched later.
539-
const DUMMY_ADDRESS: u32 = u32::MAX;
540-
const DUMMY_LABEL: Label = Label { index: u32::MAX };
539+
const DUMMY_ADDRESS: Address = Address::new(u32::MAX);
540+
const DUMMY_LABEL: Label = Label {
541+
index: Address::new(u32::MAX),
542+
};
541543

542544
/// Creates a new [`ByteCompiler`].
543545
#[inline]
@@ -802,7 +804,7 @@ impl<'ctx> ByteCompiler<'ctx> {
802804
}
803805
}
804806

805-
fn next_opcode_location(&mut self) -> u32 {
807+
fn next_opcode_location(&mut self) -> Address {
806808
self.bytecode.next_opcode_location()
807809
}
808810

@@ -819,12 +821,13 @@ impl<'ctx> ByteCompiler<'ctx> {
819821
{
820822
let start_pc = self.next_opcode_location();
821823
self.source_map_builder
822-
.push_source_position(start_pc, position.into());
824+
.push_source_position(start_pc.as_u32(), position.into());
823825
}
824826

825827
pub(crate) fn pop_source_position(&mut self) {
826828
let start_pc = self.next_opcode_location();
827-
self.source_map_builder.pop_source_position(start_pc);
829+
self.source_map_builder
830+
.pop_source_position(start_pc.as_u32());
828831
}
829832

830833
pub(crate) fn emit_get_function(&mut self, dst: &Register, index: u32) {
@@ -1144,7 +1147,7 @@ impl<'ctx> ByteCompiler<'ctx> {
11441147
fn try_fused_comparison_branch(&mut self, op: RelationalOp, binary: &Binary) -> Option<Label> {
11451148
use crate::vm::opcode::ByteCodeEmitter;
11461149

1147-
let emit_fn: fn(&mut ByteCodeEmitter, u32, VaryingOperand, VaryingOperand) = match op {
1150+
let emit_fn: fn(&mut ByteCodeEmitter, Address, VaryingOperand, VaryingOperand) = match op {
11481151
RelationalOp::LessThan => ByteCodeEmitter::emit_jump_if_not_less_than,
11491152
RelationalOp::LessThanOrEqual => ByteCodeEmitter::emit_jump_if_not_less_than_or_equal,
11501153
RelationalOp::GreaterThan => ByteCodeEmitter::emit_jump_if_not_greater_than,
@@ -1153,7 +1156,7 @@ impl<'ctx> ByteCompiler<'ctx> {
11531156
}
11541157
_ => return None,
11551158
};
1156-
let mut label_index = 0u32;
1159+
let mut label_index = Address::new(0);
11571160
self.compile_expr_operand(binary.lhs(), |compiler, lhs| {
11581161
compiler.compile_expr_operand(binary.rhs(), |compiler, rhs| {
11591162
label_index = compiler.next_opcode_location();
@@ -1217,7 +1220,7 @@ impl<'ctx> ByteCompiler<'ctx> {
12171220
}
12181221

12191222
#[track_caller]
1220-
pub(crate) fn patch_jump_with_target(&mut self, label: Label, target: u32) {
1223+
pub(crate) fn patch_jump_with_target(&mut self, label: Label, target: Address) {
12211224
self.bytecode.patch_jump(label.index, target);
12221225
}
12231226

@@ -2397,7 +2400,7 @@ impl<'ctx> ByteCompiler<'ctx> {
23972400

23982401
let register_count = self.register_allocator.finish();
23992402

2400-
let source_map_entries = self.source_map_builder.build(final_bytecode_len);
2403+
let source_map_entries = self.source_map_builder.build(final_bytecode_len.as_u32());
24012404

24022405
CodeBlock {
24032406
length: self.length,

core/engine/src/vm/code_block.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use thin_vec::ThinVec;
1919

2020
use super::{
2121
InlineCache,
22-
opcode::{ByteCode, Instruction, InstructionIterator},
22+
opcode::{Address, ByteCode, Instruction, InstructionIterator},
2323
source_info::{SourceInfo, SourceMap, SourcePath},
2424
};
2525

@@ -79,20 +79,20 @@ unsafe impl Trace for CodeBlockFlags {
7979
/// [`Handler`] and remove any environments or stack values that where pushed after the handler.
8080
#[derive(Debug, Clone, Copy)]
8181
pub(crate) struct Handler {
82-
pub(crate) start: u32,
83-
pub(crate) end: u32,
82+
pub(crate) start: Address,
83+
pub(crate) end: Address,
8484
pub(crate) environment_count: u32,
8585
}
8686

8787
impl Handler {
8888
/// Get the handler address.
89-
pub(crate) const fn handler(&self) -> u32 {
89+
pub(crate) const fn handler(&self) -> Address {
9090
self.end
9191
}
9292

9393
/// Check if the provided `pc` is contained in the handler range.
9494
pub(crate) const fn contains(&self, pc: u32) -> bool {
95-
pc < self.end && pc >= self.start
95+
pc < self.end.as_u32() && pc >= self.start.as_u32()
9696
}
9797
}
9898

@@ -944,14 +944,14 @@ impl Display for CodeBlock {
944944
let pc = iterator.pc();
945945
let handler = if let Some((i, handler)) = self.find_handler(instruction_start_pc as u32)
946946
{
947-
let border_char = if instruction_start_pc as u32 == handler.start {
947+
let border_char = if instruction_start_pc as u32 == u32::from(handler.start) {
948948
'>'
949-
} else if pc as u32 == handler.end {
949+
} else if pc as u32 == u32::from(handler.end) {
950950
'<'
951951
} else {
952952
' '
953953
};
954-
format!("{border_char}{i:2}: {:06x}", handler.handler())
954+
format!("{border_char}{i:2}: {}", handler.handler())
955955
} else {
956956
" ".to_string()
957957
};

core/engine/src/vm/flowgraph/mod.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ impl CodeBlock {
114114
graph.add_node(previous_pc, NodeShape::Diamond, label.into(), Color::None);
115115
graph.add_edge(
116116
previous_pc,
117-
address as usize,
117+
address.as_u32() as usize,
118118
None,
119119
Color::None,
120120
EdgeStyle::Line,
@@ -132,7 +132,7 @@ impl CodeBlock {
132132
graph.add_node(previous_pc, NodeShape::Diamond, label.into(), Color::None);
133133
graph.add_edge(
134134
previous_pc,
135-
address as usize,
135+
address.as_u32() as usize,
136136
Some("YES".into()),
137137
Color::Green,
138138
EdgeStyle::Line,
@@ -156,7 +156,7 @@ impl CodeBlock {
156156
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line);
157157
graph.add_edge(
158158
previous_pc,
159-
address as usize,
159+
address.as_u32() as usize,
160160
Some("SHORT CIRCUIT".into()),
161161
Color::Red,
162162
EdgeStyle::Line,
@@ -173,7 +173,7 @@ impl CodeBlock {
173173
);
174174
graph.add_edge(
175175
previous_pc,
176-
address as usize,
176+
address.as_u32() as usize,
177177
Some("YES".into()),
178178
Color::Green,
179179
EdgeStyle::Line,
@@ -193,14 +193,14 @@ impl CodeBlock {
193193
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line);
194194
graph.add_edge(
195195
previous_pc,
196-
throw_method_undefined as usize,
196+
throw_method_undefined.as_u32() as usize,
197197
Some("`throw` undefined".into()),
198198
Color::Red,
199199
EdgeStyle::Line,
200200
);
201201
graph.add_edge(
202202
previous_pc,
203-
return_method_undefined as usize,
203+
return_method_undefined.as_u32() as usize,
204204
Some("`return` undefined".into()),
205205
Color::Blue,
206206
EdgeStyle::Line,
@@ -216,14 +216,14 @@ impl CodeBlock {
216216
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line);
217217
graph.add_edge(
218218
previous_pc,
219-
r#return as usize,
219+
r#return.as_u32() as usize,
220220
Some("return".into()),
221221
Color::Yellow,
222222
EdgeStyle::Line,
223223
);
224224
graph.add_edge(
225225
previous_pc,
226-
exit as usize,
226+
exit.as_u32() as usize,
227227
Some("done".into()),
228228
Color::Blue,
229229
EdgeStyle::Line,
@@ -242,7 +242,7 @@ impl CodeBlock {
242242
graph.add_node(previous_pc, NodeShape::Diamond, label.into(), Color::None);
243243
graph.add_edge(
244244
previous_pc,
245-
address as usize,
245+
address.as_u32() as usize,
246246
Some("EXIT".into()),
247247
Color::Red,
248248
EdgeStyle::Line,
@@ -324,7 +324,7 @@ impl CodeBlock {
324324
if let Some((i, handler)) = self.find_handler(previous_pc as u32) {
325325
graph.add_edge(
326326
previous_pc,
327-
handler.handler() as usize,
327+
handler.handler().as_u32() as usize,
328328
Some(format!("Handler {i:2}: CAUGHT").into()),
329329
Color::None,
330330
EdgeStyle::Line,
@@ -336,7 +336,7 @@ impl CodeBlock {
336336
graph.add_node(previous_pc, NodeShape::Record, label.into(), Color::None);
337337
graph.add_edge(
338338
previous_pc,
339-
handler.handler() as usize,
339+
handler.handler().as_u32() as usize,
340340
Some(format!("Handler {i:2}: CAUGHT").into()),
341341
Color::None,
342342
EdgeStyle::Line,
@@ -366,7 +366,7 @@ impl CodeBlock {
366366
for (i, address) in addresses.iter().enumerate() {
367367
graph.add_edge(
368368
previous_pc,
369-
*address as usize,
369+
address.as_u32() as usize,
370370
Some(format!("[{i}]").into()),
371371
Color::None,
372372
EdgeStyle::Line,

core/engine/src/vm/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ impl Vm {
552552
let environment_sp = frame.env_fp + handler.environment_count;
553553

554554
// Go to handler location.
555-
frame.pc = catch_address;
555+
frame.pc = u32::from(catch_address);
556556

557557
self.frame.environments.truncate(environment_sp as usize);
558558

core/engine/src/vm/opcode/args.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use thin_vec::ThinVec;
22

3-
use super::VaryingOperand;
3+
use super::{Address, VaryingOperand};
44

55
/// A trait for types that can be read from a byte slice.
66
///
@@ -149,6 +149,19 @@ impl Argument for VaryingOperand {
149149
}
150150
}
151151

152+
impl Argument for Address {
153+
#[inline(always)]
154+
fn encode(self, bytes: &mut Vec<u8>) {
155+
write_u32(bytes, self.value);
156+
}
157+
158+
#[inline(always)]
159+
fn decode(bytes: &[u8], pos: usize) -> (Self, usize) {
160+
let (value, pos) = read::<u32>(bytes, pos);
161+
(Self::new(value), pos)
162+
}
163+
}
164+
152165
macro_rules! impl_argument_for_tuple {
153166
($( $i: ident $t: ident ),*) => {
154167
impl<$( $t: Argument, )*> Argument for ($( $t, )*) {

0 commit comments

Comments
 (0)