/* * Copyright (c) 2021, Andreas Kling * Copyright (c) 2021, Linus Groh * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include namespace JS { void ASTNode::generate_bytecode(Bytecode::Generator&) const { dbgln("Missing generate_bytecode()"); TODO(); } void ScopeNode::generate_bytecode(Bytecode::Generator& generator) const { generator.emit(*this); for (auto& child : children()) child.generate_bytecode(generator); } void EmptyStatement::generate_bytecode(Bytecode::Generator&) const { } void ExpressionStatement::generate_bytecode(Bytecode::Generator& generator) const { m_expression->generate_bytecode(generator); } void BinaryExpression::generate_bytecode(Bytecode::Generator& generator) const { m_lhs->generate_bytecode(generator); auto lhs_reg = generator.allocate_register(); generator.emit(lhs_reg); m_rhs->generate_bytecode(generator); switch (m_op) { case BinaryOp::Addition: generator.emit(lhs_reg); break; case BinaryOp::Subtraction: generator.emit(lhs_reg); break; case BinaryOp::Multiplication: generator.emit(lhs_reg); break; case BinaryOp::Division: generator.emit(lhs_reg); break; case BinaryOp::Modulo: generator.emit(lhs_reg); break; case BinaryOp::Exponentiation: generator.emit(lhs_reg); break; case BinaryOp::GreaterThan: generator.emit(lhs_reg); break; case BinaryOp::GreaterThanEquals: generator.emit(lhs_reg); break; case BinaryOp::LessThan: generator.emit(lhs_reg); break; case BinaryOp::LessThanEquals: generator.emit(lhs_reg); break; case BinaryOp::AbstractInequals: generator.emit(lhs_reg); break; case BinaryOp::AbstractEquals: generator.emit(lhs_reg); break; case BinaryOp::TypedInequals: generator.emit(lhs_reg); break; case BinaryOp::TypedEquals: generator.emit(lhs_reg); break; case BinaryOp::BitwiseAnd: generator.emit(lhs_reg); break; case BinaryOp::BitwiseOr: generator.emit(lhs_reg); break; case BinaryOp::BitwiseXor: generator.emit(lhs_reg); break; case BinaryOp::LeftShift: generator.emit(lhs_reg); break; case BinaryOp::RightShift: generator.emit(lhs_reg); break; case BinaryOp::UnsignedRightShift: generator.emit(lhs_reg); break; case BinaryOp::In: generator.emit(lhs_reg); break; case BinaryOp::InstanceOf: generator.emit(lhs_reg); break; default: VERIFY_NOT_REACHED(); } } void LogicalExpression::generate_bytecode(Bytecode::Generator& generator) const { m_lhs->generate_bytecode(generator); Bytecode::Op::Jump* test_instr; switch (m_op) { case LogicalOp::And: test_instr = &generator.emit(); break; case LogicalOp::Or: test_instr = &generator.emit(); break; case LogicalOp::NullishCoalescing: test_instr = &generator.emit(); break; default: VERIFY_NOT_REACHED(); } m_rhs->generate_bytecode(generator); test_instr->set_target(generator.make_label()); } void UnaryExpression::generate_bytecode(Bytecode::Generator& generator) const { m_lhs->generate_bytecode(generator); switch (m_op) { case UnaryOp::BitwiseNot: generator.emit(); break; case UnaryOp::Not: generator.emit(); break; case UnaryOp::Plus: generator.emit(); break; case UnaryOp::Minus: generator.emit(); break; case UnaryOp::Typeof: generator.emit(); break; case UnaryOp::Void: generator.emit(js_undefined()); break; default: TODO(); } } void NumericLiteral::generate_bytecode(Bytecode::Generator& generator) const { generator.emit(m_value); } void BooleanLiteral::generate_bytecode(Bytecode::Generator& generator) const { generator.emit(Value(m_value)); } void NullLiteral::generate_bytecode(Bytecode::Generator& generator) const { generator.emit(js_null()); } void BigIntLiteral::generate_bytecode(Bytecode::Generator& generator) const { generator.emit(Crypto::SignedBigInteger::from_base10(m_value.substring(0, m_value.length() - 1))); } void StringLiteral::generate_bytecode(Bytecode::Generator& generator) const { generator.emit(m_value); } void Identifier::generate_bytecode(Bytecode::Generator& generator) const { generator.emit(m_string); } void AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) const { if (is(*m_lhs)) { auto& identifier = static_cast(*m_lhs); if (m_op == AssignmentOp::Assignment) { m_rhs->generate_bytecode(generator); generator.emit(identifier.string()); return; } m_lhs->generate_bytecode(generator); auto lhs_reg = generator.allocate_register(); generator.emit(lhs_reg); m_rhs->generate_bytecode(generator); switch (m_op) { case AssignmentOp::AdditionAssignment: generator.emit(lhs_reg); break; case AssignmentOp::SubtractionAssignment: generator.emit(lhs_reg); break; case AssignmentOp::MultiplicationAssignment: generator.emit(lhs_reg); break; case AssignmentOp::DivisionAssignment: generator.emit(lhs_reg); break; case AssignmentOp::ModuloAssignment: generator.emit(lhs_reg); break; case AssignmentOp::ExponentiationAssignment: generator.emit(lhs_reg); break; case AssignmentOp::BitwiseAndAssignment: generator.emit(lhs_reg); break; case AssignmentOp::BitwiseOrAssignment: generator.emit(lhs_reg); break; case AssignmentOp::BitwiseXorAssignment: generator.emit(lhs_reg); break; case AssignmentOp::LeftShiftAssignment: generator.emit(lhs_reg); break; case AssignmentOp::RightShiftAssignment: generator.emit(lhs_reg); break; case AssignmentOp::UnsignedRightShiftAssignment: generator.emit(lhs_reg); break; default: TODO(); } generator.emit(identifier.string()); return; } if (is(*m_lhs)) { auto& expression = static_cast(*m_lhs); expression.object().generate_bytecode(generator); auto object_reg = generator.allocate_register(); generator.emit(object_reg); if (expression.is_computed()) { TODO(); } else { VERIFY(is(expression.property())); m_rhs->generate_bytecode(generator); generator.emit(object_reg, static_cast(expression.property()).string()); return; } } TODO(); } void WhileStatement::generate_bytecode(Bytecode::Generator& generator) const { generator.emit(js_undefined()); generator.begin_continuable_scope(); auto test_label = generator.make_label(); auto result_reg = generator.allocate_register(); generator.emit(result_reg); m_test->generate_bytecode(generator); auto& test_jump = generator.emit(); m_body->generate_bytecode(generator); generator.emit(test_label); test_jump.set_target(generator.make_label()); generator.end_continuable_scope(); generator.emit(result_reg); } void DoWhileStatement::generate_bytecode(Bytecode::Generator& generator) const { generator.emit(js_undefined()); generator.begin_continuable_scope(); auto head_label = generator.make_label(); m_body->generate_bytecode(generator); generator.end_continuable_scope(); auto result_reg = generator.allocate_register(); generator.emit(result_reg); m_test->generate_bytecode(generator); generator.emit(head_label); generator.emit(result_reg); } void ForStatement::generate_bytecode(Bytecode::Generator& generator) const { Bytecode::Op::Jump* test_jump { nullptr }; if (m_init) m_init->generate_bytecode(generator); generator.emit(js_undefined()); generator.begin_continuable_scope(); auto jump_label = generator.make_label(); auto result_reg = generator.allocate_register(); generator.emit(result_reg); if (m_test) { m_test->generate_bytecode(generator); test_jump = &generator.emit(); } m_body->generate_bytecode(generator); if (m_update) m_update->generate_bytecode(generator); generator.emit(jump_label); if (m_test) test_jump->set_target(generator.make_label()); generator.end_continuable_scope(); generator.emit(result_reg); } void ObjectExpression::generate_bytecode(Bytecode::Generator& generator) const { generator.emit(); if (!m_properties.is_empty()) TODO(); } void ArrayExpression::generate_bytecode(Bytecode::Generator& generator) const { Vector element_regs; for (auto& element : m_elements) { generator.emit(Value {}); if (element) { element->generate_bytecode(generator); if (is(*element)) { TODO(); continue; } } auto element_reg = generator.allocate_register(); generator.emit(element_reg); element_regs.append(element_reg); } generator.emit_with_extra_register_slots(element_regs.size(), element_regs); } void MemberExpression::generate_bytecode(Bytecode::Generator& generator) const { object().generate_bytecode(generator); if (is_computed()) { TODO(); } else { VERIFY(is(property())); generator.emit(static_cast(property()).string()); } } void FunctionDeclaration::generate_bytecode(Bytecode::Generator&) const { } void CallExpression::generate_bytecode(Bytecode::Generator& generator) const { m_callee->generate_bytecode(generator); auto callee_reg = generator.allocate_register(); generator.emit(callee_reg); // FIXME: Load the correct 'this' value into 'this_reg'. auto this_reg = generator.allocate_register(); generator.emit(js_undefined()); generator.emit(this_reg); Vector argument_registers; for (auto& arg : m_arguments) { arg.value->generate_bytecode(generator); auto arg_reg = generator.allocate_register(); generator.emit(arg_reg); argument_registers.append(arg_reg); } generator.emit_with_extra_register_slots(argument_registers.size(), callee_reg, this_reg, argument_registers); } void ReturnStatement::generate_bytecode(Bytecode::Generator& generator) const { if (m_argument) m_argument->generate_bytecode(generator); generator.emit(); } void IfStatement::generate_bytecode(Bytecode::Generator& generator) const { m_predicate->generate_bytecode(generator); auto& else_jump = generator.emit(); m_consequent->generate_bytecode(generator); if (m_alternate) { auto& if_jump = generator.emit(); else_jump.set_target(generator.make_label()); m_alternate->generate_bytecode(generator); if_jump.set_target(generator.make_label()); } else { else_jump.set_target(generator.make_label()); } } void ContinueStatement::generate_bytecode(Bytecode::Generator& generator) const { generator.emit(generator.nearest_continuable_scope()); } void DebuggerStatement::generate_bytecode(Bytecode::Generator&) const { } void ConditionalExpression::generate_bytecode(Bytecode::Generator& generator) const { m_test->generate_bytecode(generator); auto& alternate_jump = generator.emit(); m_consequent->generate_bytecode(generator); auto& end_jump = generator.emit(); alternate_jump.set_target(generator.make_label()); m_alternate->generate_bytecode(generator); end_jump.set_target(generator.make_label()); } void SequenceExpression::generate_bytecode(Bytecode::Generator& generator) const { for (auto& expression : m_expressions) expression.generate_bytecode(generator); } void TemplateLiteral::generate_bytecode(Bytecode::Generator& generator) const { auto string_reg = generator.allocate_register(); for (size_t i = 0; i < m_expressions.size(); i++) { m_expressions[i].generate_bytecode(generator); if (i == 0) { generator.emit(string_reg); } else { generator.emit(string_reg); } } } }