1mod class;
24mod declaration;
25mod declarations;
26mod env;
27mod expression;
28mod function;
29mod generator;
30mod jump_control;
31mod module;
32mod register;
33mod statement;
34mod utils;
35
36use std::{
37 borrow::{Borrow, BorrowMut},
38 cell::Cell,
39 ops::{Deref, DerefMut},
40};
41
42use crate::{
43 JsBigInt, JsStr, JsString, SourceText, SpannedSourceText,
44 builtins::function::{ThisMode, arguments::MappedArguments},
45 js_string,
46 vm::{
47 CallFrame, CodeBlock, CodeBlockFlags, Constant, GeneratorResumeKind, GlobalFunctionBinding,
48 Handler, InlineCache,
49 opcode::{Address, BindingOpcode, BytecodeEmitter, RegisterOperand},
50 source_info::{SourceInfo, SourceMap, SourceMapBuilder, SourcePath},
51 },
52};
53use boa_ast::{
54 Declaration, Expression, LinearSpan, Position, Spanned, Statement, StatementList,
55 StatementListItem,
56 declaration::{Binding, LexicalDeclaration, VarDeclaration},
57 expression::{
58 Call, Identifier, New, Optional, OptionalOperationKind,
59 access::{PropertyAccess, PropertyAccessField},
60 literal::ObjectMethodDefinition,
61 operator::{
62 Binary,
63 assign::AssignTarget,
64 binary::{BinaryOp, RelationalOp},
65 update::UpdateTarget,
66 },
67 },
68 function::{
69 ArrowFunction, AsyncArrowFunction, AsyncFunctionDeclaration, AsyncFunctionExpression,
70 AsyncGeneratorDeclaration, AsyncGeneratorExpression, ClassMethodDefinition,
71 FormalParameterList, FunctionBody, FunctionDeclaration, FunctionExpression,
72 GeneratorDeclaration, GeneratorExpression, PrivateName,
73 },
74 operations::returns_value,
75 pattern::Pattern,
76 property::MethodDefinitionKind,
77 scope::{BindingLocator, BindingLocatorError, FunctionScopes, IdentifierReference, Scope},
78};
79use boa_gc::Gc;
80use boa_interner::{Interner, Sym};
81use boa_macros::js_str;
82use boa_string::StaticJsStrings;
83use rustc_hash::FxHashMap;
84use thin_vec::ThinVec;
85
86pub(crate) use declarations::{
87 global_declaration_instantiation_context, prepare_eval_declaration_instantiation,
88};
89pub(crate) use function::FunctionCompiler;
90pub(crate) use jump_control::JumpControlInfo;
91pub(crate) use register::*;
92
93pub(crate) trait ToJsString {
94 fn to_js_string(&self, interner: &Interner) -> JsString;
95}
96
97impl ToJsString for Sym {
98 #[allow(clippy::cast_possible_truncation)]
99 fn to_js_string(&self, interner: &Interner) -> JsString {
100 let utf16 = interner.resolve_expect(*self).utf16();
101 if interner.is_latin1(*self) {
102 let bytes: Vec<u8> = utf16.iter().map(|&c| c as u8).collect();
103 js_string!(JsStr::latin1(&bytes))
104 } else {
105 js_string!(utf16)
106 }
107 }
108}
109
110impl ToJsString for Identifier {
111 fn to_js_string(&self, interner: &Interner) -> JsString {
112 self.sym().to_js_string(interner)
113 }
114}
115
116#[derive(Debug, Clone, Copy, PartialEq)]
118pub(crate) enum NodeKind {
119 Declaration,
120 Expression,
121}
122
123#[derive(Debug, Clone, Copy, PartialEq)]
125pub(crate) enum FunctionKind {
126 Ordinary,
127 Arrow,
128 AsyncArrow,
129 Async,
130 Generator,
131 AsyncGenerator,
132}
133
134impl FunctionKind {
135 pub(crate) const fn is_arrow(self) -> bool {
136 matches!(self, Self::Arrow | Self::AsyncArrow)
137 }
138
139 pub(crate) const fn is_async(self) -> bool {
140 matches!(self, Self::Async | Self::AsyncGenerator | Self::AsyncArrow)
141 }
142
143 pub(crate) const fn is_generator(self) -> bool {
144 matches!(self, Self::Generator | Self::AsyncGenerator)
145 }
146}
147
148#[derive(Debug, Clone, Copy)]
150pub(crate) struct FunctionSpec<'a> {
151 pub(crate) kind: FunctionKind,
152 pub(crate) name: Option<Identifier>,
153 parameters: &'a FormalParameterList,
154 body: &'a FunctionBody,
155 pub(crate) scopes: &'a FunctionScopes,
156 pub(crate) name_scope: Option<&'a Scope>,
157 linear_span: Option<LinearSpan>,
158 pub(crate) contains_direct_eval: bool,
159}
160
161impl PartialEq for FunctionSpec<'_> {
162 fn eq(&self, other: &Self) -> bool {
163 self.kind == other.kind
165 && self.name == other.name
166 && self.parameters == other.parameters
167 && self.body == other.body
168 && self.scopes == other.scopes
169 && self.name_scope == other.name_scope
170 }
171}
172
173impl<'a> From<&'a FunctionDeclaration> for FunctionSpec<'a> {
174 fn from(function: &'a FunctionDeclaration) -> Self {
175 FunctionSpec {
176 kind: FunctionKind::Ordinary,
177 name: Some(function.name()),
178 parameters: function.parameters(),
179 body: function.body(),
180 scopes: function.scopes(),
181 name_scope: None,
182 linear_span: Some(function.linear_span()),
183 contains_direct_eval: function.contains_direct_eval(),
184 }
185 }
186}
187
188impl<'a> From<&'a GeneratorDeclaration> for FunctionSpec<'a> {
189 fn from(function: &'a GeneratorDeclaration) -> Self {
190 FunctionSpec {
191 kind: FunctionKind::Generator,
192 name: Some(function.name()),
193 parameters: function.parameters(),
194 body: function.body(),
195 scopes: function.scopes(),
196 name_scope: None,
197 linear_span: Some(function.linear_span()),
198 contains_direct_eval: function.contains_direct_eval(),
199 }
200 }
201}
202
203impl<'a> From<&'a AsyncFunctionDeclaration> for FunctionSpec<'a> {
204 fn from(function: &'a AsyncFunctionDeclaration) -> Self {
205 FunctionSpec {
206 kind: FunctionKind::Async,
207 name: Some(function.name()),
208 parameters: function.parameters(),
209 body: function.body(),
210 scopes: function.scopes(),
211 name_scope: None,
212 linear_span: Some(function.linear_span()),
213 contains_direct_eval: function.contains_direct_eval(),
214 }
215 }
216}
217
218impl<'a> From<&'a AsyncGeneratorDeclaration> for FunctionSpec<'a> {
219 fn from(function: &'a AsyncGeneratorDeclaration) -> Self {
220 FunctionSpec {
221 kind: FunctionKind::AsyncGenerator,
222 name: Some(function.name()),
223 parameters: function.parameters(),
224 body: function.body(),
225 scopes: function.scopes(),
226 name_scope: None,
227 linear_span: Some(function.linear_span()),
228 contains_direct_eval: function.contains_direct_eval(),
229 }
230 }
231}
232
233impl<'a> From<&'a FunctionExpression> for FunctionSpec<'a> {
234 fn from(function: &'a FunctionExpression) -> Self {
235 FunctionSpec {
236 kind: FunctionKind::Ordinary,
237 name: function.name(),
238 parameters: function.parameters(),
239 body: function.body(),
240 scopes: function.scopes(),
241 name_scope: function.name_scope(),
242 linear_span: function.linear_span(),
243 contains_direct_eval: function.contains_direct_eval(),
244 }
245 }
246}
247
248impl<'a> From<&'a ArrowFunction> for FunctionSpec<'a> {
249 fn from(function: &'a ArrowFunction) -> Self {
250 FunctionSpec {
251 kind: FunctionKind::Arrow,
252 name: function.name(),
253 parameters: function.parameters(),
254 body: function.body(),
255 scopes: function.scopes(),
256 name_scope: None,
257 linear_span: Some(function.linear_span()),
258 contains_direct_eval: function.contains_direct_eval(),
259 }
260 }
261}
262
263impl<'a> From<&'a AsyncArrowFunction> for FunctionSpec<'a> {
264 fn from(function: &'a AsyncArrowFunction) -> Self {
265 FunctionSpec {
266 kind: FunctionKind::AsyncArrow,
267 name: function.name(),
268 parameters: function.parameters(),
269 body: function.body(),
270 scopes: function.scopes(),
271 name_scope: None,
272 linear_span: Some(function.linear_span()),
273 contains_direct_eval: function.contains_direct_eval(),
274 }
275 }
276}
277
278impl<'a> From<&'a AsyncFunctionExpression> for FunctionSpec<'a> {
279 fn from(function: &'a AsyncFunctionExpression) -> Self {
280 FunctionSpec {
281 kind: FunctionKind::Async,
282 name: function.name(),
283 parameters: function.parameters(),
284 body: function.body(),
285 scopes: function.scopes(),
286 name_scope: function.name_scope(),
287 linear_span: Some(function.linear_span()),
288 contains_direct_eval: function.contains_direct_eval(),
289 }
290 }
291}
292
293impl<'a> From<&'a GeneratorExpression> for FunctionSpec<'a> {
294 fn from(function: &'a GeneratorExpression) -> Self {
295 FunctionSpec {
296 kind: FunctionKind::Generator,
297 name: function.name(),
298 parameters: function.parameters(),
299 body: function.body(),
300 scopes: function.scopes(),
301 name_scope: function.name_scope(),
302 linear_span: Some(function.linear_span()),
303 contains_direct_eval: function.contains_direct_eval(),
304 }
305 }
306}
307
308impl<'a> From<&'a AsyncGeneratorExpression> for FunctionSpec<'a> {
309 fn from(function: &'a AsyncGeneratorExpression) -> Self {
310 FunctionSpec {
311 kind: FunctionKind::AsyncGenerator,
312 name: function.name(),
313 parameters: function.parameters(),
314 body: function.body(),
315 scopes: function.scopes(),
316 name_scope: function.name_scope(),
317 linear_span: Some(function.linear_span()),
318 contains_direct_eval: function.contains_direct_eval(),
319 }
320 }
321}
322
323impl<'a> From<&'a ClassMethodDefinition> for FunctionSpec<'a> {
324 fn from(method: &'a ClassMethodDefinition) -> Self {
325 let kind = match method.kind() {
326 MethodDefinitionKind::Generator => FunctionKind::Generator,
327 MethodDefinitionKind::AsyncGenerator => FunctionKind::AsyncGenerator,
328 MethodDefinitionKind::Async => FunctionKind::Async,
329 _ => FunctionKind::Ordinary,
330 };
331
332 FunctionSpec {
333 kind,
334 name: None,
335 parameters: method.parameters(),
336 body: method.body(),
337 scopes: method.scopes(),
338 name_scope: None,
339 linear_span: Some(method.linear_span()),
340 contains_direct_eval: method.contains_direct_eval(),
341 }
342 }
343}
344
345impl<'a> From<&'a ObjectMethodDefinition> for FunctionSpec<'a> {
346 fn from(method: &'a ObjectMethodDefinition) -> Self {
347 let kind = match method.kind() {
348 MethodDefinitionKind::Generator => FunctionKind::Generator,
349 MethodDefinitionKind::AsyncGenerator => FunctionKind::AsyncGenerator,
350 MethodDefinitionKind::Async => FunctionKind::Async,
351 _ => FunctionKind::Ordinary,
352 };
353
354 FunctionSpec {
355 kind,
356 name: method.name().literal(),
357 parameters: method.parameters(),
358 body: method.body(),
359 scopes: method.scopes(),
360 name_scope: None,
361 linear_span: Some(method.linear_span()),
362 contains_direct_eval: method.contains_direct_eval(),
363 }
364 }
365}
366
367#[derive(Debug, Clone, Copy)]
368pub(crate) enum MethodKind {
369 Get,
370 Set,
371 Ordinary,
372}
373
374#[derive(Debug, Clone, Copy)]
376enum Callable<'a> {
377 Call(&'a Call),
378 New(&'a New),
379}
380
381#[derive(Debug, Clone, PartialEq, Eq, Hash)]
382enum Literal {
383 String(JsString),
384 BigInt(JsBigInt),
385}
386
387#[must_use]
388#[derive(Debug, Clone, Copy, PartialEq, Eq)]
389pub(crate) struct Label {
390 index: Address,
391}
392
393pub(crate) struct HoistedOperand {
399 pub(crate) register: Register,
401 pub(crate) is_rhs: bool,
403}
404
405#[derive(Debug, Clone, Copy)]
406#[allow(variant_size_differences)]
407enum Access<'a> {
408 Variable { name: Identifier },
409 Property { access: &'a PropertyAccess },
410 This,
411}
412
413impl Access<'_> {
414 const fn from_assign_target(target: &AssignTarget) -> Result<Access<'_>, &Pattern> {
415 match target {
416 AssignTarget::Identifier(ident) => Ok(Access::Variable { name: *ident }),
417 AssignTarget::Access(access) => Ok(Access::Property { access }),
418 AssignTarget::Pattern(pat) => Err(pat),
419 }
420 }
421
422 const fn from_expression(expr: &Expression) -> Option<Access<'_>> {
423 match expr {
424 Expression::Identifier(name) => Some(Access::Variable { name: *name }),
425 Expression::PropertyAccess(access) => Some(Access::Property { access }),
426 Expression::This(_this) => Some(Access::This),
427 Expression::Parenthesized(expr) => Self::from_expression(expr.expression()),
428 _ => None,
429 }
430 }
431
432 const fn from_update_target(target: &UpdateTarget) -> Access<'_> {
433 match target {
434 UpdateTarget::Identifier(name) => Access::Variable { name: *name },
435 UpdateTarget::PropertyAccess(access) => Access::Property { access },
436 }
437 }
438}
439
440#[derive(Copy, Clone, Debug)]
441pub(crate) enum BindingAccessOpcode {
442 PutLexicalValue,
443 DefInitVar,
444 SetName,
445 SetNameByLocator,
446 GetName,
447 GetNameAndLocator,
448 GetNameOrUndefined,
449 DeleteName,
450 GetLocator,
451 DefVar,
452 DefEvalVar,
453}
454
455pub(crate) struct SourcePositionGuard<'a, 'b> {
457 compiler: &'a mut ByteCompiler<'b>,
458}
459impl<'a, 'b> SourcePositionGuard<'a, 'b> {
460 fn new(compiler: &'a mut ByteCompiler<'b>, position: Position) -> Self {
461 compiler.push_source_position(position);
462 Self { compiler }
463 }
464}
465impl Drop for SourcePositionGuard<'_, '_> {
466 fn drop(&mut self) {
467 self.pop_source_position();
468 }
469}
470impl<'a> Deref for SourcePositionGuard<'_, 'a> {
471 type Target = ByteCompiler<'a>;
472 fn deref(&self) -> &Self::Target {
473 self.compiler
474 }
475}
476impl DerefMut for SourcePositionGuard<'_, '_> {
477 fn deref_mut(&mut self) -> &mut Self::Target {
478 self.compiler
479 }
480}
481impl<'a> Borrow<ByteCompiler<'a>> for SourcePositionGuard<'_, 'a> {
482 fn borrow(&self) -> &ByteCompiler<'a> {
483 self.compiler
484 }
485}
486impl<'a> BorrowMut<ByteCompiler<'a>> for SourcePositionGuard<'_, 'a> {
487 fn borrow_mut(&mut self) -> &mut ByteCompiler<'a> {
488 self.compiler
489 }
490}
491
492#[derive(Debug)]
494#[allow(clippy::struct_excessive_bools)]
495pub struct ByteCompiler<'ctx> {
496 pub(crate) function_name: JsString,
498
499 pub(crate) length: u32,
501
502 pub(crate) register_allocator: RegisterAllocator,
503
504 pub(crate) this_mode: ThisMode,
506
507 pub(crate) params: FormalParameterList,
509
510 pub(crate) parameter_scope: Scope,
512
513 pub(crate) bytecode: BytecodeEmitter,
515
516 pub(crate) source_map_builder: SourceMapBuilder,
517 pub(crate) source_path: SourcePath,
518
519 pub(crate) constants: ThinVec<Constant>,
520
521 pub(crate) bindings: Vec<BindingLocator>,
523
524 pub(crate) local_binding_registers: FxHashMap<IdentifierReference, u32>,
525
526 pub(crate) variable_scope: Scope,
528
529 pub(crate) lexical_scope: Scope,
531
532 pub(crate) current_open_environments_count: u32,
533 code_block_flags: CodeBlockFlags,
534 handlers: ThinVec<Handler>,
535 pub(crate) ic: Vec<InlineCache>,
536 literals_map: FxHashMap<Literal, u32>,
537 names_map: FxHashMap<Sym, u32>,
538 bindings_map: FxHashMap<BindingLocator, u32>,
539
540 const_binding_cache: FxHashMap<BindingLocator, u32>,
543
544 jump_info: Vec<JumpControlInfo>,
545
546 pub(crate) async_handler: Option<u32>,
550 json_parse: bool,
551
552 pub(crate) in_with: bool,
554
555 pub(crate) emitted_mapped_arguments_object_opcode: bool,
557
558 pub(crate) interner: &'ctx mut Interner,
559 spanned_source_text: SpannedSourceText,
560
561 pub(crate) global_lexs: Vec<u32>,
562 pub(crate) global_fns: Vec<GlobalFunctionBinding>,
563 pub(crate) global_vars: Vec<u32>,
564
565 #[cfg(feature = "annex-b")]
566 pub(crate) annex_b_function_names: Vec<Sym>,
567}
568
569pub(crate) enum BindingKind {
570 Stack(u32),
571 Local(Option<u32>),
572 Global(u32),
573}
574
575#[derive(Copy, Clone)]
577enum CallResultDest<'a> {
578 Register(&'a Register),
580 Discard,
582 Stack,
584}
585
586impl<'ctx> ByteCompiler<'ctx> {
587 const DUMMY_ADDRESS: Address = Address::new(u32::MAX);
589 const DUMMY_LABEL: Label = Label {
590 index: Address::new(u32::MAX),
591 };
592
593 #[inline]
595 #[allow(clippy::too_many_arguments)]
596 #[allow(clippy::fn_params_excessive_bools)]
597 pub(crate) fn new(
598 name: JsString,
599 strict: bool,
600 json_parse: bool,
601 variable_scope: Scope,
602 lexical_scope: Scope,
603 is_async: bool,
604 is_generator: bool,
605 interner: &'ctx mut Interner,
606 in_with: bool,
607 spanned_source_text: SpannedSourceText,
608 source_path: SourcePath,
609 ) -> ByteCompiler<'ctx> {
610 let mut code_block_flags = CodeBlockFlags::empty();
611 code_block_flags.set(CodeBlockFlags::STRICT, strict);
612 code_block_flags.set(CodeBlockFlags::IS_ASYNC, is_async);
613 code_block_flags.set(CodeBlockFlags::IS_GENERATOR, is_generator);
614 code_block_flags |= CodeBlockFlags::HAS_PROTOTYPE_PROPERTY;
615
616 let mut register_allocator = RegisterAllocator::default();
617 let undefined_register = register_allocator.alloc_persistent();
618 debug_assert_eq!(
619 undefined_register.index(),
620 CallFrame::undefined_register().index()
621 );
622 if is_async {
623 let promise_register = register_allocator.alloc_persistent();
624 let resolve_register = register_allocator.alloc_persistent();
625 let reject_register = register_allocator.alloc_persistent();
626
627 debug_assert_eq!(
628 promise_register.index(),
629 CallFrame::promise_capability_promise_register().index()
630 );
631 debug_assert_eq!(
632 resolve_register.index(),
633 CallFrame::promise_capability_resolve_register().index()
634 );
635 debug_assert_eq!(
636 reject_register.index(),
637 CallFrame::promise_capability_reject_register().index()
638 );
639
640 if is_generator {
641 let async_function_object_register = register_allocator.alloc_persistent();
642 debug_assert_eq!(
643 async_function_object_register.index(),
644 CallFrame::async_generator_object_register().index()
645 );
646 }
647 }
648
649 Self {
650 function_name: name,
651 length: 0,
652 bytecode: BytecodeEmitter::new(),
653 source_map_builder: SourceMapBuilder::default(),
654 constants: ThinVec::default(),
655 bindings: Vec::default(),
656 local_binding_registers: FxHashMap::default(),
657 this_mode: ThisMode::Global,
658 params: FormalParameterList::default(),
659 parameter_scope: Scope::default(),
660 current_open_environments_count: 0,
661
662 register_allocator,
663 code_block_flags,
664 handlers: ThinVec::default(),
665 ic: Vec::default(),
666
667 literals_map: FxHashMap::default(),
668 names_map: FxHashMap::default(),
669 bindings_map: FxHashMap::default(),
670 const_binding_cache: FxHashMap::default(),
671 jump_info: Vec::new(),
672 async_handler: None,
673 json_parse,
674 variable_scope,
675 lexical_scope,
676 interner,
677 spanned_source_text,
678 source_path,
679
680 #[cfg(feature = "annex-b")]
681 annex_b_function_names: Vec::new(),
682 in_with,
683 emitted_mapped_arguments_object_opcode: false,
684
685 global_lexs: Vec::new(),
686 global_fns: Vec::new(),
687 global_vars: Vec::new(),
688 }
689 }
690
691 pub(crate) fn source_text(&self) -> SourceText {
692 self.spanned_source_text.source_text()
693 }
694
695 pub(crate) const fn strict(&self) -> bool {
696 self.code_block_flags.contains(CodeBlockFlags::STRICT)
697 }
698
699 pub(crate) const fn is_async(&self) -> bool {
700 self.code_block_flags.contains(CodeBlockFlags::IS_ASYNC)
701 }
702
703 pub(crate) const fn is_generator(&self) -> bool {
704 self.code_block_flags.contains(CodeBlockFlags::IS_GENERATOR)
705 }
706
707 pub(crate) const fn is_async_generator(&self) -> bool {
708 self.is_async() && self.is_generator()
709 }
710
711 pub(crate) fn interner(&self) -> &Interner {
712 self.interner
713 }
714
715 fn get_or_insert_literal(&mut self, literal: Literal) -> u32 {
716 if let Some(index) = self.literals_map.get(&literal) {
717 return *index;
718 }
719
720 let value = match literal.clone() {
721 Literal::String(value) => Constant::String(value),
722 Literal::BigInt(value) => Constant::BigInt(value),
723 };
724
725 let index = self.constants.len() as u32;
726 self.constants.push(value);
727 self.literals_map.insert(literal, index);
728 index
729 }
730
731 fn get_or_insert_name(&mut self, name: Sym) -> u32 {
732 if let Some(index) = self.names_map.get(&name) {
733 return *index;
734 }
735
736 let index = self.constants.len() as u32;
737 let string = name.to_js_string(self.interner());
738 self.constants.push(Constant::String(string));
739 self.names_map.insert(name, index);
740 index
741 }
742
743 fn get_or_insert_string(&mut self, value: JsString) -> u32 {
744 self.get_or_insert_literal(Literal::String(value))
745 }
746
747 #[inline]
748 fn get_or_insert_private_name(&mut self, name: PrivateName) -> u32 {
749 self.get_or_insert_name(name.description())
750 }
751
752 #[inline]
755 pub(crate) fn get_binding(&mut self, binding: &IdentifierReference) -> BindingKind {
756 if binding.is_global_object() {
757 if let Some(index) = self.bindings_map.get(&binding.locator()) {
758 return BindingKind::Global(*index);
759 }
760
761 let index = self.bindings.len() as u32;
762 self.bindings.push(binding.locator().clone());
763 self.bindings_map.insert(binding.locator(), index);
764 return BindingKind::Global(index);
765 }
766
767 if binding.local() {
768 return BindingKind::Local(self.local_binding_registers.get(binding).copied());
769 }
770
771 if let Some(index) = self.bindings_map.get(&binding.locator()) {
772 return BindingKind::Stack(*index);
773 }
774
775 let index = self.bindings.len() as u32;
776 self.bindings.push(binding.locator().clone());
777 self.bindings_map.insert(binding.locator(), index);
778 BindingKind::Stack(index)
779 }
780
781 #[inline]
782 pub(crate) fn insert_binding(&mut self, binding: IdentifierReference) -> BindingKind {
783 if binding.is_global_object() {
784 if let Some(index) = self.bindings_map.get(&binding.locator()) {
785 return BindingKind::Global(*index);
786 }
787
788 let index = self.bindings.len() as u32;
789 self.bindings.push(binding.locator().clone());
790 self.bindings_map.insert(binding.locator(), index);
791 return BindingKind::Global(index);
792 }
793
794 if binding.local() {
795 return BindingKind::Local(Some(
796 *self
797 .local_binding_registers
798 .entry(binding)
799 .or_insert_with(|| self.register_allocator.alloc_persistent().index()),
800 ));
801 }
802
803 if let Some(index) = self.bindings_map.get(&binding.locator()) {
804 return BindingKind::Stack(*index);
805 }
806
807 let index = self.bindings.len() as u32;
808 self.bindings.push(binding.locator().clone());
809 self.bindings_map.insert(binding.locator(), index);
810 BindingKind::Stack(index)
811 }
812
813 #[inline]
814 #[must_use]
815 pub(crate) fn push_function_to_constants(&mut self, function: Gc<CodeBlock>) -> u32 {
816 let index = self.constants.len() as u32;
817 self.constants.push(Constant::Function(function));
818 index
819 }
820
821 fn emit_binding(&mut self, opcode: BindingOpcode, name: JsString, value: &Register) {
822 match opcode {
823 BindingOpcode::Var => {
824 let binding = self.variable_scope.get_identifier_reference(name);
825 if !binding.locator().is_global() {
826 let index = self.insert_binding(binding);
827 self.emit_binding_access(BindingAccessOpcode::DefVar, &index, value);
828 }
829 }
830 BindingOpcode::InitVar => match self.lexical_scope.set_mutable_binding(name.clone()) {
831 Ok(binding) => {
832 let index = self.insert_binding(binding);
833 self.emit_binding_access(BindingAccessOpcode::DefInitVar, &index, value);
834 }
835 Err(BindingLocatorError::MutateImmutable) => {
836 let index = self.get_or_insert_string(name);
837 self.bytecode.emit_throw_mutate_immutable(index.into());
838 }
839 Err(BindingLocatorError::Silent) => {}
840 },
841 BindingOpcode::InitLexical => {
842 let binding = self.lexical_scope.get_identifier_reference(name);
843 let index = self.insert_binding(binding);
844 self.emit_binding_access(BindingAccessOpcode::PutLexicalValue, &index, value);
845 }
846 BindingOpcode::SetName => match self.lexical_scope.set_mutable_binding(name.clone()) {
847 Ok(binding) => {
848 let index = self.insert_binding(binding);
849 self.emit_binding_access(BindingAccessOpcode::SetName, &index, value);
850 }
851 Err(BindingLocatorError::MutateImmutable) => {
852 let index = self.get_or_insert_string(name);
853 self.bytecode.emit_throw_mutate_immutable(index.into());
854 }
855 Err(BindingLocatorError::Silent) => {}
856 },
857 }
858 }
859
860 fn next_opcode_location(&mut self) -> Address {
861 self.bytecode.next_opcode_location()
862 }
863
864 pub(crate) fn position_guard(
865 &mut self,
866 spanned: impl Spanned,
867 ) -> SourcePositionGuard<'_, 'ctx> {
868 SourcePositionGuard::new(self, spanned.span().start())
869 }
870
871 pub(crate) fn push_source_position<T>(&mut self, position: T)
872 where
873 T: Into<Option<Position>>,
874 {
875 let start_pc = self.next_opcode_location();
876 self.source_map_builder
877 .push_source_position(start_pc.as_u32(), position.into());
878 }
879
880 pub(crate) fn pop_source_position(&mut self) {
881 let start_pc = self.next_opcode_location();
882 self.source_map_builder
883 .pop_source_position(start_pc.as_u32());
884 }
885
886 pub(crate) fn emit_get_function(&mut self, dst: &Register, index: u32) {
887 self.bytecode
888 .emit_get_function(dst.variable(), index.into());
889 }
890
891 fn pop_into_register(&mut self, dst: &Register) {
892 self.bytecode.emit_pop_into_register(dst.variable());
893 }
894
895 pub(crate) fn push_from_register(&mut self, src: &Register) {
896 self.bytecode.emit_push_from_register(src.variable());
897 }
898
899 pub(crate) fn emit_binding_access(
900 &mut self,
901 opcode: BindingAccessOpcode,
902 binding: &BindingKind,
903 value: &Register,
904 ) {
905 match binding {
906 BindingKind::Global(index) => match opcode {
907 BindingAccessOpcode::SetNameByLocator => {
908 self.bytecode.emit_set_name_by_locator(value.variable());
909 }
910 BindingAccessOpcode::GetName => {
911 let ic_index = self.ic.len() as u32;
912 let name = self.bindings[*index as usize].name().clone();
913 self.ic.push(InlineCache::new(name));
914 self.bytecode.emit_get_name_global(
915 value.variable(),
916 (*index).into(),
917 ic_index.into(),
918 );
919 }
920 BindingAccessOpcode::GetLocator => self.bytecode.emit_get_locator((*index).into()),
921 BindingAccessOpcode::DefVar => self.bytecode.emit_def_var((*index).into()),
922 BindingAccessOpcode::DefEvalVar => {
923 self.bytecode.emit_def_eval_var((*index).into());
924 }
925 BindingAccessOpcode::PutLexicalValue => self
926 .bytecode
927 .emit_put_lexical_value(value.variable(), (*index).into()),
928 BindingAccessOpcode::DefInitVar => self
929 .bytecode
930 .emit_def_init_var(value.variable(), (*index).into()),
931 BindingAccessOpcode::SetName => self
932 .bytecode
933 .emit_set_name(value.variable(), (*index).into()),
934 BindingAccessOpcode::GetNameAndLocator => self
935 .bytecode
936 .emit_get_name_and_locator(value.variable(), (*index).into()),
937 BindingAccessOpcode::GetNameOrUndefined => self
938 .bytecode
939 .emit_get_name_or_undefined(value.variable(), (*index).into()),
940 BindingAccessOpcode::DeleteName => self
941 .bytecode
942 .emit_delete_name(value.variable(), (*index).into()),
943 },
944 BindingKind::Stack(index) => match opcode {
945 BindingAccessOpcode::SetNameByLocator => {
946 self.bytecode.emit_set_name_by_locator(value.variable());
947 }
948 BindingAccessOpcode::GetLocator => self.bytecode.emit_get_locator((*index).into()),
949 BindingAccessOpcode::DefVar => self.bytecode.emit_def_var((*index).into()),
950 BindingAccessOpcode::DefEvalVar => {
951 self.bytecode.emit_def_eval_var((*index).into());
952 }
953 BindingAccessOpcode::PutLexicalValue => self
954 .bytecode
955 .emit_put_lexical_value(value.variable(), (*index).into()),
956 BindingAccessOpcode::DefInitVar => self
957 .bytecode
958 .emit_def_init_var(value.variable(), (*index).into()),
959 BindingAccessOpcode::SetName => self
960 .bytecode
961 .emit_set_name(value.variable(), (*index).into()),
962 BindingAccessOpcode::GetName => self
963 .bytecode
964 .emit_get_name(value.variable(), (*index).into()),
965 BindingAccessOpcode::GetNameAndLocator => self
966 .bytecode
967 .emit_get_name_and_locator(value.variable(), (*index).into()),
968 BindingAccessOpcode::GetNameOrUndefined => self
969 .bytecode
970 .emit_get_name_or_undefined(value.variable(), (*index).into()),
971 BindingAccessOpcode::DeleteName => self
972 .bytecode
973 .emit_delete_name(value.variable(), (*index).into()),
974 },
975 BindingKind::Local(None) => {
976 let error_msg = self.get_or_insert_literal(Literal::String(js_string!(
977 "access of uninitialized binding"
978 )));
979 self.bytecode
980 .emit_throw_new_reference_error(error_msg.into());
981 }
982 BindingKind::Local(Some(index)) => match opcode {
983 BindingAccessOpcode::GetName
984 | BindingAccessOpcode::GetNameOrUndefined
985 | BindingAccessOpcode::GetNameAndLocator => {
986 self.bytecode.emit_move(value.variable(), (*index).into());
987 }
988 BindingAccessOpcode::GetLocator
989 | BindingAccessOpcode::DefVar
990 | BindingAccessOpcode::DefEvalVar => {}
991 BindingAccessOpcode::SetName
992 | BindingAccessOpcode::DefInitVar
993 | BindingAccessOpcode::PutLexicalValue
994 | BindingAccessOpcode::SetNameByLocator => {
995 self.bytecode.emit_move((*index).into(), value.variable());
996 }
997 BindingAccessOpcode::DeleteName => self.bytecode.emit_store_false(value.variable()),
998 },
999 }
1000 }
1001
1002 fn emit_get_property_by_name(
1003 &mut self,
1004 dst: &Register,
1005 receiver: Option<&Register>,
1006 value: &Register,
1007 ident: Sym,
1008 ) {
1009 let ic_index = self.ic.len() as u32;
1010
1011 let name_index = self.get_or_insert_name(ident);
1012 let Constant::String(ref name) = self.constants[name_index as usize].clone() else {
1013 unreachable!("there should be a string at index")
1014 };
1015 self.ic.push(InlineCache::new(name.clone()));
1016
1017 if let Some(receiver) = receiver {
1018 self.bytecode.emit_get_property_by_name_with_this(
1019 dst.variable(),
1020 receiver.variable(),
1021 value.variable(),
1022 ic_index.into(),
1023 );
1024 } else if name == &StaticJsStrings::LENGTH {
1025 self.bytecode.emit_get_length_property(
1026 dst.variable(),
1027 value.variable(),
1028 ic_index.into(),
1029 );
1030 } else {
1031 self.bytecode.emit_get_property_by_name(
1032 dst.variable(),
1033 value.variable(),
1034 ic_index.into(),
1035 );
1036 }
1037 }
1038
1039 fn emit_set_property_by_name(
1040 &mut self,
1041 value: &Register,
1042 receiver: Option<&Register>,
1043 object: &Register,
1044 ident: Sym,
1045 ) {
1046 let ic_index = self.ic.len() as u32;
1047
1048 let name_index = self.get_or_insert_name(ident);
1049 let Constant::String(ref name) = self.constants[name_index as usize].clone() else {
1050 unreachable!("there should be a string at index")
1051 };
1052 self.ic.push(InlineCache::new(name.clone()));
1053
1054 if let Some(receiver) = receiver {
1055 self.bytecode.emit_set_property_by_name_with_this(
1056 value.variable(),
1057 receiver.variable(),
1058 object.variable(),
1059 ic_index.into(),
1060 );
1061 } else {
1062 self.bytecode.emit_set_property_by_name(
1063 value.variable(),
1064 object.variable(),
1065 ic_index.into(),
1066 );
1067 }
1068 }
1069
1070 fn emit_type_error(&mut self, message: &str) {
1071 let error_msg = self.get_or_insert_literal(Literal::String(js_string!(message)));
1072 self.bytecode.emit_throw_new_type_error(error_msg.into());
1073 }
1074
1075 fn emit_store_integer(&mut self, value: i32, dst: &Register) {
1076 self.emit_store_integer_with_index(value, dst.variable());
1077 }
1078
1079 fn emit_store_integer_with_index(&mut self, value: i32, dst: RegisterOperand) {
1080 match value {
1081 0 => self.bytecode.emit_store_zero(dst),
1082 1 => self.bytecode.emit_store_one(dst),
1083 x if i32::from(x as i8) == x => self.bytecode.emit_store_int8(dst, x as i8),
1084 x if i32::from(x as i16) == x => {
1085 self.bytecode.emit_store_int16(dst, x as i16);
1086 }
1087 x => self.bytecode.emit_store_int32(dst, x),
1088 }
1089 }
1090
1091 fn emit_store_literal(&mut self, literal: Literal, dst: &Register) {
1092 let index = self.get_or_insert_literal(literal);
1093 self.bytecode
1094 .emit_store_literal(dst.variable(), index.into());
1095 }
1096
1097 fn emit_store_rational(&mut self, value: f64, dst: &Register) {
1098 if value.is_nan() {
1099 return self.bytecode.emit_store_nan(dst.variable());
1100 }
1101
1102 if value.is_infinite() {
1103 if value.is_sign_positive() {
1104 return self.bytecode.emit_store_positive_infinity(dst.variable());
1105 }
1106 return self.bytecode.emit_store_negative_infinity(dst.variable());
1107 }
1108
1109 if f64::from(value as i32).to_bits() == value.to_bits() {
1111 self.emit_store_integer(value as i32, dst);
1112 } else {
1113 let f32_value = value as f32;
1114
1115 #[allow(clippy::float_cmp)]
1116 if f64::from(f32_value) == value {
1117 self.bytecode.emit_store_float(dst.variable(), f32_value);
1118 } else {
1119 self.bytecode.emit_store_double(dst.variable(), value);
1120 }
1121 }
1122 }
1123
1124 fn jump(&mut self) -> Label {
1125 let index = self.next_opcode_location();
1126 self.bytecode.emit_jump(Self::DUMMY_ADDRESS);
1127 Label { index }
1128 }
1129
1130 pub(crate) fn jump_if_true(&mut self, value: &Register) -> Label {
1131 let index = self.next_opcode_location();
1132 self.bytecode
1133 .emit_jump_if_true(Self::DUMMY_ADDRESS, value.variable());
1134 Label { index }
1135 }
1136
1137 pub(crate) fn if_else(
1138 &mut self,
1139 bool: &Register,
1140 true_case: impl FnOnce(&mut ByteCompiler<'_>),
1141 false_case: impl FnOnce(&mut ByteCompiler<'_>),
1142 ) {
1143 let jump_false = self.jump_if_false(bool);
1144
1145 true_case(self);
1147 let jump_to_end = self.jump();
1148
1149 self.patch_jump(jump_false);
1151 false_case(self);
1152 self.patch_jump(jump_to_end);
1153 }
1154
1155 pub(crate) fn if_else_with_dealloc(
1159 &mut self,
1160 bool: Register,
1161 true_case: impl FnOnce(&mut ByteCompiler<'_>),
1162 false_case: impl FnOnce(&mut ByteCompiler<'_>),
1163 ) {
1164 let jump_false = self.jump_if_false(&bool);
1165 self.register_allocator.dealloc(bool);
1166
1167 true_case(self);
1169 let jump_to_end = self.jump();
1170
1171 self.patch_jump(jump_false);
1173 false_case(self);
1174 self.patch_jump(jump_to_end);
1175 }
1176
1177 pub(crate) fn jump_if_false(&mut self, value: &Register) -> Label {
1178 let index = self.next_opcode_location();
1179 self.bytecode
1180 .emit_jump_if_false(Self::DUMMY_ADDRESS, value.variable());
1181 Label { index }
1182 }
1183
1184 pub(crate) fn compile_condition_and_branch(
1193 &mut self,
1194 condition: &Expression,
1195 hoisted: Option<&HoistedOperand>,
1196 ) -> Label {
1197 if let Expression::Binary(binary) = condition
1198 && let BinaryOp::Relational(op) = binary.op()
1199 && let Some(label) = self.try_fused_comparison_branch(op, binary, hoisted)
1200 {
1201 return label;
1202 }
1203 let value = self.register_allocator.alloc();
1205 self.compile_expr(condition, &value);
1206 let label = self.jump_if_false(&value);
1207 self.register_allocator.dealloc(value);
1208 label
1209 }
1210
1211 pub(crate) fn try_hoist_loop_condition(
1217 &mut self,
1218 condition: Option<&Expression>,
1219 ) -> Option<HoistedOperand> {
1220 let condition = condition?;
1221 let Expression::Binary(binary) = condition else {
1222 return None;
1223 };
1224 let BinaryOp::Relational(op) = binary.op() else {
1225 return None;
1226 };
1227 match op {
1228 RelationalOp::LessThan
1229 | RelationalOp::LessThanOrEqual
1230 | RelationalOp::GreaterThan
1231 | RelationalOp::GreaterThanOrEqual => {}
1232 _ => return None,
1233 }
1234 if self.is_loop_invariant(binary.rhs()) {
1236 let reg = self.register_allocator.alloc();
1237 self.compile_expr(binary.rhs(), ®);
1238 return Some(HoistedOperand {
1239 register: reg,
1240 is_rhs: true,
1241 });
1242 }
1243 if self.is_loop_invariant(binary.lhs()) {
1245 let reg = self.register_allocator.alloc();
1246 self.compile_expr(binary.lhs(), ®);
1247 return Some(HoistedOperand {
1248 register: reg,
1249 is_rhs: false,
1250 });
1251 }
1252 None
1253 }
1254
1255 fn is_loop_invariant(&self, expr: &Expression) -> bool {
1266 match expr {
1267 Expression::Literal(_) => true,
1268 Expression::Identifier(name) => {
1269 let name = self.resolve_identifier_expect(*name);
1270 let binding = self.lexical_scope.get_identifier_reference(name.clone());
1271 if binding.local() {
1274 return false;
1275 }
1276 if !self.in_with && self.const_binding_cache.contains_key(&binding.locator()) {
1279 return false;
1280 }
1281 matches!(self.lexical_scope.is_binding_mutable(&name), Some(false))
1284 }
1285 _ => false,
1286 }
1287 }
1288
1289 fn try_fused_comparison_branch(
1290 &mut self,
1291 op: RelationalOp,
1292 binary: &Binary,
1293 hoisted: Option<&HoistedOperand>,
1294 ) -> Option<Label> {
1295 use crate::vm::opcode::BytecodeEmitter;
1296
1297 let emit_fn: fn(&mut BytecodeEmitter, Address, RegisterOperand, RegisterOperand) = match op
1298 {
1299 RelationalOp::LessThan => BytecodeEmitter::emit_jump_if_not_less_than,
1300 RelationalOp::LessThanOrEqual => BytecodeEmitter::emit_jump_if_not_less_than_or_equal,
1301 RelationalOp::GreaterThan => BytecodeEmitter::emit_jump_if_not_greater_than,
1302 RelationalOp::GreaterThanOrEqual => {
1303 BytecodeEmitter::emit_jump_if_not_greater_than_or_equal
1304 }
1305 _ => return None,
1306 };
1307 let mut label_index = Address::new(0);
1308 match hoisted {
1309 Some(h) if h.is_rhs => {
1310 let rhs = h.register.variable();
1311 self.compile_expr_operand(binary.lhs(), |compiler, lhs| {
1312 label_index = compiler.next_opcode_location();
1313 emit_fn(&mut compiler.bytecode, Self::DUMMY_ADDRESS, lhs, rhs);
1314 });
1315 }
1316 Some(h) => {
1317 let lhs = h.register.variable();
1318 self.compile_expr_operand(binary.rhs(), |compiler, rhs| {
1319 label_index = compiler.next_opcode_location();
1320 emit_fn(&mut compiler.bytecode, Self::DUMMY_ADDRESS, lhs, rhs);
1321 });
1322 }
1323 None => {
1324 self.compile_expr_operand(binary.lhs(), |compiler, lhs| {
1325 compiler.compile_expr_operand(binary.rhs(), |compiler, rhs| {
1326 label_index = compiler.next_opcode_location();
1327 emit_fn(&mut compiler.bytecode, Self::DUMMY_ADDRESS, lhs, rhs);
1328 });
1329 });
1330 }
1331 }
1332 Some(Label { index: label_index })
1333 }
1334
1335 pub(crate) fn jump_if_null_or_undefined(&mut self, value: &Register) -> Label {
1336 let index = self.next_opcode_location();
1337 self.bytecode
1338 .emit_jump_if_null_or_undefined(Self::DUMMY_ADDRESS, value.variable());
1339 Label { index }
1340 }
1341
1342 pub(crate) fn jump_if_not_undefined(&mut self, value: &Register) -> Label {
1343 let index = self.next_opcode_location();
1344 self.bytecode
1345 .emit_jump_if_not_undefined(Self::DUMMY_ADDRESS, value.variable());
1346 Label { index }
1347 }
1348
1349 pub(crate) fn jump_if_neq(&mut self, lhs: &Register, rhs: &Register) -> Label {
1350 let index = self.next_opcode_location();
1351 self.bytecode
1352 .emit_jump_if_not_equal(Self::DUMMY_ADDRESS, lhs.variable(), rhs.variable());
1353 Label { index }
1354 }
1355
1356 pub(crate) fn case(&mut self, value: &Register, condition: &Register) -> Label {
1357 let index = self.next_opcode_location();
1358 self.bytecode
1359 .emit_case(Self::DUMMY_ADDRESS, value.variable(), condition.variable());
1360 Label { index }
1361 }
1362
1363 pub(crate) fn template_lookup(&mut self, dst: &Register, site: u64) -> Label {
1364 let index = self.next_opcode_location();
1365 self.bytecode
1366 .emit_template_lookup(Self::DUMMY_ADDRESS, site, dst.variable());
1367 Label { index }
1368 }
1369
1370 fn emit_resume_kind(&mut self, resume_kind: GeneratorResumeKind, dst: &Register) {
1371 self.emit_store_integer(resume_kind as i32, dst);
1372 }
1373
1374 fn jump_if_not_resume_kind(
1375 &mut self,
1376 resume_kind: GeneratorResumeKind,
1377 value: &Register,
1378 ) -> Label {
1379 let r1 = self.register_allocator.alloc();
1380 self.emit_store_integer((resume_kind as u8).into(), &r1);
1381
1382 let index = self.next_opcode_location();
1383 self.bytecode
1384 .emit_jump_if_not_equal(Self::DUMMY_ADDRESS, r1.variable(), value.variable());
1385 self.register_allocator.dealloc(r1);
1386 Label { index }
1387 }
1388
1389 #[track_caller]
1390 pub(crate) fn patch_jump_with_target(&mut self, label: Label, target: Address) {
1391 self.bytecode.patch_jump(label.index, target);
1392 }
1393
1394 fn patch_jump(&mut self, label: Label) {
1395 let target = self.next_opcode_location();
1396 self.patch_jump_with_target(label, target);
1397 }
1398
1399 fn resolve_identifier_expect(&self, identifier: Identifier) -> JsString {
1400 identifier.to_js_string(self.interner())
1401 }
1402
1403 fn super_(&mut self, this: &Register, super_: &Register) {
1404 self.bytecode.emit_this(this.variable());
1406 self.bytecode.emit_get_function_object(super_.variable());
1407 self.bytecode.emit_get_home_object(super_.variable());
1408
1409 let r1 = self.register_allocator.alloc();
1410 self.bytecode.emit_store_null(r1.variable());
1411 let skip_move = self.jump_if_neq(&r1, super_);
1413 self.bytecode.emit_move(r1.variable(), this.variable());
1414 self.bytecode.emit_is_object(r1.variable());
1415
1416 let skip_eval = self.jump_if_false(&r1);
1419 self.register_allocator.dealloc(r1);
1420
1421 self.bytecode.emit_move(super_.variable(), this.variable());
1424 self.patch_jump(skip_move);
1425
1426 self.bytecode.emit_get_prototype(super_.variable());
1427
1428 self.patch_jump(skip_eval);
1429 }
1430
1431 fn access_get(&mut self, access: Access<'_>, dst: &Register) {
1432 match access {
1433 Access::Variable { name } => {
1434 let name = self.resolve_identifier_expect(name);
1435 let binding = self.lexical_scope.get_identifier_reference(name);
1436 let index = self.get_binding(&binding);
1437 if !self.in_with
1438 && let Some(&cached_reg) = self.const_binding_cache.get(&binding.locator())
1439 {
1440 self.bytecode.emit_move(dst.variable(), cached_reg.into());
1441 return;
1442 }
1443 self.emit_binding_access(BindingAccessOpcode::GetName, &index, dst);
1444 }
1445 Access::Property { access } => match access {
1446 PropertyAccess::Simple(access) => {
1447 let mut compiler = self.position_guard(access.field());
1448
1449 let object = compiler.register_allocator.alloc();
1450 compiler.compile_expr(access.target(), &object);
1451
1452 match access.field() {
1453 PropertyAccessField::Const(ident) => {
1454 compiler.emit_get_property_by_name(dst, None, &object, ident.sym());
1455 }
1456 PropertyAccessField::Expr(expr) => {
1457 let key = compiler.register_allocator.alloc();
1458 compiler.compile_expr(expr, &key);
1459 compiler.bytecode.emit_get_property_by_value(
1460 dst.variable(),
1461 key.variable(),
1462 object.variable(),
1463 object.variable(),
1464 );
1465 compiler.register_allocator.dealloc(key);
1466 }
1467 }
1468 compiler.register_allocator.dealloc(object);
1469 }
1470 PropertyAccess::Private(access) => {
1471 let mut compiler = self.position_guard(access.field());
1472
1473 let index = compiler.get_or_insert_private_name(access.field());
1474 let object = compiler.register_allocator.alloc();
1475 compiler.compile_expr(access.target(), &object);
1476 compiler.bytecode.emit_get_private_field(
1477 dst.variable(),
1478 object.variable(),
1479 index.into(),
1480 );
1481 compiler.register_allocator.dealloc(object);
1482 }
1483 PropertyAccess::Super(access) => {
1484 let mut compiler = self.position_guard(access.field());
1485
1486 let value = compiler.register_allocator.alloc();
1487 let receiver = compiler.register_allocator.alloc();
1488 compiler.super_(&receiver, &value);
1489
1490 match access.field() {
1491 PropertyAccessField::Const(ident) => {
1492 compiler.emit_get_property_by_name(
1493 dst,
1494 Some(&receiver),
1495 &value,
1496 ident.sym(),
1497 );
1498 }
1499 PropertyAccessField::Expr(expr) => {
1500 let key = compiler.register_allocator.alloc();
1501 compiler.compile_expr(expr, &key);
1502 compiler.bytecode.emit_get_property_by_value(
1503 dst.variable(),
1504 key.variable(),
1505 receiver.variable(),
1506 value.variable(),
1507 );
1508 compiler.register_allocator.dealloc(key);
1509 }
1510 }
1511 compiler.register_allocator.dealloc(receiver);
1512 compiler.register_allocator.dealloc(value);
1513 }
1514 },
1515 Access::This => {
1516 self.bytecode.emit_this(dst.variable());
1517 }
1518 }
1519 }
1520
1521 fn access_set<'a, F>(&mut self, access: Access<'_>, expr_fn: F)
1522 where
1523 F: FnOnce(&mut ByteCompiler<'_>) -> &'a Register,
1524 {
1525 match access {
1526 Access::Variable { name } => {
1527 let name = self.resolve_identifier_expect(name);
1528 let binding = self.lexical_scope.get_identifier_reference(name.clone());
1529 let is_lexical = binding.is_lexical();
1530 let index = self.get_binding(&binding);
1531
1532 let value = self.register_allocator.alloc();
1533 if !is_lexical {
1534 self.emit_binding_access(BindingAccessOpcode::GetLocator, &index, &value);
1535 }
1536 self.register_allocator.dealloc(value);
1537
1538 let value = expr_fn(self);
1539
1540 if is_lexical {
1541 match self.lexical_scope.set_mutable_binding(name.clone()) {
1542 Ok(binding) => {
1543 let index = self.insert_binding(binding);
1544 self.emit_binding_access(BindingAccessOpcode::SetName, &index, value);
1545 }
1546 Err(BindingLocatorError::MutateImmutable) => {
1547 let index = self.get_or_insert_string(name);
1548 self.bytecode.emit_throw_mutate_immutable(index.into());
1549 }
1550 Err(BindingLocatorError::Silent) => {}
1551 }
1552 } else {
1553 self.emit_binding_access(BindingAccessOpcode::SetNameByLocator, &index, value);
1554 }
1555 }
1556 Access::Property { access } => match access {
1557 PropertyAccess::Simple(access) => match access.field() {
1558 PropertyAccessField::Const(name) => {
1559 let object = self.register_allocator.alloc();
1560 self.compile_expr(access.target(), &object);
1561 let value = expr_fn(self);
1562 self.emit_set_property_by_name(value, None, &object, name.sym());
1563 self.register_allocator.dealloc(object);
1564 }
1565 PropertyAccessField::Expr(expr) => {
1566 let object = self.register_allocator.alloc();
1567 self.compile_expr(access.target(), &object);
1568
1569 let key = self.register_allocator.alloc();
1570 self.compile_expr(expr, &key);
1571
1572 let value = expr_fn(self);
1573
1574 self.bytecode.emit_set_property_by_value(
1575 value.variable(),
1576 key.variable(),
1577 object.variable(),
1578 object.variable(),
1579 );
1580
1581 self.register_allocator.dealloc(object);
1582 self.register_allocator.dealloc(key);
1583 }
1584 },
1585 PropertyAccess::Private(access) => {
1586 let index = self.get_or_insert_private_name(access.field());
1587
1588 let object = self.register_allocator.alloc();
1589 self.compile_expr(access.target(), &object);
1590
1591 let value = expr_fn(self);
1592
1593 self.bytecode.emit_set_private_field(
1594 value.variable(),
1595 object.variable(),
1596 index.into(),
1597 );
1598
1599 self.register_allocator.dealloc(object);
1600 }
1601 PropertyAccess::Super(access) => match access.field() {
1602 PropertyAccessField::Const(name) => {
1603 let object = self.register_allocator.alloc();
1604 let receiver = self.register_allocator.alloc();
1605 self.super_(&receiver, &object);
1606
1607 let value = expr_fn(self);
1608
1609 self.emit_set_property_by_name(value, Some(&receiver), &object, name.sym());
1610
1611 self.register_allocator.dealloc(receiver);
1612 self.register_allocator.dealloc(object);
1613 }
1614 PropertyAccessField::Expr(expr) => {
1615 let object = self.register_allocator.alloc();
1616 let receiver = self.register_allocator.alloc();
1617 self.super_(&receiver, &object);
1618
1619 let key = self.register_allocator.alloc();
1620 self.compile_expr(expr, &key);
1621
1622 let value = expr_fn(self);
1623
1624 self.bytecode.emit_set_property_by_value(
1625 value.variable(),
1626 key.variable(),
1627 receiver.variable(),
1628 object.variable(),
1629 );
1630
1631 self.register_allocator.dealloc(key);
1632 self.register_allocator.dealloc(receiver);
1633 self.register_allocator.dealloc(object);
1634 }
1635 },
1636 },
1637 Access::This => {
1638 let _ = expr_fn(self);
1641 }
1642 }
1643 }
1644
1645 fn access_delete(&mut self, access: Access<'_>, dst: &Register) {
1646 match access {
1647 Access::Property { access } => match access {
1648 PropertyAccess::Simple(access) => match access.field() {
1649 PropertyAccessField::Const(name) => {
1650 let index = self.get_or_insert_name(name.sym());
1651 self.compile_expr(access.target(), dst);
1652 self.bytecode
1653 .emit_delete_property_by_name(dst.variable(), index.into());
1654 }
1655 PropertyAccessField::Expr(expr) => {
1656 self.compile_expr(access.target(), dst);
1657 let key = self.register_allocator.alloc();
1658 self.compile_expr(expr, &key);
1659 self.bytecode
1660 .emit_delete_property_by_value(dst.variable(), key.variable());
1661 self.register_allocator.dealloc(key);
1662 }
1663 },
1664 PropertyAccess::Super(_) => self.bytecode.emit_delete_super_throw(),
1665 PropertyAccess::Private(_) => {
1666 unreachable!("deleting private properties should always throw early errors.")
1667 }
1668 },
1669 Access::Variable { name } => {
1670 let name = name.to_js_string(self.interner());
1671 let binding = self.lexical_scope.get_identifier_reference(name);
1672 let index = self.get_binding(&binding);
1673 self.emit_binding_access(BindingAccessOpcode::DeleteName, &index, dst);
1674 }
1675 Access::This => self.bytecode.emit_store_true(dst.variable()),
1676 }
1677 }
1678
1679 pub fn compile_statement_list(&mut self, list: &StatementList, use_expr: bool, block: bool) {
1681 if use_expr || self.jump_control_info_has_use_expr() {
1682 let mut use_expr_index = 0;
1683 for (i, statement) in list.statements().iter().enumerate() {
1684 match statement {
1685 StatementListItem::Statement(statement) => match statement.as_ref() {
1686 Statement::Break(_) | Statement::Continue(_) => break,
1687 Statement::Empty | Statement::Var(_) => {}
1688 Statement::Block(block) if !returns_value(block) => {}
1689 _ => use_expr_index = i,
1690 },
1691 StatementListItem::Declaration(_) => {}
1692 }
1693 }
1694
1695 for (i, item) in list.statements().iter().enumerate() {
1696 self.compile_stmt_list_item(item, i == use_expr_index, block);
1697 }
1698 } else {
1699 for item in list.statements() {
1700 self.compile_stmt_list_item(item, false, block);
1701 }
1702 }
1703 }
1704
1705 #[inline]
1707 pub(crate) fn compile_expr(&mut self, expr: &Expression, dst: &'_ Register) {
1708 self.compile_expr_impl(expr, dst);
1709 }
1710
1711 pub(crate) fn compile_expr_for_side_effects(&mut self, expr: &Expression) {
1716 match expr {
1717 Expression::Call(call) => {
1718 self.call(Callable::Call(call), CallResultDest::Discard);
1719 }
1720 Expression::New(new) => {
1721 self.call(Callable::New(new), CallResultDest::Discard);
1722 }
1723 Expression::Update(update) => {
1724 let tmp = self.register_allocator.alloc();
1725 self.compile_update(update, &tmp, true);
1726 self.register_allocator.dealloc(tmp);
1727 }
1728 Expression::Parenthesized(parenthesized) => {
1729 self.compile_expr_for_side_effects(parenthesized.expression());
1730 }
1731 _ => {
1732 let tmp = self.register_allocator.alloc();
1733 self.compile_expr(expr, &tmp);
1734 self.register_allocator.dealloc(tmp);
1735 }
1736 }
1737 }
1738
1739 pub(crate) fn compile_expr_to_stack(&mut self, expr: &Expression) {
1746 match expr {
1747 Expression::Call(call) => {
1748 self.call(Callable::Call(call), CallResultDest::Stack);
1749 }
1750 Expression::New(new) => {
1751 self.call(Callable::New(new), CallResultDest::Stack);
1752 }
1753 Expression::Parenthesized(parenthesized) => {
1754 self.compile_expr_to_stack(parenthesized.expression());
1755 }
1756 _ => {
1757 self.compile_expr_operand(expr, |this, op| {
1758 this.bytecode.emit_push_from_register(op);
1759 });
1760 }
1761 }
1762 }
1763
1764 pub(crate) fn compile_expr_operand(
1772 &mut self,
1773 expr: &Expression,
1774 inner_fn: impl FnOnce(&mut Self, RegisterOperand),
1775 ) {
1776 if let Expression::Identifier(name) = expr {
1777 let name = self.resolve_identifier_expect(*name);
1778 let binding = self.lexical_scope.get_identifier_reference(name);
1779 let index = self.get_binding(&binding);
1780 if let BindingKind::Local(Some(local_reg)) = &index {
1781 inner_fn(self, RegisterOperand::from(*local_reg));
1782 return;
1783 }
1784 if !self.in_with
1785 && let Some(&cached_reg) = self.const_binding_cache.get(&binding.locator())
1786 {
1787 inner_fn(self, cached_reg.into());
1788 return;
1789 }
1790 }
1791 let reg = self.register_allocator.alloc();
1792 self.compile_expr(expr, ®);
1793 let op = reg.variable();
1794 inner_fn(self, op);
1795 self.register_allocator.dealloc(reg);
1796 }
1797
1798 fn compile_access_preserve_this(
1809 &mut self,
1810 access: &PropertyAccess,
1811 this: &Register,
1812 dst: &Register,
1813 ) {
1814 match access {
1815 PropertyAccess::Simple(access) => {
1816 self.compile_expr(access.target(), this);
1817
1818 match access.field() {
1819 PropertyAccessField::Const(ident) => {
1820 self.emit_get_property_by_name(dst, None, this, ident.sym());
1821 }
1822 PropertyAccessField::Expr(field) => {
1823 let key = self.register_allocator.alloc();
1824 self.compile_expr(field, &key);
1825 self.bytecode.emit_get_property_by_value(
1826 dst.variable(),
1827 key.variable(),
1828 this.variable(),
1829 this.variable(),
1830 );
1831 self.register_allocator.dealloc(key);
1832 }
1833 }
1834 }
1835 PropertyAccess::Private(access) => {
1836 self.compile_expr(access.target(), this);
1837
1838 let index = self.get_or_insert_private_name(access.field());
1839 self.bytecode
1840 .emit_get_private_field(dst.variable(), this.variable(), index.into());
1841 }
1842 PropertyAccess::Super(access) => {
1843 let object = self.register_allocator.alloc();
1844 self.super_(this, &object);
1845
1846 match access.field() {
1847 PropertyAccessField::Const(ident) => {
1848 self.emit_get_property_by_name(dst, Some(this), &object, ident.sym());
1849 }
1850 PropertyAccessField::Expr(expr) => {
1851 let key = self.register_allocator.alloc();
1852 self.compile_expr(expr, &key);
1853 self.bytecode.emit_get_property_by_value(
1854 dst.variable(),
1855 key.variable(),
1856 this.variable(),
1857 object.variable(),
1858 );
1859 self.register_allocator.dealloc(key);
1860 }
1861 }
1862 self.register_allocator.dealloc(object);
1863 }
1864 }
1865 }
1866
1867 fn compile_optional_preserve_this(
1879 &mut self,
1880 optional: &Optional,
1881 this: &Register,
1882 value: &Register,
1883 ) {
1884 let mut jumps = Vec::with_capacity(optional.chain().len());
1885
1886 match optional.target().flatten() {
1887 Expression::PropertyAccess(access) => {
1888 self.compile_access_preserve_this(access, this, value);
1889 }
1890 Expression::Optional(opt) => self.compile_optional_preserve_this(opt, this, value),
1891 expr => {
1892 self.bytecode.emit_store_undefined(this.variable());
1893 self.compile_expr(expr, value);
1894 }
1895 }
1896
1897 jumps.push(self.jump_if_null_or_undefined(value));
1898
1899 let (first, rest) = optional
1900 .chain()
1901 .split_first()
1902 .expect("chain must have at least one element");
1903 assert!(first.shorted());
1904
1905 self.compile_optional_item_kind(first.kind(), this, value);
1906
1907 for item in rest {
1908 if item.shorted() {
1909 jumps.push(self.jump_if_null_or_undefined(value));
1910 }
1911 self.compile_optional_item_kind(item.kind(), this, value);
1912 }
1913
1914 let skip_undef = self.jump();
1915
1916 for label in jumps {
1917 self.patch_jump(label);
1918 self.bytecode.emit_store_undefined(value.variable());
1919 }
1920
1921 self.patch_jump(skip_undef);
1922 }
1923
1924 pub(crate) fn compile_optional_delete(&mut self, optional: &Optional, dst: &Register) {
1930 let value = self.register_allocator.alloc();
1931 let this = self.register_allocator.alloc();
1932
1933 let mut jumps = Vec::with_capacity(optional.chain().len());
1934
1935 match optional.target().flatten() {
1937 Expression::PropertyAccess(access) => {
1938 self.compile_access_preserve_this(access, &this, &value);
1939 }
1940 Expression::Optional(opt) => {
1941 self.compile_optional_preserve_this(opt, &this, &value);
1942 }
1943 expr => {
1944 self.bytecode.emit_store_undefined(this.variable());
1945 self.compile_expr(expr, &value);
1946 }
1947 }
1948
1949 jumps.push(self.jump_if_null_or_undefined(&value));
1950
1951 let chain = optional.chain();
1952 let chain_len = chain.len();
1953
1954 let (first, rest) = chain
1955 .split_first()
1956 .expect("chain must have at least one element");
1957 assert!(first.shorted());
1958
1959 if chain_len == 1 {
1960 self.compile_optional_delete_final(first.kind(), &this, &value, dst);
1962 } else {
1963 self.compile_optional_item_kind(first.kind(), &this, &value);
1965
1966 for (i, item) in rest.iter().enumerate() {
1967 if item.shorted() {
1968 jumps.push(self.jump_if_null_or_undefined(&value));
1969 }
1970 if i == rest.len() - 1 {
1971 self.compile_optional_delete_final(item.kind(), &this, &value, dst);
1973 } else {
1974 self.compile_optional_item_kind(item.kind(), &this, &value);
1975 }
1976 }
1977 }
1978
1979 let skip_true = self.jump();
1980
1981 for label in jumps {
1983 self.patch_jump(label);
1984 }
1985 self.bytecode.emit_store_true(dst.variable());
1986
1987 self.patch_jump(skip_true);
1988
1989 self.register_allocator.dealloc(this);
1990 self.register_allocator.dealloc(value);
1991 }
1992
1993 fn compile_optional_delete_final(
1995 &mut self,
1996 kind: &OptionalOperationKind,
1997 this: &Register,
1998 value: &Register,
1999 dst: &Register,
2000 ) {
2001 match kind {
2002 OptionalOperationKind::SimplePropertyAccess { field } => {
2003 self.bytecode.emit_move(this.variable(), value.variable());
2004 match field {
2005 PropertyAccessField::Const(name) => {
2006 let index = self.get_or_insert_name(name.sym());
2007 self.bytecode.emit_move(dst.variable(), value.variable());
2008 self.bytecode
2009 .emit_delete_property_by_name(dst.variable(), index.into());
2010 }
2011 PropertyAccessField::Expr(expr) => {
2012 self.bytecode.emit_move(dst.variable(), value.variable());
2013 let key = self.register_allocator.alloc();
2014 self.compile_expr(expr, &key);
2015 self.bytecode
2016 .emit_delete_property_by_value(dst.variable(), key.variable());
2017 self.register_allocator.dealloc(key);
2018 }
2019 }
2020 }
2021 OptionalOperationKind::PrivatePropertyAccess { .. } => {
2022 unreachable!("deleting private properties should always throw early errors.")
2023 }
2024 OptionalOperationKind::Call { .. } => {
2025 self.compile_optional_item_kind(kind, this, value);
2027 self.bytecode.emit_store_true(dst.variable());
2028 }
2029 }
2030 }
2031
2032 fn compile_optional_item_kind(
2049 &mut self,
2050 kind: &OptionalOperationKind,
2051 this: &Register,
2052 value: &Register,
2053 ) {
2054 match kind {
2055 OptionalOperationKind::SimplePropertyAccess { field } => {
2056 self.bytecode.emit_move(this.variable(), value.variable());
2057 match field {
2058 PropertyAccessField::Const(name) => {
2059 self.emit_get_property_by_name(value, None, value, name.sym());
2060 }
2061 PropertyAccessField::Expr(expr) => {
2062 let key = self.register_allocator.alloc();
2063 self.compile_expr(expr, &key);
2064 self.bytecode.emit_get_property_by_value(
2065 value.variable(),
2066 key.variable(),
2067 value.variable(),
2068 value.variable(),
2069 );
2070 self.register_allocator.dealloc(key);
2071 }
2072 }
2073 }
2074 OptionalOperationKind::PrivatePropertyAccess { field } => {
2075 self.bytecode.emit_move(this.variable(), value.variable());
2076 let index = self.get_or_insert_private_name(*field);
2077 self.bytecode.emit_get_private_field(
2078 value.variable(),
2079 value.variable(),
2080 index.into(),
2081 );
2082 }
2083 OptionalOperationKind::Call { args } => {
2084 self.push_from_register(this);
2085 self.push_from_register(value);
2086
2087 let args = &**args;
2088 let contains_spread = args.iter().any(|arg| matches!(arg, Expression::Spread(_)));
2089
2090 if contains_spread {
2091 let array = self.register_allocator.alloc();
2092 let array_op = array.variable();
2093
2094 self.bytecode.emit_store_new_array(array_op);
2095
2096 for arg in args {
2097 if let Expression::Spread(spread) = arg {
2098 let value = self.register_allocator.alloc();
2099 self.compile_expr(spread.target(), &value);
2100 self.bytecode.emit_get_iterator(value.variable());
2101 self.bytecode.emit_push_iterator_to_array(array_op);
2102 self.register_allocator.dealloc(value);
2103 } else {
2104 self.compile_expr_operand(arg, |this, op| {
2105 this.bytecode.emit_push_value_to_array(op, array_op);
2106 });
2107 }
2108 }
2109
2110 self.push_from_register(&array);
2111 self.register_allocator.dealloc(array);
2112
2113 self.bytecode.emit_call_spread();
2114 } else {
2115 for arg in args {
2116 self.compile_expr_to_stack(arg);
2117 }
2118 self.bytecode.emit_call((args.len() as u32).into());
2119 }
2120
2121 self.pop_into_register(value);
2122 self.bytecode.emit_store_undefined(this.variable());
2123 }
2124 }
2125 }
2126
2127 fn compile_var_decl(&mut self, decl: &VarDeclaration) {
2129 for variable in decl.0.as_ref() {
2130 match variable.binding() {
2131 Binding::Identifier(ident) => {
2132 let ident = ident.to_js_string(self.interner());
2133 if let Some(expr) = variable.init() {
2134 let binding = self.lexical_scope.get_identifier_reference(ident.clone());
2135 let index = self.insert_binding(binding);
2136 let value = self.register_allocator.alloc();
2137 self.emit_binding_access(BindingAccessOpcode::GetLocator, &index, &value);
2138 self.compile_expr(expr, &value);
2139 self.emit_binding_access(
2140 BindingAccessOpcode::SetNameByLocator,
2141 &index,
2142 &value,
2143 );
2144 self.register_allocator.dealloc(value);
2145 } else {
2146 let value = self.register_allocator.alloc();
2147 self.emit_binding(BindingOpcode::Var, ident, &value);
2148 self.register_allocator.dealloc(value);
2149 }
2150 }
2151 Binding::Pattern(pattern) => {
2152 let value = self.register_allocator.alloc();
2153 if let Some(init) = variable.init() {
2154 self.compile_expr(init, &value);
2155 } else {
2156 self.bytecode.emit_store_undefined(value.variable());
2157 }
2158 self.compile_declaration_pattern(pattern, BindingOpcode::InitVar, &value);
2159 self.register_allocator.dealloc(value);
2160 }
2161 }
2162 }
2163 }
2164
2165 fn compile_lexical_decl(&mut self, decl: &LexicalDeclaration) {
2167 match decl {
2168 LexicalDeclaration::Let(decls) => {
2169 for variable in decls.as_ref() {
2170 match variable.binding() {
2171 Binding::Identifier(ident) => {
2172 let ident = ident.to_js_string(self.interner());
2173 let binding = self.lexical_scope.get_identifier_reference(ident);
2174 if binding.local() {
2175 let reg = self.register_allocator.alloc_persistent();
2179 if let Some(init) = variable.init() {
2180 self.compile_expr(init, ®);
2181 } else {
2182 self.bytecode.emit_store_undefined(reg.variable());
2183 }
2184 self.local_binding_registers.insert(binding, reg.index());
2185 } else {
2186 let value = self.register_allocator.alloc();
2187 if let Some(init) = variable.init() {
2188 self.compile_expr(init, &value);
2189 } else {
2190 self.bytecode.emit_store_undefined(value.variable());
2191 }
2192 let binding_kind = self.insert_binding(binding);
2193 self.emit_binding_access(
2194 BindingAccessOpcode::PutLexicalValue,
2195 &binding_kind,
2196 &value,
2197 );
2198 self.register_allocator.dealloc(value);
2199 }
2200 }
2201 Binding::Pattern(pattern) => {
2202 let value = self.register_allocator.alloc();
2203 if let Some(init) = variable.init() {
2204 self.compile_expr(init, &value);
2205 } else {
2206 self.bytecode.emit_store_undefined(value.variable());
2207 }
2208 self.compile_declaration_pattern(
2209 pattern,
2210 BindingOpcode::InitLexical,
2211 &value,
2212 );
2213 self.register_allocator.dealloc(value);
2214 }
2215 }
2216 }
2217 }
2218 LexicalDeclaration::Const(decls) => {
2219 for variable in decls.as_ref() {
2220 match variable.binding() {
2221 Binding::Identifier(ident) => {
2222 let ident = ident.to_js_string(self.interner());
2223 let init = variable
2224 .init()
2225 .expect("const declaration must have initializer");
2226 let binding =
2227 self.lexical_scope.get_identifier_reference(ident.clone());
2228 if binding.local() {
2229 let reg = self.register_allocator.alloc_persistent();
2230 self.compile_expr(init, ®);
2231 self.local_binding_registers.insert(binding, reg.index());
2232 } else {
2233 let value = self.register_allocator.alloc();
2234 self.compile_expr(init, &value);
2235 let binding_kind = self.insert_binding(binding.clone());
2236 self.emit_binding_access(
2237 BindingAccessOpcode::PutLexicalValue,
2238 &binding_kind,
2239 &value,
2240 );
2241 let cache_reg = self.register_allocator.alloc_persistent();
2244 self.bytecode
2245 .emit_move(cache_reg.variable(), value.variable());
2246 self.const_binding_cache
2247 .insert(binding.locator(), cache_reg.index());
2248 self.register_allocator.dealloc(value);
2249 }
2250 }
2251 Binding::Pattern(pattern) => {
2252 let value = self.register_allocator.alloc();
2253 if let Some(init) = variable.init() {
2254 self.compile_expr(init, &value);
2255 } else {
2256 self.bytecode.emit_store_undefined(value.variable());
2257 }
2258 self.compile_declaration_pattern(
2259 pattern,
2260 BindingOpcode::InitLexical,
2261 &value,
2262 );
2263 self.register_allocator.dealloc(value);
2264 }
2265 }
2266 }
2267 }
2268 LexicalDeclaration::Using(decls) => {
2269 for variable in decls.as_ref() {
2274 match variable.binding() {
2275 Binding::Identifier(ident) => {
2276 let ident = ident.to_js_string(self.interner());
2277 let value = self.register_allocator.alloc();
2278
2279 if let Some(init) = variable.init() {
2280 self.compile_expr(init, &value);
2281 } else {
2282 self.bytecode.emit_store_undefined(value.variable());
2283 }
2284
2285 self.emit_binding(BindingOpcode::InitLexical, ident, &value);
2290 self.register_allocator.dealloc(value);
2291 }
2292 Binding::Pattern(pattern) => {
2293 let value = self.register_allocator.alloc();
2294
2295 if let Some(init) = variable.init() {
2296 self.compile_expr(init, &value);
2297 } else {
2298 self.bytecode.emit_store_undefined(value.variable());
2299 }
2300
2301 self.compile_declaration_pattern(
2304 pattern,
2305 BindingOpcode::InitLexical,
2306 &value,
2307 );
2308 self.register_allocator.dealloc(value);
2309 }
2310 }
2311 }
2312 }
2313 LexicalDeclaration::AwaitUsing(decls) => {
2314 for variable in decls.as_ref() {
2315 match variable.binding() {
2316 Binding::Identifier(ident) => {
2317 let ident = ident.to_js_string(self.interner());
2318 let value = self.register_allocator.alloc();
2319
2320 if let Some(init) = variable.init() {
2321 self.compile_expr(init, &value);
2322 } else {
2323 self.bytecode.emit_store_undefined(value.variable());
2324 }
2325
2326 self.emit_binding(BindingOpcode::InitLexical, ident, &value);
2331 self.register_allocator.dealloc(value);
2332 }
2333 Binding::Pattern(pattern) => {
2334 let value = self.register_allocator.alloc();
2335
2336 if let Some(init) = variable.init() {
2337 self.compile_expr(init, &value);
2338 } else {
2339 self.bytecode.emit_store_undefined(value.variable());
2340 }
2341
2342 self.compile_declaration_pattern(
2344 pattern,
2345 BindingOpcode::InitLexical,
2346 &value,
2347 );
2348 self.register_allocator.dealloc(value);
2349 }
2350 }
2351 }
2352 }
2353 }
2354 }
2355
2356 fn compile_stmt_list_item(&mut self, item: &StatementListItem, use_expr: bool, block: bool) {
2358 match item {
2359 StatementListItem::Statement(stmt) => {
2360 self.compile_stmt(stmt, use_expr, false);
2361 }
2362 StatementListItem::Declaration(decl) => self.compile_decl(decl, block),
2363 }
2364 }
2365
2366 #[allow(unused_variables)]
2368 pub fn compile_decl(&mut self, decl: &Declaration, block: bool) {
2369 match decl {
2370 #[cfg(feature = "annex-b")]
2371 Declaration::FunctionDeclaration(function) if block => {
2372 let name = function.name();
2373 if self.annex_b_function_names.contains(&name.sym()) {
2374 let name = name.to_js_string(self.interner());
2375 let binding = self.lexical_scope.get_identifier_reference(name.clone());
2376 let index = self.get_binding(&binding);
2377
2378 let value = self.register_allocator.alloc();
2379 self.emit_binding_access(BindingAccessOpcode::GetName, &index, &value);
2380 match self.variable_scope.set_mutable_binding_var(name.clone()) {
2381 Ok(binding) => {
2382 let index = self.get_binding(&binding);
2383 self.emit_binding_access(BindingAccessOpcode::SetName, &index, &value);
2384 }
2385 Err(BindingLocatorError::MutateImmutable) => {
2386 let index = self.get_or_insert_string(name);
2387 self.bytecode.emit_throw_mutate_immutable(index.into());
2388 }
2389 Err(BindingLocatorError::Silent) => {}
2390 }
2391 self.register_allocator.dealloc(value);
2392 }
2393 }
2394 Declaration::ClassDeclaration(class) => self.compile_class(class.as_ref().into(), None),
2395 Declaration::Lexical(lexical) => self.compile_lexical_decl(lexical),
2396 _ => {}
2397 }
2398 }
2399
2400 pub(crate) fn function(&mut self, function: FunctionSpec<'_>) -> u32 {
2403 let (generator, r#async, arrow) = (
2404 function.kind.is_generator(),
2405 function.kind.is_async(),
2406 function.kind.is_arrow(),
2407 );
2408
2409 let FunctionSpec {
2410 name,
2411 parameters,
2412 body,
2413 scopes,
2414 name_scope,
2415 linear_span,
2416 ..
2417 } = function;
2418
2419 let name = if let Some(name) = name {
2420 Some(name.sym().to_js_string(self.interner()))
2421 } else {
2422 Some(js_string!())
2423 };
2424
2425 let spanned_source_text = SpannedSourceText::new(self.source_text(), linear_span);
2426
2427 let code = FunctionCompiler::new(spanned_source_text)
2428 .name(name)
2429 .generator(generator)
2430 .r#async(r#async)
2431 .strict(self.strict())
2432 .arrow(arrow)
2433 .in_with(self.in_with)
2434 .name_scope(name_scope.cloned())
2435 .source_path(self.source_path.clone())
2436 .compile(
2437 parameters,
2438 body,
2439 self.variable_scope.clone(),
2440 self.lexical_scope.clone(),
2441 scopes,
2442 function.contains_direct_eval,
2443 self.interner,
2444 );
2445
2446 self.push_function_to_constants(code)
2447 }
2448
2449 pub(crate) fn function_with_binding(
2452 &mut self,
2453 function: FunctionSpec<'_>,
2454 node_kind: NodeKind,
2455 dst: &Register,
2456 ) {
2457 let name = function.name;
2458 let index = self.function(function);
2459 self.emit_get_function(dst, index);
2460 match node_kind {
2461 NodeKind::Declaration => {
2462 self.emit_binding(
2463 BindingOpcode::InitVar,
2464 name.expect("function declaration must have a name")
2465 .to_js_string(self.interner()),
2466 dst,
2467 );
2468 }
2469 NodeKind::Expression => {}
2470 }
2471 }
2472
2473 pub(crate) fn object_method(
2475 &mut self,
2476 function: FunctionSpec<'_>,
2477 kind: MethodKind,
2478 ) -> Register {
2479 let (generator, r#async, arrow) = (
2480 function.kind.is_generator(),
2481 function.kind.is_async(),
2482 function.kind.is_arrow(),
2483 );
2484 let FunctionSpec {
2485 name,
2486 parameters,
2487 body,
2488 scopes,
2489 name_scope,
2490 linear_span,
2491 ..
2492 } = function;
2493
2494 let name = if let Some(name) = name {
2495 let name = name.sym().to_js_string(self.interner());
2496 match kind {
2497 MethodKind::Ordinary => Some(name),
2498 MethodKind::Get => Some(js_string!(js_str!("get "), &name)),
2499 MethodKind::Set => Some(js_string!(js_str!("set "), &name)),
2500 }
2501 } else {
2502 Some(js_string!())
2503 };
2504
2505 let spanned_source_text = SpannedSourceText::new(self.source_text(), linear_span);
2506
2507 let code = FunctionCompiler::new(spanned_source_text)
2508 .name(name)
2509 .generator(generator)
2510 .r#async(r#async)
2511 .strict(self.strict())
2512 .arrow(arrow)
2513 .method(true)
2514 .in_with(self.in_with)
2515 .name_scope(name_scope.cloned())
2516 .source_path(self.source_path.clone())
2517 .compile(
2518 parameters,
2519 body,
2520 self.variable_scope.clone(),
2521 self.lexical_scope.clone(),
2522 scopes,
2523 function.contains_direct_eval,
2524 self.interner,
2525 );
2526
2527 let index = self.push_function_to_constants(code);
2528 let dst = self.register_allocator.alloc();
2529 self.emit_get_function(&dst, index);
2530 dst
2531 }
2532
2533 fn method(&mut self, function: FunctionSpec<'_>) -> Register {
2535 let (generator, r#async, arrow) = (
2536 function.kind.is_generator(),
2537 function.kind.is_async(),
2538 function.kind.is_arrow(),
2539 );
2540 let FunctionSpec {
2541 name,
2542 parameters,
2543 body,
2544 scopes,
2545 linear_span,
2546 ..
2547 } = function;
2548
2549 let name = if let Some(name) = name {
2550 Some(name.sym().to_js_string(self.interner()))
2551 } else {
2552 Some(js_string!())
2553 };
2554
2555 let spanned_source_text = SpannedSourceText::new(self.source_text(), linear_span);
2556
2557 let code = FunctionCompiler::new(spanned_source_text)
2558 .name(name)
2559 .generator(generator)
2560 .r#async(r#async)
2561 .strict(true)
2562 .arrow(arrow)
2563 .method(true)
2564 .in_with(self.in_with)
2565 .name_scope(function.name_scope.cloned())
2566 .source_path(self.source_path.clone())
2567 .compile(
2568 parameters,
2569 body,
2570 self.variable_scope.clone(),
2571 self.lexical_scope.clone(),
2572 scopes,
2573 function.contains_direct_eval,
2574 self.interner,
2575 );
2576
2577 let index = self.push_function_to_constants(code);
2578 let dst = self.register_allocator.alloc();
2579 self.emit_get_function(&dst, index);
2580 dst
2581 }
2582
2583 fn call(&mut self, callable: Callable<'_>, dst: CallResultDest<'_>) {
2584 #[derive(PartialEq)]
2585 enum CallKind {
2586 CallEval,
2587 Call,
2588 New,
2589 }
2590
2591 let (call, mut kind) = match callable {
2592 Callable::Call(call) => (call, CallKind::Call),
2593 Callable::New(new) => (new.call(), CallKind::New),
2594 };
2595
2596 match call.function().flatten() {
2597 Expression::PropertyAccess(access) if kind == CallKind::Call => {
2598 let this = self.register_allocator.alloc();
2599 let dst = self.register_allocator.alloc();
2600 self.compile_access_preserve_this(access, &this, &dst);
2601 self.push_from_register(&this);
2602 self.push_from_register(&dst);
2603 self.register_allocator.dealloc(this);
2604 self.register_allocator.dealloc(dst);
2605 }
2606 Expression::Optional(opt) if kind == CallKind::Call => {
2607 let this = self.register_allocator.alloc();
2608 let dst = self.register_allocator.alloc();
2609 self.compile_optional_preserve_this(opt, &this, &dst);
2610 self.push_from_register(&this);
2611 self.push_from_register(&dst);
2612 self.register_allocator.dealloc(this);
2613 self.register_allocator.dealloc(dst);
2614 }
2615 expr if kind == CallKind::Call => {
2616 if let Expression::Identifier(ident) = expr {
2617 if ident.sym() == Sym::EVAL {
2618 kind = CallKind::CallEval;
2619 }
2620
2621 if self.in_with {
2622 let name = self.resolve_identifier_expect(*ident);
2623 let binding = self.lexical_scope.get_identifier_reference(name);
2624 let index = self.get_binding(&binding);
2625 let index = match index {
2626 BindingKind::Global(index) | BindingKind::Stack(index) => index,
2627 BindingKind::Local(_) => {
2628 unreachable!("with binding cannot be local")
2629 }
2630 };
2631 let value = self.register_allocator.alloc();
2632 self.bytecode
2633 .emit_this_for_object_environment_name(value.variable(), index.into());
2634 self.push_from_register(&value);
2635 self.register_allocator.dealloc(value);
2636 } else {
2637 self.push_from_register(&CallFrame::undefined_register());
2638 }
2639 } else {
2640 self.push_from_register(&CallFrame::undefined_register());
2641 }
2642
2643 self.compile_expr_to_stack(expr);
2644 }
2645 expr => {
2646 let value = self.register_allocator.alloc();
2647 self.compile_expr(expr, &value);
2648 self.push_from_register(&CallFrame::undefined_register());
2649 self.push_from_register(&value);
2650 self.register_allocator.dealloc(value);
2651 }
2652 }
2653
2654 let mut compiler = self.position_guard(call);
2655
2656 let contains_spread = call
2657 .args()
2658 .iter()
2659 .any(|arg| matches!(arg, Expression::Spread(_)));
2660
2661 if contains_spread {
2662 let array = compiler.register_allocator.alloc();
2663 let array_op = array.variable();
2664
2665 compiler.bytecode.emit_store_new_array(array_op);
2666
2667 for arg in call.args() {
2668 if let Expression::Spread(spread) = arg {
2669 let value = compiler.register_allocator.alloc();
2670 compiler.compile_expr(spread.target(), &value);
2671 compiler.bytecode.emit_get_iterator(value.variable());
2672 compiler.bytecode.emit_push_iterator_to_array(array_op);
2673 compiler.register_allocator.dealloc(value);
2674 } else {
2675 compiler.compile_expr_operand(arg, |this, op| {
2676 this.bytecode.emit_push_value_to_array(op, array_op);
2677 });
2678 }
2679 }
2680
2681 compiler.push_from_register(&array);
2682 compiler.register_allocator.dealloc(array);
2683 } else {
2684 for arg in call.args() {
2685 compiler.compile_expr_to_stack(arg);
2686 }
2687 }
2688
2689 match kind {
2690 CallKind::CallEval => {
2691 let scope_index = compiler.constants.len() as u32;
2692 let lexical_scope = compiler.lexical_scope.clone();
2693 compiler.constants.push(Constant::Scope(lexical_scope));
2694 if contains_spread {
2695 compiler.bytecode.emit_call_eval_spread(scope_index.into());
2696 } else {
2697 compiler
2698 .bytecode
2699 .emit_call_eval((call.args().len() as u32).into(), scope_index.into());
2700 }
2701 }
2702 CallKind::Call if contains_spread => compiler.bytecode.emit_call_spread(),
2703 CallKind::Call => {
2704 compiler
2705 .bytecode
2706 .emit_call((call.args().len() as u32).into());
2707 }
2708 CallKind::New if contains_spread => compiler.bytecode.emit_new_spread(),
2709 CallKind::New => compiler
2710 .bytecode
2711 .emit_new((call.args().len() as u32).into()),
2712 }
2713 match dst {
2714 CallResultDest::Register(dst) => compiler.pop_into_register(dst),
2715 CallResultDest::Discard => compiler.bytecode.emit_pop(),
2716 CallResultDest::Stack => {} }
2718 }
2719
2720 #[inline]
2722 #[must_use]
2723 #[allow(clippy::missing_const_for_fn)]
2724 pub fn finish(mut self) -> CodeBlock {
2725 if let Some(async_handler) = self.async_handler {
2727 self.patch_handler(async_handler);
2728 }
2729 self.r#return(false);
2730
2731 let final_bytecode_len = self.next_opcode_location();
2732
2733 let mapped_arguments_binding_indices = if self.emitted_mapped_arguments_object_opcode {
2734 MappedArguments::binding_indices(&self.params, &self.parameter_scope, self.interner)
2735 } else {
2736 ThinVec::default()
2737 };
2738
2739 let register_count = self.register_allocator.finish();
2740
2741 let source_map_entries = self.source_map_builder.build(final_bytecode_len.as_u32());
2742
2743 CodeBlock {
2744 length: self.length,
2745 register_count,
2746 this_mode: self.this_mode,
2747 parameter_length: self.params.as_ref().len() as u32,
2748 mapped_arguments_binding_indices,
2749 bytecode: self.bytecode.into_bytecode(),
2750 constants: self.constants,
2751 bindings: self.bindings.into_boxed_slice(),
2752 handlers: self.handlers,
2753 flags: Cell::new(self.code_block_flags),
2754 ic: self.ic.into_boxed_slice(),
2755 source_info: SourceInfo::new(
2756 SourceMap::new(source_map_entries, self.source_path),
2757 self.function_name,
2758 self.spanned_source_text,
2759 ),
2760 global_lexs: self.global_lexs.into_boxed_slice(),
2761 global_fns: self.global_fns.into_boxed_slice(),
2762 global_vars: self.global_vars.into_boxed_slice(),
2763 debug_id: CodeBlock::get_next_codeblock_id(),
2764 #[cfg(feature = "trace")]
2765 traced: Cell::new(false),
2766 }
2767 }
2768
2769 fn compile_declaration_pattern(
2770 &mut self,
2771 pattern: &Pattern,
2772 def: BindingOpcode,
2773 object: &Register,
2774 ) {
2775 self.compile_declaration_pattern_impl(pattern, def, object);
2776 }
2777}