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