Skip to content

Commit 4083b0e

Browse files
committed
feat: add finally return support
1 parent 4b49db8 commit 4083b0e

File tree

5 files changed

+137
-111
lines changed

5 files changed

+137
-111
lines changed

crates/starlight/src/bytecode/opcodes.rs

+3
Original file line numberDiff line numberDiff line change
@@ -280,4 +280,7 @@ pub enum Opcode {
280280
OP_YIELD_STAR,
281281
OP_AWAIT,
282282
OP_NEWGENERATOR,
283+
284+
OP_FAST_CALL,
285+
OP_FAST_RET
283286
}

crates/starlight/src/bytecompiler.rs

+78-99
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,31 @@ pub struct ByteCompiler {
111111
pub variable_freelist: Vec<u32>,
112112

113113
pub info: Option<Vec<(Range<usize>, FileLocation)>>,
114+
115+
pub in_try_stmt: bool,
116+
pub fast_calls: Vec<Box<dyn FnOnce(&mut ByteCompiler)>>
114117
}
115118

116119
impl ByteCompiler {
120+
pub fn new( rt: RuntimeRef, builtins: bool,code:GcPointer<CodeBlock>,scope: Rc<RefCell<Scope>>)-> Self {
121+
Self {
122+
lci: Vec::new(),
123+
builtins,
124+
variable_freelist: Vec::with_capacity(4),
125+
code,
126+
tail_pos: false,
127+
info: None,
128+
fmap: HashMap::new(),
129+
val_map: HashMap::new(),
130+
name_map: HashMap::new(),
131+
top_level: false,
132+
scope,
133+
rt: rt,
134+
in_try_stmt: false,
135+
fast_calls: Vec::new()
136+
}
137+
}
138+
117139
pub fn get_val(&mut self, vm: &mut Runtime, val: Val) -> u32 {
118140
if let Some(ix) = self.val_map.get(&val) {
119141
return *ix;
@@ -472,20 +494,7 @@ impl ByteCompiler {
472494
depth: 0,
473495
}));
474496
let mut code = CodeBlock::new(vm, "<anonymous>".intern(), false, rel_path.into());
475-
let mut compiler = ByteCompiler {
476-
lci: Vec::new(),
477-
builtins,
478-
variable_freelist: Vec::with_capacity(4),
479-
code,
480-
tail_pos: false,
481-
info: None,
482-
fmap: HashMap::new(),
483-
val_map: HashMap::new(),
484-
name_map: HashMap::new(),
485-
top_level: false,
486-
scope,
487-
rt: RuntimeRef(&mut *vm),
488-
};
497+
let mut compiler = ByteCompiler::new(RuntimeRef(vm),builtins,code,scope);
489498
let mut p = 0;
490499
for x in params_.iter() {
491500
params.push(x.intern());
@@ -573,20 +582,7 @@ impl ByteCompiler {
573582
depth: self.scope.borrow().depth + 1,
574583
}));
575584

576-
let mut compiler = ByteCompiler {
577-
lci: Vec::new(),
578-
builtins: self.builtins,
579-
variable_freelist: Vec::with_capacity(4),
580-
code,
581-
info: None,
582-
tail_pos: false,
583-
fmap: HashMap::new(),
584-
val_map: HashMap::new(),
585-
name_map: HashMap::new(),
586-
top_level: false,
587-
scope,
588-
rt: RuntimeRef(&mut *self.rt),
589-
};
585+
let mut compiler = ByteCompiler::new(self.rt,self.builtins,code,scope);
590586
let mut p = 0;
591587
for x in function.params.iter() {
592588
match x.pat {
@@ -667,24 +663,11 @@ impl ByteCompiler {
667663

668664
let mut code = CodeBlock::new(&mut vm, name, false, path.into());
669665
code.file_name = file.to_string();
670-
let mut compiler = ByteCompiler {
671-
lci: Vec::new(),
672-
top_level: true,
673-
info: None,
674-
tail_pos: false,
675-
builtins: false,
676-
scope: Rc::new(RefCell::new(Scope {
677-
parent: None,
678-
variables: Default::default(),
679-
depth: 0,
680-
})),
681-
variable_freelist: vec![],
682-
code,
683-
val_map: Default::default(),
684-
name_map: Default::default(),
685-
fmap: Default::default(),
686-
rt: RuntimeRef(vm),
687-
};
666+
let mut compiler = ByteCompiler::new(RuntimeRef(vm),false,code,Rc::new(RefCell::new(Scope {
667+
parent: None,
668+
variables: Default::default(),
669+
depth: 0
670+
})));
688671
code.var_count = 1;
689672
code.param_count = 1;
690673
compiler.scope.borrow_mut().add_var("@module".intern(), 0);
@@ -857,24 +840,13 @@ impl ByteCompiler {
857840
let name = "<script>".intern();
858841
let mut code = CodeBlock::new(&mut vm, name, false, path.into());
859842
code.file_name = fname;
860-
let mut compiler = ByteCompiler {
861-
lci: Vec::new(),
862-
top_level: true,
863-
info: None,
864-
tail_pos: false,
865-
builtins,
866-
scope: Rc::new(RefCell::new(Scope {
843+
let mut compiler = ByteCompiler::new(
844+
RuntimeRef(vm),builtins,code,Rc::new(RefCell::new(Scope {
867845
parent: None,
868846
variables: Default::default(),
869847
depth: 0,
870-
})),
871-
variable_freelist: vec![],
872-
code,
873-
val_map: Default::default(),
874-
name_map: Default::default(),
875-
fmap: Default::default(),
876-
rt: RuntimeRef(vm),
877-
};
848+
}))
849+
);
878850

879851
let is_strict = match p.body.get(0) {
880852
Some(body) => body.is_use_strict(),
@@ -903,24 +875,11 @@ impl ByteCompiler {
903875
let name = "<script>".intern();
904876
let mut code = CodeBlock::new(&mut vm, name, false, path.into());
905877
code.file_name = fname;
906-
let mut compiler = ByteCompiler {
907-
lci: Vec::new(),
908-
top_level: true,
909-
info: None,
910-
tail_pos: false,
911-
builtins,
912-
scope: Rc::new(RefCell::new(Scope {
913-
parent: None,
914-
variables: Default::default(),
915-
depth: 0,
916-
})),
917-
variable_freelist: vec![],
918-
code,
919-
val_map: Default::default(),
920-
name_map: Default::default(),
921-
fmap: Default::default(),
922-
rt: RuntimeRef(vm),
923-
};
878+
let mut compiler = ByteCompiler::new(RuntimeRef(vm),builtins,code,Rc::new(RefCell::new(Scope {
879+
parent: None,
880+
variables: Default::default(),
881+
depth: 0,
882+
})));
924883

925884
let is_strict = match p.body.get(0) {
926885
Some(body) => body.is_use_strict(),
@@ -1122,6 +1081,10 @@ impl ByteCompiler {
11221081
None => self.emit(Opcode::OP_PUSH_UNDEF, &[], false),
11231082
};
11241083
self.tail_pos = false;
1084+
if self.in_try_stmt {
1085+
let fast_call = self.fast_call();
1086+
self.fast_calls.push(Box::new(fast_call));
1087+
}
11251088
self.emit(Opcode::OP_RET, &[], false);
11261089
}
11271090
Stmt::Break(_) => {
@@ -1303,7 +1266,8 @@ impl ByteCompiler {
13031266
}
13041267
Stmt::Try(try_stmt) => {
13051268
let try_push = self.try_();
1306-
1269+
1270+
self.in_try_stmt = true;
13071271
for stmt in try_stmt.block.stmts.iter() {
13081272
self.stmt(stmt)?;
13091273
}
@@ -1337,6 +1301,13 @@ impl ByteCompiler {
13371301

13381302
jfinally(self);
13391303
jcatch_finally(self);
1304+
while self.fast_calls.len() >0 {
1305+
let call = self.fast_calls.pop();
1306+
if let Some(c) = call {
1307+
c(self);
1308+
}
1309+
}
1310+
self.in_try_stmt = false;
13401311
match try_stmt.finalizer {
13411312
Some(ref block) => {
13421313
self.push_scope();
@@ -1349,8 +1320,12 @@ impl ByteCompiler {
13491320
}
13501321
None => {}
13511322
}
1323+
self.emit(Opcode::OP_FAST_RET,&[], false);
13521324
}
1353-
1325+
Stmt::Debugger(_) => todo!(),
1326+
Stmt::With(_) => todo!(),
1327+
Stmt::Labeled(_) => todo!(),
1328+
Stmt::DoWhile(_) => todo!(),
13541329
x => {
13551330
return Err(JsValue::new(
13561331
self.rt.new_syntax_error(format!("NYI: {:?}", x)),
@@ -1929,24 +1904,11 @@ impl ByteCompiler {
19291904
let p = self.code.path.clone();
19301905
let mut code = CodeBlock::new(&mut self.rt, name, false, p);
19311906
code.file_name = self.code.file_name.clone();
1932-
let mut compiler = ByteCompiler {
1933-
lci: Vec::new(),
1934-
top_level: false,
1935-
tail_pos: false,
1936-
builtins: self.builtins,
1937-
code,
1938-
variable_freelist: vec![],
1939-
val_map: Default::default(),
1940-
name_map: Default::default(),
1941-
info: None,
1942-
fmap: Default::default(),
1943-
rt: RuntimeRef(&mut *self.rt),
1944-
scope: Rc::new(RefCell::new(Scope {
1945-
parent: Some(self.scope.clone()),
1946-
depth: self.scope.borrow().depth + 1,
1947-
variables: HashMap::new(),
1948-
})),
1949-
};
1907+
let mut compiler = ByteCompiler::new(self.rt,self.builtins,code, Rc::new(RefCell::new(Scope {
1908+
parent: Some(self.scope.clone()),
1909+
depth: self.scope.borrow().depth + 1,
1910+
variables: HashMap::new(),
1911+
})));
19501912
code.strict = is_strict;
19511913
let mut params = vec![];
19521914
let mut rest_at = None;
@@ -2107,6 +2069,23 @@ impl ByteCompiler {
21072069
}
21082070
}
21092071

2072+
pub fn fast_call(&mut self) -> impl FnOnce(&mut Self) {
2073+
let p = self.code.code.len();
2074+
self.emit(Opcode::OP_FAST_CALL, &[0], false);
2075+
2076+
move |this: &mut Self| {
2077+
// this.emit(Opcode::OP_NOP, &[], false);
2078+
let to = this.code.code.len() - (p + 5);
2079+
let bytes = (to as u32).to_le_bytes();
2080+
this.code.code[p] = Opcode::OP_FAST_CALL as u8;
2081+
this.code.code[p + 1] = bytes[0];
2082+
this.code.code[p + 2] = bytes[1];
2083+
this.code.code[p + 3] = bytes[2];
2084+
this.code.code[p + 4] = bytes[3];
2085+
//this.code.code[p] = ins as u8;
2086+
}
2087+
}
2088+
21102089
pub fn jmp_custom(&mut self, op: Opcode) -> impl FnOnce(&mut Self) {
21112090
let p = self.code.code.len();
21122091
self.emit(op, &[0], false);

crates/starlight/src/tracingjit/tracing_interpreter.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::{
2020
use crate::{bytecode::*, gc::cell::Tracer};
2121
use profile::{ArithProfile, ByValProfile};
2222
use std::intrinsics::{likely, unlikely};
23+
use std::ptr::null_mut;
2324
use wtf_rs::unwrap_unchecked;
2425

2526
pub enum RecordResult {
@@ -88,6 +89,7 @@ pub unsafe fn eval(
8889
let stack = &mut rt.stack as *mut Stack;
8990
let stack = &mut *stack;
9091
let gcstack = rt.shadowstack();
92+
let mut last_fast_call_ip = null_mut();
9193
loop {
9294
// if trace is too large we do not want to compile it. Just return to interpreting.
9395
if trace.len() > MAX_TRACE_SIZE {
@@ -172,7 +174,13 @@ pub unsafe fn eval(
172174

173175
frame.push(JsValue::new(env));
174176
}
175-
177+
Opcode::OP_FAST_CALL => {
178+
rt.heap().collect_if_necessary();
179+
let offset = ip.cast::<i32>().read();
180+
ip = ip.add(4);
181+
last_fast_call_ip = ip;
182+
ip = ip.offset(offset as isize);
183+
}
176184
Opcode::OP_JMP => {
177185
// XXX: we do not need to record jumps?
178186
rt.heap().collect_if_necessary();
@@ -237,6 +245,14 @@ pub unsafe fn eval(
237245
trace.push((sip, Ir::PushN));
238246
frame.push(JsValue::encode_null_value());
239247
}
248+
Opcode::OP_FAST_RET => {
249+
if last_fast_call_ip.is_null(){
250+
continue;
251+
} else {
252+
ip = last_fast_call_ip;
253+
last_fast_call_ip = null_mut();
254+
}
255+
}
240256
Opcode::OP_RET => {
241257
trace.push((sip, Ir::LeaveFrame));
242258
let mut value = if frame.sp <= frame.limit {

crates/starlight/src/vm/interpreter.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::{
1919
use crate::{bytecode::*, gc::cell::Tracer};
2020
use profile::{ArithProfile, ByValProfile};
2121
use std::intrinsics::{likely, unlikely};
22+
use std::ptr::null_mut;
2223
use wtf_rs::unwrap_unchecked;
2324
pub mod frame;
2425
pub mod stack;
@@ -243,6 +244,8 @@ pub unsafe fn eval(rt: &mut Runtime, frame: *mut CallFrame) -> Result<JsValue, J
243244
let stack = &mut rt.stack as *mut Stack;
244245
let stack = &mut *stack;
245246
let gcstack = rt.shadowstack();
247+
let mut last_fast_call_ip:*mut u8 = null_mut();
248+
246249
loop {
247250
let opcode = ip.cast::<Opcode>().read_unaligned();
248251
ip = ip.add(1);
@@ -337,7 +340,13 @@ pub unsafe fn eval(rt: &mut Runtime, frame: *mut CallFrame) -> Result<JsValue, J
337340

338341
frame.push(JsValue::new(env));
339342
}
340-
343+
Opcode::OP_FAST_CALL => {
344+
rt.heap().collect_if_necessary();
345+
let offset = ip.cast::<i32>().read();
346+
ip = ip.add(4);
347+
last_fast_call_ip = ip;
348+
ip = ip.offset(offset as isize);
349+
}
341350
Opcode::OP_JMP => {
342351
rt.heap().collect_if_necessary();
343352
let offset = ip.cast::<i32>().read();
@@ -392,6 +401,14 @@ pub unsafe fn eval(rt: &mut Runtime, frame: *mut CallFrame) -> Result<JsValue, J
392401
Opcode::OP_PUSH_NULL => {
393402
frame.push(JsValue::encode_null_value());
394403
}
404+
Opcode::OP_FAST_RET => {
405+
if last_fast_call_ip.is_null(){
406+
continue;
407+
} else {
408+
ip = last_fast_call_ip;
409+
last_fast_call_ip = null_mut();
410+
}
411+
}
395412
Opcode::OP_RET => {
396413
let mut value = if frame.sp <= frame.limit {
397414
JsValue::encode_undefined_value()

0 commit comments

Comments
 (0)