diff --git a/crates/oxide_compiler/src/compiler.rs b/crates/oxide_compiler/src/compiler.rs index 6081b81..7b4d467 100644 --- a/crates/oxide_compiler/src/compiler.rs +++ b/crates/oxide_compiler/src/compiler.rs @@ -372,18 +372,10 @@ impl CompileCtx { self.count_instr_with_ext(3); } - pub(crate) fn count_ic_set_with_ext(&mut self) { - self.count_ic_instr_with_ext(); - } - pub(crate) fn count_call_instr_with_arg_ext(&mut self) { self.count_instr_with_ext(1); } - pub(crate) fn count_delete_static(&mut self) { - self.count_instr_with_ext(1); - } - pub(crate) fn count_define_accessor(&mut self) { self.count_instr_with_ext(1); } @@ -394,10 +386,6 @@ impl CompileCtx { self.count_instr(); } - pub(crate) fn count_jump(&mut self) { - self.count_instr(); - } - pub(crate) fn alloc_reg(&mut self) -> u8 { let r = self.next_reg; // Registers 254 (this) and 255 (new.target) are reserved by the VM. @@ -1291,22 +1279,10 @@ impl Compiler { pub(crate) fn count_expression(&self, expr: &Expression, ctx: &mut CompileCtx) { match expr { - Expression::BinaryExpression(_) - | Expression::PrivateInExpression(_) - | Expression::UnaryExpression(_) - | Expression::UpdateExpression(_) => self.count_operator(expr, ctx), Expression::CallExpression(_) | Expression::NewExpression(_) => self.count_call_domain(expr, ctx), - Expression::AssignmentExpression(_) => self.count_assignment(expr, ctx), - Expression::ConditionalExpression(_) - | Expression::SequenceExpression(_) - | Expression::LogicalExpression(_) => self.count_conditional_chain(expr, ctx), - Expression::ChainExpression(_) => self.count_chain_expression(expr, ctx), Expression::ArrowFunctionExpression(_) | Expression::FunctionExpression(_) | Expression::ClassExpression(_) => self.count_function_domain(expr, ctx), - Expression::StaticMemberExpression(_) - | Expression::ComputedMemberExpression(_) - | Expression::PrivateFieldExpression(_) => self.count_member_domain(expr, ctx), _ => {} } } diff --git a/crates/oxide_compiler/src/expr/assignment.rs b/crates/oxide_compiler/src/expr/assignment.rs index fe6d2ce..60ffe14 100644 --- a/crates/oxide_compiler/src/expr/assignment.rs +++ b/crates/oxide_compiler/src/expr/assignment.rs @@ -1,121 +1,9 @@ use crate::compiler::{CompileCtx, Compiler, Label}; use oxide_bytecode::module::Constant; use oxide_bytecode::opcode::{self, OpCode}; -use oxide_parser::{AssignmentOperator, Expression, LogicalOperator}; +use oxide_parser::AssignmentOperator; -impl Compiler { - fn count_assignment_expression(&self, expr: &Expression, ctx: &mut CompileCtx) { - let Expression::AssignmentExpression(assign) = expr else { - return; - }; - - if let oxide_parser::AssignmentTarget::StaticMemberExpression(member) = &assign.left { - if let Some(logical_op) = assign.operator.to_logical_operator() { - self.count_static_member_logical_assignment(member, logical_op, &assign.right, ctx); - return; - } - self.count_expression(&member.object, ctx); - self.count_expression(&assign.right, ctx); - // Both plain (IC_SET_PROP) and compound (COMPOUND_MEMBER_*) emit one opcode + 3 ext - // words after the key load — no extra instruction for the compound case. - ctx.count_load_const(); // key - ctx.count_ic_set_with_ext(); // IC_SET_PROP or COMPOUND_MEMBER_* + 3 ext words - } else if let oxide_parser::AssignmentTarget::ComputedMemberExpression(member) = &assign.left { - if let Some(logical_op) = assign.operator.to_logical_operator() { - self.count_computed_member_logical_assignment(member, logical_op, &assign.right, ctx); - return; - } - self.count_expression(&member.object, ctx); - self.count_expression(&member.expression, ctx); - self.count_expression(&assign.right, ctx); - ctx.projected_pc += 1; // SET_PROP_DYNAMIC - } else if let oxide_parser::AssignmentTarget::PrivateFieldExpression(member) = &assign.left { - self.count_expression(&member.object, ctx); - self.count_expression(&assign.right, ctx); - ctx.count_load_const(); // private id - ctx.count_instr(); // SET_PRIVATE - } else if let oxide_parser::AssignmentTarget::AssignmentTargetIdentifier(ati) = &assign.left { - let name = ati.name.as_str(); - // Check if target is an upvalue or captured cell - let is_upvalue = ctx.current_upvalue_captures.iter().any(|u| u.name == name); - let is_captured = ctx.scopes.symbols.lookup_is_captured(name); - if let Some(logical_op) = assign.operator.to_logical_operator() { - self.count_identifier_logical_assignment(logical_op, &assign.right, ctx); - } else { - self.count_expression(&assign.right, ctx); - if assign.operator != AssignmentOperator::Assign { - ctx.projected_pc += 1; // COMPOUND_* on var - } else if is_upvalue { - ctx.count_instr(); // STORE_UPVALUE - } else if is_captured { - ctx.count_instr(); // CELL_SET - } else { - ctx.alloc_reg(); - ctx.projected_pc += 1; // STORE_VAR - } - } - } else if let oxide_parser::AssignmentTarget::ArrayAssignmentTarget(ap) = &assign.left { - self.count_expression(&assign.right, ctx); - self.count_array_assignment(ap, ctx); - } else if let oxide_parser::AssignmentTarget::ObjectAssignmentTarget(op) = &assign.left { - self.count_expression(&assign.right, ctx); - self.count_object_assignment(op, ctx); - } else { - self.count_expression(&assign.right, ctx); - ctx.alloc_reg(); - ctx.projected_pc += 1; - } - } - - fn count_static_member_logical_assignment( - &self, member: &oxide_parser::StaticMemberExpression<'_>, logical_op: LogicalOperator, right: &Expression, - ctx: &mut CompileCtx, - ) { - let id = ctx.next_label_id(); - self.count_expression(&member.object, ctx); - ctx.count_load_const(); // key - ctx.count_load_var(); // current value copy - ctx.count_ic_instr_with_ext(); // IC_GET_PROP + 3 ext - self.count_logical_assign_test(logical_op, id, ctx); - self.count_expression(right, ctx); - ctx.count_ic_set_with_ext(); // IC_SET_PROP + 3 ext - ctx.projected_pc += 1; // LOAD_VAR result <- rhs - ctx.labels.label_map.insert(Label::TernaryEnd(id), ctx.projected_pc); - } - - fn count_computed_member_logical_assignment( - &self, member: &oxide_parser::ComputedMemberExpression<'_>, logical_op: LogicalOperator, right: &Expression, - ctx: &mut CompileCtx, - ) { - let id = ctx.next_label_id(); - self.count_expression(&member.object, ctx); - self.count_expression(&member.expression, ctx); - ctx.alloc_reg(); - ctx.projected_pc += 1; // GET_PROP_DYNAMIC - self.count_logical_assign_test(logical_op, id, ctx); - self.count_expression(right, ctx); - ctx.projected_pc += 1; // SET_PROP_DYNAMIC - ctx.projected_pc += 1; // LOAD_VAR result <- rhs - ctx.labels.label_map.insert(Label::TernaryEnd(id), ctx.projected_pc); - } - - fn count_identifier_logical_assignment( - &self, logical_op: LogicalOperator, right: &Expression, ctx: &mut CompileCtx, - ) { - let id = ctx.next_label_id(); - ctx.alloc_reg(); - ctx.projected_pc += 1; // LOAD_VAR result <- current var - self.count_logical_assign_test(logical_op, id, ctx); - self.count_expression(right, ctx); - ctx.projected_pc += 1; // STORE_VAR - ctx.projected_pc += 1; // LOAD_VAR result <- rhs - ctx.labels.label_map.insert(Label::TernaryEnd(id), ctx.projected_pc); - } - - pub(crate) fn count_assignment(&self, expr: &Expression, ctx: &mut CompileCtx) { - self.count_assignment_expression(expr, ctx); - } -} +impl Compiler {} impl Compiler { pub(crate) fn emit_assignment_expression( diff --git a/crates/oxide_compiler/src/expr/member/mod.rs b/crates/oxide_compiler/src/expr/member/mod.rs index c41f779..315a85c 100644 --- a/crates/oxide_compiler/src/expr/member/mod.rs +++ b/crates/oxide_compiler/src/expr/member/mod.rs @@ -3,65 +3,6 @@ use oxide_bytecode::module::Constant; use oxide_bytecode::opcode::{self, OpCode}; use oxide_parser::Expression; -impl Compiler { - fn count_static_member_expression(&self, expr: &Expression, ctx: &mut CompileCtx) { - let Expression::StaticMemberExpression(member) = expr else { - return; - }; - if matches!(&member.object, Expression::Super(_)) { - ctx.count_load_const(); // key - ctx.count_load_var(); // this - ctx.alloc_reg(); // result - ctx.count_instr(); // SUPER_GET_PROP - return; - } - self.count_expression(&member.object, ctx); - ctx.count_load_const(); // key - ctx.count_ic_instr_with_ext(); // IC_GET_PROP + 3 ext words - } - - fn count_computed_member_expression(&self, expr: &Expression, ctx: &mut CompileCtx) { - let Expression::ComputedMemberExpression(member) = expr else { - return; - }; - self.count_expression(&member.object, ctx); - self.count_expression(&member.expression, ctx); - ctx.alloc_reg(); - ctx.projected_pc += 1; // GET_PROP_DYNAMIC - } - - fn count_private_field_expression(&self, expr: &Expression, ctx: &mut CompileCtx) { - let Expression::PrivateFieldExpression(member) = expr else { - return; - }; - self.count_expression(&member.object, ctx); - ctx.count_private_access(); - } - - pub(crate) fn count_chain_expression(&self, expr: &Expression, ctx: &mut CompileCtx) { - let Expression::ChainExpression(chain) = expr else { - return; - }; - let id = ctx.next_label_id(); - self.count_chain_element(&chain.expression, true, ctx); - ctx.alloc_reg(); - ctx.projected_pc += 1; // LOAD_VAR result <- chain value - ctx.projected_pc += 1; // JMP over short-circuit writer - ctx.labels.label_map.insert(Label::TernaryElse(id), ctx.projected_pc); - ctx.projected_pc += 1; // LOAD_CONST undefined - ctx.labels.label_map.insert(Label::TernaryEnd(id), ctx.projected_pc); - } - - pub(crate) fn count_member_domain(&self, expr: &Expression, ctx: &mut CompileCtx) { - match expr { - Expression::StaticMemberExpression(_) => self.count_static_member_expression(expr, ctx), - Expression::ComputedMemberExpression(_) => self.count_computed_member_expression(expr, ctx), - Expression::PrivateFieldExpression(_) => self.count_private_field_expression(expr, ctx), - _ => {} - } - } -} - impl Compiler { fn emit_static_member_expression( &self, member: &oxide_parser::StaticMemberExpression, ctx: &mut CompileCtx, diff --git a/crates/oxide_compiler/src/expr/operator/mod.rs b/crates/oxide_compiler/src/expr/operator/mod.rs index a79f1a6..077d212 100644 --- a/crates/oxide_compiler/src/expr/operator/mod.rs +++ b/crates/oxide_compiler/src/expr/operator/mod.rs @@ -3,211 +3,6 @@ use oxide_bytecode::module::Constant; use oxide_bytecode::opcode::{self, OpCode}; use oxide_parser::{ChainElement, Expression, LogicalOperator, SimpleAssignmentTarget, UnaryOperator, UpdateOperator}; -impl Compiler { - fn count_binary_expression(&self, expr: &Expression, ctx: &mut CompileCtx) { - let Expression::BinaryExpression(bin) = expr else { - return; - }; - let checkpoint = ctx.reg_checkpoint(); - self.count_expression(&bin.left, ctx); - self.count_expression(&bin.right, ctx); - ctx.projected_pc += 1; // ADD/SUB/MUL/DIV/etc. - if is_side_effect_free(&bin.left) && is_side_effect_free(&bin.right) { - ctx.restore_reg_checkpoint(checkpoint.saturating_add(1)); - } - } - - fn count_private_in_expression(&self, expr: &Expression, ctx: &mut CompileCtx) { - let Expression::PrivateInExpression(pin) = expr else { - return; - }; - self.count_expression(&pin.right, ctx); - ctx.count_private_access(); - } - - fn count_unary_expression(&self, expr: &Expression, ctx: &mut CompileCtx) { - let Expression::UnaryExpression(un) = expr else { - return; - }; - match un.operator { - UnaryOperator::Delete => self.count_delete_expression(&un.argument, ctx), - _ => { - self.count_expression(&un.argument, ctx); - ctx.projected_pc += 1; // NEG/TYPEOF/VOID/NOT - } - } - } - - fn count_delete_expression(&self, argument: &Expression, ctx: &mut CompileCtx) { - match argument { - Expression::Identifier(_) => { - // SyntaxError at compile time, no bytecode cost. - } - Expression::StaticMemberExpression(member) => { - self.count_expression(&member.object, ctx); - ctx.count_delete_static(); - } - Expression::ComputedMemberExpression(member) => { - self.count_expression(&member.object, ctx); - self.count_expression(&member.expression, ctx); - ctx.projected_pc += 1; // DELETE_PROP_DYNAMIC - } - Expression::ChainExpression(chain) => { - self.count_delete_chain_expression(&chain.expression, ctx); - } - _ => {} - } - } - - fn count_delete_chain_expression(&self, chain: &ChainElement, ctx: &mut CompileCtx) { - match chain { - ChainElement::StaticMemberExpression(member) => { - self.count_expression(&member.object, ctx); - if member.optional { - self.count_optional_guard(ctx); - } - ctx.count_delete_static(); - } - ChainElement::ComputedMemberExpression(member) => { - self.count_expression(&member.object, ctx); - if member.optional { - self.count_optional_guard(ctx); - } - self.count_expression(&member.expression, ctx); - ctx.projected_pc += 1; // DELETE_PROP_DYNAMIC - } - _ => {} - } - ctx.projected_pc += 1; // JMP over nullish true writer - ctx.projected_pc += 1; // LOAD_CONST true - } - - fn count_update_expression(&self, expr: &Expression, ctx: &mut CompileCtx) { - let Expression::UpdateExpression(update) = expr else { - return; - }; - match &update.argument { - SimpleAssignmentTarget::AssignmentTargetIdentifier(id) => { - let name = id.name.as_str(); - let is_upvalue = ctx.current_upvalue_captures.iter().any(|u| u.name == name); - let is_captured = ctx.scopes.symbols.lookup_is_captured(name); - if is_upvalue || is_captured { - ctx.alloc_reg(); // val_reg - ctx.count_instr(); // LOAD_UPVALUE or CELL_GET - ctx.count_load_const(); // 1, alloc + instr - ctx.count_instr(); // ADD/SUB - ctx.count_instr(); // STORE_UPVALUE or CELL_SET - } else { - ctx.alloc_reg(); - ctx.projected_pc += 1; - } - } - SimpleAssignmentTarget::StaticMemberExpression(member) => { - self.count_expression(&member.object, ctx); - ctx.count_load_const(); // key - ctx.alloc_reg(); - ctx.count_ic_instr_with_ext(); // MEMBER_INC/MEMBER_DEC + 3 ext words - } - SimpleAssignmentTarget::ComputedMemberExpression(member) => { - self.count_expression(&member.object, ctx); - self.count_expression(&member.expression, ctx); - ctx.alloc_reg(); - ctx.projected_pc += 1; - } - _ => { - ctx.alloc_reg(); - ctx.projected_pc += 1; - } - } - } - - pub(crate) fn count_operator(&self, expr: &Expression, ctx: &mut CompileCtx) { - match expr { - Expression::BinaryExpression(_) => self.count_binary_expression(expr, ctx), - Expression::PrivateInExpression(_) => self.count_private_in_expression(expr, ctx), - Expression::UnaryExpression(_) => self.count_unary_expression(expr, ctx), - Expression::UpdateExpression(_) => self.count_update_expression(expr, ctx), - _ => {} - } - } - - fn count_conditional_expression(&self, expr: &Expression, ctx: &mut CompileCtx) { - let Expression::ConditionalExpression(cond) = expr else { - return; - }; - let id = ctx.next_label_id(); - let else_label = Label::TernaryElse(id); - let end_label = Label::TernaryEnd(id); - - self.count_expression(&cond.test, ctx); - ctx.projected_pc += 1; // JMP_IF_FALSE - self.count_expression(&cond.consequent, ctx); - ctx.alloc_reg(); // result register - ctx.projected_pc += 1; // LOAD_VAR result <- consequent - ctx.projected_pc += 1; // JMP to end - ctx.labels.label_map.insert(else_label, ctx.projected_pc); - self.count_expression(&cond.alternate, ctx); - ctx.projected_pc += 1; // LOAD_VAR result <- alternate - ctx.labels.label_map.insert(end_label, ctx.projected_pc); - } - - fn count_sequence_expression(&self, expr: &Expression, ctx: &mut CompileCtx) { - let Expression::SequenceExpression(seq) = expr else { - return; - }; - for e in &seq.expressions { - self.count_expression(e, ctx); - } - } - - fn count_logical_expression(&self, expr: &Expression, ctx: &mut CompileCtx) { - let Expression::LogicalExpression(log) = expr else { - return; - }; - self.count_expression(&log.left, ctx); - - let is_simple = is_side_effect_free(&log.left) && is_side_effect_free(&log.right); - - if is_simple { - self.count_expression(&log.right, ctx); - ctx.alloc_reg(); - ctx.projected_pc += 1; // AND/OR - } else if matches!(log.operator, LogicalOperator::Coalesce) { - let id = ctx.next_label_id(); - ctx.alloc_reg(); // dup register - ctx.projected_pc += 1; // LOAD_VAR (DUP) - ctx.projected_pc += 1; // JMP_IF_NULLISH - ctx.projected_pc += 1; // JMP over RHS on non-nullish - self.count_expression(&log.right, ctx); - ctx.projected_pc += 1; // LOAD_VAR (overwrite) - ctx.labels.label_map.insert(Label::TernaryElse(id), ctx.projected_pc); - ctx.labels.label_map.insert(Label::TernaryEnd(id), ctx.projected_pc); - } else { - let id = ctx.next_label_id(); - ctx.alloc_reg(); // dup register - ctx.projected_pc += 1; // LOAD_VAR (DUP) - ctx.projected_pc += 1; // JMP_IF_FALSE or JMP_IF_TRUE - self.count_expression(&log.right, ctx); - ctx.projected_pc += 1; // LOAD_VAR (overwrite) - let skip_label = match log.operator { - LogicalOperator::And => Label::TernaryEnd(id), - LogicalOperator::Or => Label::TernaryElse(id), - LogicalOperator::Coalesce => unreachable!("coalesce handled above"), - }; - ctx.labels.label_map.insert(skip_label, ctx.projected_pc); - } - } - - pub(crate) fn count_conditional_chain(&self, expr: &Expression, ctx: &mut CompileCtx) { - match expr { - Expression::ConditionalExpression(_) => self.count_conditional_expression(expr, ctx), - Expression::SequenceExpression(_) => self.count_sequence_expression(expr, ctx), - Expression::LogicalExpression(_) => self.count_logical_expression(expr, ctx), - _ => {} - } - } -} - impl Compiler { fn emit_private_in_expression( &self, pin: &oxide_parser::PrivateInExpression, ctx: &mut CompileCtx, diff --git a/crates/oxide_compiler/src/shared/binding.rs b/crates/oxide_compiler/src/shared/binding.rs index 426c849..da02a95 100644 --- a/crates/oxide_compiler/src/shared/binding.rs +++ b/crates/oxide_compiler/src/shared/binding.rs @@ -7,99 +7,6 @@ use oxide_parser::{ }; impl Compiler { - pub(crate) fn count_rest_array(&self, ctx: &mut CompileCtx) { - ctx.alloc_reg(); // rest - ctx.count_instr(); // NEW_ARRAY - ctx.count_load_const(); // idx = 0 - ctx.alloc_reg(); // has - ctx.count_instr(); // FOR_OF_DONE - ctx.count_jump(); // JMP_IF_FALSE - ctx.alloc_reg(); // val - ctx.count_instr(); // FOR_OF_NEXT - ctx.count_instr(); // SET_ELEM - ctx.alloc_reg(); // inc tmp - ctx.count_instr(); // INC_PRE - ctx.count_jump(); // JMP - } - - pub(crate) fn count_array_assignment(&self, ap: &ArrayAssignmentTarget, ctx: &mut CompileCtx) { - ctx.count_instr(); // FOR_OF_INIT - for elem in &ap.elements { - ctx.alloc_reg(); - ctx.count_instr(); // FOR_OF_DONE - ctx.alloc_reg(); - ctx.count_instr(); // FOR_OF_NEXT - if let Some(elem) = elem { - self.count_assignment_maybe_default(elem, ctx); - } - } - if let Some(rest) = &ap.rest { - self.count_rest_array(ctx); - self.count_assign_target(&rest.target, ctx); - } - ctx.count_instr(); // FOR_OF_CLOSE - } - - pub(crate) fn count_object_assignment(&self, op: &ObjectAssignmentTarget, ctx: &mut CompileCtx) { - for prop in &op.properties { - match prop { - AssignmentTargetProperty::AssignmentTargetPropertyIdentifier(id) => { - self.count_object_property_read_static(ctx); - if let Some(default_expr) = &id.init { - ctx.count_load_const(); // undefined - ctx.count_instr(); // STRICT_EQ - ctx.count_jump(); // JMP_IF_FALSE - self.count_expression(default_expr, ctx); - ctx.count_instr(); // LOAD_VAR default - } - ctx.alloc_reg(); - ctx.count_instr(); // STORE_VAR - } - AssignmentTargetProperty::AssignmentTargetPropertyProperty(prop) => { - self.count_object_property_read_key(&prop.name, prop.computed, ctx); - self.count_assignment_maybe_default(&prop.binding, ctx); - } - } - } - if let Some(rest) = &op.rest { - ctx.alloc_reg(); - ctx.count_instr_with_ext(1); // REST_OBJECT + excluded-keys ext - self.count_assign_target(&rest.target, ctx); - } - } - - pub(crate) fn count_assignment_maybe_default(&self, target: &AssignmentTargetMaybeDefault, ctx: &mut CompileCtx) { - match target { - AssignmentTargetMaybeDefault::AssignmentTargetWithDefault(default) => { - ctx.count_load_const(); // undefined - ctx.count_instr(); // STRICT_EQ - ctx.count_jump(); // JMP_IF_FALSE - self.count_expression(&default.init, ctx); - ctx.count_instr(); // LOAD_VAR default - self.count_assign_target(&default.binding, ctx); - } - AssignmentTargetMaybeDefault::ArrayAssignmentTarget(ap) => self.count_array_assignment(ap, ctx), - AssignmentTargetMaybeDefault::ObjectAssignmentTarget(op) => self.count_object_assignment(op, ctx), - AssignmentTargetMaybeDefault::AssignmentTargetIdentifier(_) => { - ctx.alloc_reg(); - ctx.count_instr(); // STORE_VAR - } - _ => {} - } - } - - pub(crate) fn count_assign_target(&self, target: &AssignmentTarget, ctx: &mut CompileCtx) { - match target { - AssignmentTarget::AssignmentTargetIdentifier(_) => { - ctx.alloc_reg(); - ctx.count_instr(); // STORE_VAR - } - AssignmentTarget::ArrayAssignmentTarget(ap) => self.count_array_assignment(ap, ctx), - AssignmentTarget::ObjectAssignmentTarget(op) => self.count_object_assignment(op, ctx), - _ => {} - } - } - fn emit_default_if_undefined( &self, val_reg: u8, default_expr: &Expression, ctx: &mut CompileCtx, ) -> Result { diff --git a/crates/oxide_compiler/src/shared/chain.rs b/crates/oxide_compiler/src/shared/chain.rs index 437c82d..97d8ed4 100644 --- a/crates/oxide_compiler/src/shared/chain.rs +++ b/crates/oxide_compiler/src/shared/chain.rs @@ -3,172 +3,6 @@ use oxide_bytecode::module::Constant; use oxide_bytecode::opcode::{self, OpCode}; use oxide_parser::{ChainElement, Expression, LogicalOperator, PropertyKey}; -impl Compiler { - pub(crate) fn count_object_property_read_static(&self, ctx: &mut CompileCtx) { - ctx.count_load_var(); - ctx.count_load_const(); - ctx.count_ic_instr_with_ext(); - } - - pub(crate) fn count_object_property_read_key(&self, key: &PropertyKey, computed: bool, ctx: &mut CompileCtx) { - if !computed { - self.count_object_property_read_static(ctx); - let _ = key; - return; - } - - ctx.count_load_var(); - match key { - PropertyKey::Identifier(ident) => { - let name = ident.name.as_str(); - let _ = ctx.lookup_or_builtin(name); - ctx.count_load_var(); - } - PropertyKey::StringLiteral(_) => { - ctx.count_load_const(); - } - PropertyKey::NumericLiteral(_) => { - ctx.count_load_const(); - } - PropertyKey::StaticIdentifier(_) => { - ctx.count_load_const(); - } - _ => {} - } - ctx.alloc_reg(); - ctx.count_instr(); - } - - pub(crate) fn count_optional_guard(&self, ctx: &mut CompileCtx) { - ctx.count_load_var(); - ctx.count_jump(); - } - - pub(crate) fn count_static_member_get_preserve_base( - &self, member: &oxide_parser::StaticMemberExpression, short_chain: bool, ctx: &mut CompileCtx, - ) { - self.count_chainable_expression(&member.object, short_chain, ctx); - if short_chain && member.optional { - self.count_optional_guard(ctx); - } - ctx.count_load_const(); - ctx.count_load_var(); - ctx.count_ic_instr_with_ext(); - } - - pub(crate) fn count_computed_member_get_preserve_base( - &self, member: &oxide_parser::ComputedMemberExpression, short_chain: bool, ctx: &mut CompileCtx, - ) { - self.count_chainable_expression(&member.object, short_chain, ctx); - if short_chain && member.optional { - self.count_optional_guard(ctx); - } - self.count_expression(&member.expression, ctx); - ctx.alloc_reg(); - ctx.count_instr(); - } - - pub(crate) fn count_chain_call( - &self, call: &oxide_parser::CallExpression, short_chain: bool, ctx: &mut CompileCtx, - ) { - match &call.callee { - Expression::StaticMemberExpression(member) => { - self.count_static_member_get_preserve_base(member, short_chain, ctx) - } - Expression::ComputedMemberExpression(member) => { - self.count_computed_member_get_preserve_base(member, short_chain, ctx); - } - Expression::PrivateFieldExpression(member) => { - self.count_chainable_expression(&member.object, short_chain, ctx); - if short_chain && member.optional { - self.count_optional_guard(ctx); - } - ctx.count_private_access(); - } - _ => { - self.count_chainable_expression(&call.callee, short_chain, ctx); - if short_chain && call.optional { - self.count_optional_guard(ctx); - } - ctx.alloc_reg(); - ctx.projected_pc += 1; - } - } - if short_chain - && call.optional - && matches!( - &call.callee, - Expression::StaticMemberExpression(_) - | Expression::ComputedMemberExpression(_) - | Expression::PrivateFieldExpression(_) - ) - { - self.count_optional_guard(ctx); - } - for arg in &call.arguments { - if let Some(expr) = arg.as_expression() { - self.count_expression(expr, ctx); - } - } - ctx.count_call_instr_with_arg_ext(); - ctx.count_load_var(); - } - - pub(crate) fn count_chainable_expression(&self, expr: &Expression, short_chain: bool, ctx: &mut CompileCtx) { - match expr { - Expression::StaticMemberExpression(member) => { - self.count_static_member_get_preserve_base(member, short_chain, ctx) - } - Expression::ComputedMemberExpression(member) => { - self.count_computed_member_get_preserve_base(member, short_chain, ctx) - } - Expression::PrivateFieldExpression(member) => { - self.count_chainable_expression(&member.object, short_chain, ctx); - if short_chain && member.optional { - self.count_optional_guard(ctx); - } - ctx.count_private_access(); - } - Expression::CallExpression(call) => self.count_chain_call(call, short_chain, ctx), - Expression::ChainExpression(chain) => self.count_chain_element(&chain.expression, short_chain, ctx), - _ => self.count_expression(expr, ctx), - } - } - - pub(crate) fn count_chain_element(&self, element: &ChainElement, short_chain: bool, ctx: &mut CompileCtx) { - match element { - ChainElement::StaticMemberExpression(member) => { - self.count_static_member_get_preserve_base(member, short_chain, ctx) - } - ChainElement::ComputedMemberExpression(member) => { - self.count_computed_member_get_preserve_base(member, short_chain, ctx) - } - ChainElement::PrivateFieldExpression(member) => { - self.count_chainable_expression(&member.object, short_chain, ctx); - if short_chain && member.optional { - self.count_optional_guard(ctx); - } - ctx.count_private_access(); - } - ChainElement::CallExpression(call) => self.count_chain_call(call, short_chain, ctx), - ChainElement::TSNonNullExpression(_) => {} - } - } - - pub(crate) fn count_logical_assign_test(&self, op: LogicalOperator, id: u32, ctx: &mut CompileCtx) { - match op { - LogicalOperator::And | LogicalOperator::Or => { - ctx.projected_pc += 1; - } - LogicalOperator::Coalesce => { - ctx.projected_pc += 1; - ctx.projected_pc += 1; - ctx.labels.label_map.insert(Label::TernaryElse(id), ctx.projected_pc); - } - } - } -} - impl Compiler { fn emit_optional_guard(&self, reg: u8, short_label: Label, ctx: &mut CompileCtx) -> Result<(), String> { let dup_reg = ctx.alloc_reg();