From 9480d78c54d34ec316cfe52d0055c5698bee2ffa Mon Sep 17 00:00:00 2001 From: raskad <32105367+raskad@users.noreply.github.com> Date: Wed, 10 May 2023 23:58:19 +0200 Subject: [PATCH 1/4] Fix tagged template creation --- boa_ast/src/expression/tagged_template.rs | 10 ++ boa_engine/src/builtins/eval/mod.rs | 1 + boa_engine/src/bytecompiler/expression/mod.rs | 25 ++--- boa_engine/src/context/mod.rs | 11 ++ boa_engine/src/realm.rs | 16 ++- boa_engine/src/vm/code_block.rs | 4 +- boa_engine/src/vm/flowgraph/mod.rs | 2 +- boa_engine/src/vm/opcode/mod.rs | 17 +++ boa_engine/src/vm/opcode/templates/mod.rs | 104 ++++++++++++++++++ boa_parser/src/parser/cursor/mod.rs | 17 +++ .../expression/left_hand_side/template.rs | 10 +- boa_parser/src/parser/mod.rs | 8 ++ 12 files changed, 205 insertions(+), 20 deletions(-) create mode 100644 boa_engine/src/vm/opcode/templates/mod.rs diff --git a/boa_ast/src/expression/tagged_template.rs b/boa_ast/src/expression/tagged_template.rs index c138d74160c..b463ce5724a 100644 --- a/boa_ast/src/expression/tagged_template.rs +++ b/boa_ast/src/expression/tagged_template.rs @@ -21,6 +21,7 @@ pub struct TaggedTemplate { raws: Box<[Sym]>, cookeds: Box<[Option]>, exprs: Box<[Expression]>, + identifier: u64, } impl TaggedTemplate { @@ -33,12 +34,14 @@ impl TaggedTemplate { raws: Box<[Sym]>, cookeds: Box<[Option]>, exprs: Box<[Expression]>, + identifier: u64, ) -> Self { Self { tag: tag.into(), raws, cookeds, exprs, + identifier, } } @@ -69,6 +72,13 @@ impl TaggedTemplate { pub const fn exprs(&self) -> &[Expression] { &self.exprs } + + /// Gets the unique identifier of the template. + #[inline] + #[must_use] + pub const fn identifier(&self) -> u64 { + self.identifier + } } impl ToInternedString for TaggedTemplate { diff --git a/boa_engine/src/builtins/eval/mod.rs b/boa_engine/src/builtins/eval/mod.rs index 89b838b7c3c..629baff3866 100644 --- a/boa_engine/src/builtins/eval/mod.rs +++ b/boa_engine/src/builtins/eval/mod.rs @@ -112,6 +112,7 @@ impl Eval { // c. If script Contains ScriptBody is false, return undefined. // d. Let body be the ScriptBody of script. let mut parser = Parser::new(Source::from_bytes(&x)); + parser.set_identifier(context.next_parser_identifier()); if strict { parser.set_strict(); } diff --git a/boa_engine/src/bytecompiler/expression/mod.rs b/boa_engine/src/bytecompiler/expression/mod.rs index 40681b44085..2131dad8c13 100644 --- a/boa_engine/src/bytecompiler/expression/mod.rs +++ b/boa_engine/src/bytecompiler/expression/mod.rs @@ -17,7 +17,6 @@ use boa_ast::{ }, Expression, }; -use boa_interner::Sym; impl ByteCompiler<'_, '_> { fn compile_literal(&mut self, lit: &AstLiteral, use_expr: bool) { @@ -255,8 +254,14 @@ impl ByteCompiler<'_, '_> { } } - self.emit_opcode(Opcode::PushNewArray); - for cooked in template.cookeds() { + let site = template.identifier() as u32; + let count = template.cookeds().len() as u32; + + let index = self.next_opcode_location(); + self.emit(Opcode::TemplateLookup, &[Self::DUMMY_ADDRESS, site]); + let jump_label = Label { index }; + + for (cooked, raw) in template.cookeds().iter().zip(template.raws()) { if let Some(cooked) = cooked { self.emit_push_literal(Literal::String( self.interner().resolve_expect(*cooked).into_common(false), @@ -264,22 +269,14 @@ impl ByteCompiler<'_, '_> { } else { self.emit_opcode(Opcode::PushUndefined); } - self.emit_opcode(Opcode::PushValueToArray); - } - self.emit_opcode(Opcode::Dup); - self.emit_opcode(Opcode::Dup); - - self.emit_opcode(Opcode::PushNewArray); - for raw in template.raws() { self.emit_push_literal(Literal::String( self.interner().resolve_expect(*raw).into_common(false), )); - self.emit_opcode(Opcode::PushValueToArray); } - let index = self.get_or_insert_name(Sym::RAW.into()); - self.emit(Opcode::SetPropertyByName, &[index]); - self.emit(Opcode::Pop, &[]); + self.emit(Opcode::TemplateCreate, &[site, count]); + + self.patch_jump(jump_label); for expr in template.exprs() { self.compile_expr(expr, true); diff --git a/boa_engine/src/context/mod.rs b/boa_engine/src/context/mod.rs index caecfd72f7e..02aa8397b6d 100644 --- a/boa_engine/src/context/mod.rs +++ b/boa_engine/src/context/mod.rs @@ -112,6 +112,9 @@ pub struct Context<'host> { optimizer_options: OptimizerOptions, root_shape: SharedShape, + + /// Unique identifier for each parser instance used during the context lifetime. + parser_identifier: usize, } impl std::fmt::Debug for Context<'_> { @@ -656,6 +659,13 @@ impl Context<'_> { std::mem::swap(&mut self.realm, realm); } + /// Get and increment the parser identifier. + pub(crate) fn next_parser_identifier(&mut self) -> usize { + let identifier = self.parser_identifier; + self.parser_identifier += 1; + identifier + } + /// `CanDeclareGlobalFunction ( N )` /// /// More information: @@ -1025,6 +1035,7 @@ impl<'icu, 'hooks, 'queue> ContextBuilder<'icu, 'hooks, 'queue> { }), optimizer_options: OptimizerOptions::OPTIMIZE_ALL, root_shape, + parser_identifier: 0, }; builtins::set_default_global_bindings(&mut context)?; diff --git a/boa_engine/src/realm.rs b/boa_engine/src/realm.rs index 3967f32d38e..bf62830a8c3 100644 --- a/boa_engine/src/realm.rs +++ b/boa_engine/src/realm.rs @@ -6,15 +6,15 @@ //! //! A realm is represented in this implementation as a Realm struct with the fields specified from the spec. -use std::fmt; - use crate::{ context::{intrinsics::Intrinsics, HostHooks}, environments::DeclarativeEnvironment, object::{shape::shared_shape::SharedShape, JsObject}, }; -use boa_gc::{Finalize, Gc, Trace}; +use boa_gc::{Finalize, Gc, GcRefCell, Trace}; use boa_profiler::Profiler; +use rustc_hash::FxHashMap; +use std::fmt; /// Representation of a Realm. /// @@ -49,6 +49,7 @@ struct Inner { environment: Gc, global_object: JsObject, global_this: JsObject, + template_map: GcRefCell>, } impl Realm { @@ -69,6 +70,7 @@ impl Realm { environment: Gc::new(DeclarativeEnvironment::new_global()), global_object, global_this, + template_map: GcRefCell::new(FxHashMap::default()), }), }; @@ -103,4 +105,12 @@ impl Realm { bindings.resize(binding_number, None); } } + + pub(crate) fn push_template(&self, site: u32, template: JsObject) { + self.inner.template_map.borrow_mut().insert(site, template); + } + + pub(crate) fn lookup_template(&self, site: u32) -> Option { + self.inner.template_map.borrow().get(&site).cloned() + } } diff --git a/boa_engine/src/vm/code_block.rs b/boa_engine/src/vm/code_block.rs index 1c1e6506e1c..a1fe40d9c7f 100644 --- a/boa_engine/src/vm/code_block.rs +++ b/boa_engine/src/vm/code_block.rs @@ -293,7 +293,9 @@ impl CodeBlock { | Opcode::LoopStart | Opcode::TryStart | Opcode::AsyncGeneratorNext - | Opcode::GeneratorAsyncDelegateNext => { + | Opcode::GeneratorAsyncDelegateNext + | Opcode::TemplateLookup + | Opcode::TemplateCreate => { let operand1 = self.read::(*pc); *pc += size_of::(); let operand2 = self.read::(*pc); diff --git a/boa_engine/src/vm/flowgraph/mod.rs b/boa_engine/src/vm/flowgraph/mod.rs index f78a9ba90c0..b29e0990fcf 100644 --- a/boa_engine/src/vm/flowgraph/mod.rs +++ b/boa_engine/src/vm/flowgraph/mod.rs @@ -138,7 +138,7 @@ impl CodeBlock { graph.add_node(previous_pc, NodeShape::None, label.into(), Color::Red); graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); } - Opcode::LoopStart => { + Opcode::LoopStart | Opcode::TemplateLookup | Opcode::TemplateCreate => { let start_address = self.read::(pc); pc += size_of::(); let end_address = self.read::(pc); diff --git a/boa_engine/src/vm/opcode/mod.rs b/boa_engine/src/vm/opcode/mod.rs index 612b63032eb..f0ec9383321 100644 --- a/boa_engine/src/vm/opcode/mod.rs +++ b/boa_engine/src/vm/opcode/mod.rs @@ -27,6 +27,7 @@ mod rest_parameter; mod set; mod swap; mod switch; +mod templates; mod to; mod unary_ops; mod value; @@ -79,6 +80,8 @@ pub(crate) use swap::*; #[doc(inline)] pub(crate) use switch::*; #[doc(inline)] +pub(crate) use templates::*; +#[doc(inline)] pub(crate) use to::*; #[doc(inline)] pub(crate) use unary_ops::*; @@ -1602,6 +1605,20 @@ generate_impl! { /// Stack: value **=>** is_object IsObject, + /// Lookup if a tagged template object is cached and skip the creation if it is. + /// + /// Operands: jump: `u32`, site: `u32` + /// + /// Stack: **=>** template (if cached) + TemplateLookup, + + /// Create a new tagged template object and cache it. + /// + /// Operands: site: `u32`, count: `u32` + /// + /// Stack: count * (cooked_value, raw_value) **=>** template + TemplateCreate, + /// No-operation instruction, does nothing. /// /// Operands: diff --git a/boa_engine/src/vm/opcode/templates/mod.rs b/boa_engine/src/vm/opcode/templates/mod.rs new file mode 100644 index 00000000000..aae538a8bcd --- /dev/null +++ b/boa_engine/src/vm/opcode/templates/mod.rs @@ -0,0 +1,104 @@ +use crate::{ + builtins::array::Array, + object::IntegrityLevel, + property::PropertyDescriptor, + vm::{opcode::Operation, CompletionType}, + Context, JsResult, +}; +use boa_macros::utf16; + +/// `TemplateLookup` implements the Opcode Operation for `Opcode::TemplateLookup` +/// +/// Operation: +/// - Lookup if a tagged template object is cached and skip the creation if it is. +#[derive(Debug, Clone, Copy)] +pub(crate) struct TemplateLookup; + +impl Operation for TemplateLookup { + const NAME: &'static str = "TemplateLookup"; + const INSTRUCTION: &'static str = "INST - TemplateLookup"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let jump = context.vm.read::(); + let site = context.vm.read::(); + + if let Some(template) = context.realm().lookup_template(site) { + context.vm.push(template); + context.vm.frame_mut().pc = jump as usize; + } + + Ok(CompletionType::Normal) + } +} + +/// `TemplateCreate` implements the Opcode Operation for `Opcode::TemplateCreate` +/// +/// Operation: +/// - Create a new tagged template object and cache it. +#[derive(Debug, Clone, Copy)] +pub(crate) struct TemplateCreate; + +impl Operation for TemplateCreate { + const NAME: &'static str = "TemplateCreate"; + const INSTRUCTION: &'static str = "INST - TemplateCreate"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let site = context.vm.read::(); + let count = context.vm.read::(); + + let template = + Array::array_create(count.into(), None, context).expect("cannot fail per spec"); + let raw_obj = + Array::array_create(count.into(), None, context).expect("cannot fail per spec"); + + for index in (0..count).rev() { + let raw_value = context.vm.pop(); + let cooked_value = context.vm.pop(); + template + .define_property_or_throw( + index, + PropertyDescriptor::builder() + .value(cooked_value) + .writable(false) + .enumerable(true) + .configurable(false), + context, + ) + .expect("should not fail on new array"); + raw_obj + .define_property_or_throw( + index, + PropertyDescriptor::builder() + .value(raw_value) + .writable(false) + .enumerable(true) + .configurable(false), + context, + ) + .expect("should not fail on new array"); + } + + raw_obj + .set_integrity_level(IntegrityLevel::Frozen, context) + .expect("should never fail per spec"); + template + .define_property_or_throw( + utf16!("raw"), + PropertyDescriptor::builder() + .value(raw_obj) + .writable(false) + .enumerable(false) + .configurable(false), + context, + ) + .expect("should never fail per spec"); + template + .set_integrity_level(IntegrityLevel::Frozen, context) + .expect("should never fail per spec"); + + context.realm().push_template(site, template.clone()); + + context.vm.push(template); + Ok(CompletionType::Normal) + } +} diff --git a/boa_parser/src/parser/cursor/mod.rs b/boa_parser/src/parser/cursor/mod.rs index 12162270f3b..4aacd1e22fc 100644 --- a/boa_parser/src/parser/cursor/mod.rs +++ b/boa_parser/src/parser/cursor/mod.rs @@ -36,6 +36,10 @@ pub(super) struct Cursor { /// Indicate if the cursor is used in `JSON.parse`. json_parse: bool, + + /// A unique identifier for each parser instance. + /// This is used to generate unique identifiers tagged template literals. + identifier: usize, } impl Cursor @@ -50,6 +54,7 @@ where private_environment_root_index: 0, arrow: false, json_parse: false, + identifier: 0, } } @@ -169,6 +174,18 @@ where self.private_environment_nested_index != 0 } + /// Set the identifier of the cursor. + #[inline] + pub(super) fn set_identifier(&mut self, identifier: usize) { + self.identifier = identifier; + } + + /// Get the identifier of the cursor. + #[inline] + pub(super) const fn identifier(&self) -> usize { + self.identifier + } + /// Returns an error if the next token is not of kind `kind`. pub(super) fn expect( &mut self, diff --git a/boa_parser/src/parser/expression/left_hand_side/template.rs b/boa_parser/src/parser/expression/left_hand_side/template.rs index fc1f09081f2..f165cf98d6e 100644 --- a/boa_parser/src/parser/expression/left_hand_side/template.rs +++ b/boa_parser/src/parser/expression/left_hand_side/template.rs @@ -9,7 +9,8 @@ use crate::{ use boa_ast::{self as ast, expression::TaggedTemplate, Position, Punctuator}; use boa_interner::Interner; use boa_profiler::Profiler; -use std::io::Read; +use rustc_hash::FxHasher; +use std::{hash::Hasher, io::Read}; /// Parses a tagged template. /// @@ -60,6 +61,7 @@ where let mut exprs = Vec::new(); let mut token = cursor.next(interner).or_abrupt()?; + let start_position = token.span().start(); loop { match token.kind() { @@ -77,6 +79,11 @@ where )?; } TokenKind::TemplateNoSubstitution(template_string) => { + let mut hasher = FxHasher::default(); + hasher.write_u32(start_position.line_number()); + hasher.write_u32(start_position.column_number()); + hasher.write_usize(cursor.identifier()); + raws.push(template_string.as_raw()); cookeds.push(template_string.to_owned_cooked(interner).ok()); return Ok(TaggedTemplate::new( @@ -84,6 +91,7 @@ where raws.into_boxed_slice(), cookeds.into_boxed_slice(), exprs.into_boxed_slice(), + hasher.finish(), )); } _ => { diff --git a/boa_parser/src/parser/mod.rs b/boa_parser/src/parser/mod.rs index 5e18af8a7c5..f1b623963d7 100644 --- a/boa_parser/src/parser/mod.rs +++ b/boa_parser/src/parser/mod.rs @@ -218,6 +218,14 @@ impl Parser<'_, R> { { self.cursor.set_json_parse(true); } + + /// Set the unique identifier for the parser. + pub fn set_identifier(&mut self, identifier: usize) + where + R: Read, + { + self.cursor.set_identifier(identifier); + } } /// Parses a full script. From ee3146a39cb1929921a1a542c6d90e802a5e76f7 Mon Sep 17 00:00:00 2001 From: raskad <32105367+raskad@users.noreply.github.com> Date: Thu, 11 May 2023 01:52:39 +0200 Subject: [PATCH 2/4] Fix template identifier hash --- boa_engine/src/builtins/function/mod.rs | 37 +++++++++++-------- boa_engine/src/context/mod.rs | 9 +++-- boa_parser/src/parser/cursor/mod.rs | 21 ++++++++--- .../expression/left_hand_side/template.rs | 11 +----- boa_parser/src/parser/mod.rs | 2 +- 5 files changed, 44 insertions(+), 36 deletions(-) diff --git a/boa_engine/src/builtins/function/mod.rs b/boa_engine/src/builtins/function/mod.rs index d86ebc9df05..9bae66296c5 100644 --- a/boa_engine/src/builtins/function/mod.rs +++ b/boa_engine/src/builtins/function/mod.rs @@ -586,17 +586,22 @@ impl BuiltInFunctionObject { let parameters = parameters.join(utf16!(",")); // TODO: make parser generic to u32 iterators - let parameters = - match Parser::new(Source::from_bytes(&String::from_utf16_lossy(¶meters))) - .parse_formal_parameters(context.interner_mut(), generator, r#async) - { - Ok(parameters) => parameters, - Err(e) => { - return Err(JsNativeError::syntax() - .with_message(format!("failed to parse function parameters: {e}")) - .into()) - } - }; + let parameters = String::from_utf16_lossy(¶meters); + let mut parser = Parser::new(Source::from_bytes(¶meters)); + parser.set_identifier(context.next_parser_identifier()); + + let parameters = match parser.parse_formal_parameters( + context.interner_mut(), + generator, + r#async, + ) { + Ok(parameters) => parameters, + Err(e) => { + return Err(JsNativeError::syntax() + .with_message(format!("failed to parse function parameters: {e}")) + .into()) + } + }; if generator && contains(¶meters, ContainsSymbol::YieldExpression) { return Err(JsNativeError::syntax().with_message( @@ -626,11 +631,11 @@ impl BuiltInFunctionObject { let body = b"\n".chain(body_arg.as_bytes()).chain(b"\n".as_slice()); // TODO: make parser generic to u32 iterators - let body = match Parser::new(Source::from_reader(body, None)).parse_function_body( - context.interner_mut(), - generator, - r#async, - ) { + let mut parser = Parser::new(Source::from_reader(body, None)); + parser.set_identifier(context.next_parser_identifier()); + + let body = match parser.parse_function_body(context.interner_mut(), generator, r#async) + { Ok(statement_list) => statement_list, Err(e) => { return Err(JsNativeError::syntax() diff --git a/boa_engine/src/context/mod.rs b/boa_engine/src/context/mod.rs index 02aa8397b6d..9fde27a844e 100644 --- a/boa_engine/src/context/mod.rs +++ b/boa_engine/src/context/mod.rs @@ -114,7 +114,7 @@ pub struct Context<'host> { root_shape: SharedShape, /// Unique identifier for each parser instance used during the context lifetime. - parser_identifier: usize, + parser_identifier: u32, } impl std::fmt::Debug for Context<'_> { @@ -233,6 +233,7 @@ impl<'host> Context<'host> { ) -> Result { let _timer = Profiler::global().start_event("Script parsing", "Main"); let mut parser = Parser::new(src); + parser.set_identifier(self.next_parser_identifier()); if self.strict { parser.set_strict(); } @@ -250,6 +251,7 @@ impl<'host> Context<'host> { ) -> Result { let _timer = Profiler::global().start_event("Module parsing", "Main"); let mut parser = Parser::new(src); + parser.set_identifier(self.next_parser_identifier()); parser.parse_module(&mut self.interner) } @@ -660,10 +662,9 @@ impl Context<'_> { } /// Get and increment the parser identifier. - pub(crate) fn next_parser_identifier(&mut self) -> usize { - let identifier = self.parser_identifier; + pub(crate) fn next_parser_identifier(&mut self) -> u32 { self.parser_identifier += 1; - identifier + self.parser_identifier } /// `CanDeclareGlobalFunction ( N )` diff --git a/boa_parser/src/parser/cursor/mod.rs b/boa_parser/src/parser/cursor/mod.rs index 4aacd1e22fc..22eeb5805ad 100644 --- a/boa_parser/src/parser/cursor/mod.rs +++ b/boa_parser/src/parser/cursor/mod.rs @@ -9,7 +9,8 @@ use crate::{ use boa_ast::{Position, Punctuator}; use boa_interner::Interner; use buffered_lexer::BufferedLexer; -use std::io::Read; +use rustc_hash::FxHasher; +use std::{hash::Hasher, io::Read}; /// The result of a peek for a semicolon. #[derive(Debug)] @@ -39,7 +40,10 @@ pub(super) struct Cursor { /// A unique identifier for each parser instance. /// This is used to generate unique identifiers tagged template literals. - identifier: usize, + identifier: u32, + + /// Tracks the number of tagged templates that are currently being parsed. + tagged_templates_count: u32, } impl Cursor @@ -55,6 +59,7 @@ where arrow: false, json_parse: false, identifier: 0, + tagged_templates_count: 0, } } @@ -176,14 +181,18 @@ where /// Set the identifier of the cursor. #[inline] - pub(super) fn set_identifier(&mut self, identifier: usize) { + pub(super) fn set_identifier(&mut self, identifier: u32) { self.identifier = identifier; } - /// Get the identifier of the cursor. + /// Get the identifier for a tagged template. #[inline] - pub(super) const fn identifier(&self) -> usize { - self.identifier + pub(super) fn tagged_template_identifier(&mut self) -> u64 { + let mut hasher = FxHasher::default(); + hasher.write_u32(self.identifier); + hasher.write_u32(self.tagged_templates_count); + self.tagged_templates_count += 1; + hasher.finish() } /// Returns an error if the next token is not of kind `kind`. diff --git a/boa_parser/src/parser/expression/left_hand_side/template.rs b/boa_parser/src/parser/expression/left_hand_side/template.rs index f165cf98d6e..ffd353fe59a 100644 --- a/boa_parser/src/parser/expression/left_hand_side/template.rs +++ b/boa_parser/src/parser/expression/left_hand_side/template.rs @@ -9,8 +9,7 @@ use crate::{ use boa_ast::{self as ast, expression::TaggedTemplate, Position, Punctuator}; use boa_interner::Interner; use boa_profiler::Profiler; -use rustc_hash::FxHasher; -use std::{hash::Hasher, io::Read}; +use std::io::Read; /// Parses a tagged template. /// @@ -61,7 +60,6 @@ where let mut exprs = Vec::new(); let mut token = cursor.next(interner).or_abrupt()?; - let start_position = token.span().start(); loop { match token.kind() { @@ -79,11 +77,6 @@ where )?; } TokenKind::TemplateNoSubstitution(template_string) => { - let mut hasher = FxHasher::default(); - hasher.write_u32(start_position.line_number()); - hasher.write_u32(start_position.column_number()); - hasher.write_usize(cursor.identifier()); - raws.push(template_string.as_raw()); cookeds.push(template_string.to_owned_cooked(interner).ok()); return Ok(TaggedTemplate::new( @@ -91,7 +84,7 @@ where raws.into_boxed_slice(), cookeds.into_boxed_slice(), exprs.into_boxed_slice(), - hasher.finish(), + cursor.tagged_template_identifier(), )); } _ => { diff --git a/boa_parser/src/parser/mod.rs b/boa_parser/src/parser/mod.rs index f1b623963d7..1e33bdf3156 100644 --- a/boa_parser/src/parser/mod.rs +++ b/boa_parser/src/parser/mod.rs @@ -220,7 +220,7 @@ impl Parser<'_, R> { } /// Set the unique identifier for the parser. - pub fn set_identifier(&mut self, identifier: usize) + pub fn set_identifier(&mut self, identifier: u32) where R: Read, { From 06bd97756388230ba3625849e5e274643461edda Mon Sep 17 00:00:00 2001 From: raskad <32105367+raskad@users.noreply.github.com> Date: Thu, 11 May 2023 04:36:56 +0200 Subject: [PATCH 3/4] Apply suggestion --- boa_engine/src/bytecompiler/expression/mod.rs | 10 +++++----- boa_engine/src/realm.rs | 6 +++--- boa_engine/src/vm/code_block.rs | 11 ++++++++--- boa_engine/src/vm/flowgraph/mod.rs | 12 +++++++++++- boa_engine/src/vm/opcode/mod.rs | 4 ++-- boa_engine/src/vm/opcode/templates/mod.rs | 4 ++-- boa_parser/src/parser/cursor/mod.rs | 12 ++++++------ 7 files changed, 37 insertions(+), 22 deletions(-) diff --git a/boa_engine/src/bytecompiler/expression/mod.rs b/boa_engine/src/bytecompiler/expression/mod.rs index 2131dad8c13..2203c95d4c9 100644 --- a/boa_engine/src/bytecompiler/expression/mod.rs +++ b/boa_engine/src/bytecompiler/expression/mod.rs @@ -254,12 +254,11 @@ impl ByteCompiler<'_, '_> { } } - let site = template.identifier() as u32; + let site = template.identifier(); let count = template.cookeds().len() as u32; - let index = self.next_opcode_location(); - self.emit(Opcode::TemplateLookup, &[Self::DUMMY_ADDRESS, site]); - let jump_label = Label { index }; + let jump_label = self.emit_opcode_with_operand(Opcode::TemplateLookup); + self.emit_u64(site); for (cooked, raw) in template.cookeds().iter().zip(template.raws()) { if let Some(cooked) = cooked { @@ -274,7 +273,8 @@ impl ByteCompiler<'_, '_> { )); } - self.emit(Opcode::TemplateCreate, &[site, count]); + self.emit(Opcode::TemplateCreate, &[count]); + self.emit_u64(site); self.patch_jump(jump_label); diff --git a/boa_engine/src/realm.rs b/boa_engine/src/realm.rs index bf62830a8c3..37d48d59eda 100644 --- a/boa_engine/src/realm.rs +++ b/boa_engine/src/realm.rs @@ -49,7 +49,7 @@ struct Inner { environment: Gc, global_object: JsObject, global_this: JsObject, - template_map: GcRefCell>, + template_map: GcRefCell>, } impl Realm { @@ -106,11 +106,11 @@ impl Realm { } } - pub(crate) fn push_template(&self, site: u32, template: JsObject) { + pub(crate) fn push_template(&self, site: u64, template: JsObject) { self.inner.template_map.borrow_mut().insert(site, template); } - pub(crate) fn lookup_template(&self, site: u32) -> Option { + pub(crate) fn lookup_template(&self, site: u64) -> Option { self.inner.template_map.borrow().get(&site).cloned() } } diff --git a/boa_engine/src/vm/code_block.rs b/boa_engine/src/vm/code_block.rs index a1fe40d9c7f..3de7dfed4fe 100644 --- a/boa_engine/src/vm/code_block.rs +++ b/boa_engine/src/vm/code_block.rs @@ -293,15 +293,20 @@ impl CodeBlock { | Opcode::LoopStart | Opcode::TryStart | Opcode::AsyncGeneratorNext - | Opcode::GeneratorAsyncDelegateNext - | Opcode::TemplateLookup - | Opcode::TemplateCreate => { + | Opcode::GeneratorAsyncDelegateNext => { let operand1 = self.read::(*pc); *pc += size_of::(); let operand2 = self.read::(*pc); *pc += size_of::(); format!("{operand1}, {operand2}") } + Opcode::TemplateLookup | Opcode::TemplateCreate => { + let operand1 = self.read::(*pc); + *pc += size_of::(); + let operand2 = self.read::(*pc); + *pc += size_of::(); + format!("{operand1}, {operand2}") + } Opcode::GeneratorAsyncDelegateResume => { let operand1 = self.read::(*pc); *pc += size_of::(); diff --git a/boa_engine/src/vm/flowgraph/mod.rs b/boa_engine/src/vm/flowgraph/mod.rs index b29e0990fcf..eb70abc6ca0 100644 --- a/boa_engine/src/vm/flowgraph/mod.rs +++ b/boa_engine/src/vm/flowgraph/mod.rs @@ -138,7 +138,7 @@ impl CodeBlock { graph.add_node(previous_pc, NodeShape::None, label.into(), Color::Red); graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); } - Opcode::LoopStart | Opcode::TemplateLookup | Opcode::TemplateCreate => { + Opcode::LoopStart => { let start_address = self.read::(pc); pc += size_of::(); let end_address = self.read::(pc); @@ -148,6 +148,16 @@ impl CodeBlock { graph.add_node(previous_pc, NodeShape::None, label.into(), Color::Red); graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); } + Opcode::TemplateLookup | Opcode::TemplateCreate => { + let start_address = self.read::(pc); + pc += size_of::(); + let end_address = self.read::(pc); + pc += size_of::(); + + let label = format!("{opcode_str} {start_address}, {end_address}"); + graph.add_node(previous_pc, NodeShape::None, label.into(), Color::Red); + graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); + } Opcode::Break => { let jump_operand = self.read::(pc); pc += size_of::(); diff --git a/boa_engine/src/vm/opcode/mod.rs b/boa_engine/src/vm/opcode/mod.rs index f0ec9383321..0a57ec89852 100644 --- a/boa_engine/src/vm/opcode/mod.rs +++ b/boa_engine/src/vm/opcode/mod.rs @@ -1607,14 +1607,14 @@ generate_impl! { /// Lookup if a tagged template object is cached and skip the creation if it is. /// - /// Operands: jump: `u32`, site: `u32` + /// Operands: jump: `u32`, site: `u64` /// /// Stack: **=>** template (if cached) TemplateLookup, /// Create a new tagged template object and cache it. /// - /// Operands: site: `u32`, count: `u32` + /// Operands: count: `u32`, site: `u64` /// /// Stack: count * (cooked_value, raw_value) **=>** template TemplateCreate, diff --git a/boa_engine/src/vm/opcode/templates/mod.rs b/boa_engine/src/vm/opcode/templates/mod.rs index aae538a8bcd..4e193d4ffa2 100644 --- a/boa_engine/src/vm/opcode/templates/mod.rs +++ b/boa_engine/src/vm/opcode/templates/mod.rs @@ -20,7 +20,7 @@ impl Operation for TemplateLookup { fn execute(context: &mut Context<'_>) -> JsResult { let jump = context.vm.read::(); - let site = context.vm.read::(); + let site = context.vm.read::(); if let Some(template) = context.realm().lookup_template(site) { context.vm.push(template); @@ -43,8 +43,8 @@ impl Operation for TemplateCreate { const INSTRUCTION: &'static str = "INST - TemplateCreate"; fn execute(context: &mut Context<'_>) -> JsResult { - let site = context.vm.read::(); let count = context.vm.read::(); + let site = context.vm.read::(); let template = Array::array_create(count.into(), None, context).expect("cannot fail per spec"); diff --git a/boa_parser/src/parser/cursor/mod.rs b/boa_parser/src/parser/cursor/mod.rs index 22eeb5805ad..0b91a3cb060 100644 --- a/boa_parser/src/parser/cursor/mod.rs +++ b/boa_parser/src/parser/cursor/mod.rs @@ -9,8 +9,7 @@ use crate::{ use boa_ast::{Position, Punctuator}; use boa_interner::Interner; use buffered_lexer::BufferedLexer; -use rustc_hash::FxHasher; -use std::{hash::Hasher, io::Read}; +use std::io::Read; /// The result of a peek for a semicolon. #[derive(Debug)] @@ -188,11 +187,12 @@ where /// Get the identifier for a tagged template. #[inline] pub(super) fn tagged_template_identifier(&mut self) -> u64 { - let mut hasher = FxHasher::default(); - hasher.write_u32(self.identifier); - hasher.write_u32(self.tagged_templates_count); self.tagged_templates_count += 1; - hasher.finish() + + let identifier = u64::from(self.identifier); + let count = u64::from(self.tagged_templates_count); + + (count << 32) | identifier } /// Returns an error if the next token is not of kind `kind`. From e2e9b87dee3fff895fc008309f4b585411835474 Mon Sep 17 00:00:00 2001 From: raskad <32105367+raskad@users.noreply.github.com> Date: Sat, 13 May 2023 04:59:06 +0200 Subject: [PATCH 4/4] Apply suggestion --- boa_engine/src/context/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boa_engine/src/context/mod.rs b/boa_engine/src/context/mod.rs index 9fde27a844e..9280c9eee0f 100644 --- a/boa_engine/src/context/mod.rs +++ b/boa_engine/src/context/mod.rs @@ -661,7 +661,7 @@ impl Context<'_> { std::mem::swap(&mut self.realm, realm); } - /// Get and increment the parser identifier. + /// Increment and get the parser identifier. pub(crate) fn next_parser_identifier(&mut self) -> u32 { self.parser_identifier += 1; self.parser_identifier