From 281a7bdca3253360fd1195aac96ce840c061f563 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 7 Oct 2024 21:42:06 +0200 Subject: [PATCH] rework constants with SoA --- Cargo.lock | 8 + crates/dash_compiler/Cargo.toml | 1 + crates/dash_compiler/src/instruction.rs | 96 +++++++--- crates/dash_compiler/src/lib.rs | 50 +++--- crates/dash_decompiler/src/decompiler.rs | 113 ++++++------ crates/dash_decompiler/src/lib.rs | 4 +- .../dash_llvm_jit_backend/src/codegen/mod.rs | 16 +- crates/dash_llvm_jit_backend/src/trace.rs | 2 +- crates/dash_middle/Cargo.toml | 1 + crates/dash_middle/src/compiler/constant.rs | 134 +++++--------- .../dash_middle/src/compiler/instruction.rs | 9 +- crates/dash_middle/src/compiler/mod.rs | 2 +- crates/dash_middle/src/indexvec.rs | 105 +++++++++++ crates/dash_middle/src/lib.rs | 3 +- .../dash_typed_cfg/src/passes/type_infer.rs | 31 ++-- crates/dash_typed_cfg/src/util.rs | 9 +- crates/dash_vm/src/dispatch.rs | 167 +++++++++++++----- crates/dash_vm/src/frame.rs | 2 +- crates/dash_vm/src/gc/trace.rs | 37 ++-- crates/dash_vm/src/jit/mod.rs | 32 ++-- crates/dash_vm/src/jit/query.rs | 39 ++-- crates/dash_vm/src/value/mod.rs | 78 -------- 22 files changed, 524 insertions(+), 415 deletions(-) create mode 100644 crates/dash_middle/src/indexvec.rs diff --git a/Cargo.lock b/Cargo.lock index 0ec720c3..e9acf9f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -414,6 +414,7 @@ dependencies = [ "dash_middle", "dash_optimizer", "dash_parser", + "dash_regex", "rustc-hash", "strum", "strum_macros", @@ -486,6 +487,7 @@ dependencies = [ "smallvec", "strum", "strum_macros", + "thin-vec", ] [[package]] @@ -2161,6 +2163,12 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +[[package]] +name = "thin-vec" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" + [[package]] name = "thiserror" version = "1.0.63" diff --git a/crates/dash_compiler/Cargo.toml b/crates/dash_compiler/Cargo.toml index 145a5639..4696b1e7 100644 --- a/crates/dash_compiler/Cargo.toml +++ b/crates/dash_compiler/Cargo.toml @@ -10,6 +10,7 @@ from_string = ["dash_parser", "dash_lexer"] decompile = [] [dependencies] +dash_regex = { path = "../dash_regex" } dash_middle = { path = "../dash_middle" } strum = "0.24.0" strum_macros = "0.24.0" diff --git a/crates/dash_compiler/src/instruction.rs b/crates/dash_compiler/src/instruction.rs index 6b2f9461..12427849 100755 --- a/crates/dash_compiler/src/instruction.rs +++ b/crates/dash_compiler/src/instruction.rs @@ -1,4 +1,8 @@ -use dash_middle::compiler::constant::{Constant, LimitExceededError}; +use std::rc::Rc; + +use dash_middle::compiler::constant::{ + BooleanConstant, Function, FunctionConstant, LimitExceededError, NumberConstant, RegexConstant, SymbolConstant, +}; use dash_middle::compiler::instruction::{AssignKind, Instruction, IntrinsicOperation}; use dash_middle::compiler::{ ExportPropertyKind, FunctionCallMetadata, ObjectMemberKind as CompilerObjectMemberKind, StaticImportKind, @@ -81,12 +85,6 @@ impl<'cx, 'interner> InstructionBuilder<'cx, 'interner> { self.writew(tc_depth); } - pub fn build_constant(&mut self, constant: Constant) -> Result<(), LimitExceededError> { - let id = self.current_function_mut().cp.add(constant)?; - self.write_wide_instr(Instruction::Constant, Instruction::ConstantW, id); - Ok(()) - } - pub fn write_bool(&mut self, b: bool) { self.write(b.into()); } @@ -112,15 +110,67 @@ impl<'cx, 'interner> InstructionBuilder<'cx, 'interner> { compile_local_load_into(&mut self.current_function_mut().buf, index, is_extern); } + pub fn build_string_constant(&mut self, sym: Symbol) -> Result<(), LimitExceededError> { + let SymbolConstant(id) = self.current_function_mut().cp.add_symbol(sym)?; + self.write_instr(Instruction::String); + self.writew(id); + Ok(()) + } + + pub fn build_boolean_constant(&mut self, b: bool) -> Result<(), LimitExceededError> { + let BooleanConstant(id) = self.current_function_mut().cp.add_boolean(b)?; + self.write_instr(Instruction::Boolean); + self.writew(id); + Ok(()) + } + + pub fn build_number_constant(&mut self, n: f64) -> Result<(), LimitExceededError> { + let NumberConstant(id) = self.current_function_mut().cp.add_number(n)?; + self.write_instr(Instruction::Number); + self.writew(id); + Ok(()) + } + + pub fn build_regex_constant( + &mut self, + regex: dash_regex::ParsedRegex, + flags: dash_regex::Flags, + sym: Symbol, + ) -> Result<(), LimitExceededError> { + let RegexConstant(id) = self.current_function_mut().cp.add_regex((regex, flags, sym))?; + self.write_instr(Instruction::Regex); + self.writew(id); + Ok(()) + } + + pub fn build_null_constant(&mut self) -> Result<(), LimitExceededError> { + self.write_instr(Instruction::Null); + Ok(()) + } + + pub fn build_undefined_constant(&mut self) -> Result<(), LimitExceededError> { + self.write_instr(Instruction::Undefined); + Ok(()) + } + + pub fn build_function_constant(&mut self, fun: Function) -> Result<(), LimitExceededError> { + let FunctionConstant(id) = self.current_function_mut().cp.add_function(Rc::new(fun))?; + self.write_instr(Instruction::Function); + self.writew(id); + Ok(()) + } + + // pub fn build_boolean_constant(&mut self, b: bool) -> Result< + pub fn build_global_load(&mut self, ident: Symbol) -> Result<(), LimitExceededError> { - let id = self.current_function_mut().cp.add(Constant::Identifier(ident))?; + let SymbolConstant(id) = self.current_function_mut().cp.add_symbol(ident)?; self.write_instr(Instruction::LdGlobal); self.writew(id); Ok(()) } pub fn build_global_store(&mut self, kind: AssignKind, ident: Symbol) -> Result<(), LimitExceededError> { - let id = self.current_function_mut().cp.add(Constant::Identifier(ident))?; + let SymbolConstant(id) = self.current_function_mut().cp.add_symbol(ident)?; self.write_wide_instr(Instruction::StoreGlobal, Instruction::StoreGlobalW, id); self.write(kind as u8); Ok(()) @@ -196,7 +246,7 @@ impl<'cx, 'interner> InstructionBuilder<'cx, 'interner> { } pub fn build_static_prop_access(&mut self, ident: Symbol, preserve_this: bool) -> Result<(), LimitExceededError> { - let id = self.current_function_mut().cp.add(Constant::Identifier(ident))?; + let SymbolConstant(id) = self.current_function_mut().cp.add_symbol(ident)?; self.write_instr(Instruction::StaticPropAccess); self.writew(id); self.write(preserve_this.into()); @@ -210,7 +260,7 @@ impl<'cx, 'interner> InstructionBuilder<'cx, 'interner> { } pub fn build_static_prop_assign(&mut self, kind: AssignKind, ident: Symbol) -> Result<(), LimitExceededError> { - let id = self.current_function_mut().cp.add(Constant::Identifier(ident))?; + let SymbolConstant(id) = self.current_function_mut().cp.add_symbol(ident)?; self.write_instr(Instruction::StaticPropAssign); self.write(kind as u8); self.writew(id); @@ -255,10 +305,10 @@ impl<'cx, 'interner> InstructionBuilder<'cx, 'interner> { name: Symbol, kind_id: u8, ) -> Result<(), Error> { - let id = ib + let SymbolConstant(id) = ib .current_function_mut() .cp - .add(Constant::Identifier(name)) + .add_symbol(name) .map_err(|_| Error::ConstantPoolLimitExceeded(span))?; ib.write(kind_id); @@ -284,20 +334,20 @@ impl<'cx, 'interner> InstructionBuilder<'cx, 'interner> { Ok(()) } - pub fn build_static_import(&mut self, import: StaticImportKind, local_id: u16, path_id: u16) { + pub fn build_static_import(&mut self, import: StaticImportKind, local_id: u16, path_id: SymbolConstant) { self.write_instr(Instruction::ImportStatic); self.write(import as u8); self.writew(local_id); - self.writew(path_id); + self.writew(path_id.0); } pub fn build_dynamic_import(&mut self) { self.write_instr(Instruction::ImportDyn); } - pub fn build_static_delete(&mut self, id: u16) { + pub fn build_static_delete(&mut self, id: SymbolConstant) { self.write_instr(Instruction::DeletePropertyStatic); - self.writew(id); + self.writew(id.0); } pub fn build_named_export(&mut self, span: Span, it: &[NamedExportKind]) -> Result<(), Error> { @@ -315,11 +365,11 @@ impl<'cx, 'interner> InstructionBuilder<'cx, 'interner> { NamedExportKind::Local { loc_id, ident_id } => { self.write(ExportPropertyKind::Local as u8); self.writew(loc_id); - self.writew(ident_id); + self.writew(ident_id.0); } NamedExportKind::Global { ident_id } => { self.write(ExportPropertyKind::Global as u8); - self.writew(ident_id); + self.writew(ident_id.0); } } } @@ -546,10 +596,10 @@ impl<'cx, 'interner> InstructionBuilder<'cx, 'interner> { } pub fn build_typeof_global_ident(&mut self, at: Span, ident: Symbol) -> Result<(), Error> { - let id = self + let SymbolConstant(id) = self .current_function_mut() .cp - .add(Constant::Identifier(ident)) + .add_symbol(ident) .map_err(|_| Error::ConstantPoolLimitExceeded(at))?; self.write_instr(Instruction::TypeOfGlobalIdent); self.writew(id); @@ -559,8 +609,8 @@ impl<'cx, 'interner> InstructionBuilder<'cx, 'interner> { #[derive(Copy, Clone)] pub enum NamedExportKind { - Local { loc_id: u16, ident_id: u16 }, - Global { ident_id: u16 }, + Local { loc_id: u16, ident_id: SymbolConstant }, + Global { ident_id: SymbolConstant }, } pub fn compile_local_load_into(out: &mut Vec, index: u16, is_extern: bool) { diff --git a/crates/dash_compiler/src/lib.rs b/crates/dash_compiler/src/lib.rs index 54985e47..2a7df317 100644 --- a/crates/dash_compiler/src/lib.rs +++ b/crates/dash_compiler/src/lib.rs @@ -4,7 +4,7 @@ use std::mem; use std::rc::Rc; use dash_log::{debug, span, Level}; -use dash_middle::compiler::constant::{Buffer, Constant, ConstantPool, Function}; +use dash_middle::compiler::constant::{Buffer, ConstantPool, Function, NumberConstant, SymbolConstant}; use dash_middle::compiler::external::External; use dash_middle::compiler::instruction::{AssignKind, Instruction, IntrinsicOperation}; use dash_middle::compiler::scope::{CompileValueType, LimitExceededError, Local, ScopeGraph}; @@ -64,9 +64,7 @@ enum Breakable { struct FunctionLocalState { /// Instruction buffer buf: Vec, - /// A list of constants used throughout this function. - /// - /// Bytecode can refer to constants using the [Instruction::Constant] instruction, followed by a u8 index. + /// A list of constants used throughout this function cp: ConstantPool, /// Current `try` depth (note that this does NOT include `catch`es) try_depth: u16, @@ -107,7 +105,7 @@ impl FunctionLocalState { pub fn new(ty: FunctionKind, id: ScopeId) -> Self { Self { buf: Vec::new(), - cp: ConstantPool::new(), + cp: ConstantPool::default(), try_depth: 0, finally_labels: Vec::new(), finally_counter: Counter::new(), @@ -717,11 +715,17 @@ impl<'interner> Visitor> for FunctionCompiler<'interner> { } fn visit_literal_expression(&mut self, span: Span, expr: LiteralExpr) -> Result<(), Error> { - let constant = Constant::from_literal(&expr); - InstructionBuilder::new(self) - .build_constant(constant) - .map_err(|_| Error::ConstantPoolLimitExceeded(span))?; - Ok(()) + let mut ib = InstructionBuilder::new(self); + let res = match expr { + LiteralExpr::Boolean(b) => ib.build_boolean_constant(b), + LiteralExpr::Number(n) => ib.build_number_constant(n), + LiteralExpr::String(s) => ib.build_string_constant(s), + LiteralExpr::Identifier(_) => unreachable!("identifiers are handled in visit_identifier_expression"), + LiteralExpr::Regex(regex, flags, sym) => ib.build_regex_constant(regex, flags, sym), + LiteralExpr::Null => ib.build_null_constant(), + LiteralExpr::Undefined => ib.build_undefined_constant(), + }; + res.map_err(|_| Error::ConstantPoolLimitExceeded(span)) } fn visit_identifier_expression(&mut self, span: Span, ident: Symbol) -> Result<(), Error> { @@ -782,7 +786,7 @@ impl<'interner> Visitor> for FunctionCompiler<'interner> { let id = ib .current_function_mut() .cp - .add(Constant::Identifier(ident)) + .add_symbol(ident) .map_err(|_| Error::ConstantPoolLimitExceeded(span))?; ib.build_static_delete(id); } @@ -797,12 +801,12 @@ impl<'interner> Visitor> for FunctionCompiler<'interner> { let id = ib .current_function_mut() .cp - .add(Constant::Identifier(ident)) + .add_symbol(ident) .map_err(|_| Error::ConstantPoolLimitExceeded(span))?; ib.build_static_delete(id); } _ => { - ib.build_constant(Constant::Boolean(true)) + ib.build_boolean_constant(true) .map_err(|_| Error::ConstantPoolLimitExceeded(span))?; } } @@ -876,15 +880,15 @@ impl<'interner> Visitor> for FunctionCompiler<'interner> { let name = alias.unwrap_or(name); let id = ib.find_local_from_binding(Binding { id: local, ident: name }); - let var_id = ib + let NumberConstant(var_id) = ib .current_function_mut() .cp - .add(Constant::Number(id as f64)) + .add_number(id as f64) .map_err(|_| Error::ConstantPoolLimitExceeded(span))?; - let ident_id = ib + let SymbolConstant(ident_id) = ib .current_function_mut() .cp - .add(Constant::Identifier(name)) + .add_symbol(name) .map_err(|_| Error::ConstantPoolLimitExceeded(span))?; ib.writew(var_id); ib.writew(ident_id); @@ -910,10 +914,10 @@ impl<'interner> Visitor> for FunctionCompiler<'interner> { if let Some(name) = name { let id = ib.find_local_from_binding(name); - let id = ib + let NumberConstant(id) = ib .current_function_mut() .cp - .add(Constant::Number(id as f64)) + .add_number(id as f64) .map_err(|_| Error::ConstantPoolLimitExceeded(span))?; ib.writew(id); @@ -1765,7 +1769,7 @@ impl<'interner> Visitor> for FunctionCompiler<'interner> { let function = Function { buffer: Buffer(Cell::new(cmp.buf.into())), - constants: cmp.cp.into_vec().into(), + constants: cmp.cp, locals, name: name.map(|binding| binding.ident), ty, @@ -1780,7 +1784,7 @@ impl<'interner> Visitor> for FunctionCompiler<'interner> { source: Rc::clone(&ib.source), references_arguments: cmp.references_arguments.is_some(), }; - ib.build_constant(Constant::Function(Rc::new(function))) + ib.build_function_constant(function) .map_err(|_| Error::ConstantPoolLimitExceeded(span))?; Ok(()) @@ -1988,7 +1992,7 @@ impl<'interner> Visitor> for FunctionCompiler<'interner> { let path_id = ib .current_function_mut() .cp - .add(Constant::String(path)) + .add_symbol(path) .map_err(|_| Error::ConstantPoolLimitExceeded(span))?; ib.build_static_import( @@ -2021,7 +2025,7 @@ impl<'interner> Visitor> for FunctionCompiler<'interner> { let ident_id = ib .current_function_mut() .cp - .add(Constant::Identifier(name)) + .add_symbol(name) .map_err(|_| Error::ConstantPoolLimitExceeded(span))?; match ib.find_local(name) { diff --git a/crates/dash_decompiler/src/decompiler.rs b/crates/dash_decompiler/src/decompiler.rs index 5ec114e2..8edd513e 100644 --- a/crates/dash_decompiler/src/decompiler.rs +++ b/crates/dash_decompiler/src/decompiler.rs @@ -1,4 +1,4 @@ -use dash_middle::compiler::constant::Constant; +use dash_middle::compiler::constant::{ConstantPool, FunctionConstant, SymbolConstant}; use dash_middle::compiler::instruction::{Instruction, IntrinsicOperation}; use dash_middle::compiler::{FunctionCallMetadata, ObjectMemberKind}; use dash_middle::interner::StringInterner; @@ -12,7 +12,7 @@ use crate::DecompileError; pub struct FunctionDecompiler<'interner, 'buf> { interner: &'interner StringInterner, reader: Reader<&'buf [u8]>, - constants: &'buf [Constant], + constants: &'buf ConstantPool, name: &'buf str, out: String, /// Index of the current instruction in the bytecode @@ -23,7 +23,7 @@ impl<'interner, 'buf> FunctionDecompiler<'interner, 'buf> { pub fn new( interner: &'interner StringInterner, buf: &'buf [u8], - constants: &'buf [Constant], + constants: &'buf ConstantPool, name: &'buf str, ) -> Self { Self { @@ -110,10 +110,6 @@ impl<'interner, 'buf> FunctionDecompiler<'interner, 'buf> { self.reader.read_u32_ne().ok_or(DecompileError::AbruptEof) } - fn display(&self, constant: &'buf Constant) -> DisplayConstant<'interner, 'buf> { - DisplayConstant(self.interner, constant) - } - pub fn run(mut self) -> Result { let mut functions = Vec::new(); @@ -138,22 +134,22 @@ impl<'interner, 'buf> FunctionDecompiler<'interner, 'buf> { Instruction::Eq => self.handle_opless_instr("eq"), Instruction::Ne => self.handle_opless_instr("ne"), Instruction::Pop => self.handle_opless_instr("pop"), - Instruction::Constant => { - let b = self.read()?; - let constant = &self.constants[b as usize]; - if let Constant::Function(fun) = constant { - functions.push(Rc::clone(fun)); - } - self.handle_op_instr("constant", &[&self.display(constant)]); - } - Instruction::ConstantW => { - let b = self.read_u16()?; - let constant = &self.constants[b as usize]; - if let Constant::Function(fun) = constant { - functions.push(Rc::clone(fun)); - } - self.handle_op_instr("constant", &[&self.display(constant)]); + Instruction::Function => { + let id = self.read_u16()?; + let fun = Rc::clone(&self.constants.functions[FunctionConstant(id)]); + let name = match fun.name { + Some(sym) => self.interner.resolve(sym).to_owned(), + None => String::from(""), + }; + functions.push(fun); + self.handle_op_instr("function", &[&format_args!("function {name}")]); } + Instruction::String + | Instruction::Number + | Instruction::Boolean + | Instruction::Regex + | Instruction::Null + | Instruction::Undefined => todo!(), Instruction::LdLocal => { let b = self.read()?; // TODO: use debug symbols to find the name @@ -190,8 +186,12 @@ impl<'interner, 'buf> FunctionDecompiler<'interner, 'buf> { } Instruction::Arguments => self.handle_opless_instr("arguments"), Instruction::LdGlobal => { - let b = self.read_i16()?; - self.handle_op_instr("ldglobal", &[&self.display(&self.constants[b as usize])]); + let b = self.read_u16()?; + let ident = self + .interner + .resolve(self.constants.symbols[SymbolConstant(b)]) + .to_owned(); + self.handle_op_instr("ldglobal", &[&ident]); } Instruction::StoreLocal => self.handle_inc_op_instr2("storelocal")?, Instruction::StoreLocalW => self.handle_inc_op_instr2("storelocalw")?, @@ -206,9 +206,13 @@ impl<'interner, 'buf> FunctionDecompiler<'interner, 'buf> { ); } Instruction::StaticPropAccess => { - let b = self.read_i16()?; + let b = self.read_u16()?; let _preserve_this = self.read()?; - self.handle_op_instr("staticpropaccess", &[&self.display(&self.constants[b as usize])]); + let ident = self + .interner + .resolve(self.constants.symbols[SymbolConstant(b)]) + .to_owned(); + self.handle_op_instr("staticpropaccess", &[&ident]); } Instruction::Ret => { self.read_u16()?; // intentionally ignored @@ -219,20 +223,32 @@ impl<'interner, 'buf> FunctionDecompiler<'interner, 'buf> { Instruction::Neg => self.handle_opless_instr("neg"), Instruction::TypeOfGlobalIdent => { let id = self.read_u16()?; - self.handle_op_instr("typeof", &[&self.display(&self.constants[id as usize])]); + let ident = self + .interner + .resolve(self.constants.symbols[SymbolConstant(id)]) + .to_owned(); + self.handle_op_instr("typeof", &[&ident]); } Instruction::TypeOf => self.handle_opless_instr("typeof"), Instruction::BitNot => self.handle_opless_instr("bitnot"), Instruction::Not => self.handle_opless_instr("not"), Instruction::StoreGlobal => { let b = self.read()?; - let _kind = self.read(); - self.handle_op_instr("storeglobal", &[&self.display(&self.constants[b as usize])]); + let _kind = self.read()?; + let ident = self + .interner + .resolve(self.constants.symbols[SymbolConstant(b as u16)]) + .to_owned(); + self.handle_op_instr("storeglobal", &[&ident]); } Instruction::StoreGlobalW => { let b = self.read_u16()?; - let _kind = self.read(); - self.handle_op_instr("storeglobalw", &[&self.display(&self.constants[b as usize])]); + let _kind = self.read()?; + let ident = self + .interner + .resolve(self.constants.symbols[SymbolConstant(b)]) + .to_owned(); + self.handle_op_instr("storeglobalw", &[&ident]); } Instruction::DynamicPropAccess => { let b = self.read()?; @@ -253,7 +269,11 @@ impl<'interner, 'buf> FunctionDecompiler<'interner, 'buf> { } ObjectMemberKind::Static | ObjectMemberKind::Getter | ObjectMemberKind::Setter => { let cid = self.read_u16()?; - props.push(self.display(&self.constants[cid as usize]).to_string()); + let ident = self + .interner + .resolve(self.constants.symbols[SymbolConstant(cid)]) + .to_owned(); + props.push(ident); } ObjectMemberKind::Spread => { props.push(String::from("")); @@ -269,7 +289,11 @@ impl<'interner, 'buf> FunctionDecompiler<'interner, 'buf> { Instruction::StaticPropAssign => { let _k = self.read()?; let b = self.read_u16()?; - self.handle_op_instr("staticpropassign", &[&self.display(&self.constants[b as usize])]); + let ident = self + .interner + .resolve(self.constants.symbols[SymbolConstant(b)]) + .to_owned(); + self.handle_op_instr("staticpropassign", &[&ident]); } Instruction::DynamicPropAssign => { let _k = self.read()?; @@ -430,26 +454,3 @@ impl<'interner, 'buf> FunctionDecompiler<'interner, 'buf> { Ok(self.out) } } - -struct DisplayConstant<'i, 'a>(&'i StringInterner, &'a Constant); -impl fmt::Display for DisplayConstant<'_, '_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.1 { - Constant::Number(n) => write!(f, "{n}"), - Constant::String(s) => write!(f, "\"{}\"", self.0.resolve(*s)), - Constant::Boolean(b) => write!(f, "{b}"), - Constant::Identifier(ident) => write!(f, "{}", self.0.resolve(*ident)), - Constant::Function(fun) => write!( - f, - "", - fun.name.map(|v| self.0.resolve(v)).unwrap_or("") - ), - Constant::Null => f.write_str("null"), - Constant::Undefined => f.write_str("undefined"), - Constant::Regex(regex) => { - let (_, _, sym) = &**regex; - write!(f, "{}", self.0.resolve(*sym)) - } - } - } -} diff --git a/crates/dash_decompiler/src/lib.rs b/crates/dash_decompiler/src/lib.rs index c15ebbcc..ba968808 100644 --- a/crates/dash_decompiler/src/lib.rs +++ b/crates/dash_decompiler/src/lib.rs @@ -1,4 +1,4 @@ -use dash_middle::compiler::constant::Constant; +use dash_middle::compiler::constant::ConstantPool; use dash_middle::compiler::instruction::Instruction; use dash_middle::interner::StringInterner; use decompiler::FunctionDecompiler; @@ -22,7 +22,7 @@ pub enum DecompileError { pub fn decompile( interner: &StringInterner, - constants: &[Constant], + constants: &ConstantPool, instructions: &[u8], ) -> Result { FunctionDecompiler::new(interner, instructions, constants, "
").run() diff --git a/crates/dash_llvm_jit_backend/src/codegen/mod.rs b/crates/dash_llvm_jit_backend/src/codegen/mod.rs index b3f1d741..71e50ef4 100644 --- a/crates/dash_llvm_jit_backend/src/codegen/mod.rs +++ b/crates/dash_llvm_jit_backend/src/codegen/mod.rs @@ -1,5 +1,6 @@ use std::collections::{HashMap, HashSet}; +use dash_middle::compiler::constant::{BooleanConstant, NumberConstant}; use dash_middle::compiler::instruction::{AssignKind, Instruction, IntrinsicOperation}; use dash_typed_cfg::passes::bb_generation::{ BasicBlockKey, BasicBlockMap, BasicBlockSuccessor, ConditionalBranchAction, @@ -106,7 +107,8 @@ impl JitConstant { } pub trait CodegenQuery { - fn get_constant(&self, cid: u16) -> JitConstant; + fn boolean_constant(&self, id: BooleanConstant) -> bool; + fn number_constant(&self, id: NumberConstant) -> f64; } pub struct CodegenCtxt<'a, 'q, Q> { @@ -332,11 +334,13 @@ impl<'a, 'q, Q: CodegenQuery> CodegenCtxt<'a, 'q, Q> { let value = self.load_local(id.into()); stack.push(value); } - Instruction::Constant => { - let cid = dcx.next_byte(); - let constant = self.query.get_constant(cid.into()); - stack.push(constant.to_llvm_value(&self.llcx)); - } + Instruction::Boolean + | Instruction::Number + | Instruction::String + | Instruction::Regex + | Instruction::Null + | Instruction::Undefined + | Instruction::Function => todo!(), Instruction::Pop => drop(stack.pop()), Instruction::Jmp => { let bb = &self.bb_map[&bbk]; diff --git a/crates/dash_llvm_jit_backend/src/trace.rs b/crates/dash_llvm_jit_backend/src/trace.rs index 6a85e2cc..328c85ed 100644 --- a/crates/dash_llvm_jit_backend/src/trace.rs +++ b/crates/dash_llvm_jit_backend/src/trace.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use dash_middle::compiler::constant::{Constant, Function}; +use dash_middle::compiler::constant::Function; use dash_middle::compiler::instruction as inst; use dash_typed_cfg::passes::bb_generation::ConditionalBranchAction; use indexmap::IndexMap; diff --git a/crates/dash_middle/Cargo.toml b/crates/dash_middle/Cargo.toml index ed0ee864..7037c61e 100644 --- a/crates/dash_middle/Cargo.toml +++ b/crates/dash_middle/Cargo.toml @@ -24,3 +24,4 @@ rustc-hash = "1.1.0" memchr = "2.5.0" owo-colors = "3.5.0" dash_proc_macro = { path = "../dash_proc_macro" } +thin-vec = "0.2.13" diff --git a/crates/dash_middle/src/compiler/constant.rs b/crates/dash_middle/src/compiler/constant.rs index e8ccda7c..d96c05d7 100755 --- a/crates/dash_middle/src/compiler/constant.rs +++ b/crates/dash_middle/src/compiler/constant.rs @@ -1,14 +1,13 @@ use core::fmt; use std::cell::{Cell, RefCell}; use std::collections::HashSet; -use std::ops::Deref; use std::rc::Rc; -#[cfg(feature = "format")] -use serde::{Deserialize, Serialize}; +use dash_regex::{Flags, ParsedRegex}; +use crate::index_type; +use crate::indexvec::IndexThinVec; use crate::interner::Symbol; -use crate::parser::expr::LiteralExpr; use crate::parser::statement::FunctionKind; use super::external::External; @@ -35,7 +34,7 @@ impl Buffer { } #[cfg(feature = "format")] -impl Serialize for Buffer { +impl serde::Serialize for Buffer { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, @@ -45,7 +44,7 @@ impl Serialize for Buffer { } #[cfg(feature = "format")] -impl<'de> Deserialize<'de> for Buffer { +impl<'de> serde::Deserialize<'de> for Buffer { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -66,7 +65,7 @@ impl Clone for Buffer { } } -#[cfg_attr(feature = "format", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "format", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, Clone)] pub struct Function { pub name: Option, @@ -74,7 +73,7 @@ pub struct Function { pub ty: FunctionKind, pub locals: usize, pub params: usize, - pub constants: Box<[Constant]>, + pub constants: ConstantPool, pub externals: Box<[External]>, /// If the parameter list uses the rest operator ..., then this will be Some(local_id) pub rest_local: Option, @@ -95,97 +94,44 @@ impl Function { self.poison_ips.borrow().contains(&ip) } } - -#[cfg_attr(feature = "format", derive(Serialize, Deserialize))] -#[derive(Debug, Clone)] -pub enum Constant { - Number(f64), - String(Symbol), - Identifier(Symbol), - Boolean(bool), - Function(Rc), - // Boxed because this otherwise bloats the enum way too much. - // This makes evaluating regex constants slower but they're *far* less common than e.g. number literals - // TODO: avoid cloning `Constant`s when turning them into Values, - // because there's no point in cloning this box - Regex(Box<(dash_regex::ParsedRegex, dash_regex::Flags, Symbol)>), - Null, - Undefined, -} - -impl Constant { - pub fn as_number(&self) -> Option { - match self { - Constant::Number(n) => Some(*n), - _ => None, - } - } - - pub fn as_string(&self) -> Option { - match self { - Constant::String(s) => Some(*s), - _ => None, - } - } - - pub fn as_identifier(&self) -> Option { - match self { - Constant::Identifier(s) => Some(*s), - _ => None, - } - } - - pub fn as_boolean(&self) -> Option { - match self { - Constant::Boolean(b) => Some(*b), - _ => None, - } - } - - pub fn from_literal(expr: &LiteralExpr) -> Self { - match expr { - LiteralExpr::Number(n) => Self::Number(*n), - LiteralExpr::Identifier(s) => Self::Identifier(*s), - LiteralExpr::String(s) => Self::String(*s), - LiteralExpr::Boolean(b) => Self::Boolean(*b), - LiteralExpr::Null => Self::Null, - LiteralExpr::Undefined => Self::Undefined, - LiteralExpr::Regex(regex, flags, source) => Self::Regex(Box::new((regex.clone(), *flags, *source))), - } - } -} - -#[cfg_attr(feature = "format", derive(Serialize, Deserialize))] -#[derive(Debug, Clone, Default)] +index_type!(NumberConstant u16); +index_type!(BooleanConstant u16); +index_type!(FunctionConstant u16); +index_type!(RegexConstant u16); +index_type!(SymbolConstant u16); + +#[cfg_attr(feature = "format", derive(serde::Serialize, serde::Deserialize))] +#[derive(Default, Debug, Clone)] pub struct ConstantPool { - constants: Vec, + pub numbers: IndexThinVec, + /// Strings and identifiers + pub symbols: IndexThinVec, + pub booleans: IndexThinVec, + pub functions: IndexThinVec, FunctionConstant>, + pub regexes: IndexThinVec<(ParsedRegex, Flags, Symbol), RegexConstant>, } pub struct LimitExceededError; -impl ConstantPool { - pub fn new() -> Self { - Self::default() - } - pub fn add(&mut self, constant: Constant) -> Result { - if self.constants.len() > u16::MAX as usize { - Err(LimitExceededError) - } else { - let id = self.constants.len() as u16; - self.constants.push(constant); - Ok(id) - } - } - - pub fn into_vec(self) -> Vec { - self.constants - } +macro_rules! define_push_methods { + ($($method:ident($field:ident, $valty:ty) -> $constant:ty),*) => { + $( + pub fn $method( + &mut self, + val: $valty, + ) -> Result<$constant, LimitExceededError> { + self.$field.try_push(val).map_err(|_| LimitExceededError) + } + )* + }; } -impl Deref for ConstantPool { - type Target = [Constant]; - - fn deref(&self) -> &Self::Target { - &self.constants - } +impl ConstantPool { + define_push_methods!( + add_number(numbers, f64) -> NumberConstant, + add_symbol(symbols, Symbol) -> SymbolConstant, + add_boolean(booleans, bool) -> BooleanConstant, + add_function(functions, Rc) -> FunctionConstant, + add_regex(regexes, (ParsedRegex, Flags, Symbol)) -> RegexConstant + ); } diff --git a/crates/dash_middle/src/compiler/instruction.rs b/crates/dash_middle/src/compiler/instruction.rs index 74a801d9..9f205cef 100644 --- a/crates/dash_middle/src/compiler/instruction.rs +++ b/crates/dash_middle/src/compiler/instruction.rs @@ -22,8 +22,13 @@ pub enum Instruction { LdLocal, LdLocalW, LdGlobal, - Constant, - ConstantW, + String, + Boolean, + Number, + Regex, + Null, + Undefined, + Function, Pos, Neg, TypeOf, diff --git a/crates/dash_middle/src/compiler/mod.rs b/crates/dash_middle/src/compiler/mod.rs index 32a8ba56..58eccac9 100644 --- a/crates/dash_middle/src/compiler/mod.rs +++ b/crates/dash_middle/src/compiler/mod.rs @@ -1,11 +1,11 @@ use std::rc::Rc; +use constant::ConstantPool; use strum_macros::FromRepr; use crate::parser; use crate::sourcemap::Span; -use self::constant::ConstantPool; use self::external::External; #[cfg(feature = "format")] diff --git a/crates/dash_middle/src/indexvec.rs b/crates/dash_middle/src/indexvec.rs new file mode 100644 index 00000000..161e3f8d --- /dev/null +++ b/crates/dash_middle/src/indexvec.rs @@ -0,0 +1,105 @@ +use std::marker::PhantomData; + +use thin_vec::ThinVec; + +pub trait Index: Copy + TryFrom + Into {} + +#[derive(Debug, Clone)] +pub struct IndexThinVec(ThinVec, PhantomData); + +impl IndexThinVec { + pub fn new() -> Self { + Self(ThinVec::new(), PhantomData) + } + + pub fn try_push(&mut self, element: T) -> Result>::Error> { + let len = self.0.len(); + self.0.push(element); + I::try_from(len) + } + + pub fn as_slice(&self) -> &[T] { + &self.0 + } +} +impl std::ops::Index for IndexThinVec { + type Output = T; + + fn index(&self, index: I) -> &Self::Output { + &self.0[Into::::into(index)] + } +} +impl Default for IndexThinVec { + fn default() -> Self { + Self(ThinVec::default(), PhantomData) + } +} + +#[macro_export] +macro_rules! index_type { + ($name:ident $repr:ty) => { + #[derive(Copy, Clone, Debug)] + pub struct $name(pub $repr); + + impl TryFrom for $name { + type Error = <$repr as TryFrom>::Error; + + fn try_from(value: usize) -> Result { + Ok(Self(<$repr>::try_from(value)?)) + } + } + impl From<$name> for usize { + fn from(v: $name) -> usize { + v.0.into() + } + } + + impl $crate::indexvec::Index for $name {} + }; +} + +impl Index for u16 {} + +#[cfg(feature = "format")] +impl serde::Serialize for IndexThinVec { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeSeq; + + let mut seq = serializer.serialize_seq(Some(self.0.len()))?; + for elem in self.0.iter() { + seq.serialize_element(elem)?; + } + seq.end() + } +} + +#[cfg(feature = "format")] +impl<'de, T: serde::Deserialize<'de>, I> serde::Deserialize<'de> for IndexThinVec { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct Vis(PhantomData<(T, I)>); + impl<'de, T: serde::Deserialize<'de>, I> serde::de::Visitor<'de> for Vis { + type Value = IndexThinVec; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a sequence") + } + fn visit_seq(self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + let mut data = ThinVec::with_capacity(seq.size_hint().unwrap_or_default()); + while let Some(elem) = seq.next_element::()? { + data.push(elem); + } + Ok(IndexThinVec(data, PhantomData)) + } + } + deserializer.deserialize_seq(Vis(PhantomData)) + } +} diff --git a/crates/dash_middle/src/lib.rs b/crates/dash_middle/src/lib.rs index 16ec83a8..4e935c2e 100644 --- a/crates/dash_middle/src/lib.rs +++ b/crates/dash_middle/src/lib.rs @@ -1,4 +1,5 @@ pub mod compiler; +pub mod indexvec; pub mod interner; pub mod iterator_with; pub mod lexer; @@ -7,5 +8,3 @@ pub mod sourcemap; pub mod tree; pub mod util; pub mod visitor; -// Unused for now. -// pub mod walker; diff --git a/crates/dash_typed_cfg/src/passes/type_infer.rs b/crates/dash_typed_cfg/src/passes/type_infer.rs index 2b56a4ed..543ab641 100644 --- a/crates/dash_typed_cfg/src/passes/type_infer.rs +++ b/crates/dash_typed_cfg/src/passes/type_infer.rs @@ -1,6 +1,8 @@ use std::collections::{HashMap, HashSet}; +use dash_middle::compiler::constant::NumberConstant; use dash_middle::compiler::instruction::{Instruction, IntrinsicOperation}; +use dash_middle::util::is_integer; use crate::error::Error; use crate::util::DecodeCtxt; @@ -18,7 +20,7 @@ pub enum Type { pub trait TypeInferQuery { fn type_of_local(&self, index: u16) -> Type; - fn type_of_constant(&self, index: u16) -> Type; + fn number_constant(&self, id: NumberConstant) -> f64; } #[derive(Clone, Default)] @@ -113,15 +115,24 @@ impl<'a, 'q, Q: TypeInferQuery> TypeInferCtxt<'a, 'q, Q> { let ty = self.get_or_insert_local_ty(index); ty_stack.push(ty); } - Instruction::Constant | Instruction::ConstantW => { - let index = match instr { - Instruction::Constant => dcx.next_byte().into(), - Instruction::ConstantW => dcx.next_wide(), - _ => unreachable!(), - }; - - let ty = self.query.type_of_constant(index); - ty_stack.push(ty); + Instruction::Boolean => { + dcx.next_wide(); + ty_stack.push(Type::Boolean); + } + Instruction::Number => { + let id = dcx.next_wide(); + ty_stack.push(if is_integer(self.query.number_constant(NumberConstant(id))) { + Type::I64 + } else { + Type::F64 + }); + } + Instruction::String + | Instruction::Regex + | Instruction::Null + | Instruction::Undefined + | Instruction::Function => { + todo!("unimplemented constant type: {instr:?}") } Instruction::StoreLocal | Instruction::StoreLocalW => { let index = match instr { diff --git a/crates/dash_typed_cfg/src/util.rs b/crates/dash_typed_cfg/src/util.rs index 9479d11c..b745387d 100644 --- a/crates/dash_typed_cfg/src/util.rs +++ b/crates/dash_typed_cfg/src/util.rs @@ -58,8 +58,13 @@ impl<'a> DecodeCtxt<'a> { | Instruction::Div | Instruction::Rem | Instruction::BitAnd => {} - Instruction::Constant => drop(self.next_byte()), - Instruction::ConstantW => drop(self.next_wide()), + Instruction::Boolean + | Instruction::Number + | Instruction::String + | Instruction::Regex + | Instruction::Null + | Instruction::Undefined + | Instruction::Function => drop(self.next_byte()), Instruction::LdLocal => drop(self.next_byte()), Instruction::LdLocalW => drop(self.next_wide()), Instruction::StoreLocal => { diff --git a/crates/dash_vm/src/dispatch.rs b/crates/dash_vm/src/dispatch.rs index 492ef727..90b053fb 100755 --- a/crates/dash_vm/src/dispatch.rs +++ b/crates/dash_vm/src/dispatch.rs @@ -1,4 +1,5 @@ use dash_log::warn; +use dash_middle::compiler::constant::{ConstantPool, NumberConstant, SymbolConstant}; use std::ops::{Deref, DerefMut}; use std::vec::Drain; @@ -9,7 +10,6 @@ use crate::value::{ExternalValue, Root, Unrooted}; use super::value::Value; use super::Vm; -use dash_middle::compiler::constant::Constant; use dash_middle::compiler::instruction::Instruction; #[derive(Debug)] @@ -153,28 +153,8 @@ impl<'vm> DispatchContext<'vm> { .expect("Dispatch Context attempted to reference missing frame") } - pub fn constant(&self, index: usize) -> &Constant { - &self.active_frame().function.constants[index] - } - - pub fn identifier_constant(&self, index: usize) -> JsString { - self.constant(index) - .as_identifier() - .expect("Bytecode attempted to reference invalid identifier constant") - .into() - } - - pub fn string_constant(&self, index: usize) -> JsString { - self.constant(index) - .as_string() - .expect("Bytecode attempted to reference invalid string constant") - .into() - } - - pub fn number_constant(&self, index: usize) -> f64 { - self.constant(index) - .as_number() - .expect("Bytecode attempted to reference invalid number constant") + pub fn constants(&self) -> &ConstantPool { + &self.active_frame().function.constants } } @@ -195,6 +175,7 @@ mod extract { use std::convert::Infallible; use std::marker::PhantomData; + use dash_middle::compiler::constant::{NumberConstant, SymbolConstant}; use dash_middle::compiler::{ArrayMemberKind, ExportPropertyKind, ObjectMemberKind}; use dash_middle::iterator_with::IteratorWith; @@ -315,7 +296,7 @@ mod extract { fn extract(cx: &mut DispatchContext<'_>) -> Result { let id = cx.fetchw_and_inc_ip(); - Ok(Self(cx.identifier_constant(id.into()))) + Ok(Self(cx.constants().symbols[SymbolConstant(id)].into())) } } @@ -326,7 +307,7 @@ mod extract { fn extract(cx: &mut DispatchContext<'_>) -> Result { let id = cx.fetchw_and_inc_ip(); - Ok(Self(cx.number_constant(id.into()))) + Ok(Self(cx.constants().numbers[NumberConstant(id)])) } } @@ -542,48 +523,137 @@ mod extract { } mod handlers { + use dash_middle::compiler::constant::{BooleanConstant, FunctionConstant, RegexConstant}; + use dash_middle::compiler::external::External; use dash_middle::compiler::instruction::{AssignKind, IntrinsicOperation}; use dash_middle::compiler::{FunctionCallMetadata, StaticImportKind}; use dash_middle::interner::sym; use dash_middle::iterator_with::{InfallibleIteratorWith, IteratorWith}; + use dash_middle::parser::statement::{Asyncness, FunctionKind as ParserFunctionKind}; use handlers::extract::{extract, ForwardSequence, FrontIteratorWith}; use hashbrown::hash_map::Entry; use if_chain::if_chain; use smallvec::SmallVec; use std::ops::{Add, ControlFlow, Div, Mul, Rem, Sub}; + use std::rc::Rc; use crate::frame::{FrameState, TryBlock}; use crate::throw; use crate::util::unlikely; use crate::value::array::{Array, ArrayIterator, Element}; + use crate::value::function::r#async::AsyncFunction; + use crate::value::function::closure::Closure; + use crate::value::function::generator::GeneratorFunction; use crate::value::function::user::UserFunction; use crate::value::function::{adjust_stack_from_flat_call, Function, FunctionKind}; use crate::value::object::{NamedObject, Object, ObjectMap, PropertyKey, PropertyValue, PropertyValueKind}; use crate::value::ops::conversions::ValueConversion; use crate::value::ops::equality; use crate::value::primitive::Number; + use crate::value::regex::RegExp; + use crate::value::ValueContext; use self::extract::{ArrayElement, BackwardSequence, ExportProperty, IdentW, NumberWConstant, ObjectProperty}; use super::*; - fn constant_instruction(mut cx: DispatchContext<'_>, idx: usize) -> Result<(), Value> { - let constant = cx.constant(idx); + pub fn string_constant(mut cx: DispatchContext<'_>) -> Result, Unrooted> { + let id = cx.fetchw_and_inc_ip(); + let sym = JsString::from(cx.constants().symbols[SymbolConstant(id)]); + cx.push_stack(Value::String(sym).into()); + Ok(None) + } - let value = Value::from_constant(constant.clone(), &mut cx); - cx.stack.push(value); - Ok(()) + pub fn boolean_constant(mut cx: DispatchContext<'_>) -> Result, Unrooted> { + let id = cx.fetchw_and_inc_ip(); + let b = cx.constants().booleans[BooleanConstant(id)]; + cx.push_stack(Value::Boolean(b).into()); + Ok(None) } - pub fn constant(mut cx: DispatchContext<'_>) -> Result, Unrooted> { - let id = cx.fetch_and_inc_ip(); - constant_instruction(cx, id as usize)?; + pub fn number_constant(mut cx: DispatchContext<'_>) -> Result, Unrooted> { + let id = cx.fetchw_and_inc_ip(); + let n = cx.constants().numbers[NumberConstant(id)]; + cx.push_stack(Value::number(n).into()); + Ok(None) + } + + pub fn regex_constant(mut cx: DispatchContext<'_>) -> Result, Unrooted> { + let id = cx.fetchw_and_inc_ip(); + let (nodes, flags, source) = &cx.constants().regexes[RegexConstant(id)]; + + let regex = RegExp::new(nodes.clone(), *flags, JsString::from(*source), &cx.scope); + let regex = cx.scope.register(regex); + cx.push_stack(Value::Object(regex).into()); + Ok(None) + } + + pub fn null_constant(mut cx: DispatchContext<'_>) -> Result, Unrooted> { + cx.push_stack(Value::null().into()); + Ok(None) + } + + pub fn undefined_constant(mut cx: DispatchContext<'_>) -> Result, Unrooted> { + cx.push_stack(Value::undefined().into()); Ok(None) } - pub fn constantw(mut cx: DispatchContext<'_>) -> Result, Unrooted> { + pub fn function_constant(mut cx: DispatchContext<'_>) -> Result, Unrooted> { + fn register_function_externals( + function: &dash_middle::compiler::constant::Function, + sc: &mut LocalScope<'_>, + ) -> Vec { + let mut externals = Vec::new(); + + for External { id, is_nested_external } in function.externals.iter().copied() { + let id = usize::from(id); + + let val = if is_nested_external { + sc.get_external(id).expect("Referenced local not found").clone() + } else { + let v = sc.get_local_raw(id).expect("Referenced local not found"); + + match v { + Value::External(v) => v, + other => { + // TODO: comment what's happening here -- Value -> Handle -> ExternaValue(..) + let ext = ExternalValue::new(sc.register(other)); + sc.set_local(id, Value::External(ext.clone()).into()); + ext + } + } + }; + + externals.push(val); + } + + externals + } + let id = cx.fetchw_and_inc_ip(); - constant_instruction(cx, id as usize)?; + let fun = Rc::clone(&cx.constants().functions[FunctionConstant(id)]); + + let externals = register_function_externals(&fun, &mut cx.scope); + + let name = fun.name.map(Into::into); + let ty = fun.ty; + + let fun = UserFunction::new(fun, externals.into()); + + let kind = match ty { + ParserFunctionKind::Function(Asyncness::Yes) => FunctionKind::Async(AsyncFunction::new(fun)), + ParserFunctionKind::Function(Asyncness::No) => FunctionKind::User(fun), + ParserFunctionKind::Arrow => FunctionKind::Closure(Closure { + fun, + this: cx.scope.active_frame().this.clone().unwrap_or_undefined(), + }), + ParserFunctionKind::Generator => FunctionKind::Generator(GeneratorFunction::new(fun)), + }; + + let function = Function::new(&cx.scope, name, kind); + let function = cx.scope.register(function); + cx.push_stack(Value::Object(function).into()); + Ok(None) } @@ -813,7 +883,7 @@ mod handlers { pub fn ldglobal(mut cx: DispatchContext<'_>) -> Result, Unrooted> { let id = cx.fetchw_and_inc_ip(); - let name = cx.identifier_constant(id.into()); + let name = JsString::from(cx.constants().symbols[SymbolConstant(id)]); let value = match cx.global.as_any().downcast_ref::() { Some(value) => match value.get_raw_property(name.into()) { @@ -832,7 +902,7 @@ mod handlers { pub fn storeglobal(mut cx: DispatchContext<'_>) -> Result, Unrooted> { let id = cx.fetch_and_inc_ip(); - let name = cx.identifier_constant(id.into()); + let name = JsString::from(cx.constants().symbols[SymbolConstant(id.into())]); let kind = AssignKind::from_repr(cx.fetch_and_inc_ip()).unwrap(); macro_rules! op { @@ -1506,7 +1576,7 @@ mod handlers { pub fn staticpropertyaccess(mut cx: DispatchContext<'_>) -> Result, Unrooted> { let id = cx.fetchw_and_inc_ip(); - let ident = cx.identifier_constant(id.into()); + let ident = JsString::from(cx.constants().symbols[SymbolConstant(id)]); let preserve_this = cx.fetch_and_inc_ip() == 1; @@ -1524,7 +1594,7 @@ mod handlers { pub fn staticpropertyassign(mut cx: DispatchContext<'_>) -> Result, Unrooted> { let kind = AssignKind::from_repr(cx.fetch_and_inc_ip()).unwrap(); let id = cx.fetchw_and_inc_ip(); - let key = cx.identifier_constant(id.into()); + let key = JsString::from(cx.constants().symbols[SymbolConstant(id)]); macro_rules! op { ($op:expr) => {{ @@ -1802,11 +1872,11 @@ mod handlers { pub fn type_of_ident(mut cx: DispatchContext<'_>) -> Result, Unrooted> { let id = cx.fetchw_and_inc_ip(); - let constant = cx.identifier_constant(id.into()); + let ident = JsString::from(cx.constants().symbols[SymbolConstant(id)]); let prop = cx .global .clone() - .get_property(&mut cx.scope, constant.into())? + .get_property(&mut cx.scope, ident.into())? .root(&mut cx.scope); cx.stack.push(prop.type_of().as_value()); @@ -1842,10 +1912,10 @@ mod handlers { let local_id = cx.fetchw_and_inc_ip(); let path_id = cx.fetchw_and_inc_ip(); - let path = cx.string_constant(path_id.into()); + let path = cx.constants().symbols[SymbolConstant(path_id)]; let value = match cx.params.static_import_callback() { - Some(cb) => cb(&mut cx, ty, path)?, + Some(cb) => cb(&mut cx, ty, path.into())?, None => throw!(cx, Error, "Static imports are disabled for this context."), }; @@ -1973,7 +2043,7 @@ mod handlers { pub fn delete_property_static(mut cx: DispatchContext<'_>) -> Result, Unrooted> { let target = cx.pop_stack_rooted(); let cid = cx.fetchw_and_inc_ip(); - let con = cx.identifier_constant(cid.into()); + let con = JsString::from(cx.constants().symbols[SymbolConstant(cid)]); let value = target.delete_property(&mut cx, con.into())?; // TODO: not correct, as `undefined` might have been the actual value @@ -2262,8 +2332,13 @@ pub fn handle(vm: &mut Vm, instruction: Instruction) -> Result handlers::pop(cx), Instruction::LdLocal => handlers::ldlocal(cx), Instruction::LdGlobal => handlers::ldglobal(cx), - Instruction::Constant => handlers::constant(cx), - Instruction::ConstantW => handlers::constantw(cx), + Instruction::String => handlers::string_constant(cx), + Instruction::Boolean => handlers::boolean_constant(cx), + Instruction::Number => handlers::number_constant(cx), + Instruction::Regex => handlers::regex_constant(cx), + Instruction::Null => handlers::null_constant(cx), + Instruction::Undefined => handlers::undefined_constant(cx), + Instruction::Function => handlers::function_constant(cx), Instruction::Pos => handlers::pos(cx), Instruction::Neg => handlers::neg(cx), Instruction::TypeOf => handlers::type_of(cx), diff --git a/crates/dash_vm/src/frame.rs b/crates/dash_vm/src/frame.rs index 5f8dc9e5..4bbfed51 100755 --- a/crates/dash_vm/src/frame.rs +++ b/crates/dash_vm/src/frame.rs @@ -168,7 +168,7 @@ impl Frame { let fun = Function { buffer: Buffer(Cell::new(cr.instructions.into())), - constants: cr.cp.into_vec().into(), + constants: cr.cp, externals: Vec::new().into(), locals: cr.locals, name: None, diff --git a/crates/dash_vm/src/gc/trace.rs b/crates/dash_vm/src/gc/trace.rs index e3e74348..bb2c176e 100644 --- a/crates/dash_vm/src/gc/trace.rs +++ b/crates/dash_vm/src/gc/trace.rs @@ -4,7 +4,8 @@ use std::collections::{HashMap, HashSet}; use std::path::{Path, PathBuf}; use std::rc::Rc; -use dash_middle::compiler::constant::Constant; +use dash_middle::compiler::constant::ConstantPool; +use dash_regex::{Flags, ParsedRegex}; use crate::value::primitive::{Null, Number, Undefined}; use crate::value::typedarray::TypedArrayKind; @@ -160,33 +161,29 @@ unsafe impl Trace for dash_middle::compiler::constant::Function { ty: _, locals: _, params: _, - constants, + constants: + ConstantPool { + numbers, + symbols, + booleans, + functions, + regexes, + }, externals: _, rest_local: _, poison_ips: _, - source: _, + source: Rc { .. }, debug_symbols: _, references_arguments: _, } = self; name.trace(cx); - constants.trace(cx); - } -} + numbers.as_slice().trace(cx); + symbols.as_slice().trace(cx); + booleans.as_slice().trace(cx); + functions.as_slice().trace(cx); -unsafe impl Trace for Constant { - fn trace(&self, cx: &mut TraceCtxt<'_>) { - match self { - Constant::Number(_) => {} - Constant::String(sym) => sym.trace(cx), - Constant::Identifier(sym) => sym.trace(cx), - Constant::Boolean(_) => {} - Constant::Function(func) => func.trace(cx), - Constant::Regex(s) => { - let (_, _, sym) = &**s; - sym.trace(cx); - } - Constant::Null => {} - Constant::Undefined => {} + for (ParsedRegex { .. }, Flags { .. }, sym) in regexes.as_slice() { + sym.trace(cx); } } } diff --git a/crates/dash_vm/src/jit/mod.rs b/crates/dash_vm/src/jit/mod.rs index 88782f4e..e70440c1 100644 --- a/crates/dash_vm/src/jit/mod.rs +++ b/crates/dash_vm/src/jit/mod.rs @@ -85,7 +85,8 @@ mod tests { use dash_compiler::FunctionCompiler; use dash_llvm_jit_backend::codegen; - use dash_llvm_jit_backend::codegen::{CodegenQuery, JitConstant}; + use dash_llvm_jit_backend::codegen::CodegenQuery; + use dash_middle::compiler::constant::{BooleanConstant, NumberConstant}; use dash_middle::interner::StringInterner; use dash_optimizer::OptLevel; use dash_typed_cfg::passes::bb_generation::{BBGenerationQuery, ConditionalBranchAction}; @@ -107,31 +108,22 @@ mod tests { } impl TypeInferQuery for TestQueryProvider { - fn type_of_constant(&self, index: u16) -> dash_typed_cfg::passes::type_infer::Type { - match index { - #[allow(clippy::manual_range_patterns)] - 0 | 1 | 2 => Type::I64, - _ => todo!("{index}"), - } + fn number_constant(&self, _: NumberConstant) -> f64 { + 1.0 } - fn type_of_local(&self, index: u16) -> Type { - match index { - 0 => Type::I64, - 1 => Type::Boolean, - o => todo!("{o}"), - } + fn type_of_local(&self, _: u16) -> Type { + Type::I64 } } impl CodegenQuery for TestQueryProvider { - fn get_constant(&self, cid: u16) -> JitConstant { - match cid { - 0 => JitConstant::I64(0), - 1 => JitConstant::I64(10), - 2 => JitConstant::I64(3), - _ => todo!(), - } + fn boolean_constant(&self, _: BooleanConstant) -> bool { + true + } + + fn number_constant(&self, _: NumberConstant) -> f64 { + 1.0 } } diff --git a/crates/dash_vm/src/jit/query.rs b/crates/dash_vm/src/jit/query.rs index 4b29ccd2..d31686ed 100644 --- a/crates/dash_vm/src/jit/query.rs +++ b/crates/dash_vm/src/jit/query.rs @@ -1,6 +1,6 @@ -use dash_llvm_jit_backend::codegen::{CodegenQuery, JitConstant}; +use dash_llvm_jit_backend::codegen::CodegenQuery; use dash_llvm_jit_backend::Trace; -use dash_middle::compiler::constant::Constant; +use dash_middle::compiler::constant::{BooleanConstant, NumberConstant}; use dash_middle::util::is_integer; use dash_typed_cfg::passes::bb_generation::{BBGenerationQuery, ConditionalBranchAction}; use dash_typed_cfg::passes::type_infer::{Type, TypeInferQuery}; @@ -24,20 +24,10 @@ impl<'a> BBGenerationQuery for QueryProvider<'a> { } impl<'a> TypeInferQuery for QueryProvider<'a> { - fn type_of_constant(&self, index: u16) -> Type { - let constant = &self.vm.active_frame().function.constants[usize::from(index)]; - match constant { - Constant::Boolean(..) => Type::Boolean, - Constant::Number(n) => { - if is_integer(*n) { - Type::I64 - } else { - Type::F64 - } - } - _ => panic!("invalid jit type"), - } + fn number_constant(&self, id: NumberConstant) -> f64 { + self.vm.active_frame().function.constants.numbers[id] } + fn type_of_local(&self, index: u16) -> Type { match self.vm.get_local(index.into()).unwrap() { Value::Boolean(..) => Type::Boolean, @@ -54,18 +44,11 @@ impl<'a> TypeInferQuery for QueryProvider<'a> { } impl<'a> CodegenQuery for QueryProvider<'a> { - fn get_constant(&self, id: u16) -> JitConstant { - let constant = &self.vm.active_frame().function.constants[usize::from(id)]; - match constant { - Constant::Boolean(b) => JitConstant::Boolean(*b), - Constant::Number(n) => { - if is_integer(*n) { - JitConstant::I64(*n as i64) - } else { - JitConstant::F64(*n) - } - } - _ => todo!(), - } + fn boolean_constant(&self, id: BooleanConstant) -> bool { + self.vm.active_frame().function.constants.booleans[id] + } + + fn number_constant(&self, id: NumberConstant) -> f64 { + self.vm.active_frame().function.constants.numbers[id] } } diff --git a/crates/dash_vm/src/value/mod.rs b/crates/dash_vm/src/value/mod.rs index 1e0b258b..f9eb0f02 100755 --- a/crates/dash_vm/src/value/mod.rs +++ b/crates/dash_vm/src/value/mod.rs @@ -18,9 +18,6 @@ pub mod typedarray; use std::any::TypeId; use std::ops::ControlFlow; -use dash_middle::compiler::constant::Constant; -use dash_middle::compiler::external::External; -use dash_middle::parser::statement::{Asyncness, FunctionKind as ParserFunctionKind}; use dash_middle::util::ThreadSafeStorage; use dash_proc_macro::Trace; @@ -29,18 +26,11 @@ use crate::gc::handle::Handle; use crate::gc::interner::sym; use crate::gc::trace::{Trace, TraceCtxt}; use crate::util::cold_path; -use crate::value::function::FunctionKind; use crate::value::primitive::{Null, Undefined}; use crate::{delegate, throw}; -use self::function::r#async::AsyncFunction; -use self::function::closure::Closure; -use self::function::generator::GeneratorFunction; -use self::function::user::UserFunction; -use self::function::Function; use self::object::{Object, PropertyKey, PropertyValue}; use self::primitive::{InternalSlots, Number, Symbol}; -use self::regex::RegExp; use self::string::JsString; use super::localscope::LocalScope; @@ -415,75 +405,7 @@ unsafe impl Trace for Value { } } -fn register_function_externals( - function: &dash_middle::compiler::constant::Function, - sc: &mut LocalScope<'_>, -) -> Vec { - let mut externals = Vec::new(); - - for External { id, is_nested_external } in function.externals.iter().copied() { - let id = usize::from(id); - - let val = if is_nested_external { - sc.get_external(id).expect("Referenced local not found").clone() - } else { - let v = sc.get_local_raw(id).expect("Referenced local not found"); - - match v { - Value::External(v) => v, - other => { - // TODO: comment what's happening here -- Value -> Handle -> ExternaValue(..) - let ext = ExternalValue::new(sc.register(other)); - sc.set_local(id, Value::External(ext.clone()).into()); - ext - } - } - }; - - externals.push(val); - } - - externals -} - impl Value { - pub fn from_constant(constant: Constant, sc: &mut LocalScope<'_>) -> Self { - match constant { - Constant::Number(n) => Value::number(n), - Constant::Boolean(b) => Value::Boolean(b), - Constant::String(s) => Value::String(s.into()), - Constant::Undefined => Value::undefined(), - Constant::Null => Value::null(), - Constant::Regex(regex) => { - let (nodes, flags, source) = *regex; - let regex = RegExp::new(nodes, flags, source.into(), sc); - Value::Object(sc.register(regex)) - } - Constant::Function(f) => { - let externals = register_function_externals(&f, sc); - - let name = f.name.map(Into::into); - let ty = f.ty; - - let fun = UserFunction::new(f, externals.into()); - - let kind = match ty { - ParserFunctionKind::Function(Asyncness::Yes) => FunctionKind::Async(AsyncFunction::new(fun)), - ParserFunctionKind::Function(Asyncness::No) => FunctionKind::User(fun), - ParserFunctionKind::Arrow => FunctionKind::Closure(Closure { - fun, - this: sc.active_frame().this.clone().unwrap_or_undefined(), - }), - ParserFunctionKind::Generator => FunctionKind::Generator(GeneratorFunction::new(fun)), - }; - - let function = Function::new(sc, name, kind); - sc.register(function).into() - } - Constant::Identifier(_) => unreachable!(), - } - } - pub fn get_property(&self, sc: &mut LocalScope, key: PropertyKey) -> Result { match self { Self::Object(o) => o.get_property(sc, key),