1use crate::{
6 Context, JsBigInt, JsString, JsValue, SpannedSourceText,
7 builtins::{
8 OrdinaryObject,
9 function::{OrdinaryFunction, ThisMode},
10 },
11 object::JsObject,
12};
13use bitflags::bitflags;
14use boa_ast::scope::{BindingLocator, Scope};
15use boa_gc::{Finalize, Gc, Trace, empty_trace};
16use itertools::Itertools;
17use std::{cell::Cell, fmt::Display, fmt::Write as _};
18use thin_vec::ThinVec;
19
20use super::{
21 InlineCache,
22 opcode::{Address, Bytecode, Instruction, InstructionIterator},
23 source_info::{SourceInfo, SourceMap, SourcePath},
24};
25
26bitflags! {
27 #[derive(Clone, Copy, Debug, Finalize)]
29 pub(crate) struct CodeBlockFlags: u16 {
30 const STRICT = 0b0000_0001;
32
33 const HAS_BINDING_IDENTIFIER = 0b0000_0010;
35
36 const IS_CLASS_CONSTRUCTOR = 0b0000_0100;
38
39 const IN_CLASS_FIELD_INITIALIZER = 0b0000_1000;
41
42 const IS_DERIVED_CONSTRUCTOR = 0b0001_0000;
44
45 const IS_ASYNC = 0b0010_0000;
46 const IS_GENERATOR = 0b0100_0000;
47
48 const HAS_PROTOTYPE_PROPERTY = 0b1000_0000;
50
51 const HAS_FUNCTION_SCOPE = 0b1_0000_0000;
53
54 #[cfg(feature = "trace")]
56 const TRACEABLE = 0b1000_0000_0000_0000;
57 }
58}
59
60impl CodeBlockFlags {
61 #[must_use]
63 pub(crate) fn has_function_scope(self) -> bool {
64 self.contains(Self::HAS_FUNCTION_SCOPE)
65 }
66}
67
68unsafe impl Trace for CodeBlockFlags {
70 empty_trace!();
71}
72
73#[derive(Debug, Clone, Copy)]
81pub(crate) struct Handler {
82 pub(crate) start: Address,
83 pub(crate) end: Address,
84 pub(crate) environment_count: u32,
85}
86
87impl Handler {
88 pub(crate) const fn handler(&self) -> Address {
90 self.end
91 }
92
93 pub(crate) const fn contains(&self, pc: u32) -> bool {
95 pc < self.end.as_u32() && pc >= self.start.as_u32()
96 }
97}
98
99#[derive(Clone, Debug, Trace, Finalize)]
100pub(crate) enum Constant {
101 String(JsString),
103 Function(Gc<CodeBlock>),
104 BigInt(#[unsafe_ignore_trace] JsBigInt),
105
106 Scope(#[unsafe_ignore_trace] Scope),
109}
110
111#[derive(Copy, Clone, Debug, Trace, Finalize)]
113#[boa_gc(empty_trace)]
114pub(crate) struct GlobalFunctionBinding {
115 pub(crate) name_index: u32,
117 pub(crate) function_index: u32,
119}
120
121#[derive(Clone, Debug, Trace, Finalize)]
127pub struct CodeBlock {
128 #[unsafe_ignore_trace]
129 pub(crate) flags: Cell<CodeBlockFlags>,
130
131 pub(crate) length: u32,
133
134 pub(crate) parameter_length: u32,
135
136 pub(crate) register_count: u32,
137
138 pub(crate) this_mode: ThisMode,
140
141 #[unsafe_ignore_trace]
143 pub(crate) mapped_arguments_binding_indices: ThinVec<Option<u32>>,
144
145 #[unsafe_ignore_trace]
147 pub(crate) bytecode: Bytecode,
148
149 pub(crate) constants: ThinVec<Constant>,
150
151 #[unsafe_ignore_trace]
153 pub(crate) bindings: Box<[BindingLocator]>,
154
155 #[unsafe_ignore_trace]
157 pub(crate) handlers: ThinVec<Handler>,
158
159 pub(crate) ic: Box<[InlineCache]>,
161
162 pub(crate) source_info: SourceInfo,
164
165 pub(crate) global_lexs: Box<[u32]>,
166 pub(crate) global_fns: Box<[GlobalFunctionBinding]>,
167 pub(crate) global_vars: Box<[u32]>,
168
169 pub(crate) debug_id: u64,
171
172 #[cfg(feature = "trace")]
173 #[unsafe_ignore_trace]
174 pub(crate) traced: Cell<bool>,
175
176 #[cfg(feature = "jit")]
177 #[unsafe_ignore_trace]
178 pub(crate) jit: crate::vm::jit::JitSlot,
179}
180
181impl CodeBlock {
183 #[must_use]
185 pub fn new(name: JsString, length: u32, strict: bool) -> Self {
186 let mut flags = CodeBlockFlags::empty();
187 flags.set(CodeBlockFlags::STRICT, strict);
188 Self {
189 bytecode: Bytecode::default(),
190 constants: ThinVec::default(),
191 bindings: Box::default(),
192 flags: Cell::new(flags),
193 length,
194 register_count: 0,
195 this_mode: ThisMode::Global,
196 mapped_arguments_binding_indices: ThinVec::new(),
197 parameter_length: 0,
198 handlers: ThinVec::default(),
199 ic: Box::default(),
200 source_info: SourceInfo::new(
201 SourceMap::new(Box::default(), SourcePath::None),
202 name,
203 SpannedSourceText::new_empty(),
204 ),
205 global_lexs: Box::default(),
206 global_fns: Box::default(),
207 global_vars: Box::default(),
208 debug_id: CodeBlock::get_next_codeblock_id(),
209 #[cfg(feature = "trace")]
210 traced: Cell::new(false),
211 #[cfg(feature = "jit")]
212 jit: crate::vm::jit::JitSlot::default(),
213 }
214 }
215
216 #[must_use]
218 pub fn name(&self) -> &JsString {
219 self.source_info.function_name()
220 }
221
222 #[must_use]
224 pub fn path(&self) -> &SourcePath {
225 self.source_info.map().path()
226 }
227
228 #[cfg(feature = "trace")]
230 pub(crate) fn traceable(&self) -> bool {
231 self.flags.get().contains(CodeBlockFlags::TRACEABLE)
232 }
233 #[cfg(feature = "trace")]
235 #[inline]
236 pub fn set_traceable(&self, value: bool) {
237 let mut flags = self.flags.get();
238 flags.set(CodeBlockFlags::TRACEABLE, value);
239 self.flags.set(flags);
240 }
241
242 pub(crate) fn is_class_constructor(&self) -> bool {
244 self.flags
245 .get()
246 .contains(CodeBlockFlags::IS_CLASS_CONSTRUCTOR)
247 }
248
249 pub(crate) fn strict(&self) -> bool {
251 self.flags.get().contains(CodeBlockFlags::STRICT)
252 }
253
254 pub(crate) fn has_binding_identifier(&self) -> bool {
256 self.flags
257 .get()
258 .contains(CodeBlockFlags::HAS_BINDING_IDENTIFIER)
259 }
260
261 pub(crate) fn in_class_field_initializer(&self) -> bool {
263 self.flags
264 .get()
265 .contains(CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER)
266 }
267
268 pub(crate) fn is_derived_constructor(&self) -> bool {
270 self.flags
271 .get()
272 .contains(CodeBlockFlags::IS_DERIVED_CONSTRUCTOR)
273 }
274
275 pub(crate) fn is_async(&self) -> bool {
277 self.flags.get().contains(CodeBlockFlags::IS_ASYNC)
278 }
279
280 pub(crate) fn is_generator(&self) -> bool {
282 self.flags.get().contains(CodeBlockFlags::IS_GENERATOR)
283 }
284
285 pub(crate) fn is_async_generator(&self) -> bool {
287 self.flags
288 .get()
289 .contains(CodeBlockFlags::IS_ASYNC | CodeBlockFlags::IS_GENERATOR)
290 }
291
292 pub(crate) fn is_ordinary(&self) -> bool {
294 !self.is_async() && !self.is_generator()
295 }
296
297 pub(crate) fn has_prototype_property(&self) -> bool {
299 self.flags
300 .get()
301 .contains(CodeBlockFlags::HAS_PROTOTYPE_PROPERTY)
302 }
303
304 pub(crate) fn has_function_scope(&self) -> bool {
306 self.flags.get().has_function_scope()
307 }
308
309 #[inline]
311 pub(crate) fn find_handler(&self, pc: u32) -> Option<(usize, &Handler)> {
312 self.handlers
313 .iter()
314 .enumerate()
315 .rev()
316 .find(|(_, handler)| handler.contains(pc))
317 }
318
319 pub(crate) fn constant_string(&self, index: usize) -> JsString {
326 if let Some(Constant::String(value)) = self.constants.get(index) {
327 return value.clone();
328 }
329
330 panic!("expected string constant at index {index}")
331 }
332
333 pub(crate) fn constant_function(&self, index: usize) -> Gc<Self> {
340 if let Some(Constant::Function(value)) = self.constants.get(index) {
341 return value.clone();
342 }
343
344 panic!("expected function constant at index {index}")
345 }
346
347 pub(crate) fn constant_scope(&self, index: usize) -> Scope {
354 if let Some(Constant::Scope(value)) = self.constants.get(index) {
355 return value.clone();
356 }
357
358 panic!("expected scope constant at index {index}")
359 }
360
361 pub(crate) fn source_info(&self) -> &SourceInfo {
362 &self.source_info
363 }
364
365 pub(crate) fn get_next_codeblock_id() -> u64 {
366 thread_local! {
367 static CODEBLOCK_ID_COUNTER: Cell<u64> = const { Cell::new(0) };
368 }
369
370 CODEBLOCK_ID_COUNTER.with(|c| {
371 let id = c.get();
372 c.set(id + 1);
373 id
374 })
375 }
376}
377
378impl CodeBlock {
380 pub(crate) fn instruction_operands(&self, instruction: &Instruction) -> String {
385 match instruction {
386 Instruction::SetRegisterFromAccumulator { dst }
387 | Instruction::PopIntoRegister { dst }
388 | Instruction::StoreZero { dst }
389 | Instruction::StoreOne { dst }
390 | Instruction::StoreNan { dst }
391 | Instruction::StorePositiveInfinity { dst }
392 | Instruction::StoreNegativeInfinity { dst }
393 | Instruction::StoreNull { dst }
394 | Instruction::StoreTrue { dst }
395 | Instruction::StoreFalse { dst }
396 | Instruction::StoreUndefined { dst }
397 | Instruction::Exception { dst }
398 | Instruction::This { dst }
399 | Instruction::NewTarget { dst }
400 | Instruction::ImportMeta { dst }
401 | Instruction::CreateMappedArgumentsObject { dst }
402 | Instruction::CreateUnmappedArgumentsObject { dst }
403 | Instruction::RestParameterInit { dst }
404 | Instruction::StoreNewArray { dst } => format!("dst:{dst}"),
405 Instruction::Add { lhs, rhs, dst }
406 | Instruction::Sub { lhs, rhs, dst }
407 | Instruction::Div { lhs, rhs, dst }
408 | Instruction::Mul { lhs, rhs, dst }
409 | Instruction::Mod { lhs, rhs, dst }
410 | Instruction::Pow { lhs, rhs, dst }
411 | Instruction::ShiftRight { lhs, rhs, dst }
412 | Instruction::ShiftLeft { lhs, rhs, dst }
413 | Instruction::UnsignedShiftRight { lhs, rhs, dst }
414 | Instruction::BitOr { lhs, rhs, dst }
415 | Instruction::BitAnd { lhs, rhs, dst }
416 | Instruction::BitXor { lhs, rhs, dst }
417 | Instruction::In { lhs, rhs, dst }
418 | Instruction::Eq { lhs, rhs, dst }
419 | Instruction::StrictEq { lhs, rhs, dst }
420 | Instruction::NotEq { lhs, rhs, dst }
421 | Instruction::StrictNotEq { lhs, rhs, dst }
422 | Instruction::GreaterThan { lhs, rhs, dst }
423 | Instruction::GreaterThanOrEq { lhs, rhs, dst }
424 | Instruction::LessThan { lhs, rhs, dst }
425 | Instruction::LessThanOrEq { lhs, rhs, dst }
426 | Instruction::InstanceOf { lhs, rhs, dst } => {
427 format!("lhs:{lhs}, rhs:{rhs}, dst:{dst}")
428 }
429 Instruction::InPrivate { dst, index, rhs } => {
430 format!("rhs:{rhs}, index:{index}, dst:{dst}")
431 }
432 Instruction::Inc { src, dst }
433 | Instruction::Dec { src, dst }
434 | Instruction::Move { src, dst }
435 | Instruction::ToPropertyKey { src, dst } => {
436 format!("src:{src}, dst:{dst}")
437 }
438 Instruction::SetFunctionName {
439 function,
440 name,
441 prefix,
442 } => {
443 format!(
444 "function:{function}, name:{name}, prefix:{}",
445 match u32::from(*prefix) {
446 0 => "prefix:",
447 1 => "prefix: get",
448 2 => "prefix: set",
449 _ => unreachable!(),
450 }
451 )
452 }
453 Instruction::StoreInt8 { value, dst } => {
454 format!("value:{value}, dst:{dst}")
455 }
456 Instruction::StoreInt16 { value, dst } => {
457 format!("value:{value}, dst:{dst}")
458 }
459 Instruction::StoreInt32 { value, dst } => {
460 format!("value:{value}, dst:{dst}")
461 }
462 Instruction::StoreFloat { value, dst } => {
463 format!("value:{value}, dst:{dst}")
464 }
465 Instruction::StoreDouble { value, dst } => {
466 format!("value:{value}, dst:{dst}")
467 }
468 Instruction::StoreLiteral { index, dst }
469 | Instruction::ThisForObjectEnvironmentName { index, dst }
470 | Instruction::GetFunction { index, dst }
471 | Instruction::GetArgument { index, dst } => {
472 format!("index:{index}, dst:{dst}")
473 }
474 Instruction::ThrowNewTypeError { message }
475 | Instruction::ThrowNewReferenceError { message } => format!("message:{message}"),
476 Instruction::StoreRegexp {
477 pattern_index,
478 flags_index,
479 dst,
480 } => {
481 format!("pattern:{pattern_index}, flags:{flags_index}, dst:{dst}")
482 }
483 Instruction::Jump { address } => format!("address:{address}"),
484 Instruction::JumpIfTrue { address, value }
485 | Instruction::JumpIfFalse { address, value }
486 | Instruction::JumpIfNotUndefined { address, value }
487 | Instruction::JumpIfNullOrUndefined { address, value }
488 | Instruction::LogicalAnd { address, value }
489 | Instruction::LogicalOr { address, value }
490 | Instruction::Coalesce { address, value } => {
491 format!("value:{value}, address:{address}")
492 }
493 Instruction::JumpIfNotLessThan { address, lhs, rhs }
494 | Instruction::JumpIfNotLessThanOrEqual { address, lhs, rhs }
495 | Instruction::JumpIfNotGreaterThan { address, lhs, rhs }
496 | Instruction::JumpIfNotGreaterThanOrEqual { address, lhs, rhs }
497 | Instruction::JumpIfNotEqual { address, lhs, rhs } => {
498 format!("lhs:{lhs}, rhs:{rhs}, address:{address}")
499 }
500 Instruction::Case {
501 address,
502 value,
503 condition,
504 } => {
505 format!("value:{value}, condition:{condition}, address:{address}")
506 }
507 Instruction::CallEval {
508 argument_count,
509 scope_index,
510 } => {
511 format!("argument_count:{argument_count}, scope_index:{scope_index}")
512 }
513 Instruction::CallEvalSpread { scope_index }
514 | Instruction::PushScope { scope_index } => {
515 format!("scope_index:{scope_index}")
516 }
517 Instruction::Call { argument_count }
518 | Instruction::New { argument_count }
519 | Instruction::SuperCall { argument_count } => {
520 format!("argument_count:{argument_count}")
521 }
522 Instruction::DefVar { binding_index }
523 | Instruction::DefEvalVar { binding_index }
524 | Instruction::GetLocator { binding_index } => format!("binding_index:{binding_index}"),
525 Instruction::DefInitVar { src, binding_index }
526 | Instruction::PutLexicalValue { src, binding_index }
527 | Instruction::SetName { src, binding_index } => {
528 format!("src:{src}, binding_index:{binding_index}")
529 }
530 Instruction::GetName { dst, binding_index }
531 | Instruction::GetNameAndLocator { dst, binding_index }
532 | Instruction::GetNameOrUndefined { dst, binding_index }
533 | Instruction::DeleteName { dst, binding_index } => {
534 format!("dst:{dst}, binding_index:{binding_index}")
535 }
536 Instruction::GetNameGlobal {
537 dst,
538 binding_index,
539 ic_index,
540 } => {
541 format!("dst:{dst}, binding_index:{binding_index}, ic_index:{ic_index}")
542 }
543 Instruction::DefineOwnPropertyByName {
544 object,
545 value,
546 name_index,
547 }
548 | Instruction::SetPropertyGetterByName {
549 object,
550 value,
551 name_index,
552 }
553 | Instruction::SetPropertySetterByName {
554 object,
555 value,
556 name_index,
557 }
558 | Instruction::DefinePrivateField {
559 object,
560 value,
561 name_index,
562 }
563 | Instruction::SetPrivateMethod {
564 object,
565 value,
566 name_index,
567 }
568 | Instruction::SetPrivateSetter {
569 object,
570 value,
571 name_index,
572 }
573 | Instruction::SetPrivateGetter {
574 object,
575 value,
576 name_index,
577 }
578 | Instruction::PushClassPrivateGetter {
579 object,
580 value,
581 name_index,
582 }
583 | Instruction::PushClassPrivateSetter {
584 object,
585 value,
586 name_index,
587 }
588 | Instruction::DefineClassStaticMethodByName {
589 object,
590 value,
591 name_index,
592 }
593 | Instruction::DefineClassMethodByName {
594 object,
595 value,
596 name_index,
597 }
598 | Instruction::DefineClassStaticGetterByName {
599 object,
600 value,
601 name_index,
602 }
603 | Instruction::DefineClassGetterByName {
604 object,
605 value,
606 name_index,
607 }
608 | Instruction::DefineClassStaticSetterByName {
609 object,
610 value,
611 name_index,
612 }
613 | Instruction::DefineClassSetterByName {
614 object,
615 value,
616 name_index,
617 }
618 | Instruction::SetPrivateField {
619 object,
620 value,
621 name_index,
622 }
623 | Instruction::PushClassFieldPrivate {
624 object,
625 value,
626 name_index,
627 } => {
628 format!("object:{object}, value:{value}, name_index:{name_index}")
629 }
630 Instruction::GetPrivateField {
631 dst,
632 object,
633 name_index,
634 } => {
635 format!("dst:{dst}, object:{object}, name_index:{name_index}")
636 }
637 Instruction::PushClassPrivateMethod {
638 object,
639 proto,
640 value,
641 name_index,
642 } => {
643 format!("object:{object}, proto:{proto}, value:{value}, name_index:{name_index}")
644 }
645 Instruction::ThrowMutateImmutable { index } => {
646 format!("index:{index}")
647 }
648 Instruction::DeletePropertyByName { object, name_index }
649 | Instruction::GetMethod { object, name_index } => {
650 format!("object:{object}, name_index:{name_index}")
651 }
652 Instruction::GetLengthProperty {
653 dst,
654 value,
655 ic_index,
656 }
657 | Instruction::GetPropertyByName {
658 dst,
659 value,
660 ic_index,
661 } => {
662 let ic = &self.ic[u32::from(*ic_index) as usize];
663 format!("dst:{dst}, value:{value}, ic:{ic}")
664 }
665 Instruction::GetPropertyByNameWithThis {
666 dst,
667 receiver,
668 value,
669 ic_index,
670 } => {
671 let ic = &self.ic[u32::from(*ic_index) as usize];
672 format!("dst:{dst}, receiver:{receiver}, value:{value}, ic:{ic}")
673 }
674 Instruction::SetPropertyByName {
675 value,
676 object,
677 ic_index,
678 } => {
679 let ic = &self.ic[u32::from(*ic_index) as usize];
680 format!("object:{object}, value:{value}, ic:{ic}")
681 }
682 Instruction::SetPropertyByNameWithThis {
683 value,
684 receiver,
685 object,
686 ic_index,
687 } => {
688 let ic = &self.ic[u32::from(*ic_index) as usize];
689 format!("object:{object}, receiver:{receiver}, value:{value}, ic:{ic}")
690 }
691 Instruction::GetPropertyByIndex { dst, object, index } => {
692 format!("dst:{dst}, object:{object}, index:{index}")
693 }
694 Instruction::SetPropertyByIndex {
695 value,
696 object,
697 index,
698 } => {
699 format!("value:{value}, object:{object}, index:{index}")
700 }
701 Instruction::GetPropertyByValue {
702 dst,
703 key,
704 receiver,
705 object,
706 }
707 | Instruction::GetPropertyByValuePush {
708 dst,
709 key,
710 receiver,
711 object,
712 } => {
713 format!("dst:{dst}, object:{object}, receiver:{receiver}, key:{key}")
714 }
715 Instruction::SetPropertyByValue {
716 value,
717 key,
718 receiver,
719 object,
720 } => {
721 format!("object:{object}, receiver:{receiver}, key:{key}, value:{value}")
722 }
723 Instruction::DefineOwnPropertyByValue { value, key, object }
724 | Instruction::DefineClassStaticMethodByValue { value, key, object }
725 | Instruction::DefineClassMethodByValue { value, key, object }
726 | Instruction::SetPropertyGetterByValue { value, key, object }
727 | Instruction::DefineClassStaticGetterByValue { value, key, object }
728 | Instruction::DefineClassGetterByValue { value, key, object }
729 | Instruction::SetPropertySetterByValue { value, key, object }
730 | Instruction::DefineClassStaticSetterByValue { value, key, object }
731 | Instruction::DefineClassSetterByValue { value, key, object } => {
732 format!("object:{object}, key:{key}, value:{value}")
733 }
734 Instruction::DeletePropertyByValue { key, object } => {
735 format!("object:{object}, key:{key}")
736 }
737 Instruction::CreateIteratorResult { value, done } => {
738 format!("value:{value}, done:{done}")
739 }
740 Instruction::StoreClassPrototype {
741 dst,
742 class,
743 superclass,
744 } => {
745 format!("dst:{dst}, class:{class}, superclass:{superclass}")
746 }
747 Instruction::SetClassPrototype {
748 dst,
749 prototype,
750 class,
751 } => {
752 format!("dst:{dst}, prototype:{prototype}, class:{class}")
753 }
754 Instruction::SetHomeObject { function, home } => {
755 format!("function:{function}, home:{home}")
756 }
757 Instruction::GetHomeObject { function } => {
758 format!("function:{function}")
759 }
760 Instruction::SetPrototype { object, prototype } => {
761 format!("object:{object}, prototype:{prototype}")
762 }
763 Instruction::GetPrototype { object } => {
764 format!("object:{object}")
765 }
766 Instruction::PushValueToArray { value, array } => {
767 format!("value:{value}, array:{array}")
768 }
769 Instruction::PushElisionToArray { array }
770 | Instruction::PushIteratorToArray { array } => {
771 format!("array:{array}")
772 }
773 Instruction::TypeOf { value }
774 | Instruction::LogicalNot { value }
775 | Instruction::Pos { value }
776 | Instruction::Neg { value }
777 | Instruction::IsObject { value }
778 | Instruction::BindThisValue { value }
779 | Instruction::BitNot { value } => {
780 format!("value:{value}")
781 }
782 Instruction::ImportCall {
783 specifier,
784 options,
785 phase,
786 } => {
787 let phase_str = match u32::from(*phase) {
788 0 => "evaluation",
789 1 => "defer",
790 2 => "source",
791 _ => "unknown",
792 };
793 format!("specifier:{specifier}, options:{options}, phase:{phase_str}")
794 }
795 Instruction::PushClassField {
796 object,
797 name,
798 value,
799 is_anonymous_function,
800 } => {
801 format!(
802 "object:{object}, value:{value}, name:{name}, is_anonymous_function:{is_anonymous_function}"
803 )
804 }
805 Instruction::MaybeException {
806 has_exception,
807 exception,
808 } => {
809 format!("has_exception:{has_exception}, exception:{exception}")
810 }
811 Instruction::SetAccumulator { src }
812 | Instruction::PushFromRegister { src }
813 | Instruction::Throw { src }
814 | Instruction::SetNameByLocator { src }
815 | Instruction::PushObjectEnvironment { src }
816 | Instruction::CreateForInIterator { src }
817 | Instruction::GetIterator { src }
818 | Instruction::GetAsyncIterator { src }
819 | Instruction::ValueNotNullOrUndefined { src }
820 | Instruction::GeneratorYield { src }
821 | Instruction::AsyncGeneratorYield { src }
822 | Instruction::Await { src } => {
823 format!("src:{src}")
824 }
825 Instruction::IteratorPush { iterator, next }
826 | Instruction::IteratorPop { iterator, next } => {
827 format!("iterator:{iterator}, next:{next}")
828 }
829 Instruction::IteratorUpdateResult { result } => {
830 format!("result:{result}")
831 }
832 Instruction::IteratorDone { dst }
833 | Instruction::IteratorValue { dst }
834 | Instruction::IteratorResult { dst }
835 | Instruction::IteratorToArray { dst }
836 | Instruction::IteratorStackEmpty { dst }
837 | Instruction::StoreEmptyObject { dst } => {
838 format!("dst:{dst}")
839 }
840 Instruction::IteratorFinishAsyncNext { resume_kind, value } => {
841 format!("resume_kind:{resume_kind}, value:{value}")
842 }
843 Instruction::IteratorReturn { value, called } => {
844 format!("value:{value}, called:{called}")
845 }
846 Instruction::PushPrivateEnvironment {
847 class,
848 name_indices,
849 } => {
850 format!("class:{class}, names:{name_indices:?}")
851 }
852 Instruction::TemplateLookup { address, site, dst } => {
853 format!("address:{address}, site:{site}, dst:{dst}")
854 }
855 Instruction::JumpTable { index, addresses } => {
856 format!(
857 "index:{index}, jump_table:({})",
858 addresses.iter().format(", ")
859 )
860 }
861 Instruction::ConcatToString { dst, values } => {
862 format!("dst:{dst}, values:{values:?}")
863 }
864 Instruction::CopyDataProperties {
865 object,
866 source,
867 excluded_keys,
868 } => {
869 format!("object:{object}, source:{source}, excluded_keys:{excluded_keys:?}")
870 }
871 Instruction::TemplateCreate { site, dst, values } => {
872 format!("site:{site}, dst:{dst}, values:{values:?}")
873 }
874 Instruction::GetFunctionObject { function_object } => {
875 format!("function_object:{function_object}")
876 }
877 Instruction::Pop
878 | Instruction::DeleteSuperThrow
879 | Instruction::ReThrow
880 | Instruction::CheckReturn
881 | Instruction::Return
882 | Instruction::AsyncGeneratorClose
883 | Instruction::CreatePromiseCapability
884 | Instruction::PopEnvironment
885 | Instruction::IncrementLoopIteration
886 | Instruction::IteratorNext
887 | Instruction::SuperCallDerived
888 | Instruction::CallSpread
889 | Instruction::NewSpread
890 | Instruction::SuperCallSpread
891 | Instruction::PopPrivateEnvironment
892 | Instruction::Generator
893 | Instruction::AsyncGenerator => String::new(),
894 Instruction::CallMath { operands } => operands.to_string(),
895 Instruction::PrepareMath { operands } => operands.to_string(),
896 Instruction::Reserved3
897 | Instruction::Reserved4
898 | Instruction::Reserved5
899 | Instruction::Reserved6
900 | Instruction::Reserved7
901 | Instruction::Reserved8
902 | Instruction::Reserved9
903 | Instruction::Reserved10
904 | Instruction::Reserved11
905 | Instruction::Reserved12
906 | Instruction::Reserved13
907 | Instruction::Reserved14
908 | Instruction::Reserved15
909 | Instruction::Reserved16
910 | Instruction::Reserved17
911 | Instruction::Reserved18
912 | Instruction::Reserved19
913 | Instruction::Reserved20
914 | Instruction::Reserved21
915 | Instruction::Reserved22
916 | Instruction::Reserved23
917 | Instruction::Reserved24
918 | Instruction::Reserved25
919 | Instruction::Reserved26
920 | Instruction::Reserved27
921 | Instruction::Reserved28
922 | Instruction::Reserved29
923 | Instruction::Reserved30
924 | Instruction::Reserved31
925 | Instruction::Reserved32
926 | Instruction::Reserved33
927 | Instruction::Reserved34
928 | Instruction::Reserved35
929 | Instruction::Reserved36
930 | Instruction::Reserved37
931 | Instruction::Reserved38
932 | Instruction::Reserved39
933 | Instruction::Reserved40
934 | Instruction::Reserved41
935 | Instruction::Reserved42
936 | Instruction::Reserved43
937 | Instruction::Reserved44
938 | Instruction::Reserved45
939 | Instruction::Reserved46
940 | Instruction::Reserved47
941 | Instruction::Reserved48
942 | Instruction::Reserved49
943 | Instruction::Reserved50
944 | Instruction::Reserved51
945 | Instruction::Reserved52
946 | Instruction::Reserved53
947 | Instruction::Reserved54
948 | Instruction::Reserved55
949 | Instruction::Reserved56
950 | Instruction::Reserved57 => unreachable!("Reserved opcodes are unreachable"),
951 }
952 }
953}
954
955impl Display for CodeBlock {
956 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
957 let name = self.name();
958 writeln!(
959 f,
960 "{:-^80}",
961 format!(
962 " Compiled Output: {} ",
963 if name.is_empty() {
964 format!("[anon#{}]", self.debug_id)
965 } else {
966 format!("'{}'", name.to_std_string_escaped())
967 }
968 ),
969 )?;
970 writeln!(
971 f,
972 "Location Handler Opcode Operands"
973 )?;
974 let mut iterator = InstructionIterator::new(&self.bytecode);
975 while let Some((instruction_start_pc, opcode, instruction)) = iterator.next() {
976 let opcode = opcode.as_str();
977 let operands = self.instruction_operands(&instruction);
978 let pc = iterator.pc();
979 let handler = if let Some((i, handler)) = self.find_handler(instruction_start_pc as u32)
980 {
981 let border_char = if instruction_start_pc as u32 == u32::from(handler.start) {
982 '>'
983 } else if pc as u32 == u32::from(handler.end) {
984 '<'
985 } else {
986 ' '
987 };
988 format!("{border_char}{i:2}: {}", handler.handler())
989 } else {
990 " ".to_string()
991 };
992 writeln!(
993 f,
994 " {instruction_start_pc:>06x} {handler} {opcode:<32} {operands}",
995 )?;
996 }
997 writeln!(
998 f,
999 "\nRegister Count: {}, Flags: {:?}",
1000 self.register_count,
1001 self.flags.get()
1002 )?;
1003 f.write_str("Constants:")?;
1004 if self.constants.is_empty() {
1005 f.write_str(" <empty>\n")?;
1006 } else {
1007 f.write_char('\n')?;
1008 for (i, value) in self.constants.iter().enumerate() {
1009 write!(f, " {i:04}: ")?;
1010 match value {
1011 Constant::String(v) => {
1012 writeln!(
1013 f,
1014 "[STRING] \"{}\"",
1015 v.to_std_string_escaped().escape_debug()
1016 )?;
1017 }
1018 Constant::BigInt(v) => writeln!(f, "[BIGINT] {v}n")?,
1019 Constant::Function(code) => writeln!(
1020 f,
1021 "[FUNCTION] name: '{}' (length: {})",
1022 code.name().to_std_string_escaped(),
1023 code.length
1024 )?,
1025 Constant::Scope(v) => {
1026 writeln!(
1027 f,
1028 "[SCOPE] index: {}, bindings: {}",
1029 v.scope_index(),
1030 v.num_bindings()
1031 )?;
1032 }
1033 }
1034 }
1035 }
1036 f.write_str("Bindings:")?;
1037 if self.bindings.is_empty() {
1038 f.write_str(" <empty>\n")?;
1039 } else {
1040 f.write_char('\n')?;
1041 for (i, binding_locator) in self.bindings.iter().enumerate() {
1042 writeln!(
1043 f,
1044 " {i:04}: {}, scope: {:?}",
1045 binding_locator.name().to_std_string_escaped(),
1046 binding_locator.scope()
1047 )?;
1048 }
1049 }
1050 f.write_str("Handlers:")?;
1051 if self.handlers.is_empty() {
1052 f.write_str(" <empty>\n")?;
1053 } else {
1054 f.write_char('\n')?;
1055 for (i, handler) in self.handlers.iter().enumerate() {
1056 writeln!(
1057 f,
1058 " {i:04}: Range: [{:04}, {:04}): Handler: {:04}, Environment: {:02}",
1059 handler.start,
1060 handler.end,
1061 handler.handler(),
1062 handler.environment_count,
1063 )?;
1064 }
1065 }
1066 f.write_str("Source Map:")?;
1067 if self.source_info().map().entries().is_empty() {
1068 f.write_str(" <empty>\n")?;
1069 } else {
1070 f.write_char('\n')?;
1071
1072 let bytecode_len = self.bytecode.bytes.len() as u32;
1073 for (i, handler) in self.source_info().map().entries().windows(2).enumerate() {
1074 let current = handler[0];
1075 let next = handler.get(1);
1076
1077 write!(
1078 f,
1079 " {i:04}: {:?}: ",
1080 current.pc..next.map_or(bytecode_len, |entry| entry.pc),
1081 )?;
1082
1083 if let Some(position) = current.position {
1084 writeln!(
1085 f,
1086 "({}, {})",
1087 position.line_number(),
1088 position.column_number()
1089 )?;
1090 } else {
1091 f.write_str("unknown")?;
1092 }
1093 }
1094 }
1095 Ok(())
1096 }
1097}
1098
1099pub(crate) fn create_function_object(
1109 code: Gc<CodeBlock>,
1110 prototype: JsObject,
1111 context: &mut Context,
1112) -> JsObject {
1113 let name: JsValue = code.name().clone().into();
1114 let length: JsValue = code.length.into();
1115
1116 let script_or_module = context.get_active_script_or_module();
1117
1118 let is_async = code.is_async();
1119 let is_generator = code.is_generator();
1120 let function = OrdinaryFunction::new(
1121 code,
1122 context.vm.frame().environments.snapshot_for_closure(),
1123 script_or_module,
1124 context.realm().clone(),
1125 );
1126
1127 let templates = context.intrinsics().templates();
1128
1129 let (mut template, storage, constructor_prototype) = if is_generator {
1130 let prototype = JsObject::from_proto_and_data_with_shared_shape(
1131 context.root_shape(),
1132 if is_async {
1133 context.intrinsics().objects().async_generator()
1134 } else {
1135 context.intrinsics().objects().generator()
1136 },
1137 OrdinaryObject,
1138 );
1139
1140 (
1141 templates.function_with_prototype_without_proto().clone(),
1142 vec![length, name, prototype.into()],
1143 None,
1144 )
1145 } else if is_async {
1146 (
1147 templates.function_without_proto().clone(),
1148 vec![length, name],
1149 None,
1150 )
1151 } else {
1152 let constructor_prototype = templates
1153 .function_prototype()
1154 .create(OrdinaryObject, vec![JsValue::undefined()]);
1155
1156 let template = templates.function_with_prototype_without_proto();
1157
1158 (
1159 template.clone(),
1160 vec![length, name, constructor_prototype.clone().into()],
1161 Some(constructor_prototype),
1162 )
1163 };
1164
1165 template.set_prototype(prototype);
1166
1167 let constructor = template.create(function, storage);
1168
1169 if let Some(constructor_prototype) = &constructor_prototype {
1170 constructor_prototype.borrow_mut().properties_mut().storage[0] = constructor.clone().into();
1171 }
1172 constructor
1173}
1174
1175pub(crate) fn create_function_object_fast(code: Gc<CodeBlock>, context: &mut Context) -> JsObject {
1181 let name: JsValue = code.name().clone().into();
1182 let length: JsValue = code.length.into();
1183
1184 let script_or_module = context.get_active_script_or_module();
1185
1186 let is_async = code.is_async();
1187 let is_generator = code.is_generator();
1188 let has_prototype_property = code.has_prototype_property();
1189 let function = OrdinaryFunction::new(
1190 code,
1191 context.vm.frame().environments.snapshot_for_closure(),
1192 script_or_module,
1193 context.realm().clone(),
1194 );
1195
1196 if is_generator {
1197 let prototype = JsObject::from_proto_and_data_with_shared_shape(
1198 context.root_shape(),
1199 if is_async {
1200 context.intrinsics().objects().async_generator()
1201 } else {
1202 context.intrinsics().objects().generator()
1203 },
1204 OrdinaryObject,
1205 );
1206 let template = if is_async {
1207 context.intrinsics().templates().async_generator_function()
1208 } else {
1209 context.intrinsics().templates().generator_function()
1210 };
1211
1212 template.create(function, vec![length, name, prototype.into()])
1213 } else if is_async {
1214 context
1215 .intrinsics()
1216 .templates()
1217 .async_function()
1218 .create(function, vec![length, name])
1219 } else if !has_prototype_property {
1220 context
1221 .intrinsics()
1222 .templates()
1223 .function()
1224 .create(function, vec![length, name])
1225 } else {
1226 let prototype = context
1227 .intrinsics()
1228 .templates()
1229 .function_prototype()
1230 .create(OrdinaryObject, vec![JsValue::undefined()]);
1231
1232 let constructor = context
1233 .intrinsics()
1234 .templates()
1235 .function_with_prototype()
1236 .create(function, vec![length, name, prototype.clone().into()]);
1237
1238 prototype.borrow_mut().properties_mut().storage[0] = constructor.clone().into();
1239
1240 constructor
1241 }
1242}