diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/jsparagus-emitter/src/emitter.rs | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | third_party/rust/jsparagus-emitter/src/emitter.rs | 1461 |
1 files changed, 1461 insertions, 0 deletions
diff --git a/third_party/rust/jsparagus-emitter/src/emitter.rs b/third_party/rust/jsparagus-emitter/src/emitter.rs new file mode 100644 index 0000000000..1bcefab1ae --- /dev/null +++ b/third_party/rust/jsparagus-emitter/src/emitter.rs @@ -0,0 +1,1461 @@ +//! Low-level bytecode emitter, used by ast_builder. +//! +//! This API makes it easy to emit correct individual bytecode instructions. + +// Most of this functionality isn't used yet. +#![allow(dead_code)] + +use ast::source_atom_set::SourceAtomSetIndex; +use byteorder::{ByteOrder, LittleEndian}; +use std::cmp; +use std::collections::HashMap; +use std::convert::TryFrom; +use std::convert::TryInto; +use std::fmt; +use stencil::bytecode_offset::{BytecodeOffset, BytecodeOffsetDiff}; +use stencil::frame_slot::FrameSlot; +use stencil::gcthings::{GCThingIndex, GCThingList}; +use stencil::opcode::Opcode; +use stencil::regexp::RegExpIndex; +use stencil::scope::ScopeIndex; +use stencil::scope_notes::{ScopeNoteIndex, ScopeNoteList}; +use stencil::script::{ + ImmutableScriptData, ImmutableScriptDataList, ScriptStencil, ScriptStencilIndex, SourceExtent, +}; + +// WARNING +// The following section is generated by update_stencil.py. +// Do mot modify manually. +// +// @@@@ BEGIN TYPES @@@@ +#[derive(Debug, Clone, Copy)] +pub enum AsyncFunctionResolveKind { + Fulfill = 0, + Reject = 1, +} + +#[derive(Debug, Clone, Copy)] +pub enum CheckIsObjectKind { + IteratorNext = 0, + IteratorReturn = 1, + IteratorThrow = 2, + GetIterator = 3, + GetAsyncIterator = 4, +} + +#[derive(Debug, Clone, Copy)] +pub enum CompletionKind { + Normal = 0, + Return = 1, + Throw = 2, +} + +#[derive(Debug, Clone, Copy)] +pub enum FunctionPrefixKind { + None = 0, + Get = 1, + Set = 2, +} + +#[derive(Debug, Clone, Copy)] +pub enum GeneratorResumeKind { + Next = 0, + Throw = 1, + Return = 2, +} + +#[derive(Debug, Clone, Copy)] +pub enum ThrowMsgKind { + AssignToCall = 0, + IteratorNoThrow = 1, + CantDeleteSuper = 2, + PrivateDoubleInit = 3, + PrivateBrandDoubleInit = 4, + MissingPrivateOnGet = 5, + MissingPrivateOnSet = 6, + AssignToPrivateMethod = 7, + DecoratorInvalidReturnType = 8, +} + +#[derive(Debug, Clone, Copy)] +pub enum ThrowCondition { + ThrowHas = 0, + ThrowHasNot = 1, + OnlyCheckRhs = 2, +} + +#[derive(Debug, Clone, Copy)] +pub enum TryNoteKind { + Catch = 0, + Finally = 1, + ForIn = 2, + Destructuring = 3, + ForOf = 4, + ForOfIterClose = 5, + Loop = 6, +} + +#[derive(Debug, Clone, Copy)] +pub enum SymbolCode { + IsConcatSpreadable = 0, + Iterator = 1, + Match = 2, + Replace = 3, + Search = 4, + Species = 5, + HasInstance = 6, + Split = 7, + ToPrimitive = 8, + ToStringTag = 9, + Unscopables = 10, + AsyncIterator = 11, + MatchAll = 12, +} + +#[derive(Debug, Clone, Copy)] +pub enum SrcNoteType { + Null = 0, + AssignOp = 1, + ColSpan = 2, + NewLine = 3, + SetLine = 4, + Breakpoint = 5, + StepSep = 6, + Unused7 = 7, + XDelta = 8, +} + +// @@@@ END TYPES @@@@ + +#[allow(non_camel_case_types)] +pub type u24 = u32; + +/// Low-level bytecode emitter. +pub struct InstructionWriter { + bytecode: Vec<u8>, + + /// To de-duplicate atoms in gcthings list, note the index for each atom. + atom_to_gcindex_map: HashMap<SourceAtomSetIndex, GCThingIndex>, + + gcthings: GCThingList, + scope_notes: ScopeNoteList, + + last_jump_target_offset: Option<BytecodeOffset>, + + main_offset: BytecodeOffset, + + /// The maximum number of fixed frame slots. + max_fixed_slots: FrameSlot, + + /// Stack depth after the instructions emitted so far. + stack_depth: usize, + + /// Maximum stack_depth at any point in the instructions emitted so far. + maximum_stack_depth: usize, + + body_scope_index: Option<GCThingIndex>, + + /// Number of JOF_IC instructions emitted so far. + num_ic_entries: usize, +} + +#[derive(Debug)] +pub struct EmitOptions { + pub no_script_rval: bool, + pub extent: SourceExtent, +} +impl EmitOptions { + pub fn new(extent: SourceExtent) -> Self { + Self { + no_script_rval: false, + extent, + } + } +} + +/// The error of bytecode-compilation. +#[derive(Clone, Debug)] +pub enum EmitError { + NotImplemented(&'static str), +} + +impl fmt::Display for EmitError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + EmitError::NotImplemented(message) => write!(f, "not implemented: {}", message), + } + } +} + +impl InstructionWriter { + pub fn new() -> Self { + Self { + bytecode: Vec::new(), + gcthings: GCThingList::new(), + atom_to_gcindex_map: HashMap::new(), + scope_notes: ScopeNoteList::new(), + last_jump_target_offset: None, + main_offset: BytecodeOffset::from(0usize), + max_fixed_slots: FrameSlot::new(0), + stack_depth: 0, + maximum_stack_depth: 0, + body_scope_index: None, + num_ic_entries: 0, + } + } + + fn write_i8(&mut self, value: i8) { + self.write_u8(value as u8); + } + + fn write_u8(&mut self, value: u8) { + self.bytecode.push(value); + } + + fn write_u16(&mut self, value: u16) { + self.bytecode.extend_from_slice(&value.to_le_bytes()); + } + + fn write_u24(&mut self, value: u24) { + let slice = value.to_le_bytes(); + assert!(slice.len() == 4 && slice[3] == 0); + self.bytecode.extend_from_slice(&slice[0..3]); + } + + fn write_i32(&mut self, value: i32) { + self.bytecode.extend_from_slice(&value.to_le_bytes()); + } + + fn write_u32(&mut self, value: u32) { + self.bytecode.extend_from_slice(&value.to_le_bytes()); + } + + fn write_g_c_thing_index(&mut self, value: GCThingIndex) { + self.write_u32(usize::from(value) as u32); + } + + fn write_offset(&mut self, offset: i32) { + self.write_i32(offset); + } + + fn write_bytecode_offset_diff(&mut self, offset: BytecodeOffsetDiff) { + self.write_i32(i32::from(offset)); + } + + fn write_f64(&mut self, val: f64) { + self.bytecode + .extend_from_slice(&val.to_bits().to_le_bytes()); + } + + fn write_ic_index(&mut self) { + self.write_u32(self.num_ic_entries.try_into().unwrap()); + } + + fn emit_op(&mut self, opcode: Opcode) { + let nuses: isize = opcode.nuses(); + assert!(nuses >= 0); + self.emit_op_common(opcode, nuses as usize); + } + + fn emit_argc_op(&mut self, opcode: Opcode, argc: u16) { + assert!(opcode.has_argc()); + assert_eq!(opcode.nuses(), -1); + let nuses = match opcode { + Opcode::Call + | Opcode::CallIgnoresRv + | Opcode::Eval + | Opcode::CallIter + | Opcode::StrictEval => { + // callee, this, arguments... + 2 + (argc as usize) + } + + Opcode::New | Opcode::SuperCall => { + // callee, isConstructing, arguments..., newtarget + 2 + (argc as usize) + 1 + } + + _ => panic!("Unsupported opcode"), + }; + self.emit_op_common(opcode, nuses); + } + + fn emit_pop_n_op(&mut self, opcode: Opcode, n: u16) { + assert_eq!(opcode.nuses(), -1); + debug_assert_eq!(opcode, Opcode::PopN); + self.emit_op_common(opcode, n as usize); + } + + fn emit_op_common(&mut self, opcode: Opcode, nuses: usize) { + assert!( + self.stack_depth >= nuses as usize, + "InstructionWriter misuse! Not enough arguments on the stack." + ); + self.stack_depth -= nuses as usize; + + let ndefs = opcode.ndefs(); + if ndefs > 0 { + self.stack_depth += ndefs; + if self.stack_depth > self.maximum_stack_depth { + self.maximum_stack_depth = self.stack_depth; + } + } + + if opcode.has_ic_entry() { + self.num_ic_entries += 1; + } + + self.bytecode.push(opcode.to_byte()); + } + + fn set_last_jump_target_offset(&mut self, target: BytecodeOffset) { + self.last_jump_target_offset = Some(target); + } + + fn get_end_of_bytecode(&mut self, offset: BytecodeOffset) -> usize { + // find the offset after the end of bytecode associated with this offset. + let target_opcode = Opcode::try_from(self.bytecode[offset.offset]).unwrap(); + offset.offset + target_opcode.instruction_length() + } + + pub fn emit_jump_target_and_patch(&mut self, jumplist: &Vec<BytecodeOffset>) { + let mut target = self.bytecode_offset(); + let last_jump = self.last_jump_target_offset; + match last_jump { + Some(offset) => { + if self.get_end_of_bytecode(offset) != target.offset { + self.jump_target(); + self.set_last_jump_target_offset(target); + } else { + target = offset; + } + } + None => { + self.jump_target(); + self.set_last_jump_target_offset(target); + } + } + + for jump in jumplist { + self.patch_jump_to_target(target, *jump); + } + } + + pub fn patch_jump_to_target(&mut self, target: BytecodeOffset, jump: BytecodeOffset) { + let diff = target.diff_from(jump).into(); + let index = jump.offset + 1; + // FIXME: Use native endian instead of little endian + LittleEndian::write_i32(&mut self.bytecode[index..index + 4], diff); + } + + pub fn bytecode_offset(&mut self) -> BytecodeOffset { + BytecodeOffset::from(self.bytecode.len()) + } + + pub fn stack_depth(&self) -> usize { + self.stack_depth + } + + pub fn set_stack_depth(&mut self, depth: usize) { + self.stack_depth = depth; + } + + // Public methods to emit each instruction. + + pub fn emit_boolean(&mut self, value: bool) { + self.emit_op(if value { Opcode::True } else { Opcode::False }); + } + + pub fn emit_unary_op(&mut self, opcode: Opcode) { + assert!(opcode.is_simple_unary_operator()); + self.emit_op(opcode); + } + + pub fn emit_binary_op(&mut self, opcode: Opcode) { + assert!(opcode.is_simple_binary_operator()); + debug_assert_eq!(opcode.nuses(), 2); + debug_assert_eq!(opcode.ndefs(), 1); + self.emit_op(opcode); + } + + pub fn table_switch( + &mut self, + _len: i32, + _low: i32, + _high: i32, + _first_resume_index: u24, + ) -> Result<(), EmitError> { + Err(EmitError::NotImplemented("TODO: table_switch")) + } + + pub fn numeric(&mut self, value: f64) { + if value.is_finite() && value.fract() == 0.0 { + if i8::min_value() as f64 <= value && value <= i8::max_value() as f64 { + match value as i8 { + 0 => self.zero(), + 1 => self.one(), + i => self.int8(i), + } + return; + } + if 0.0 <= value { + if value <= u16::max_value() as f64 { + self.uint16(value as u16); + return; + } + if value <= 0x00ffffff as f64 { + self.uint24(value as u24); + return; + } + } + if i32::min_value() as f64 <= value && value <= i32::max_value() as f64 { + self.int32(value as i32); + return; + } + } + self.double_(value); + } + + // WARNING + // The following section is generated by update_stencil.py. + // Do mot modify manually. + // + // @@@@ BEGIN METHODS @@@@ + pub fn undefined(&mut self) { + self.emit_op(Opcode::Undefined); + } + + pub fn null(&mut self) { + self.emit_op(Opcode::Null); + } + + pub fn int32(&mut self, val: i32) { + self.emit_op(Opcode::Int32); + self.write_i32(val); + } + + pub fn zero(&mut self) { + self.emit_op(Opcode::Zero); + } + + pub fn one(&mut self) { + self.emit_op(Opcode::One); + } + + pub fn int8(&mut self, val: i8) { + self.emit_op(Opcode::Int8); + self.write_i8(val); + } + + pub fn uint16(&mut self, val: u16) { + self.emit_op(Opcode::Uint16); + self.write_u16(val); + } + + pub fn uint24(&mut self, val: u24) { + self.emit_op(Opcode::Uint24); + self.write_u24(val); + } + + pub fn double_(&mut self, val: f64) { + self.emit_op(Opcode::Double); + self.write_f64(val); + } + + pub fn big_int(&mut self, big_int_index: u32) { + self.emit_op(Opcode::BigInt); + self.write_u32(big_int_index); + } + + pub fn string(&mut self, atom_index: GCThingIndex) { + self.emit_op(Opcode::String); + self.write_g_c_thing_index(atom_index); + } + + pub fn symbol(&mut self, symbol: u8) { + self.emit_op(Opcode::Symbol); + self.write_u8(symbol); + } + + pub fn typeof_(&mut self) { + self.emit_op(Opcode::Typeof); + } + + pub fn typeof_expr(&mut self) { + self.emit_op(Opcode::TypeofExpr); + } + + pub fn inc(&mut self) { + self.emit_op(Opcode::Inc); + } + + pub fn dec(&mut self) { + self.emit_op(Opcode::Dec); + } + + pub fn to_property_key(&mut self) { + self.emit_op(Opcode::ToPropertyKey); + } + + pub fn to_numeric(&mut self) { + self.emit_op(Opcode::ToNumeric); + } + + pub fn to_string(&mut self) { + self.emit_op(Opcode::ToString); + } + + pub fn is_null_or_undefined(&mut self) { + self.emit_op(Opcode::IsNullOrUndefined); + } + + pub fn global_this(&mut self) { + self.emit_op(Opcode::GlobalThis); + } + + pub fn non_syntactic_global_this(&mut self) { + self.emit_op(Opcode::NonSyntacticGlobalThis); + } + + pub fn new_target(&mut self) { + self.emit_op(Opcode::NewTarget); + } + + pub fn dynamic_import(&mut self) { + self.emit_op(Opcode::DynamicImport); + } + + pub fn import_meta(&mut self) { + self.emit_op(Opcode::ImportMeta); + } + + pub fn new_init(&mut self) { + self.emit_op(Opcode::NewInit); + } + + pub fn new_object(&mut self, shape_index: GCThingIndex) { + self.emit_op(Opcode::NewObject); + self.write_g_c_thing_index(shape_index); + } + + pub fn object(&mut self, object_index: GCThingIndex) { + self.emit_op(Opcode::Object); + self.write_g_c_thing_index(object_index); + } + + pub fn obj_with_proto(&mut self) { + self.emit_op(Opcode::ObjWithProto); + } + + pub fn init_prop(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::InitProp); + self.write_g_c_thing_index(name_index); + } + + pub fn init_hidden_prop(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::InitHiddenProp); + self.write_g_c_thing_index(name_index); + } + + pub fn init_locked_prop(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::InitLockedProp); + self.write_g_c_thing_index(name_index); + } + + pub fn init_elem(&mut self) { + self.emit_op(Opcode::InitElem); + } + + pub fn init_hidden_elem(&mut self) { + self.emit_op(Opcode::InitHiddenElem); + } + + pub fn init_locked_elem(&mut self) { + self.emit_op(Opcode::InitLockedElem); + } + + pub fn init_prop_getter(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::InitPropGetter); + self.write_g_c_thing_index(name_index); + } + + pub fn init_hidden_prop_getter(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::InitHiddenPropGetter); + self.write_g_c_thing_index(name_index); + } + + pub fn init_elem_getter(&mut self) { + self.emit_op(Opcode::InitElemGetter); + } + + pub fn init_hidden_elem_getter(&mut self) { + self.emit_op(Opcode::InitHiddenElemGetter); + } + + pub fn init_prop_setter(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::InitPropSetter); + self.write_g_c_thing_index(name_index); + } + + pub fn init_hidden_prop_setter(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::InitHiddenPropSetter); + self.write_g_c_thing_index(name_index); + } + + pub fn init_elem_setter(&mut self) { + self.emit_op(Opcode::InitElemSetter); + } + + pub fn init_hidden_elem_setter(&mut self) { + self.emit_op(Opcode::InitHiddenElemSetter); + } + + pub fn get_prop(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::GetProp); + self.write_g_c_thing_index(name_index); + } + + pub fn get_elem(&mut self) { + self.emit_op(Opcode::GetElem); + } + + pub fn set_prop(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::SetProp); + self.write_g_c_thing_index(name_index); + } + + pub fn strict_set_prop(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::StrictSetProp); + self.write_g_c_thing_index(name_index); + } + + pub fn set_elem(&mut self) { + self.emit_op(Opcode::SetElem); + } + + pub fn strict_set_elem(&mut self) { + self.emit_op(Opcode::StrictSetElem); + } + + pub fn del_prop(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::DelProp); + self.write_g_c_thing_index(name_index); + } + + pub fn strict_del_prop(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::StrictDelProp); + self.write_g_c_thing_index(name_index); + } + + pub fn del_elem(&mut self) { + self.emit_op(Opcode::DelElem); + } + + pub fn strict_del_elem(&mut self) { + self.emit_op(Opcode::StrictDelElem); + } + + pub fn has_own(&mut self) { + self.emit_op(Opcode::HasOwn); + } + + pub fn check_private_field(&mut self, throw_condition: ThrowCondition, msg_kind: ThrowMsgKind) { + self.emit_op(Opcode::CheckPrivateField); + self.write_u8(throw_condition as u8); + self.write_u8(msg_kind as u8); + } + + pub fn new_private_name(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::NewPrivateName); + self.write_g_c_thing_index(name_index); + } + + pub fn super_base(&mut self) { + self.emit_op(Opcode::SuperBase); + } + + pub fn get_prop_super(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::GetPropSuper); + self.write_g_c_thing_index(name_index); + } + + pub fn get_elem_super(&mut self) { + self.emit_op(Opcode::GetElemSuper); + } + + pub fn set_prop_super(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::SetPropSuper); + self.write_g_c_thing_index(name_index); + } + + pub fn strict_set_prop_super(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::StrictSetPropSuper); + self.write_g_c_thing_index(name_index); + } + + pub fn set_elem_super(&mut self) { + self.emit_op(Opcode::SetElemSuper); + } + + pub fn strict_set_elem_super(&mut self) { + self.emit_op(Opcode::StrictSetElemSuper); + } + + pub fn iter(&mut self) { + self.emit_op(Opcode::Iter); + } + + pub fn more_iter(&mut self) { + self.emit_op(Opcode::MoreIter); + } + + pub fn is_no_iter(&mut self) { + self.emit_op(Opcode::IsNoIter); + } + + pub fn end_iter(&mut self) { + self.emit_op(Opcode::EndIter); + } + + pub fn close_iter(&mut self, kind: CompletionKind) { + self.emit_op(Opcode::CloseIter); + self.write_u8(kind as u8); + } + + pub fn check_is_obj(&mut self, kind: CheckIsObjectKind) { + self.emit_op(Opcode::CheckIsObj); + self.write_u8(kind as u8); + } + + pub fn check_obj_coercible(&mut self) { + self.emit_op(Opcode::CheckObjCoercible); + } + + pub fn to_async_iter(&mut self) { + self.emit_op(Opcode::ToAsyncIter); + } + + pub fn mutate_proto(&mut self) { + self.emit_op(Opcode::MutateProto); + } + + pub fn new_array(&mut self, length: u32) { + self.emit_op(Opcode::NewArray); + self.write_u32(length); + } + + pub fn init_elem_array(&mut self, index: u32) { + self.emit_op(Opcode::InitElemArray); + self.write_u32(index); + } + + pub fn init_elem_inc(&mut self) { + self.emit_op(Opcode::InitElemInc); + } + + pub fn hole(&mut self) { + self.emit_op(Opcode::Hole); + } + + pub fn reg_exp(&mut self, regexp_index: GCThingIndex) { + self.emit_op(Opcode::RegExp); + self.write_g_c_thing_index(regexp_index); + } + + pub fn lambda(&mut self, func_index: GCThingIndex) { + self.emit_op(Opcode::Lambda); + self.write_g_c_thing_index(func_index); + } + + pub fn set_fun_name(&mut self, prefix_kind: FunctionPrefixKind) { + self.emit_op(Opcode::SetFunName); + self.write_u8(prefix_kind as u8); + } + + pub fn init_home_object(&mut self) { + self.emit_op(Opcode::InitHomeObject); + } + + pub fn check_class_heritage(&mut self) { + self.emit_op(Opcode::CheckClassHeritage); + } + + pub fn fun_with_proto(&mut self, func_index: GCThingIndex) { + self.emit_op(Opcode::FunWithProto); + self.write_g_c_thing_index(func_index); + } + + pub fn builtin_object(&mut self, kind: u8) { + self.emit_op(Opcode::BuiltinObject); + self.write_u8(kind); + } + + pub fn call(&mut self, argc: u16) { + self.emit_argc_op(Opcode::Call, argc); + self.write_u16(argc); + } + + pub fn call_content(&mut self, argc: u16) { + self.emit_argc_op(Opcode::CallContent, argc); + self.write_u16(argc); + } + + pub fn call_iter(&mut self, argc: u16) { + self.emit_argc_op(Opcode::CallIter, argc); + self.write_u16(argc); + } + + pub fn call_content_iter(&mut self, argc: u16) { + self.emit_argc_op(Opcode::CallContentIter, argc); + self.write_u16(argc); + } + + pub fn call_ignores_rv(&mut self, argc: u16) { + self.emit_argc_op(Opcode::CallIgnoresRv, argc); + self.write_u16(argc); + } + + pub fn spread_call(&mut self) { + self.emit_op(Opcode::SpreadCall); + } + + pub fn optimize_spread_call(&mut self) { + self.emit_op(Opcode::OptimizeSpreadCall); + } + + pub fn eval(&mut self, argc: u16) { + self.emit_argc_op(Opcode::Eval, argc); + self.write_u16(argc); + } + + pub fn spread_eval(&mut self) { + self.emit_op(Opcode::SpreadEval); + } + + pub fn strict_eval(&mut self, argc: u16) { + self.emit_argc_op(Opcode::StrictEval, argc); + self.write_u16(argc); + } + + pub fn strict_spread_eval(&mut self) { + self.emit_op(Opcode::StrictSpreadEval); + } + + pub fn implicit_this(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::ImplicitThis); + self.write_g_c_thing_index(name_index); + } + + pub fn call_site_obj(&mut self, object_index: GCThingIndex) { + self.emit_op(Opcode::CallSiteObj); + self.write_g_c_thing_index(object_index); + } + + pub fn is_constructing(&mut self) { + self.emit_op(Opcode::IsConstructing); + } + + pub fn new_(&mut self, argc: u16) { + self.emit_argc_op(Opcode::New, argc); + self.write_u16(argc); + } + + pub fn new_content(&mut self, argc: u16) { + self.emit_argc_op(Opcode::NewContent, argc); + self.write_u16(argc); + } + + pub fn super_call(&mut self, argc: u16) { + self.emit_argc_op(Opcode::SuperCall, argc); + self.write_u16(argc); + } + + pub fn spread_new(&mut self) { + self.emit_op(Opcode::SpreadNew); + } + + pub fn spread_super_call(&mut self) { + self.emit_op(Opcode::SpreadSuperCall); + } + + pub fn super_fun(&mut self) { + self.emit_op(Opcode::SuperFun); + } + + pub fn check_this_reinit(&mut self) { + self.emit_op(Opcode::CheckThisReinit); + } + + pub fn generator(&mut self) { + self.emit_op(Opcode::Generator); + } + + pub fn initial_yield(&mut self, resume_index: u24) { + self.emit_op(Opcode::InitialYield); + self.write_u24(resume_index); + } + + pub fn after_yield(&mut self) { + self.emit_op(Opcode::AfterYield); + self.write_ic_index(); + } + + pub fn final_yield_rval(&mut self) { + self.emit_op(Opcode::FinalYieldRval); + } + + pub fn yield_(&mut self, resume_index: u24) { + self.emit_op(Opcode::Yield); + self.write_u24(resume_index); + } + + pub fn is_gen_closing(&mut self) { + self.emit_op(Opcode::IsGenClosing); + } + + pub fn async_await(&mut self) { + self.emit_op(Opcode::AsyncAwait); + } + + pub fn async_resolve(&mut self, fulfill_or_reject: AsyncFunctionResolveKind) { + self.emit_op(Opcode::AsyncResolve); + self.write_u8(fulfill_or_reject as u8); + } + + pub fn await_(&mut self, resume_index: u24) { + self.emit_op(Opcode::Await); + self.write_u24(resume_index); + } + + pub fn can_skip_await(&mut self) { + self.emit_op(Opcode::CanSkipAwait); + } + + pub fn maybe_extract_await_value(&mut self) { + self.emit_op(Opcode::MaybeExtractAwaitValue); + } + + pub fn resume_kind(&mut self, resume_kind: GeneratorResumeKind) { + self.emit_op(Opcode::ResumeKind); + self.write_u8(resume_kind as u8); + } + + pub fn check_resume_kind(&mut self) { + self.emit_op(Opcode::CheckResumeKind); + } + + pub fn resume(&mut self) { + self.emit_op(Opcode::Resume); + } + + pub fn jump_target(&mut self) { + self.emit_op(Opcode::JumpTarget); + self.write_ic_index(); + } + + pub fn loop_head(&mut self, depth_hint: u8) { + self.emit_op(Opcode::LoopHead); + self.write_ic_index(); + self.write_u8(depth_hint); + } + + pub fn goto_(&mut self, offset: BytecodeOffsetDiff) { + self.emit_op(Opcode::Goto); + self.write_bytecode_offset_diff(offset); + } + + pub fn jump_if_false(&mut self, forward_offset: BytecodeOffsetDiff) { + self.emit_op(Opcode::JumpIfFalse); + self.write_bytecode_offset_diff(forward_offset); + } + + pub fn jump_if_true(&mut self, offset: BytecodeOffsetDiff) { + self.emit_op(Opcode::JumpIfTrue); + self.write_bytecode_offset_diff(offset); + } + + pub fn and_(&mut self, forward_offset: BytecodeOffsetDiff) { + self.emit_op(Opcode::And); + self.write_bytecode_offset_diff(forward_offset); + } + + pub fn or_(&mut self, forward_offset: BytecodeOffsetDiff) { + self.emit_op(Opcode::Or); + self.write_bytecode_offset_diff(forward_offset); + } + + pub fn coalesce(&mut self, forward_offset: BytecodeOffsetDiff) { + self.emit_op(Opcode::Coalesce); + self.write_bytecode_offset_diff(forward_offset); + } + + pub fn case_(&mut self, forward_offset: BytecodeOffsetDiff) { + self.emit_op(Opcode::Case); + self.write_bytecode_offset_diff(forward_offset); + } + + pub fn default_(&mut self, forward_offset: BytecodeOffsetDiff) { + self.emit_op(Opcode::Default); + self.write_bytecode_offset_diff(forward_offset); + } + + pub fn return_(&mut self) { + self.emit_op(Opcode::Return); + } + + pub fn get_rval(&mut self) { + self.emit_op(Opcode::GetRval); + } + + pub fn set_rval(&mut self) { + self.emit_op(Opcode::SetRval); + } + + pub fn ret_rval(&mut self) { + self.emit_op(Opcode::RetRval); + } + + pub fn check_return(&mut self) { + self.emit_op(Opcode::CheckReturn); + } + + pub fn throw_(&mut self) { + self.emit_op(Opcode::Throw); + } + + pub fn throw_msg(&mut self, msg_number: ThrowMsgKind) { + self.emit_op(Opcode::ThrowMsg); + self.write_u8(msg_number as u8); + } + + pub fn throw_set_const(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::ThrowSetConst); + self.write_g_c_thing_index(name_index); + } + + pub fn try_(&mut self) { + self.emit_op(Opcode::Try); + } + + pub fn try_destructuring(&mut self) { + self.emit_op(Opcode::TryDestructuring); + } + + pub fn exception(&mut self) { + self.emit_op(Opcode::Exception); + } + + pub fn finally(&mut self) { + self.emit_op(Opcode::Finally); + } + + pub fn uninitialized(&mut self) { + self.emit_op(Opcode::Uninitialized); + } + + pub fn init_lexical(&mut self, localno: u24) { + self.emit_op(Opcode::InitLexical); + self.write_u24(localno); + } + + pub fn init_g_lexical(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::InitGLexical); + self.write_g_c_thing_index(name_index); + } + + pub fn init_aliased_lexical(&mut self, hops: u8, slot: u24) { + self.emit_op(Opcode::InitAliasedLexical); + self.write_u8(hops); + self.write_u24(slot); + } + + pub fn check_lexical(&mut self, localno: u24) { + self.emit_op(Opcode::CheckLexical); + self.write_u24(localno); + } + + pub fn check_aliased_lexical(&mut self, hops: u8, slot: u24) { + self.emit_op(Opcode::CheckAliasedLexical); + self.write_u8(hops); + self.write_u24(slot); + } + + pub fn check_this(&mut self) { + self.emit_op(Opcode::CheckThis); + } + + pub fn bind_g_name(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::BindGName); + self.write_g_c_thing_index(name_index); + } + + pub fn bind_name(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::BindName); + self.write_g_c_thing_index(name_index); + } + + pub fn get_name(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::GetName); + self.write_g_c_thing_index(name_index); + } + + pub fn get_g_name(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::GetGName); + self.write_g_c_thing_index(name_index); + } + + pub fn get_arg(&mut self, argno: u16) { + self.emit_op(Opcode::GetArg); + self.write_u16(argno); + } + + pub fn get_local(&mut self, localno: u24) { + self.emit_op(Opcode::GetLocal); + self.write_u24(localno); + } + + pub fn get_aliased_var(&mut self, hops: u8, slot: u24) { + self.emit_op(Opcode::GetAliasedVar); + self.write_u8(hops); + self.write_u24(slot); + } + + pub fn get_aliased_debug_var(&mut self, hops: u8, slot: u24) { + self.emit_op(Opcode::GetAliasedDebugVar); + self.write_u8(hops); + self.write_u24(slot); + } + + pub fn get_import(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::GetImport); + self.write_g_c_thing_index(name_index); + } + + pub fn get_bound_name(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::GetBoundName); + self.write_g_c_thing_index(name_index); + } + + pub fn get_intrinsic(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::GetIntrinsic); + self.write_g_c_thing_index(name_index); + } + + pub fn callee(&mut self) { + self.emit_op(Opcode::Callee); + } + + pub fn env_callee(&mut self, num_hops: u8) { + self.emit_op(Opcode::EnvCallee); + self.write_u8(num_hops); + } + + pub fn set_name(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::SetName); + self.write_g_c_thing_index(name_index); + } + + pub fn strict_set_name(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::StrictSetName); + self.write_g_c_thing_index(name_index); + } + + pub fn set_g_name(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::SetGName); + self.write_g_c_thing_index(name_index); + } + + pub fn strict_set_g_name(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::StrictSetGName); + self.write_g_c_thing_index(name_index); + } + + pub fn set_arg(&mut self, argno: u16) { + self.emit_op(Opcode::SetArg); + self.write_u16(argno); + } + + pub fn set_local(&mut self, localno: u24) { + self.emit_op(Opcode::SetLocal); + self.write_u24(localno); + } + + pub fn set_aliased_var(&mut self, hops: u8, slot: u24) { + self.emit_op(Opcode::SetAliasedVar); + self.write_u8(hops); + self.write_u24(slot); + } + + pub fn set_intrinsic(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::SetIntrinsic); + self.write_g_c_thing_index(name_index); + } + + pub fn push_lexical_env(&mut self, lexical_scope_index: GCThingIndex) { + self.emit_op(Opcode::PushLexicalEnv); + self.write_g_c_thing_index(lexical_scope_index); + } + + pub fn pop_lexical_env(&mut self) { + self.emit_op(Opcode::PopLexicalEnv); + } + + pub fn debug_leave_lexical_env(&mut self) { + self.emit_op(Opcode::DebugLeaveLexicalEnv); + } + + pub fn recreate_lexical_env(&mut self, lexical_scope_index: GCThingIndex) { + self.emit_op(Opcode::RecreateLexicalEnv); + self.write_g_c_thing_index(lexical_scope_index); + } + + pub fn freshen_lexical_env(&mut self, lexical_scope_index: GCThingIndex) { + self.emit_op(Opcode::FreshenLexicalEnv); + self.write_g_c_thing_index(lexical_scope_index); + } + + pub fn push_class_body_env(&mut self, lexical_scope_index: GCThingIndex) { + self.emit_op(Opcode::PushClassBodyEnv); + self.write_g_c_thing_index(lexical_scope_index); + } + + pub fn push_var_env(&mut self, scope_index: GCThingIndex) { + self.emit_op(Opcode::PushVarEnv); + self.write_g_c_thing_index(scope_index); + } + + pub fn enter_with(&mut self, static_with_index: GCThingIndex) { + self.emit_op(Opcode::EnterWith); + self.write_g_c_thing_index(static_with_index); + } + + pub fn leave_with(&mut self) { + self.emit_op(Opcode::LeaveWith); + } + + pub fn bind_var(&mut self) { + self.emit_op(Opcode::BindVar); + } + + pub fn global_or_eval_decl_instantiation(&mut self, last_fun: u32) { + self.emit_op(Opcode::GlobalOrEvalDeclInstantiation); + self.write_u32(last_fun); + } + + pub fn del_name(&mut self, name_index: GCThingIndex) { + self.emit_op(Opcode::DelName); + self.write_g_c_thing_index(name_index); + } + + pub fn arguments(&mut self) { + self.emit_op(Opcode::Arguments); + } + + pub fn rest(&mut self) { + self.emit_op(Opcode::Rest); + } + + pub fn function_this(&mut self) { + self.emit_op(Opcode::FunctionThis); + } + + pub fn pop(&mut self) { + self.emit_op(Opcode::Pop); + } + + pub fn pop_n(&mut self, n: u16) { + self.emit_pop_n_op(Opcode::PopN, n); + self.write_u16(n); + } + + pub fn dup(&mut self) { + self.emit_op(Opcode::Dup); + } + + pub fn dup2(&mut self) { + self.emit_op(Opcode::Dup2); + } + + pub fn dup_at(&mut self, n: u24) { + self.emit_op(Opcode::DupAt); + self.write_u24(n); + } + + pub fn swap(&mut self) { + self.emit_op(Opcode::Swap); + } + + pub fn pick(&mut self, n: u8) { + self.emit_op(Opcode::Pick); + self.write_u8(n); + } + + pub fn unpick(&mut self, n: u8) { + self.emit_op(Opcode::Unpick); + self.write_u8(n); + } + + pub fn nop(&mut self) { + self.emit_op(Opcode::Nop); + } + + pub fn lineno(&mut self, lineno: u32) { + self.emit_op(Opcode::Lineno); + self.write_u32(lineno); + } + + pub fn nop_destructuring(&mut self) { + self.emit_op(Opcode::NopDestructuring); + } + + pub fn force_interpreter(&mut self) { + self.emit_op(Opcode::ForceInterpreter); + } + + pub fn debug_check_self_hosted(&mut self) { + self.emit_op(Opcode::DebugCheckSelfHosted); + } + + pub fn debugger(&mut self) { + self.emit_op(Opcode::Debugger); + } + + // @@@@ END METHODS @@@@ + + pub fn get_atom_gcthing_index(&mut self, atom: SourceAtomSetIndex) -> GCThingIndex { + match self.atom_to_gcindex_map.get(&atom) { + Some(index) => *index, + None => { + let index = self.gcthings.push_atom(atom); + self.atom_to_gcindex_map.insert(atom, index); + index + } + } + } + + pub fn get_function_gcthing_index(&mut self, fun_index: ScriptStencilIndex) -> GCThingIndex { + self.gcthings.push_function(fun_index) + } + + pub fn get_regexp_gcthing_index(&mut self, regexp_index: RegExpIndex) -> GCThingIndex { + self.gcthings.push_regexp(regexp_index) + } + + fn update_max_frame_slots(&mut self, max_frame_slots: FrameSlot) { + self.max_fixed_slots = cmp::max(self.max_fixed_slots, max_frame_slots); + } + + pub fn enter_global_scope(&mut self, scope_index: ScopeIndex) { + let index = self.gcthings.push_scope(scope_index); + self.body_scope_index = Some(index); + } + + pub fn leave_global_scope(&self) {} + + pub fn enter_lexical_scope( + &mut self, + scope_index: ScopeIndex, + parent_scope_note_index: Option<ScopeNoteIndex>, + next_frame_slot: FrameSlot, + needs_environment_object: bool, + ) -> ScopeNoteIndex { + self.update_max_frame_slots(next_frame_slot); + + let gcthing_index = self.gcthings.push_scope(scope_index); + let offset = self.bytecode_offset(); + let note_index = + self.scope_notes + .enter_scope(gcthing_index, offset, parent_scope_note_index); + + if needs_environment_object { + self.push_lexical_env(gcthing_index); + } + + note_index + } + + pub fn leave_lexical_scope(&mut self, index: ScopeNoteIndex, needs_environment_object: bool) { + self.emit_leave_lexical_scope(needs_environment_object); + let offset = self.bytecode_offset(); + self.scope_notes.leave_scope(index, offset); + } + + fn emit_leave_lexical_scope(&mut self, needs_environment_object: bool) { + if needs_environment_object { + self.pop_lexical_env(); + } else { + self.debug_leave_lexical_env(); + } + } + + pub fn enter_scope_hole_from_lexical( + &mut self, + maybe_hole_scope_note_index: &Option<ScopeNoteIndex>, + parent_scope_note_index: Option<ScopeNoteIndex>, + needs_environment_object: bool, + ) -> ScopeNoteIndex { + self.emit_leave_lexical_scope(needs_environment_object); + self.enter_scope_hole(maybe_hole_scope_note_index, parent_scope_note_index) + } + + fn enter_scope_hole( + &mut self, + maybe_hole_scope_note_index: &Option<ScopeNoteIndex>, + parent_scope_note_index: Option<ScopeNoteIndex>, + ) -> ScopeNoteIndex { + let offset = self.bytecode_offset(); + + let gcthing_index = match maybe_hole_scope_note_index { + Some(index) => self.scope_notes.get_scope_hole_gcthing_index(index), + None => self + .body_scope_index + .expect("we should have a body scope index"), + }; + + self.scope_notes + .enter_scope(gcthing_index, offset, parent_scope_note_index) + } + + pub fn leave_scope_hole(&mut self, index: ScopeNoteIndex) { + let offset = self.bytecode_offset(); + self.scope_notes.leave_scope(index, offset); + } + + pub fn switch_to_main(&mut self) { + self.main_offset = self.bytecode_offset(); + } + + pub fn into_stencil( + self, + script_data_list: &mut ImmutableScriptDataList, + extent: SourceExtent, + ) -> Result<ScriptStencil, EmitError> { + let main_offset: usize = self.main_offset.into(); + let nfixed: u32 = self.max_fixed_slots.into(); + let nslots = nfixed as usize + self.maximum_stack_depth; + + let immutable_script_data = script_data_list.push(ImmutableScriptData { + main_offset: main_offset + .try_into() + .map_err(|_| EmitError::NotImplemented("Throwing allocation overflow"))?, + nfixed: self.max_fixed_slots, + nslots: nslots + .try_into() + .map_err(|_| EmitError::NotImplemented("Throwing JSMSG_NEED_DIET"))?, + body_scope_index: usize::from(self.body_scope_index.expect("body scope should be set")) + .try_into() + .map_err(|_| EmitError::NotImplemented("Throwing allocation overflow"))?, + num_ic_entries: self.num_ic_entries.try_into().unwrap(), + fun_length: 0, + + bytecode: self.bytecode, + scope_notes: self.scope_notes.into(), + }); + + Ok(ScriptStencil::top_level_script( + self.gcthings.into(), + immutable_script_data, + extent, + )) + } +} |