/* * Copyright (c) 2021-2024, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace JS::Bytecode { bool g_dump_bytecode = false; static ByteString format_operand(StringView name, Operand operand, Bytecode::Executable const& executable) { StringBuilder builder; if (!name.is_empty()) builder.appendff("\033[32m{}\033[0m:", name); switch (operand.type()) { case Operand::Type::Register: builder.appendff("\033[33mreg{}\033[0m", operand.index()); break; case Operand::Type::Local: // FIXME: Show local name. builder.appendff("\033[34mloc{}\033[0m", operand.index()); break; case Operand::Type::Constant: { builder.append("\033[36m"sv); auto value = executable.constants[operand.index()]; if (value.is_empty()) builder.append(""sv); else if (value.is_boolean()) builder.appendff("Bool({})", value.as_bool() ? "true"sv : "false"sv); else if (value.is_int32()) builder.appendff("Int32({})", value.as_i32()); else if (value.is_double()) builder.appendff("Double({})", value.as_double()); else if (value.is_undefined()) builder.append("Undefined"sv); else if (value.is_null()) builder.append("Null"sv); else builder.appendff("Value: {}", value); builder.append("\033[0m"sv); break; } default: VERIFY_NOT_REACHED(); } return builder.to_byte_string(); } static ByteString format_operand_list(StringView name, ReadonlySpan operands, Bytecode::Executable const& executable) { StringBuilder builder; if (!name.is_empty()) builder.appendff(", \033[32{}\033[0m:[", name); for (size_t i = 0; i < operands.size(); ++i) { if (i != 0) builder.append(", "sv); builder.appendff("{}", format_operand(""sv, operands[i], executable)); } builder.append("]"sv); return builder.to_byte_string(); } NonnullOwnPtr CallFrame::create(size_t register_count) { size_t allocation_size = sizeof(CallFrame) + sizeof(Value) * register_count; auto* memory = malloc(allocation_size); VERIFY(memory); auto call_frame = adopt_own(*new (memory) CallFrame); call_frame->register_count = register_count; for (auto i = 0u; i < register_count; ++i) new (&call_frame->register_values[i]) Value(); return call_frame; } Interpreter::Interpreter(VM& vm) : m_vm(vm) { } Interpreter::~Interpreter() { } void Interpreter::visit_edges(Cell::Visitor& visitor) { for (auto& frame : m_call_frames) { frame.visit([&](auto& value) { value->visit_edges(visitor); }); } } ALWAYS_INLINE Value Interpreter::get(Operand op) const { switch (op.type()) { case Operand::Type::Register: return reg(Register { op.index() }); case Operand::Type::Local: return vm().running_execution_context().locals[op.index()]; case Operand::Type::Constant: return current_executable().constants[op.index()]; } __builtin_unreachable(); } ALWAYS_INLINE void Interpreter::set(Operand op, Value value) { switch (op.type()) { case Operand::Type::Register: reg(Register { op.index() }) = value; return; case Operand::Type::Local: vm().running_execution_context().locals[op.index()] = value; return; case Operand::Type::Constant: VERIFY_NOT_REACHED(); } __builtin_unreachable(); } // 16.1.6 ScriptEvaluation ( scriptRecord ), https://tc39.es/ecma262/#sec-runtime-semantics-scriptevaluation ThrowCompletionOr Interpreter::run(Script& script_record, JS::GCPtr lexical_environment_override) { auto& vm = this->vm(); // 1. Let globalEnv be scriptRecord.[[Realm]].[[GlobalEnv]]. auto& global_environment = script_record.realm().global_environment(); // 2. Let scriptContext be a new ECMAScript code execution context. auto script_context = ExecutionContext::create(vm.heap()); // 3. Set the Function of scriptContext to null. // NOTE: This was done during execution context construction. // 4. Set the Realm of scriptContext to scriptRecord.[[Realm]]. script_context->realm = &script_record.realm(); // 5. Set the ScriptOrModule of scriptContext to scriptRecord. script_context->script_or_module = NonnullGCPtr