1mod class;
4mod declaration;
5mod declarations;
6mod env;
7mod expression;
8mod function;
9mod jump_control;
10mod module;
11mod register;
12mod statement;
13mod utils;
14
15use std::{
16 borrow::{Borrow, BorrowMut},
17 cell::Cell,
18 ops::{Deref, DerefMut},
19};
20
21use crate::{
22 JsBigInt, JsStr, JsString, SourceText, SpannedSourceText,
23 builtins::function::{ThisMode, arguments::MappedArguments},
24 js_string,
25 vm::{
26 CallFrame, CodeBlock, CodeBlockFlags, Constant, GeneratorResumeKind, Handler, InlineCache,
27 opcode::{BindingOpcode, ByteCodeEmitter, VaryingOperand},
28 source_info::{SourceInfo, SourceMap, SourceMapBuilder, SourcePath},
29 },
30};
31use boa_ast::{
32 Declaration, Expression, LinearSpan, Position, Spanned, Statement, StatementList,
33 StatementListItem,
34 declaration::{Binding, LexicalDeclaration, VarDeclaration},
35 expression::{
36 Call, Identifier, New, Optional, OptionalOperationKind,
37 access::{PropertyAccess, PropertyAccessField},
38 literal::ObjectMethodDefinition,
39 operator::{assign::AssignTarget, update::UpdateTarget},
40 },
41 function::{
42 ArrowFunction, AsyncArrowFunction, AsyncFunctionDeclaration, AsyncFunctionExpression,
43 AsyncGeneratorDeclaration, AsyncGeneratorExpression, ClassMethodDefinition,
44 FormalParameterList, FunctionBody, FunctionDeclaration, FunctionExpression,
45 GeneratorDeclaration, GeneratorExpression, PrivateName,
46 },
47 operations::returns_value,
48 pattern::Pattern,
49 property::MethodDefinitionKind,
50 scope::{BindingLocator, BindingLocatorError, FunctionScopes, IdentifierReference, Scope},
51};
52use boa_gc::Gc;
53use boa_interner::{Interner, Sym};
54use boa_macros::js_str;
55use rustc_hash::FxHashMap;
56use thin_vec::ThinVec;
57
58pub(crate) use declarations::{
59 eval_declaration_instantiation_context, global_declaration_instantiation_context,
60};
61pub(crate) use function::FunctionCompiler;
62pub(crate) use jump_control::JumpControlInfo;
63pub(crate) use register::*;
64
65pub(crate) trait ToJsString {
66 fn to_js_string(&self, interner: &Interner) -> JsString;
67}
68
69impl ToJsString for Sym {
70 fn to_js_string(&self, interner: &Interner) -> JsString {
71 let string = interner.resolve_expect(*self).utf16();
73 for c in string {
74 if u8::try_from(*c).is_err() {
75 return js_string!(string);
76 }
77 }
78 let string = string.iter().map(|c| *c as u8).collect::<Vec<_>>();
79 js_string!(JsStr::latin1(&string))
80 }
81}
82
83impl ToJsString for Identifier {
84 fn to_js_string(&self, interner: &Interner) -> JsString {
85 self.sym().to_js_string(interner)
86 }
87}
88
89#[derive(Debug, Clone, Copy, PartialEq)]
91pub(crate) enum NodeKind {
92 Declaration,
93 Expression,
94}
95
96#[derive(Debug, Clone, Copy, PartialEq)]
98pub(crate) enum FunctionKind {
99 Ordinary,
100 Arrow,
101 AsyncArrow,
102 Async,
103 Generator,
104 AsyncGenerator,
105}
106
107impl FunctionKind {
108 pub(crate) const fn is_arrow(self) -> bool {
109 matches!(self, Self::Arrow | Self::AsyncArrow)
110 }
111
112 pub(crate) const fn is_async(self) -> bool {
113 matches!(self, Self::Async | Self::AsyncGenerator | Self::AsyncArrow)
114 }
115
116 pub(crate) const fn is_generator(self) -> bool {
117 matches!(self, Self::Generator | Self::AsyncGenerator)
118 }
119}
120
121#[derive(Debug, Clone, Copy)]
123pub(crate) struct FunctionSpec<'a> {
124 pub(crate) kind: FunctionKind,
125 pub(crate) name: Option<Identifier>,
126 parameters: &'a FormalParameterList,
127 body: &'a FunctionBody,
128 pub(crate) scopes: &'a FunctionScopes,
129 pub(crate) name_scope: Option<&'a Scope>,
130 linear_span: Option<LinearSpan>,
131 pub(crate) contains_direct_eval: bool,
132}
133
134impl PartialEq for FunctionSpec<'_> {
135 fn eq(&self, other: &Self) -> bool {
136 self.kind == other.kind
138 && self.name == other.name
139 && self.parameters == other.parameters
140 && self.body == other.body
141 && self.scopes == other.scopes
142 && self.name_scope == other.name_scope
143 }
144}
145
146impl<'a> From<&'a FunctionDeclaration> for FunctionSpec<'a> {
147 fn from(function: &'a FunctionDeclaration) -> Self {
148 FunctionSpec {
149 kind: FunctionKind::Ordinary,
150 name: Some(function.name()),
151 parameters: function.parameters(),
152 body: function.body(),
153 scopes: function.scopes(),
154 name_scope: None,
155 linear_span: Some(function.linear_span()),
156 contains_direct_eval: function.contains_direct_eval(),
157 }
158 }
159}
160
161impl<'a> From<&'a GeneratorDeclaration> for FunctionSpec<'a> {
162 fn from(function: &'a GeneratorDeclaration) -> Self {
163 FunctionSpec {
164 kind: FunctionKind::Generator,
165 name: Some(function.name()),
166 parameters: function.parameters(),
167 body: function.body(),
168 scopes: function.scopes(),
169 name_scope: None,
170 linear_span: Some(function.linear_span()),
171 contains_direct_eval: function.contains_direct_eval(),
172 }
173 }
174}
175
176impl<'a> From<&'a AsyncFunctionDeclaration> for FunctionSpec<'a> {
177 fn from(function: &'a AsyncFunctionDeclaration) -> Self {
178 FunctionSpec {
179 kind: FunctionKind::Async,
180 name: Some(function.name()),
181 parameters: function.parameters(),
182 body: function.body(),
183 scopes: function.scopes(),
184 name_scope: None,
185 linear_span: Some(function.linear_span()),
186 contains_direct_eval: function.contains_direct_eval(),
187 }
188 }
189}
190
191impl<'a> From<&'a AsyncGeneratorDeclaration> for FunctionSpec<'a> {
192 fn from(function: &'a AsyncGeneratorDeclaration) -> Self {
193 FunctionSpec {
194 kind: FunctionKind::AsyncGenerator,
195 name: Some(function.name()),
196 parameters: function.parameters(),
197 body: function.body(),
198 scopes: function.scopes(),
199 name_scope: None,
200 linear_span: Some(function.linear_span()),
201 contains_direct_eval: function.contains_direct_eval(),
202 }
203 }
204}
205
206impl<'a> From<&'a FunctionExpression> for FunctionSpec<'a> {
207 fn from(function: &'a FunctionExpression) -> Self {
208 FunctionSpec {
209 kind: FunctionKind::Ordinary,
210 name: function.name(),
211 parameters: function.parameters(),
212 body: function.body(),
213 scopes: function.scopes(),
214 name_scope: function.name_scope(),
215 linear_span: function.linear_span(),
216 contains_direct_eval: function.contains_direct_eval(),
217 }
218 }
219}
220
221impl<'a> From<&'a ArrowFunction> for FunctionSpec<'a> {
222 fn from(function: &'a ArrowFunction) -> Self {
223 FunctionSpec {
224 kind: FunctionKind::Arrow,
225 name: function.name(),
226 parameters: function.parameters(),
227 body: function.body(),
228 scopes: function.scopes(),
229 name_scope: None,
230 linear_span: Some(function.linear_span()),
231 contains_direct_eval: function.contains_direct_eval(),
232 }
233 }
234}
235
236impl<'a> From<&'a AsyncArrowFunction> for FunctionSpec<'a> {
237 fn from(function: &'a AsyncArrowFunction) -> Self {
238 FunctionSpec {
239 kind: FunctionKind::AsyncArrow,
240 name: function.name(),
241 parameters: function.parameters(),
242 body: function.body(),
243 scopes: function.scopes(),
244 name_scope: None,
245 linear_span: Some(function.linear_span()),
246 contains_direct_eval: function.contains_direct_eval(),
247 }
248 }
249}
250
251impl<'a> From<&'a AsyncFunctionExpression> for FunctionSpec<'a> {
252 fn from(function: &'a AsyncFunctionExpression) -> Self {
253 FunctionSpec {
254 kind: FunctionKind::Async,
255 name: function.name(),
256 parameters: function.parameters(),
257 body: function.body(),
258 scopes: function.scopes(),
259 name_scope: function.name_scope(),
260 linear_span: Some(function.linear_span()),
261 contains_direct_eval: function.contains_direct_eval(),
262 }
263 }
264}
265
266impl<'a> From<&'a GeneratorExpression> for FunctionSpec<'a> {
267 fn from(function: &'a GeneratorExpression) -> Self {
268 FunctionSpec {
269 kind: FunctionKind::Generator,
270 name: function.name(),
271 parameters: function.parameters(),
272 body: function.body(),
273 scopes: function.scopes(),
274 name_scope: function.name_scope(),
275 linear_span: Some(function.linear_span()),
276 contains_direct_eval: function.contains_direct_eval(),
277 }
278 }
279}
280
281impl<'a> From<&'a AsyncGeneratorExpression> for FunctionSpec<'a> {
282 fn from(function: &'a AsyncGeneratorExpression) -> Self {
283 FunctionSpec {
284 kind: FunctionKind::AsyncGenerator,
285 name: function.name(),
286 parameters: function.parameters(),
287 body: function.body(),
288 scopes: function.scopes(),
289 name_scope: function.name_scope(),
290 linear_span: Some(function.linear_span()),
291 contains_direct_eval: function.contains_direct_eval(),
292 }
293 }
294}
295
296impl<'a> From<&'a ClassMethodDefinition> for FunctionSpec<'a> {
297 fn from(method: &'a ClassMethodDefinition) -> Self {
298 let kind = match method.kind() {
299 MethodDefinitionKind::Generator => FunctionKind::Generator,
300 MethodDefinitionKind::AsyncGenerator => FunctionKind::AsyncGenerator,
301 MethodDefinitionKind::Async => FunctionKind::Async,
302 _ => FunctionKind::Ordinary,
303 };
304
305 FunctionSpec {
306 kind,
307 name: None,
308 parameters: method.parameters(),
309 body: method.body(),
310 scopes: method.scopes(),
311 name_scope: None,
312 linear_span: Some(method.linear_span()),
313 contains_direct_eval: method.contains_direct_eval(),
314 }
315 }
316}
317
318impl<'a> From<&'a ObjectMethodDefinition> for FunctionSpec<'a> {
319 fn from(method: &'a ObjectMethodDefinition) -> Self {
320 let kind = match method.kind() {
321 MethodDefinitionKind::Generator => FunctionKind::Generator,
322 MethodDefinitionKind::AsyncGenerator => FunctionKind::AsyncGenerator,
323 MethodDefinitionKind::Async => FunctionKind::Async,
324 _ => FunctionKind::Ordinary,
325 };
326
327 FunctionSpec {
328 kind,
329 name: method.name().literal(),
330 parameters: method.parameters(),
331 body: method.body(),
332 scopes: method.scopes(),
333 name_scope: None,
334 linear_span: Some(method.linear_span()),
335 contains_direct_eval: method.contains_direct_eval(),
336 }
337 }
338}
339
340#[derive(Debug, Clone, Copy)]
341pub(crate) enum MethodKind {
342 Get,
343 Set,
344 Ordinary,
345}
346
347#[derive(Debug, Clone, Copy)]
349enum Callable<'a> {
350 Call(&'a Call),
351 New(&'a New),
352}
353
354#[derive(Debug, Clone, PartialEq, Eq, Hash)]
355enum Literal {
356 String(JsString),
357 BigInt(JsBigInt),
358}
359
360#[must_use]
361#[derive(Debug, Clone, Copy, PartialEq, Eq)]
362pub(crate) struct Label {
363 index: u32,
364}
365
366#[derive(Debug, Clone, Copy)]
367#[allow(variant_size_differences)]
368enum Access<'a> {
369 Variable { name: Identifier },
370 Property { access: &'a PropertyAccess },
371 This,
372}
373
374impl Access<'_> {
375 const fn from_assign_target(target: &AssignTarget) -> Result<Access<'_>, &Pattern> {
376 match target {
377 AssignTarget::Identifier(ident) => Ok(Access::Variable { name: *ident }),
378 AssignTarget::Access(access) => Ok(Access::Property { access }),
379 AssignTarget::Pattern(pat) => Err(pat),
380 }
381 }
382
383 const fn from_expression(expr: &Expression) -> Option<Access<'_>> {
384 match expr {
385 Expression::Identifier(name) => Some(Access::Variable { name: *name }),
386 Expression::PropertyAccess(access) => Some(Access::Property { access }),
387 Expression::This(_this) => Some(Access::This),
388 Expression::Parenthesized(expr) => Self::from_expression(expr.expression()),
389 _ => None,
390 }
391 }
392
393 const fn from_update_target(target: &UpdateTarget) -> Access<'_> {
394 match target {
395 UpdateTarget::Identifier(name) => Access::Variable { name: *name },
396 UpdateTarget::PropertyAccess(access) => Access::Property { access },
397 }
398 }
399}
400
401#[derive(Copy, Clone, Debug)]
402pub(crate) enum BindingAccessOpcode {
403 PutLexicalValue,
404 DefInitVar,
405 SetName,
406 SetNameByLocator,
407 GetName,
408 GetNameAndLocator,
409 GetNameOrUndefined,
410 DeleteName,
411 GetLocator,
412 DefVar,
413}
414
415pub(crate) struct SourcePositionGuard<'a, 'b> {
417 compiler: &'a mut ByteCompiler<'b>,
418}
419impl<'a, 'b> SourcePositionGuard<'a, 'b> {
420 fn new(compiler: &'a mut ByteCompiler<'b>, position: Position) -> Self {
421 compiler.push_source_position(position);
422 Self { compiler }
423 }
424}
425impl Drop for SourcePositionGuard<'_, '_> {
426 fn drop(&mut self) {
427 self.pop_source_position();
428 }
429}
430impl<'a> Deref for SourcePositionGuard<'_, 'a> {
431 type Target = ByteCompiler<'a>;
432 fn deref(&self) -> &Self::Target {
433 self.compiler
434 }
435}
436impl DerefMut for SourcePositionGuard<'_, '_> {
437 fn deref_mut(&mut self) -> &mut Self::Target {
438 self.compiler
439 }
440}
441impl<'a> Borrow<ByteCompiler<'a>> for SourcePositionGuard<'_, 'a> {
442 fn borrow(&self) -> &ByteCompiler<'a> {
443 self.compiler
444 }
445}
446impl<'a> BorrowMut<ByteCompiler<'a>> for SourcePositionGuard<'_, 'a> {
447 fn borrow_mut(&mut self) -> &mut ByteCompiler<'a> {
448 self.compiler
449 }
450}
451
452#[derive(Debug)]
454#[allow(clippy::struct_excessive_bools)]
455pub struct ByteCompiler<'ctx> {
456 pub(crate) function_name: JsString,
458
459 pub(crate) length: u32,
461
462 pub(crate) register_allocator: RegisterAllocator,
463
464 pub(crate) this_mode: ThisMode,
466
467 pub(crate) params: FormalParameterList,
469
470 pub(crate) parameter_scope: Scope,
472
473 pub(crate) bytecode: ByteCodeEmitter,
475
476 pub(crate) source_map_builder: SourceMapBuilder,
477 pub(crate) source_path: SourcePath,
478
479 pub(crate) constants: ThinVec<Constant>,
480
481 pub(crate) bindings: Vec<BindingLocator>,
483
484 pub(crate) local_binding_registers: FxHashMap<IdentifierReference, u32>,
485
486 pub(crate) variable_scope: Scope,
488
489 pub(crate) lexical_scope: Scope,
491
492 pub(crate) current_open_environments_count: u32,
493 code_block_flags: CodeBlockFlags,
494 handlers: ThinVec<Handler>,
495 pub(crate) ic: Vec<InlineCache>,
496 literals_map: FxHashMap<Literal, u32>,
497 names_map: FxHashMap<Sym, u32>,
498 bindings_map: FxHashMap<BindingLocator, u32>,
499 jump_info: Vec<JumpControlInfo>,
500
501 pub(crate) async_handler: Option<u32>,
505 json_parse: bool,
506
507 pub(crate) in_with: bool,
509
510 pub(crate) emitted_mapped_arguments_object_opcode: bool,
512
513 pub(crate) interner: &'ctx mut Interner,
514 spanned_source_text: SpannedSourceText,
515
516 #[cfg(feature = "annex-b")]
517 pub(crate) annex_b_function_names: Vec<Sym>,
518}
519
520pub(crate) enum BindingKind {
521 Stack(u32),
522 Local(Option<u32>),
523 Global(u32),
524}
525
526impl<'ctx> ByteCompiler<'ctx> {
527 const DUMMY_ADDRESS: u32 = u32::MAX;
529 const DUMMY_LABEL: Label = Label { index: u32::MAX };
530
531 #[inline]
533 #[allow(clippy::too_many_arguments)]
534 #[allow(clippy::fn_params_excessive_bools)]
535 pub(crate) fn new(
536 name: JsString,
537 strict: bool,
538 json_parse: bool,
539 variable_scope: Scope,
540 lexical_scope: Scope,
541 is_async: bool,
542 is_generator: bool,
543 interner: &'ctx mut Interner,
544 in_with: bool,
545 spanned_source_text: SpannedSourceText,
546 source_path: SourcePath,
547 ) -> ByteCompiler<'ctx> {
548 let mut code_block_flags = CodeBlockFlags::empty();
549 code_block_flags.set(CodeBlockFlags::STRICT, strict);
550 code_block_flags.set(CodeBlockFlags::IS_ASYNC, is_async);
551 code_block_flags.set(CodeBlockFlags::IS_GENERATOR, is_generator);
552 code_block_flags |= CodeBlockFlags::HAS_PROTOTYPE_PROPERTY;
553
554 let mut register_allocator = RegisterAllocator::default();
555 if is_async {
556 let promise_register = register_allocator.alloc_persistent();
557 let resolve_register = register_allocator.alloc_persistent();
558 let reject_register = register_allocator.alloc_persistent();
559
560 debug_assert_eq!(
561 promise_register.index(),
562 CallFrame::PROMISE_CAPABILITY_PROMISE_REGISTER_INDEX as u32
563 );
564 debug_assert_eq!(
565 resolve_register.index(),
566 CallFrame::PROMISE_CAPABILITY_RESOLVE_REGISTER_INDEX as u32
567 );
568 debug_assert_eq!(
569 reject_register.index(),
570 CallFrame::PROMISE_CAPABILITY_REJECT_REGISTER_INDEX as u32
571 );
572
573 if is_generator {
574 let async_function_object_register = register_allocator.alloc_persistent();
575 debug_assert_eq!(
576 async_function_object_register.index(),
577 CallFrame::ASYNC_GENERATOR_OBJECT_REGISTER_INDEX as u32
578 );
579 }
580 }
581
582 Self {
583 function_name: name,
584 length: 0,
585 bytecode: ByteCodeEmitter::new(),
586 source_map_builder: SourceMapBuilder::default(),
587 constants: ThinVec::default(),
588 bindings: Vec::default(),
589 local_binding_registers: FxHashMap::default(),
590 this_mode: ThisMode::Global,
591 params: FormalParameterList::default(),
592 parameter_scope: Scope::default(),
593 current_open_environments_count: 0,
594
595 register_allocator,
596 code_block_flags,
597 handlers: ThinVec::default(),
598 ic: Vec::default(),
599
600 literals_map: FxHashMap::default(),
601 names_map: FxHashMap::default(),
602 bindings_map: FxHashMap::default(),
603 jump_info: Vec::new(),
604 async_handler: None,
605 json_parse,
606 variable_scope,
607 lexical_scope,
608 interner,
609 spanned_source_text,
610 source_path,
611
612 #[cfg(feature = "annex-b")]
613 annex_b_function_names: Vec::new(),
614 in_with,
615 emitted_mapped_arguments_object_opcode: false,
616 }
617 }
618
619 pub(crate) fn source_text(&self) -> SourceText {
620 self.spanned_source_text.source_text()
621 }
622
623 pub(crate) const fn strict(&self) -> bool {
624 self.code_block_flags.contains(CodeBlockFlags::STRICT)
625 }
626
627 pub(crate) const fn is_async(&self) -> bool {
628 self.code_block_flags.contains(CodeBlockFlags::IS_ASYNC)
629 }
630
631 pub(crate) const fn is_generator(&self) -> bool {
632 self.code_block_flags.contains(CodeBlockFlags::IS_GENERATOR)
633 }
634
635 pub(crate) const fn is_async_generator(&self) -> bool {
636 self.is_async() && self.is_generator()
637 }
638
639 pub(crate) fn interner(&self) -> &Interner {
640 self.interner
641 }
642
643 fn get_or_insert_literal(&mut self, literal: Literal) -> u32 {
644 if let Some(index) = self.literals_map.get(&literal) {
645 return *index;
646 }
647
648 let value = match literal.clone() {
649 Literal::String(value) => Constant::String(value),
650 Literal::BigInt(value) => Constant::BigInt(value),
651 };
652
653 let index = self.constants.len() as u32;
654 self.constants.push(value);
655 self.literals_map.insert(literal, index);
656 index
657 }
658
659 fn get_or_insert_name(&mut self, name: Sym) -> u32 {
660 if let Some(index) = self.names_map.get(&name) {
661 return *index;
662 }
663
664 let index = self.constants.len() as u32;
665 let string = name.to_js_string(self.interner());
666 self.constants.push(Constant::String(string));
667 self.names_map.insert(name, index);
668 index
669 }
670
671 fn get_or_insert_string(&mut self, value: JsString) -> u32 {
672 self.get_or_insert_literal(Literal::String(value))
673 }
674
675 #[inline]
676 fn get_or_insert_private_name(&mut self, name: PrivateName) -> u32 {
677 self.get_or_insert_name(name.description())
678 }
679
680 #[inline]
683 pub(crate) fn get_binding(&mut self, binding: &IdentifierReference) -> BindingKind {
684 if binding.is_global_object() {
685 if let Some(index) = self.bindings_map.get(&binding.locator()) {
686 return BindingKind::Global(*index);
687 }
688
689 let index = self.bindings.len() as u32;
690 self.bindings.push(binding.locator().clone());
691 self.bindings_map.insert(binding.locator(), index);
692 return BindingKind::Global(index);
693 }
694
695 if binding.local() {
696 return BindingKind::Local(self.local_binding_registers.get(binding).copied());
697 }
698
699 if let Some(index) = self.bindings_map.get(&binding.locator()) {
700 return BindingKind::Stack(*index);
701 }
702
703 let index = self.bindings.len() as u32;
704 self.bindings.push(binding.locator().clone());
705 self.bindings_map.insert(binding.locator(), index);
706 BindingKind::Stack(index)
707 }
708
709 #[inline]
710 pub(crate) fn insert_binding(&mut self, binding: IdentifierReference) -> BindingKind {
711 if binding.is_global_object() {
712 if let Some(index) = self.bindings_map.get(&binding.locator()) {
713 return BindingKind::Global(*index);
714 }
715
716 let index = self.bindings.len() as u32;
717 self.bindings.push(binding.locator().clone());
718 self.bindings_map.insert(binding.locator(), index);
719 return BindingKind::Global(index);
720 }
721
722 if binding.local() {
723 return BindingKind::Local(Some(
724 *self
725 .local_binding_registers
726 .entry(binding)
727 .or_insert_with(|| self.register_allocator.alloc_persistent().index()),
728 ));
729 }
730
731 if let Some(index) = self.bindings_map.get(&binding.locator()) {
732 return BindingKind::Stack(*index);
733 }
734
735 let index = self.bindings.len() as u32;
736 self.bindings.push(binding.locator().clone());
737 self.bindings_map.insert(binding.locator(), index);
738 BindingKind::Stack(index)
739 }
740
741 #[inline]
742 #[must_use]
743 pub(crate) fn push_function_to_constants(&mut self, function: Gc<CodeBlock>) -> u32 {
744 let index = self.constants.len() as u32;
745 self.constants.push(Constant::Function(function));
746 index
747 }
748
749 fn emit_binding(&mut self, opcode: BindingOpcode, name: JsString, value: &Register) {
750 match opcode {
751 BindingOpcode::Var => {
752 let binding = self.variable_scope.get_identifier_reference(name);
753 if !binding.locator().is_global() {
754 let index = self.insert_binding(binding);
755 self.emit_binding_access(BindingAccessOpcode::DefVar, &index, value);
756 }
757 }
758 BindingOpcode::InitVar => match self.lexical_scope.set_mutable_binding(name.clone()) {
759 Ok(binding) => {
760 let index = self.insert_binding(binding);
761 self.emit_binding_access(BindingAccessOpcode::DefInitVar, &index, value);
762 }
763 Err(BindingLocatorError::MutateImmutable) => {
764 let index = self.get_or_insert_string(name);
765 self.bytecode.emit_throw_mutate_immutable(index.into());
766 }
767 Err(BindingLocatorError::Silent) => {}
768 },
769 BindingOpcode::InitLexical => {
770 let binding = self.lexical_scope.get_identifier_reference(name);
771 let index = self.insert_binding(binding);
772 self.emit_binding_access(BindingAccessOpcode::PutLexicalValue, &index, value);
773 }
774 BindingOpcode::SetName => match self.lexical_scope.set_mutable_binding(name.clone()) {
775 Ok(binding) => {
776 let index = self.insert_binding(binding);
777 self.emit_binding_access(BindingAccessOpcode::SetName, &index, value);
778 }
779 Err(BindingLocatorError::MutateImmutable) => {
780 let index = self.get_or_insert_string(name);
781 self.bytecode.emit_throw_mutate_immutable(index.into());
782 }
783 Err(BindingLocatorError::Silent) => {}
784 },
785 }
786 }
787
788 fn next_opcode_location(&mut self) -> u32 {
789 self.bytecode.next_opcode_location()
790 }
791
792 pub(crate) fn position_guard(
793 &mut self,
794 spanned: impl Spanned,
795 ) -> SourcePositionGuard<'_, 'ctx> {
796 SourcePositionGuard::new(self, spanned.span().start())
797 }
798
799 pub(crate) fn push_source_position<T>(&mut self, position: T)
800 where
801 T: Into<Option<Position>>,
802 {
803 let start_pc = self.next_opcode_location();
804 self.source_map_builder
805 .push_source_position(start_pc, position.into());
806 }
807
808 pub(crate) fn pop_source_position(&mut self) {
809 let start_pc = self.next_opcode_location();
810 self.source_map_builder.pop_source_position(start_pc);
811 }
812
813 pub(crate) fn emit_get_function(&mut self, dst: &Register, index: u32) {
814 self.bytecode
815 .emit_get_function(dst.variable(), index.into());
816 }
817
818 fn pop_into_register(&mut self, dst: &Register) {
819 self.bytecode.emit_pop_into_register(dst.variable());
820 }
821
822 pub(crate) fn push_from_register(&mut self, src: &Register) {
823 self.bytecode.emit_push_from_register(src.variable());
824 }
825
826 pub(crate) fn emit_binding_access(
827 &mut self,
828 opcode: BindingAccessOpcode,
829 binding: &BindingKind,
830 value: &Register,
831 ) {
832 match binding {
833 BindingKind::Global(index) => match opcode {
834 BindingAccessOpcode::SetNameByLocator => {
835 self.bytecode.emit_set_name_by_locator(value.variable());
836 }
837 BindingAccessOpcode::GetName => {
838 let ic_index = self.ic.len() as u32;
839 let name = self.bindings[*index as usize].name().clone();
840 self.ic.push(InlineCache::new(name));
841 self.bytecode.emit_get_name_global(
842 value.variable(),
843 (*index).into(),
844 ic_index.into(),
845 );
846 }
847 BindingAccessOpcode::GetLocator => self.bytecode.emit_get_locator((*index).into()),
848 BindingAccessOpcode::DefVar => self.bytecode.emit_def_var((*index).into()),
849 BindingAccessOpcode::PutLexicalValue => self
850 .bytecode
851 .emit_put_lexical_value(value.variable(), (*index).into()),
852 BindingAccessOpcode::DefInitVar => self
853 .bytecode
854 .emit_def_init_var(value.variable(), (*index).into()),
855 BindingAccessOpcode::SetName => self
856 .bytecode
857 .emit_set_name(value.variable(), (*index).into()),
858 BindingAccessOpcode::GetNameAndLocator => self
859 .bytecode
860 .emit_get_name_and_locator(value.variable(), (*index).into()),
861 BindingAccessOpcode::GetNameOrUndefined => self
862 .bytecode
863 .emit_get_name_or_undefined(value.variable(), (*index).into()),
864 BindingAccessOpcode::DeleteName => self
865 .bytecode
866 .emit_delete_name(value.variable(), (*index).into()),
867 },
868 BindingKind::Stack(index) => match opcode {
869 BindingAccessOpcode::SetNameByLocator => {
870 self.bytecode.emit_set_name_by_locator(value.variable());
871 }
872 BindingAccessOpcode::GetLocator => self.bytecode.emit_get_locator((*index).into()),
873 BindingAccessOpcode::DefVar => self.bytecode.emit_def_var((*index).into()),
874 BindingAccessOpcode::PutLexicalValue => self
875 .bytecode
876 .emit_put_lexical_value(value.variable(), (*index).into()),
877 BindingAccessOpcode::DefInitVar => self
878 .bytecode
879 .emit_def_init_var(value.variable(), (*index).into()),
880 BindingAccessOpcode::SetName => self
881 .bytecode
882 .emit_set_name(value.variable(), (*index).into()),
883 BindingAccessOpcode::GetName => self
884 .bytecode
885 .emit_get_name(value.variable(), (*index).into()),
886 BindingAccessOpcode::GetNameAndLocator => self
887 .bytecode
888 .emit_get_name_and_locator(value.variable(), (*index).into()),
889 BindingAccessOpcode::GetNameOrUndefined => self
890 .bytecode
891 .emit_get_name_or_undefined(value.variable(), (*index).into()),
892 BindingAccessOpcode::DeleteName => self
893 .bytecode
894 .emit_delete_name(value.variable(), (*index).into()),
895 },
896 BindingKind::Local(None) => {
897 let error_msg = self.get_or_insert_literal(Literal::String(js_string!(
898 "access of uninitialized binding"
899 )));
900 self.bytecode
901 .emit_throw_new_reference_error(error_msg.into());
902 }
903 BindingKind::Local(Some(index)) => match opcode {
904 BindingAccessOpcode::GetName
905 | BindingAccessOpcode::GetNameOrUndefined
906 | BindingAccessOpcode::GetNameAndLocator => {
907 self.bytecode.emit_move(value.variable(), (*index).into());
908 }
909 BindingAccessOpcode::GetLocator | BindingAccessOpcode::DefVar => {}
910 BindingAccessOpcode::SetName
911 | BindingAccessOpcode::DefInitVar
912 | BindingAccessOpcode::PutLexicalValue
913 | BindingAccessOpcode::SetNameByLocator => {
914 self.bytecode.emit_move((*index).into(), value.variable());
915 }
916 BindingAccessOpcode::DeleteName => self.bytecode.emit_push_false(value.variable()),
917 },
918 }
919 }
920
921 fn emit_get_property_by_name(
922 &mut self,
923 dst: &Register,
924 receiver: &Register,
925 value: &Register,
926 ident: Sym,
927 ) {
928 let ic_index = self.ic.len() as u32;
929
930 let name_index = self.get_or_insert_name(ident);
931 let Constant::String(ref name) = self.constants[name_index as usize].clone() else {
932 unreachable!("there should be a string at index")
933 };
934 self.ic.push(InlineCache::new(name.clone()));
935
936 self.bytecode.emit_get_property_by_name(
937 dst.variable(),
938 receiver.variable(),
939 value.variable(),
940 ic_index.into(),
941 );
942 }
943
944 fn emit_set_property_by_name(
945 &mut self,
946 value: &Register,
947 receiver: &Register,
948 object: &Register,
949 ident: Sym,
950 ) {
951 let ic_index = self.ic.len() as u32;
952
953 let name_index = self.get_or_insert_name(ident);
954 let Constant::String(ref name) = self.constants[name_index as usize].clone() else {
955 unreachable!("there should be a string at index")
956 };
957 self.ic.push(InlineCache::new(name.clone()));
958
959 self.bytecode.emit_set_property_by_name(
960 value.variable(),
961 receiver.variable(),
962 object.variable(),
963 ic_index.into(),
964 );
965 }
966
967 fn emit_type_error(&mut self, message: &str) {
968 let error_msg = self.get_or_insert_literal(Literal::String(js_string!(message)));
969 self.bytecode.emit_throw_new_type_error(error_msg.into());
970 }
971 fn emit_syntax_error(&mut self, message: &str) {
972 let error_msg = self.get_or_insert_literal(Literal::String(js_string!(message)));
973 self.bytecode.emit_throw_new_syntax_error(error_msg.into());
974 }
975
976 fn emit_push_integer(&mut self, value: i32, dst: &Register) {
977 self.emit_push_integer_with_index(value, dst.variable());
978 }
979
980 fn emit_push_integer_with_index(&mut self, value: i32, dst: VaryingOperand) {
981 match value {
982 0 => self.bytecode.emit_push_zero(dst),
983 1 => self.bytecode.emit_push_one(dst),
984 x if i32::from(x as i8) == x => self.bytecode.emit_push_int8(dst, x as i8),
985 x if i32::from(x as i16) == x => {
986 self.bytecode.emit_push_int16(dst, x as i16);
987 }
988 x => self.bytecode.emit_push_int32(dst, x),
989 }
990 }
991
992 fn emit_push_literal(&mut self, literal: Literal, dst: &Register) {
993 let index = self.get_or_insert_literal(literal);
994 self.bytecode
995 .emit_push_literal(dst.variable(), index.into());
996 }
997
998 fn emit_push_rational(&mut self, value: f64, dst: &Register) {
999 if value.is_nan() {
1000 return self.bytecode.emit_push_nan(dst.variable());
1001 }
1002
1003 if value.is_infinite() {
1004 if value.is_sign_positive() {
1005 return self.bytecode.emit_push_positive_infinity(dst.variable());
1006 }
1007 return self.bytecode.emit_push_negative_infinity(dst.variable());
1008 }
1009
1010 if f64::from(value as i32).to_bits() == value.to_bits() {
1012 self.emit_push_integer(value as i32, dst);
1013 } else {
1014 let f32_value = value as f32;
1015
1016 #[allow(clippy::float_cmp)]
1017 if f64::from(f32_value) == value {
1018 self.bytecode.emit_push_float(dst.variable(), f32_value);
1019 } else {
1020 self.bytecode.emit_push_double(dst.variable(), value);
1021 }
1022 }
1023 }
1024
1025 fn jump(&mut self) -> Label {
1026 let index = self.next_opcode_location();
1027 self.bytecode.emit_jump(Self::DUMMY_ADDRESS);
1028 Label { index }
1029 }
1030
1031 pub(crate) fn jump_if_true(&mut self, value: &Register) -> Label {
1032 let index = self.next_opcode_location();
1033 self.bytecode
1034 .emit_jump_if_true(Self::DUMMY_ADDRESS, value.variable());
1035 Label { index }
1036 }
1037
1038 pub(crate) fn jump_if_false(&mut self, value: &Register) -> Label {
1039 let index = self.next_opcode_location();
1040 self.bytecode
1041 .emit_jump_if_false(Self::DUMMY_ADDRESS, value.variable());
1042 Label { index }
1043 }
1044
1045 pub(crate) fn jump_if_null_or_undefined(&mut self, value: &Register) -> Label {
1046 let index = self.next_opcode_location();
1047 self.bytecode
1048 .emit_jump_if_null_or_undefined(Self::DUMMY_ADDRESS, value.variable());
1049 Label { index }
1050 }
1051
1052 pub(crate) fn emit_jump_if_not_undefined(&mut self, value: &Register) -> Label {
1053 let index = self.next_opcode_location();
1054 self.bytecode
1055 .emit_jump_if_not_undefined(Self::DUMMY_ADDRESS, value.variable());
1056 Label { index }
1057 }
1058
1059 pub(crate) fn case(&mut self, value: &Register, condition: &Register) -> Label {
1060 let index = self.next_opcode_location();
1061 self.bytecode
1062 .emit_case(Self::DUMMY_ADDRESS, value.variable(), condition.variable());
1063 Label { index }
1064 }
1065
1066 pub(crate) fn template_lookup(&mut self, dst: &Register, site: u64) -> Label {
1067 let index = self.next_opcode_location();
1068 self.bytecode
1069 .emit_template_lookup(Self::DUMMY_ADDRESS, site, dst.variable());
1070 Label { index }
1071 }
1072
1073 fn emit_resume_kind(&mut self, resume_kind: GeneratorResumeKind, dst: &Register) {
1074 self.emit_push_integer(resume_kind as i32, dst);
1075 }
1076
1077 fn jump_if_not_resume_kind(
1078 &mut self,
1079 resume_kind: GeneratorResumeKind,
1080 value: &Register,
1081 ) -> Label {
1082 let index = self.next_opcode_location();
1083 self.bytecode.emit_jump_if_not_resume_kind(
1084 Self::DUMMY_ADDRESS,
1085 (resume_kind as u8).into(),
1086 value.variable(),
1087 );
1088 Label { index }
1089 }
1090
1091 #[track_caller]
1092 pub(crate) fn patch_jump_with_target(&mut self, label: Label, target: u32) {
1093 self.bytecode.patch_jump(label.index, target);
1094 }
1095
1096 fn patch_jump(&mut self, label: Label) {
1097 let target = self.next_opcode_location();
1098 self.patch_jump_with_target(label, target);
1099 }
1100
1101 fn resolve_identifier_expect(&self, identifier: Identifier) -> JsString {
1102 identifier.to_js_string(self.interner())
1103 }
1104
1105 fn access_get(&mut self, access: Access<'_>, dst: &Register) {
1106 match access {
1107 Access::Variable { name } => {
1108 let name = self.resolve_identifier_expect(name);
1109 let binding = self.lexical_scope.get_identifier_reference(name);
1110 let index = self.get_binding(&binding);
1111 self.emit_binding_access(BindingAccessOpcode::GetName, &index, dst);
1112 }
1113 Access::Property { access } => match access {
1114 PropertyAccess::Simple(access) => {
1115 let mut compiler = self.position_guard(access.field());
1116
1117 let object = compiler.register_allocator.alloc();
1118 compiler.compile_expr(access.target(), &object);
1119
1120 match access.field() {
1121 PropertyAccessField::Const(ident) => {
1122 compiler.emit_get_property_by_name(dst, &object, &object, ident.sym());
1123 }
1124 PropertyAccessField::Expr(expr) => {
1125 let key = compiler.register_allocator.alloc();
1126 compiler.compile_expr(expr, &key);
1127 compiler.bytecode.emit_get_property_by_value(
1128 dst.variable(),
1129 key.variable(),
1130 object.variable(),
1131 object.variable(),
1132 );
1133 compiler.register_allocator.dealloc(key);
1134 }
1135 }
1136 compiler.register_allocator.dealloc(object);
1137 }
1138 PropertyAccess::Private(access) => {
1139 let mut compiler = self.position_guard(access.field());
1140
1141 let index = compiler.get_or_insert_private_name(access.field());
1142 let object = compiler.register_allocator.alloc();
1143 compiler.compile_expr(access.target(), &object);
1144 compiler.bytecode.emit_get_private_field(
1145 dst.variable(),
1146 object.variable(),
1147 index.into(),
1148 );
1149 compiler.register_allocator.dealloc(object);
1150 }
1151 PropertyAccess::Super(access) => {
1152 let mut compiler = self.position_guard(access.field());
1153
1154 let value = compiler.register_allocator.alloc();
1155 let receiver = compiler.register_allocator.alloc();
1156 compiler.bytecode.emit_super(value.variable());
1157 compiler.bytecode.emit_this(receiver.variable());
1158 match access.field() {
1159 PropertyAccessField::Const(ident) => {
1160 compiler.emit_get_property_by_name(dst, &receiver, &value, ident.sym());
1161 }
1162 PropertyAccessField::Expr(expr) => {
1163 let key = compiler.register_allocator.alloc();
1164 compiler.compile_expr(expr, &key);
1165 compiler.bytecode.emit_get_property_by_value(
1166 dst.variable(),
1167 key.variable(),
1168 receiver.variable(),
1169 value.variable(),
1170 );
1171 compiler.register_allocator.dealloc(key);
1172 }
1173 }
1174 compiler.register_allocator.dealloc(receiver);
1175 compiler.register_allocator.dealloc(value);
1176 }
1177 },
1178 Access::This => {
1179 self.bytecode.emit_this(dst.variable());
1180 }
1181 }
1182 }
1183
1184 fn access_set<'a, F>(&mut self, access: Access<'_>, expr_fn: F)
1185 where
1186 F: FnOnce(&mut ByteCompiler<'_>) -> &'a Register,
1187 {
1188 match access {
1189 Access::Variable { name } => {
1190 let name = self.resolve_identifier_expect(name);
1191 let binding = self.lexical_scope.get_identifier_reference(name.clone());
1192 let is_lexical = binding.is_lexical();
1193 let index = self.get_binding(&binding);
1194
1195 let value = self.register_allocator.alloc();
1196 if !is_lexical {
1197 self.emit_binding_access(BindingAccessOpcode::GetLocator, &index, &value);
1198 }
1199 self.register_allocator.dealloc(value);
1200
1201 let value = expr_fn(self);
1202
1203 if is_lexical {
1204 match self.lexical_scope.set_mutable_binding(name.clone()) {
1205 Ok(binding) => {
1206 let index = self.insert_binding(binding);
1207 self.emit_binding_access(BindingAccessOpcode::SetName, &index, value);
1208 }
1209 Err(BindingLocatorError::MutateImmutable) => {
1210 let index = self.get_or_insert_string(name);
1211 self.bytecode.emit_throw_mutate_immutable(index.into());
1212 }
1213 Err(BindingLocatorError::Silent) => {}
1214 }
1215 } else {
1216 self.emit_binding_access(BindingAccessOpcode::SetNameByLocator, &index, value);
1217 }
1218 }
1219 Access::Property { access } => match access {
1220 PropertyAccess::Simple(access) => match access.field() {
1221 PropertyAccessField::Const(name) => {
1222 let object = self.register_allocator.alloc();
1223 self.compile_expr(access.target(), &object);
1224 let value = expr_fn(self);
1225 self.emit_set_property_by_name(value, &object, &object, name.sym());
1226 self.register_allocator.dealloc(object);
1227 }
1228 PropertyAccessField::Expr(expr) => {
1229 let object = self.register_allocator.alloc();
1230 self.compile_expr(access.target(), &object);
1231
1232 let key = self.register_allocator.alloc();
1233 self.compile_expr(expr, &key);
1234
1235 let value = expr_fn(self);
1236
1237 self.bytecode.emit_set_property_by_value(
1238 value.variable(),
1239 key.variable(),
1240 object.variable(),
1241 object.variable(),
1242 );
1243
1244 self.register_allocator.dealloc(object);
1245 self.register_allocator.dealloc(key);
1246 }
1247 },
1248 PropertyAccess::Private(access) => {
1249 let index = self.get_or_insert_private_name(access.field());
1250
1251 let object = self.register_allocator.alloc();
1252 self.compile_expr(access.target(), &object);
1253
1254 let value = expr_fn(self);
1255
1256 self.bytecode.emit_set_private_field(
1257 value.variable(),
1258 object.variable(),
1259 index.into(),
1260 );
1261
1262 self.register_allocator.dealloc(object);
1263 }
1264 PropertyAccess::Super(access) => match access.field() {
1265 PropertyAccessField::Const(name) => {
1266 let object = self.register_allocator.alloc();
1267 self.bytecode.emit_super(object.variable());
1268
1269 let receiver = self.register_allocator.alloc();
1270 self.bytecode.emit_this(receiver.variable());
1271
1272 let value = expr_fn(self);
1273
1274 self.emit_set_property_by_name(value, &receiver, &object, name.sym());
1275
1276 self.register_allocator.dealloc(receiver);
1277 self.register_allocator.dealloc(object);
1278 }
1279 PropertyAccessField::Expr(expr) => {
1280 let object = self.register_allocator.alloc();
1281 self.bytecode.emit_super(object.variable());
1282
1283 let receiver = self.register_allocator.alloc();
1284 self.bytecode.emit_this(receiver.variable());
1285
1286 let key = self.register_allocator.alloc();
1287 self.compile_expr(expr, &key);
1288
1289 let value = expr_fn(self);
1290
1291 self.bytecode.emit_set_property_by_value(
1292 value.variable(),
1293 key.variable(),
1294 receiver.variable(),
1295 object.variable(),
1296 );
1297
1298 self.register_allocator.dealloc(key);
1299 self.register_allocator.dealloc(receiver);
1300 self.register_allocator.dealloc(object);
1301 }
1302 },
1303 },
1304 Access::This => todo!("access_set `this`"),
1305 }
1306 }
1307
1308 fn access_delete(&mut self, access: Access<'_>, dst: &Register) {
1309 match access {
1310 Access::Property { access } => match access {
1311 PropertyAccess::Simple(access) => match access.field() {
1312 PropertyAccessField::Const(name) => {
1313 let index = self.get_or_insert_name(name.sym());
1314 self.compile_expr(access.target(), dst);
1315 self.bytecode
1316 .emit_delete_property_by_name(dst.variable(), index.into());
1317 }
1318 PropertyAccessField::Expr(expr) => {
1319 self.compile_expr(access.target(), dst);
1320 let key = self.register_allocator.alloc();
1321 self.compile_expr(expr, &key);
1322 self.bytecode
1323 .emit_delete_property_by_value(dst.variable(), key.variable());
1324 self.register_allocator.dealloc(key);
1325 }
1326 },
1327 PropertyAccess::Super(_) => self.bytecode.emit_delete_super_throw(),
1328 PropertyAccess::Private(_) => {
1329 unreachable!("deleting private properties should always throw early errors.")
1330 }
1331 },
1332 Access::Variable { name } => {
1333 let name = name.to_js_string(self.interner());
1334 let binding = self.lexical_scope.get_identifier_reference(name);
1335 let index = self.get_binding(&binding);
1336 self.emit_binding_access(BindingAccessOpcode::DeleteName, &index, dst);
1337 }
1338 Access::This => self.bytecode.emit_push_true(dst.variable()),
1339 }
1340 }
1341
1342 pub fn compile_statement_list(&mut self, list: &StatementList, use_expr: bool, block: bool) {
1344 if use_expr || self.jump_control_info_has_use_expr() {
1345 let mut use_expr_index = 0;
1346 for (i, statement) in list.statements().iter().enumerate() {
1347 match statement {
1348 StatementListItem::Statement(statement) => match statement.as_ref() {
1349 Statement::Break(_) | Statement::Continue(_) => break,
1350 Statement::Empty | Statement::Var(_) => {}
1351 Statement::Block(block) if !returns_value(block) => {}
1352 _ => use_expr_index = i,
1353 },
1354 StatementListItem::Declaration(_) => {}
1355 }
1356 }
1357
1358 for (i, item) in list.statements().iter().enumerate() {
1359 self.compile_stmt_list_item(item, i == use_expr_index, block);
1360 }
1361 } else {
1362 for item in list.statements() {
1363 self.compile_stmt_list_item(item, false, block);
1364 }
1365 }
1366 }
1367
1368 #[inline]
1370 pub(crate) fn compile_expr(&mut self, expr: &Expression, dst: &'_ Register) {
1371 self.compile_expr_impl(expr, dst);
1372 }
1373
1374 fn compile_access_preserve_this(
1385 &mut self,
1386 access: &PropertyAccess,
1387 this: &Register,
1388 dst: &Register,
1389 ) {
1390 match access {
1391 PropertyAccess::Simple(access) => {
1392 self.compile_expr(access.target(), this);
1393
1394 match access.field() {
1395 PropertyAccessField::Const(ident) => {
1396 self.emit_get_property_by_name(dst, this, this, ident.sym());
1397 }
1398 PropertyAccessField::Expr(field) => {
1399 let key = self.register_allocator.alloc();
1400 self.compile_expr(field, &key);
1401 self.bytecode.emit_get_property_by_value(
1402 dst.variable(),
1403 key.variable(),
1404 this.variable(),
1405 this.variable(),
1406 );
1407 self.register_allocator.dealloc(key);
1408 }
1409 }
1410 }
1411 PropertyAccess::Private(access) => {
1412 self.compile_expr(access.target(), this);
1413
1414 let index = self.get_or_insert_private_name(access.field());
1415 self.bytecode
1416 .emit_get_private_field(dst.variable(), this.variable(), index.into());
1417 }
1418 PropertyAccess::Super(access) => {
1419 let object = self.register_allocator.alloc();
1420 self.bytecode.emit_this(this.variable());
1421 self.bytecode.emit_super(object.variable());
1422
1423 match access.field() {
1424 PropertyAccessField::Const(ident) => {
1425 self.emit_get_property_by_name(dst, this, &object, ident.sym());
1426 }
1427 PropertyAccessField::Expr(expr) => {
1428 let key = self.register_allocator.alloc();
1429 self.compile_expr(expr, &key);
1430 self.bytecode.emit_get_property_by_value(
1431 dst.variable(),
1432 key.variable(),
1433 this.variable(),
1434 object.variable(),
1435 );
1436 self.register_allocator.dealloc(key);
1437 }
1438 }
1439 self.register_allocator.dealloc(object);
1440 }
1441 }
1442 }
1443
1444 fn compile_optional_preserve_this(
1456 &mut self,
1457 optional: &Optional,
1458 this: &Register,
1459 value: &Register,
1460 ) {
1461 let mut jumps = Vec::with_capacity(optional.chain().len());
1462
1463 match optional.target().flatten() {
1464 Expression::PropertyAccess(access) => {
1465 self.compile_access_preserve_this(access, this, value);
1466 }
1467 Expression::Optional(opt) => self.compile_optional_preserve_this(opt, this, value),
1468 expr => {
1469 self.bytecode.emit_push_undefined(this.variable());
1470 self.compile_expr(expr, value);
1471 }
1472 }
1473
1474 jumps.push(self.jump_if_null_or_undefined(value));
1475
1476 let (first, rest) = optional
1477 .chain()
1478 .split_first()
1479 .expect("chain must have at least one element");
1480 assert!(first.shorted());
1481
1482 self.compile_optional_item_kind(first.kind(), this, value);
1483
1484 for item in rest {
1485 if item.shorted() {
1486 jumps.push(self.jump_if_null_or_undefined(value));
1487 }
1488 self.compile_optional_item_kind(item.kind(), this, value);
1489 }
1490
1491 let skip_undef = self.jump();
1492
1493 for label in jumps {
1494 self.patch_jump(label);
1495 self.bytecode.emit_push_undefined(value.variable());
1496 }
1497
1498 self.patch_jump(skip_undef);
1499 }
1500
1501 fn compile_optional_item_kind(
1518 &mut self,
1519 kind: &OptionalOperationKind,
1520 this: &Register,
1521 value: &Register,
1522 ) {
1523 match kind {
1524 OptionalOperationKind::SimplePropertyAccess { field } => {
1525 self.bytecode.emit_move(this.variable(), value.variable());
1526 match field {
1527 PropertyAccessField::Const(name) => {
1528 self.emit_get_property_by_name(value, value, value, name.sym());
1529 }
1530 PropertyAccessField::Expr(expr) => {
1531 let key = self.register_allocator.alloc();
1532 self.compile_expr(expr, &key);
1533 self.bytecode.emit_get_property_by_value(
1534 value.variable(),
1535 key.variable(),
1536 value.variable(),
1537 value.variable(),
1538 );
1539 self.register_allocator.dealloc(key);
1540 }
1541 }
1542 }
1543 OptionalOperationKind::PrivatePropertyAccess { field } => {
1544 self.bytecode.emit_move(this.variable(), value.variable());
1545 let index = self.get_or_insert_private_name(*field);
1546 self.bytecode.emit_get_private_field(
1547 value.variable(),
1548 value.variable(),
1549 index.into(),
1550 );
1551 }
1552 OptionalOperationKind::Call { args } => {
1553 self.push_from_register(this);
1554 self.push_from_register(value);
1555
1556 let args = &**args;
1557 let contains_spread = args.iter().any(|arg| matches!(arg, Expression::Spread(_)));
1558
1559 if contains_spread {
1560 let array = self.register_allocator.alloc();
1561 let value = self.register_allocator.alloc();
1562
1563 self.bytecode.emit_push_new_array(array.variable());
1564
1565 for arg in args {
1566 self.compile_expr(arg, &value);
1567 if let Expression::Spread(_) = arg {
1568 self.bytecode.emit_get_iterator(value.variable());
1569 self.bytecode.emit_push_iterator_to_array(array.variable());
1570 } else {
1571 self.bytecode
1572 .emit_push_value_to_array(value.variable(), array.variable());
1573 }
1574 }
1575
1576 self.push_from_register(&array);
1577
1578 self.register_allocator.dealloc(value);
1579 self.register_allocator.dealloc(array);
1580
1581 self.bytecode.emit_call_spread();
1582 } else {
1583 for arg in args {
1584 let value = self.register_allocator.alloc();
1585 self.compile_expr(arg, &value);
1586 self.push_from_register(&value);
1587 self.register_allocator.dealloc(value);
1588 }
1589 self.bytecode.emit_call((args.len() as u32).into());
1590 }
1591
1592 self.pop_into_register(value);
1593 self.bytecode.emit_push_undefined(this.variable());
1594 }
1595 }
1596 }
1597
1598 fn compile_var_decl(&mut self, decl: &VarDeclaration) {
1600 for variable in decl.0.as_ref() {
1601 match variable.binding() {
1602 Binding::Identifier(ident) => {
1603 let ident = ident.to_js_string(self.interner());
1604 if let Some(expr) = variable.init() {
1605 let binding = self.lexical_scope.get_identifier_reference(ident.clone());
1606 let index = self.insert_binding(binding);
1607 let value = self.register_allocator.alloc();
1608 self.emit_binding_access(BindingAccessOpcode::GetLocator, &index, &value);
1609 self.compile_expr(expr, &value);
1610 self.emit_binding_access(
1611 BindingAccessOpcode::SetNameByLocator,
1612 &index,
1613 &value,
1614 );
1615 self.register_allocator.dealloc(value);
1616 } else {
1617 let value = self.register_allocator.alloc();
1618 self.emit_binding(BindingOpcode::Var, ident, &value);
1619 self.register_allocator.dealloc(value);
1620 }
1621 }
1622 Binding::Pattern(pattern) => {
1623 let value = self.register_allocator.alloc();
1624 if let Some(init) = variable.init() {
1625 self.compile_expr(init, &value);
1626 } else {
1627 self.bytecode.emit_push_undefined(value.variable());
1628 }
1629 self.compile_declaration_pattern(pattern, BindingOpcode::InitVar, &value);
1630 self.register_allocator.dealloc(value);
1631 }
1632 }
1633 }
1634 }
1635
1636 fn compile_lexical_decl(&mut self, decl: &LexicalDeclaration) {
1638 match decl {
1639 LexicalDeclaration::Let(decls) => {
1640 for variable in decls.as_ref() {
1641 match variable.binding() {
1642 Binding::Identifier(ident) => {
1643 let ident = ident.to_js_string(self.interner());
1644 let value = self.register_allocator.alloc();
1645 if let Some(init) = variable.init() {
1646 self.compile_expr(init, &value);
1647 } else {
1648 self.bytecode.emit_push_undefined(value.variable());
1649 }
1650 self.emit_binding(BindingOpcode::InitLexical, ident, &value);
1651 self.register_allocator.dealloc(value);
1652 }
1653 Binding::Pattern(pattern) => {
1654 let value = self.register_allocator.alloc();
1655 if let Some(init) = variable.init() {
1656 self.compile_expr(init, &value);
1657 } else {
1658 self.bytecode.emit_push_undefined(value.variable());
1659 }
1660 self.compile_declaration_pattern(
1661 pattern,
1662 BindingOpcode::InitLexical,
1663 &value,
1664 );
1665 self.register_allocator.dealloc(value);
1666 }
1667 }
1668 }
1669 }
1670 LexicalDeclaration::Const(decls) => {
1671 for variable in decls.as_ref() {
1672 match variable.binding() {
1673 Binding::Identifier(ident) => {
1674 let ident = ident.to_js_string(self.interner());
1675 let init = variable
1676 .init()
1677 .expect("const declaration must have initializer");
1678 let value = self.register_allocator.alloc();
1679 self.compile_expr(init, &value);
1680 self.emit_binding(BindingOpcode::InitLexical, ident, &value);
1681 self.register_allocator.dealloc(value);
1682 }
1683 Binding::Pattern(pattern) => {
1684 let value = self.register_allocator.alloc();
1685 if let Some(init) = variable.init() {
1686 self.compile_expr(init, &value);
1687 } else {
1688 self.bytecode.emit_push_undefined(value.variable());
1689 }
1690 self.compile_declaration_pattern(
1691 pattern,
1692 BindingOpcode::InitLexical,
1693 &value,
1694 );
1695 self.register_allocator.dealloc(value);
1696 }
1697 }
1698 }
1699 }
1700 }
1701 }
1702
1703 fn compile_stmt_list_item(&mut self, item: &StatementListItem, use_expr: bool, block: bool) {
1705 match item {
1706 StatementListItem::Statement(stmt) => {
1707 self.compile_stmt(stmt, use_expr, false);
1708 }
1709 StatementListItem::Declaration(decl) => self.compile_decl(decl, block),
1710 }
1711 }
1712
1713 #[allow(unused_variables)]
1715 pub fn compile_decl(&mut self, decl: &Declaration, block: bool) {
1716 match decl {
1717 #[cfg(feature = "annex-b")]
1718 Declaration::FunctionDeclaration(function) if block => {
1719 let name = function.name();
1720 if self.annex_b_function_names.contains(&name.sym()) {
1721 let name = name.to_js_string(self.interner());
1722 let binding = self.lexical_scope.get_identifier_reference(name.clone());
1723 let index = self.get_binding(&binding);
1724
1725 let value = self.register_allocator.alloc();
1726 self.emit_binding_access(BindingAccessOpcode::GetName, &index, &value);
1727 match self.variable_scope.set_mutable_binding_var(name.clone()) {
1728 Ok(binding) => {
1729 let index = self.get_binding(&binding);
1730 self.emit_binding_access(BindingAccessOpcode::SetName, &index, &value);
1731 }
1732 Err(BindingLocatorError::MutateImmutable) => {
1733 let index = self.get_or_insert_string(name);
1734 self.bytecode.emit_throw_mutate_immutable(index.into());
1735 }
1736 Err(BindingLocatorError::Silent) => {}
1737 }
1738 self.register_allocator.dealloc(value);
1739 }
1740 }
1741 Declaration::ClassDeclaration(class) => self.compile_class(class.as_ref().into(), None),
1742 Declaration::Lexical(lexical) => self.compile_lexical_decl(lexical),
1743 _ => {}
1744 }
1745 }
1746
1747 pub(crate) fn function(&mut self, function: FunctionSpec<'_>) -> u32 {
1750 let (generator, r#async, arrow) = (
1751 function.kind.is_generator(),
1752 function.kind.is_async(),
1753 function.kind.is_arrow(),
1754 );
1755
1756 let FunctionSpec {
1757 name,
1758 parameters,
1759 body,
1760 scopes,
1761 name_scope,
1762 linear_span,
1763 ..
1764 } = function;
1765
1766 let name = if let Some(name) = name {
1767 Some(name.sym().to_js_string(self.interner()))
1768 } else {
1769 Some(js_string!())
1770 };
1771
1772 let spanned_source_text = SpannedSourceText::new(self.source_text(), linear_span);
1773
1774 let code = FunctionCompiler::new(spanned_source_text)
1775 .name(name)
1776 .generator(generator)
1777 .r#async(r#async)
1778 .strict(self.strict())
1779 .arrow(arrow)
1780 .in_with(self.in_with)
1781 .name_scope(name_scope.cloned())
1782 .source_path(self.source_path.clone())
1783 .compile(
1784 parameters,
1785 body,
1786 self.variable_scope.clone(),
1787 self.lexical_scope.clone(),
1788 scopes,
1789 function.contains_direct_eval,
1790 self.interner,
1791 );
1792
1793 self.push_function_to_constants(code)
1794 }
1795
1796 pub(crate) fn function_with_binding(
1799 &mut self,
1800 function: FunctionSpec<'_>,
1801 node_kind: NodeKind,
1802 dst: &Register,
1803 ) {
1804 let name = function.name;
1805 let index = self.function(function);
1806 self.emit_get_function(dst, index);
1807 match node_kind {
1808 NodeKind::Declaration => {
1809 self.emit_binding(
1810 BindingOpcode::InitVar,
1811 name.expect("function declaration must have a name")
1812 .to_js_string(self.interner()),
1813 dst,
1814 );
1815 }
1816 NodeKind::Expression => {}
1817 }
1818 }
1819
1820 pub(crate) fn object_method(
1822 &mut self,
1823 function: FunctionSpec<'_>,
1824 kind: MethodKind,
1825 ) -> Register {
1826 let (generator, r#async, arrow) = (
1827 function.kind.is_generator(),
1828 function.kind.is_async(),
1829 function.kind.is_arrow(),
1830 );
1831 let FunctionSpec {
1832 name,
1833 parameters,
1834 body,
1835 scopes,
1836 name_scope,
1837 linear_span,
1838 ..
1839 } = function;
1840
1841 let name = if let Some(name) = name {
1842 let name = name.sym().to_js_string(self.interner());
1843 match kind {
1844 MethodKind::Ordinary => Some(name),
1845 MethodKind::Get => Some(js_string!(js_str!("get "), &name)),
1846 MethodKind::Set => Some(js_string!(js_str!("set "), &name)),
1847 }
1848 } else {
1849 Some(js_string!())
1850 };
1851
1852 let spanned_source_text = SpannedSourceText::new(self.source_text(), linear_span);
1853
1854 let code = FunctionCompiler::new(spanned_source_text)
1855 .name(name)
1856 .generator(generator)
1857 .r#async(r#async)
1858 .strict(self.strict())
1859 .arrow(arrow)
1860 .method(true)
1861 .in_with(self.in_with)
1862 .name_scope(name_scope.cloned())
1863 .source_path(self.source_path.clone())
1864 .compile(
1865 parameters,
1866 body,
1867 self.variable_scope.clone(),
1868 self.lexical_scope.clone(),
1869 scopes,
1870 function.contains_direct_eval,
1871 self.interner,
1872 );
1873
1874 let index = self.push_function_to_constants(code);
1875 let dst = self.register_allocator.alloc();
1876 self.emit_get_function(&dst, index);
1877 dst
1878 }
1879
1880 fn method(&mut self, function: FunctionSpec<'_>) -> Register {
1882 let (generator, r#async, arrow) = (
1883 function.kind.is_generator(),
1884 function.kind.is_async(),
1885 function.kind.is_arrow(),
1886 );
1887 let FunctionSpec {
1888 name,
1889 parameters,
1890 body,
1891 scopes,
1892 linear_span,
1893 ..
1894 } = function;
1895
1896 let name = if let Some(name) = name {
1897 Some(name.sym().to_js_string(self.interner()))
1898 } else {
1899 Some(js_string!())
1900 };
1901
1902 let spanned_source_text = SpannedSourceText::new(self.source_text(), linear_span);
1903
1904 let code = FunctionCompiler::new(spanned_source_text)
1905 .name(name)
1906 .generator(generator)
1907 .r#async(r#async)
1908 .strict(true)
1909 .arrow(arrow)
1910 .method(true)
1911 .in_with(self.in_with)
1912 .name_scope(function.name_scope.cloned())
1913 .source_path(self.source_path.clone())
1914 .compile(
1915 parameters,
1916 body,
1917 self.variable_scope.clone(),
1918 self.lexical_scope.clone(),
1919 scopes,
1920 function.contains_direct_eval,
1921 self.interner,
1922 );
1923
1924 let index = self.push_function_to_constants(code);
1925 let dst = self.register_allocator.alloc();
1926 self.emit_get_function(&dst, index);
1927 dst
1928 }
1929
1930 fn call(&mut self, callable: Callable<'_>, dst: &Register) {
1931 #[derive(PartialEq)]
1932 enum CallKind {
1933 CallEval,
1934 Call,
1935 New,
1936 }
1937
1938 let (call, mut kind) = match callable {
1939 Callable::Call(call) => (call, CallKind::Call),
1940 Callable::New(new) => (new.call(), CallKind::New),
1941 };
1942
1943 match call.function().flatten() {
1944 Expression::PropertyAccess(access) if kind == CallKind::Call => {
1945 let this = self.register_allocator.alloc();
1946 let dst = self.register_allocator.alloc();
1947 self.compile_access_preserve_this(access, &this, &dst);
1948 self.push_from_register(&this);
1949 self.push_from_register(&dst);
1950 self.register_allocator.dealloc(this);
1951 self.register_allocator.dealloc(dst);
1952 }
1953 Expression::Optional(opt) if kind == CallKind::Call => {
1954 let this = self.register_allocator.alloc();
1955 let dst = self.register_allocator.alloc();
1956 self.compile_optional_preserve_this(opt, &this, &dst);
1957 self.push_from_register(&this);
1958 self.push_from_register(&dst);
1959 self.register_allocator.dealloc(this);
1960 self.register_allocator.dealloc(dst);
1961 }
1962 expr if kind == CallKind::Call => {
1963 if let Expression::Identifier(ident) = expr {
1964 if ident.sym() == Sym::EVAL {
1965 kind = CallKind::CallEval;
1966 }
1967
1968 if self.in_with {
1969 let name = self.resolve_identifier_expect(*ident);
1970 let binding = self.lexical_scope.get_identifier_reference(name);
1971 let index = self.get_binding(&binding);
1972 let index = match index {
1973 BindingKind::Global(index) | BindingKind::Stack(index) => index,
1974 BindingKind::Local(_) => {
1975 unreachable!("with binding cannot be local")
1976 }
1977 };
1978 let value = self.register_allocator.alloc();
1979 self.bytecode
1980 .emit_this_for_object_environment_name(value.variable(), index.into());
1981 self.push_from_register(&value);
1982 self.register_allocator.dealloc(value);
1983 } else {
1984 let value = self.register_allocator.alloc();
1985 self.bytecode.emit_push_undefined(value.variable());
1986 self.push_from_register(&value);
1987 self.register_allocator.dealloc(value);
1988 }
1989 } else {
1990 let value = self.register_allocator.alloc();
1991 self.bytecode.emit_push_undefined(value.variable());
1992 self.push_from_register(&value);
1993 self.register_allocator.dealloc(value);
1994 }
1995
1996 let value = self.register_allocator.alloc();
1997 self.compile_expr(expr, &value);
1998 self.push_from_register(&value);
1999 self.register_allocator.dealloc(value);
2000 }
2001 expr => {
2002 let this = self.register_allocator.alloc();
2003 let value = self.register_allocator.alloc();
2004 self.compile_expr(expr, &value);
2005 self.bytecode.emit_push_undefined(this.variable());
2006 self.push_from_register(&this);
2007 self.push_from_register(&value);
2008 self.register_allocator.dealloc(this);
2009 self.register_allocator.dealloc(value);
2010 }
2011 }
2012
2013 let mut compiler = self.position_guard(call);
2014
2015 let contains_spread = call
2016 .args()
2017 .iter()
2018 .any(|arg| matches!(arg, Expression::Spread(_)));
2019
2020 if contains_spread {
2021 let array = compiler.register_allocator.alloc();
2022 let value = compiler.register_allocator.alloc();
2023
2024 compiler.bytecode.emit_push_new_array(array.variable());
2025
2026 for arg in call.args() {
2027 compiler.compile_expr(arg, &value);
2028 if let Expression::Spread(_) = arg {
2029 compiler.bytecode.emit_get_iterator(value.variable());
2030 compiler
2031 .bytecode
2032 .emit_push_iterator_to_array(array.variable());
2033 } else {
2034 compiler
2035 .bytecode
2036 .emit_push_value_to_array(value.variable(), array.variable());
2037 }
2038 }
2039
2040 compiler.push_from_register(&array);
2041
2042 compiler.register_allocator.dealloc(array);
2043 compiler.register_allocator.dealloc(value);
2044 } else {
2045 for arg in call.args() {
2046 let value = compiler.register_allocator.alloc();
2047 compiler.compile_expr(arg, &value);
2048 compiler.push_from_register(&value);
2049 compiler.register_allocator.dealloc(value);
2050 }
2051 }
2052
2053 match kind {
2054 CallKind::CallEval => {
2055 let scope_index = compiler.constants.len() as u32;
2056 let lexical_scope = compiler.lexical_scope.clone();
2057 compiler.constants.push(Constant::Scope(lexical_scope));
2058 if contains_spread {
2059 compiler.bytecode.emit_call_eval_spread(scope_index.into());
2060 } else {
2061 compiler
2062 .bytecode
2063 .emit_call_eval((call.args().len() as u32).into(), scope_index.into());
2064 }
2065 }
2066 CallKind::Call if contains_spread => compiler.bytecode.emit_call_spread(),
2067 CallKind::Call => {
2068 compiler
2069 .bytecode
2070 .emit_call((call.args().len() as u32).into());
2071 }
2072 CallKind::New if contains_spread => compiler.bytecode.emit_new_spread(),
2073 CallKind::New => compiler
2074 .bytecode
2075 .emit_new((call.args().len() as u32).into()),
2076 }
2077 compiler.pop_into_register(dst);
2078 }
2079
2080 #[inline]
2082 #[must_use]
2083 #[allow(clippy::missing_const_for_fn)]
2084 pub fn finish(mut self) -> CodeBlock {
2085 if let Some(async_handler) = self.async_handler {
2087 self.patch_handler(async_handler);
2088 }
2089 self.r#return(false);
2090
2091 let final_bytecode_len = self.next_opcode_location();
2092
2093 let mapped_arguments_binding_indices = if self.emitted_mapped_arguments_object_opcode {
2094 MappedArguments::binding_indices(&self.params, &self.parameter_scope, self.interner)
2095 } else {
2096 ThinVec::default()
2097 };
2098
2099 let register_count = self.register_allocator.finish();
2100
2101 let source_map_entries = self.source_map_builder.build(final_bytecode_len);
2102
2103 CodeBlock {
2104 length: self.length,
2105 register_count,
2106 this_mode: self.this_mode,
2107 parameter_length: self.params.as_ref().len() as u32,
2108 mapped_arguments_binding_indices,
2109 bytecode: self.bytecode.into_bytecode(),
2110 constants: self.constants,
2111 bindings: self.bindings.into_boxed_slice(),
2112 handlers: self.handlers,
2113 flags: Cell::new(self.code_block_flags),
2114 ic: self.ic.into_boxed_slice(),
2115 source_info: SourceInfo::new(
2116 SourceMap::new(source_map_entries, self.source_path),
2117 self.function_name,
2118 self.spanned_source_text,
2119 ),
2120 }
2121 }
2122
2123 fn compile_declaration_pattern(
2124 &mut self,
2125 pattern: &Pattern,
2126 def: BindingOpcode,
2127 object: &Register,
2128 ) {
2129 self.compile_declaration_pattern_impl(pattern, def, object);
2130 }
2131}