//! 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(0 usize),
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 <= 0 x00ffffff 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,
))
}
}
Messung V0.5 in Prozent C=99 H=100 G=99
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.17Bemerkung:
(vorverarbeitet am 2026-06-24)
¤
*Bot Zugriff