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