2021-06-03 10:46:30 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
2021-06-07 21:13:37 +01:00
|
|
|
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
2021-06-09 18:18:56 +02:00
|
|
|
* Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org>
|
2021-06-03 10:46:30 +02:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
*/
|
|
|
|
|
2021-06-13 15:30:32 -07:00
|
|
|
#include <AK/HashTable.h>
|
2021-06-03 10:46:30 +02:00
|
|
|
#include <LibJS/Bytecode/Interpreter.h>
|
|
|
|
#include <LibJS/Bytecode/Op.h>
|
2021-06-08 23:06:52 +02:00
|
|
|
#include <LibJS/Runtime/Array.h>
|
2021-06-08 07:59:25 +02:00
|
|
|
#include <LibJS/Runtime/BigInt.h>
|
2021-07-01 12:24:46 +02:00
|
|
|
#include <LibJS/Runtime/DeclarativeEnvironment.h>
|
2021-09-24 22:40:38 +02:00
|
|
|
#include <LibJS/Runtime/ECMAScriptFunctionObject.h>
|
2021-07-01 12:24:46 +02:00
|
|
|
#include <LibJS/Runtime/Environment.h>
|
2021-06-03 18:26:32 +02:00
|
|
|
#include <LibJS/Runtime/GlobalObject.h>
|
2021-06-13 13:40:48 -07:00
|
|
|
#include <LibJS/Runtime/IteratorOperations.h>
|
2021-06-19 17:17:40 -07:00
|
|
|
#include <LibJS/Runtime/RegExpObject.h>
|
2021-06-03 10:46:30 +02:00
|
|
|
#include <LibJS/Runtime/Value.h>
|
|
|
|
|
2021-06-07 15:12:43 +02:00
|
|
|
namespace JS::Bytecode {
|
|
|
|
|
2021-06-09 10:02:01 +02:00
|
|
|
String Instruction::to_string(Bytecode::Executable const& executable) const
|
2021-06-07 15:12:43 +02:00
|
|
|
{
|
|
|
|
#define __BYTECODE_OP(op) \
|
|
|
|
case Instruction::Type::op: \
|
2021-06-15 18:08:12 +04:30
|
|
|
return static_cast<Bytecode::Op::op const&>(*this).to_string_impl(executable);
|
2021-06-07 15:12:43 +02:00
|
|
|
|
|
|
|
switch (type()) {
|
|
|
|
ENUMERATE_BYTECODE_OPS(__BYTECODE_OP)
|
|
|
|
default:
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef __BYTECODE_OP
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-06-03 10:46:30 +02:00
|
|
|
namespace JS::Bytecode::Op {
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void Load::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-03 10:46:30 +02:00
|
|
|
{
|
2021-06-07 20:58:36 -07:00
|
|
|
interpreter.accumulator() = interpreter.reg(m_src);
|
2021-06-03 10:46:30 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void LoadImmediate::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-07 22:05:09 +02:00
|
|
|
{
|
2021-06-07 20:58:36 -07:00
|
|
|
interpreter.accumulator() = m_value;
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void Store::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-07 20:58:36 -07:00
|
|
|
{
|
|
|
|
interpreter.reg(m_dst) = interpreter.accumulator();
|
2021-06-07 22:05:09 +02:00
|
|
|
}
|
|
|
|
|
2021-10-19 00:13:29 +03:00
|
|
|
static ThrowCompletionOr<Value> abstract_inequals(GlobalObject& global_object, Value src1, Value src2)
|
2021-06-03 10:46:30 +02:00
|
|
|
{
|
2021-10-19 00:13:29 +03:00
|
|
|
return Value(!TRY(is_loosely_equal(global_object, src1, src2)));
|
2021-06-03 10:46:30 +02:00
|
|
|
}
|
|
|
|
|
2021-10-19 00:13:29 +03:00
|
|
|
static ThrowCompletionOr<Value> abstract_equals(GlobalObject& global_object, Value src1, Value src2)
|
2021-06-03 18:32:33 +02:00
|
|
|
{
|
2021-10-19 00:13:29 +03:00
|
|
|
return Value(TRY(is_loosely_equal(global_object, src1, src2)));
|
2021-06-03 18:32:33 +02:00
|
|
|
}
|
|
|
|
|
2021-10-19 00:13:29 +03:00
|
|
|
static ThrowCompletionOr<Value> typed_inequals(GlobalObject&, Value src1, Value src2)
|
2021-06-07 19:17:20 +02:00
|
|
|
{
|
2021-09-23 23:43:28 +02:00
|
|
|
return Value(!is_strictly_equal(src1, src2));
|
2021-06-07 19:17:20 +02:00
|
|
|
}
|
|
|
|
|
2021-10-19 00:13:29 +03:00
|
|
|
static ThrowCompletionOr<Value> typed_equals(GlobalObject&, Value src1, Value src2)
|
2021-06-07 19:17:20 +02:00
|
|
|
{
|
2021-09-23 23:43:28 +02:00
|
|
|
return Value(is_strictly_equal(src1, src2));
|
2021-06-07 19:17:20 +02:00
|
|
|
}
|
|
|
|
|
2021-10-19 00:13:29 +03:00
|
|
|
#define JS_DEFINE_COMMON_BINARY_OP(OpTitleCase, op_snake_case) \
|
|
|
|
void OpTitleCase::execute_impl(Bytecode::Interpreter& interpreter) const \
|
|
|
|
{ \
|
|
|
|
auto lhs = interpreter.reg(m_lhs_reg); \
|
|
|
|
auto rhs = interpreter.accumulator(); \
|
|
|
|
auto result_or_error = op_snake_case(interpreter.global_object(), lhs, rhs); \
|
|
|
|
if (result_or_error.is_error()) \
|
|
|
|
return; \
|
|
|
|
interpreter.accumulator() = result_or_error.release_value(); \
|
|
|
|
} \
|
|
|
|
String OpTitleCase::to_string_impl(Bytecode::Executable const&) const \
|
|
|
|
{ \
|
|
|
|
return String::formatted(#OpTitleCase " {}", m_lhs_reg); \
|
2021-06-07 23:08:35 +02:00
|
|
|
}
|
2021-06-07 21:13:37 +01:00
|
|
|
|
2021-06-07 23:08:35 +02:00
|
|
|
JS_ENUMERATE_COMMON_BINARY_OPS(JS_DEFINE_COMMON_BINARY_OP)
|
2021-06-07 21:18:19 +01:00
|
|
|
|
2021-10-19 00:13:29 +03:00
|
|
|
static ThrowCompletionOr<Value> not_(GlobalObject&, Value value)
|
2021-06-07 21:13:37 +01:00
|
|
|
{
|
2021-06-07 23:08:35 +02:00
|
|
|
return Value(!value.to_boolean());
|
2021-06-07 21:13:37 +01:00
|
|
|
}
|
|
|
|
|
2021-10-19 00:13:29 +03:00
|
|
|
static ThrowCompletionOr<Value> typeof_(GlobalObject& global_object, Value value)
|
2021-06-07 19:53:47 +01:00
|
|
|
{
|
2021-10-19 00:13:29 +03:00
|
|
|
return Value(js_string(global_object.vm(), value.typeof()));
|
2021-06-07 19:53:47 +01:00
|
|
|
}
|
|
|
|
|
2021-10-19 00:13:29 +03:00
|
|
|
#define JS_DEFINE_COMMON_UNARY_OP(OpTitleCase, op_snake_case) \
|
|
|
|
void OpTitleCase::execute_impl(Bytecode::Interpreter& interpreter) const \
|
|
|
|
{ \
|
|
|
|
auto result_or_error = op_snake_case(interpreter.global_object(), interpreter.accumulator()); \
|
|
|
|
if (result_or_error.is_error()) \
|
|
|
|
return; \
|
|
|
|
interpreter.accumulator() = result_or_error.release_value(); \
|
|
|
|
} \
|
|
|
|
String OpTitleCase::to_string_impl(Bytecode::Executable const&) const \
|
|
|
|
{ \
|
|
|
|
return #OpTitleCase; \
|
2021-06-07 23:08:35 +02:00
|
|
|
}
|
2021-06-07 19:53:47 +01:00
|
|
|
|
2021-06-07 23:08:35 +02:00
|
|
|
JS_ENUMERATE_COMMON_UNARY_OPS(JS_DEFINE_COMMON_UNARY_OP)
|
2021-06-07 19:53:47 +01:00
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void NewBigInt::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-08 07:59:25 +02:00
|
|
|
{
|
2021-06-07 20:58:36 -07:00
|
|
|
interpreter.accumulator() = js_bigint(interpreter.vm().heap(), m_bigint);
|
2021-06-08 07:59:25 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void NewArray::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-08 23:06:52 +02:00
|
|
|
{
|
|
|
|
Vector<Value> elements;
|
|
|
|
elements.ensure_capacity(m_element_count);
|
|
|
|
for (size_t i = 0; i < m_element_count; i++)
|
|
|
|
elements.append(interpreter.reg(m_elements[i]));
|
|
|
|
interpreter.accumulator() = Array::create_from(interpreter.global_object(), elements);
|
|
|
|
}
|
|
|
|
|
2021-06-13 14:06:26 -07:00
|
|
|
void IteratorToArray::execute_impl(Bytecode::Interpreter& interpreter) const
|
|
|
|
{
|
|
|
|
auto& global_object = interpreter.global_object();
|
|
|
|
auto& vm = interpreter.vm();
|
2021-10-12 19:24:57 +01:00
|
|
|
auto iterator_or_error = interpreter.accumulator().to_object(global_object);
|
|
|
|
if (iterator_or_error.is_error())
|
2021-06-13 14:06:26 -07:00
|
|
|
return;
|
2021-10-12 19:24:57 +01:00
|
|
|
auto* iterator = iterator_or_error.release_value();
|
2021-06-13 14:06:26 -07:00
|
|
|
|
2021-07-04 01:36:44 +03:00
|
|
|
auto array = Array::create(global_object, 0);
|
2021-06-13 14:06:26 -07:00
|
|
|
size_t index = 0;
|
|
|
|
|
|
|
|
while (true) {
|
2021-10-20 08:44:30 -04:00
|
|
|
auto iterator_result_or_error = iterator_next(*iterator);
|
|
|
|
if (iterator_result_or_error.is_error())
|
2021-06-13 14:06:26 -07:00
|
|
|
return;
|
2021-10-20 08:44:30 -04:00
|
|
|
auto* iterator_result = iterator_result_or_error.release_value();
|
2021-06-13 14:06:26 -07:00
|
|
|
|
2021-10-20 09:00:37 -04:00
|
|
|
auto complete_or_error = iterator_complete(global_object, *iterator_result);
|
|
|
|
if (complete_or_error.is_error())
|
2021-06-13 14:06:26 -07:00
|
|
|
return;
|
2021-10-20 09:00:37 -04:00
|
|
|
auto complete = complete_or_error.release_value();
|
2021-06-13 14:06:26 -07:00
|
|
|
|
|
|
|
if (complete) {
|
|
|
|
interpreter.accumulator() = array;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto value = iterator_value(global_object, *iterator_result);
|
|
|
|
if (vm.exception())
|
|
|
|
return;
|
|
|
|
|
2021-10-03 01:18:46 +01:00
|
|
|
MUST(array->create_data_property_or_throw(index, value));
|
2021-06-13 14:06:26 -07:00
|
|
|
index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void NewString::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-03 18:26:32 +02:00
|
|
|
{
|
2021-06-09 10:02:01 +02:00
|
|
|
interpreter.accumulator() = js_string(interpreter.vm(), interpreter.current_executable().get_string(m_string));
|
2021-06-03 18:26:32 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void NewObject::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-04 20:30:23 +02:00
|
|
|
{
|
2021-06-16 20:52:30 +01:00
|
|
|
interpreter.accumulator() = Object::create(interpreter.global_object(), interpreter.global_object().object_prototype());
|
2021-06-07 20:58:36 -07:00
|
|
|
}
|
|
|
|
|
2021-06-19 17:17:40 -07:00
|
|
|
void NewRegExp::execute_impl(Bytecode::Interpreter& interpreter) const
|
|
|
|
{
|
|
|
|
auto source = interpreter.current_executable().get_string(m_source_index);
|
|
|
|
auto flags = interpreter.current_executable().get_string(m_flags_index);
|
|
|
|
|
2021-07-22 08:04:31 -04:00
|
|
|
interpreter.accumulator() = regexp_create(interpreter.global_object(), js_string(interpreter.vm(), source), js_string(interpreter.vm(), flags));
|
2021-06-19 17:17:40 -07:00
|
|
|
}
|
|
|
|
|
2021-06-13 15:30:32 -07:00
|
|
|
void CopyObjectExcludingProperties::execute_impl(Bytecode::Interpreter& interpreter) const
|
|
|
|
{
|
2021-10-12 19:24:57 +01:00
|
|
|
auto from_object_or_error = interpreter.reg(m_from_object).to_object(interpreter.global_object());
|
|
|
|
if (from_object_or_error.is_error())
|
2021-06-13 15:30:32 -07:00
|
|
|
return;
|
2021-10-12 19:24:57 +01:00
|
|
|
auto* from_object = from_object_or_error.release_value();
|
2021-06-13 15:30:32 -07:00
|
|
|
|
|
|
|
auto* to_object = Object::create(interpreter.global_object(), interpreter.global_object().object_prototype());
|
|
|
|
|
|
|
|
HashTable<Value, ValueTraits> excluded_names;
|
|
|
|
for (size_t i = 0; i < m_excluded_names_count; ++i) {
|
|
|
|
excluded_names.set(interpreter.reg(m_excluded_names[i]));
|
|
|
|
if (interpreter.vm().exception())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-09-29 18:58:03 +01:00
|
|
|
auto own_keys_or_error = from_object->internal_own_property_keys();
|
|
|
|
if (own_keys_or_error.is_error())
|
LibJS: Rewrite most of Object for spec compliance :^)
This is a huge patch, I know. In hindsight this perhaps could've been
done slightly more incremental, but I started and then fixed everything
until it worked, and here we are. I tried splitting of some completely
unrelated changes into separate commits, however. Anyway.
This is a rewrite of most of Object, and by extension large parts of
Array, Proxy, Reflect, String, TypedArray, and some other things.
What we already had worked fine for about 90% of things, but getting the
last 10% right proved to be increasingly difficult with the current code
that sort of grew organically and is only very loosely based on the
spec - this became especially obvious when we started fixing a large
number of test262 failures.
Key changes include:
- 1:1 matching function names and parameters of all object-related
functions, to avoid ambiguity. Previously we had things like put(),
which the spec doesn't have - as a result it wasn't always clear which
need to be used.
- Better separation between object abstract operations and internal
methods - the former are always the same, the latter can be overridden
(and are therefore virtual). The internal methods (i.e. [[Foo]] in the
spec) are now prefixed with 'internal_' for clarity - again, it was
previously not always clear which AO a certain method represents,
get() could've been both Get and [[Get]] (I don't know which one it
was closer to right now).
Note that some of the old names have been kept until all code relying
on them is updated, but they are now simple wrappers around the
closest matching standard abstract operation.
- Simplifications of the storage layer: functions that write values to
storage are now prefixed with 'storage_' to make their purpose clear,
and as they are not part of the spec they should not contain any steps
specified by it. Much functionality is now covered by the layers above
it and was removed (e.g. handling of accessors, attribute checks).
- PropertyAttributes has been greatly simplified, and is being replaced
by PropertyDescriptor - a concept similar to the current
implementation, but more aligned with the actual spec. See the commit
message of the previous commit where it was introduced for details.
- As a bonus, and since I had to look at the spec a whole lot anyway, I
introduced more inline comments with the exact steps from the spec -
this makes it super easy to verify correctness.
- East-const all the things.
As a result of all of this, things are much more correct but a bit
slower now. Retaining speed wasn't a consideration at all, I have done
no profiling of the new code - there might be low hanging fruits, which
we can then harvest separately.
Special thanks to Idan for helping me with this by tracking down bugs,
updating everything outside of LibJS to work with these changes (LibWeb,
Spreadsheet, HackStudio), as well as providing countless patches to fix
regressions I introduced - there still are very few (we got it down to
5), but we also get many new passing test262 tests in return. :^)
Co-authored-by: Idan Horowitz <idan.horowitz@gmail.com>
2021-07-04 18:14:16 +01:00
|
|
|
return;
|
2021-09-29 18:58:03 +01:00
|
|
|
auto own_keys = own_keys_or_error.release_value();
|
2021-06-13 15:30:32 -07:00
|
|
|
|
|
|
|
for (auto& key : own_keys) {
|
|
|
|
if (!excluded_names.contains(key)) {
|
2021-10-16 22:20:23 +03:00
|
|
|
auto property_name_or_error = key.to_property_key(interpreter.global_object());
|
|
|
|
if (property_name_or_error.is_error())
|
|
|
|
return;
|
|
|
|
PropertyName property_name = property_name_or_error.release_value();
|
2021-10-02 23:52:27 +01:00
|
|
|
auto property_value_or_error = from_object->get(property_name);
|
|
|
|
if (property_value_or_error.is_error())
|
2021-06-13 15:30:32 -07:00
|
|
|
return;
|
2021-10-02 23:52:27 +01:00
|
|
|
auto property_value = property_value_or_error.release_value();
|
2021-07-06 02:15:08 +03:00
|
|
|
to_object->define_direct_property(property_name, property_value, JS::default_attributes);
|
2021-06-13 15:30:32 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
interpreter.accumulator() = to_object;
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void ConcatString::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-07 20:58:36 -07:00
|
|
|
{
|
2021-10-19 00:13:29 +03:00
|
|
|
auto result_or_error = add(interpreter.global_object(), interpreter.reg(m_lhs), interpreter.accumulator());
|
|
|
|
if (result_or_error.is_error())
|
|
|
|
return;
|
|
|
|
interpreter.reg(m_lhs) = result_or_error.release_value();
|
2021-06-04 20:30:23 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void GetVariable::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-03 18:26:32 +02:00
|
|
|
{
|
2021-09-22 12:44:56 +02:00
|
|
|
auto& vm = interpreter.vm();
|
|
|
|
auto reference = vm.resolve_binding(interpreter.current_executable().get_string(m_identifier));
|
|
|
|
if (vm.exception())
|
|
|
|
return;
|
|
|
|
|
|
|
|
interpreter.accumulator() = reference.get_value(interpreter.global_object());
|
2021-06-03 18:26:32 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void SetVariable::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-03 18:26:32 +02:00
|
|
|
{
|
2021-09-22 12:44:56 +02:00
|
|
|
auto& vm = interpreter.vm();
|
|
|
|
auto reference = vm.resolve_binding(interpreter.current_executable().get_string(m_identifier));
|
|
|
|
if (vm.exception())
|
|
|
|
return;
|
|
|
|
|
|
|
|
reference.put_value(interpreter.global_object(), interpreter.accumulator());
|
2021-06-03 18:26:32 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void GetById::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-04 21:03:53 +02:00
|
|
|
{
|
2021-10-12 19:24:57 +01:00
|
|
|
auto object_or_error = interpreter.accumulator().to_object(interpreter.global_object());
|
|
|
|
if (object_or_error.is_error())
|
|
|
|
return;
|
|
|
|
auto* object = object_or_error.release_value();
|
|
|
|
auto value_or_error = object->get(interpreter.current_executable().get_string(m_property));
|
|
|
|
if (value_or_error.is_error())
|
|
|
|
return;
|
|
|
|
interpreter.accumulator() = value_or_error.release_value();
|
2021-06-04 21:03:53 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void PutById::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-04 20:47:07 +02:00
|
|
|
{
|
2021-10-12 19:24:57 +01:00
|
|
|
auto object_or_error = interpreter.reg(m_base).to_object(interpreter.global_object());
|
|
|
|
if (object_or_error.is_error())
|
|
|
|
return;
|
|
|
|
auto* object = object_or_error.release_value();
|
|
|
|
MUST(object->set(interpreter.current_executable().get_string(m_property), interpreter.accumulator(), Object::ShouldThrowExceptions::Yes));
|
2021-06-04 20:47:07 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void Jump::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-04 12:07:38 +02:00
|
|
|
{
|
2021-06-09 06:49:58 +04:30
|
|
|
interpreter.jump(*m_true_target);
|
2021-06-04 12:07:38 +02:00
|
|
|
}
|
|
|
|
|
2021-06-13 20:40:20 +04:30
|
|
|
void Jump::replace_references_impl(BasicBlock const& from, BasicBlock const& to)
|
|
|
|
{
|
|
|
|
if (m_true_target.has_value() && &m_true_target->block() == &from)
|
|
|
|
m_true_target = Label { to };
|
|
|
|
if (m_false_target.has_value() && &m_false_target->block() == &from)
|
|
|
|
m_false_target = Label { to };
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void JumpConditional::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-04 12:07:38 +02:00
|
|
|
{
|
2021-06-09 06:49:58 +04:30
|
|
|
VERIFY(m_true_target.has_value());
|
|
|
|
VERIFY(m_false_target.has_value());
|
2021-06-07 20:58:36 -07:00
|
|
|
auto result = interpreter.accumulator();
|
2021-06-07 22:53:33 +02:00
|
|
|
if (result.to_boolean())
|
2021-06-09 06:49:58 +04:30
|
|
|
interpreter.jump(m_true_target.value());
|
|
|
|
else
|
|
|
|
interpreter.jump(m_false_target.value());
|
2021-06-04 12:20:44 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void JumpNullish::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-08 02:18:47 +02:00
|
|
|
{
|
2021-06-09 06:49:58 +04:30
|
|
|
VERIFY(m_true_target.has_value());
|
|
|
|
VERIFY(m_false_target.has_value());
|
2021-06-07 20:58:36 -07:00
|
|
|
auto result = interpreter.accumulator();
|
2021-06-09 06:49:58 +04:30
|
|
|
if (result.is_nullish())
|
|
|
|
interpreter.jump(m_true_target.value());
|
|
|
|
else
|
|
|
|
interpreter.jump(m_false_target.value());
|
2021-06-08 02:18:47 +02:00
|
|
|
}
|
|
|
|
|
2021-06-13 12:24:40 -07:00
|
|
|
void JumpUndefined::execute_impl(Bytecode::Interpreter& interpreter) const
|
|
|
|
{
|
|
|
|
VERIFY(m_true_target.has_value());
|
|
|
|
VERIFY(m_false_target.has_value());
|
|
|
|
auto result = interpreter.accumulator();
|
|
|
|
if (result.is_undefined())
|
|
|
|
interpreter.jump(m_true_target.value());
|
|
|
|
else
|
|
|
|
interpreter.jump(m_false_target.value());
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void Call::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-05 15:15:30 +02:00
|
|
|
{
|
|
|
|
auto callee = interpreter.reg(m_callee);
|
|
|
|
if (!callee.is_function()) {
|
|
|
|
TODO();
|
|
|
|
}
|
|
|
|
auto& function = callee.as_function();
|
|
|
|
|
|
|
|
auto this_value = interpreter.reg(m_this_value);
|
|
|
|
|
|
|
|
Value return_value;
|
|
|
|
|
2021-06-10 23:01:49 +02:00
|
|
|
if (m_argument_count == 0 && m_type == CallType::Call) {
|
2021-09-23 20:56:28 +03:00
|
|
|
auto return_value_or_error = interpreter.vm().call(function, this_value);
|
|
|
|
if (!return_value_or_error.is_error())
|
|
|
|
return_value = return_value_or_error.release_value();
|
2021-06-05 15:15:30 +02:00
|
|
|
} else {
|
|
|
|
MarkedValueList argument_values { interpreter.vm().heap() };
|
2021-06-07 15:12:43 +02:00
|
|
|
for (size_t i = 0; i < m_argument_count; ++i) {
|
|
|
|
argument_values.append(interpreter.reg(m_arguments[i]));
|
2021-06-05 15:15:30 +02:00
|
|
|
}
|
2021-09-23 20:56:28 +03:00
|
|
|
if (m_type == CallType::Call) {
|
|
|
|
auto return_value_or_error = interpreter.vm().call(function, this_value, move(argument_values));
|
|
|
|
if (!return_value_or_error.is_error())
|
|
|
|
return_value = return_value_or_error.release_value();
|
|
|
|
} else {
|
2021-06-10 23:17:29 +02:00
|
|
|
return_value = interpreter.vm().construct(function, function, move(argument_values));
|
2021-09-23 20:56:28 +03:00
|
|
|
}
|
2021-06-05 15:15:30 +02:00
|
|
|
}
|
|
|
|
|
2021-06-07 20:58:36 -07:00
|
|
|
interpreter.accumulator() = return_value;
|
2021-06-05 15:15:30 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void NewFunction::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-05 15:14:09 +02:00
|
|
|
{
|
|
|
|
auto& vm = interpreter.vm();
|
2021-10-11 20:29:31 +02:00
|
|
|
interpreter.accumulator() = ECMAScriptFunctionObject::create(interpreter.global_object(), m_function_node.name(), m_function_node.body(), m_function_node.parameters(), m_function_node.function_length(), vm.lexical_environment(), vm.running_execution_context().private_environment, m_function_node.kind(), m_function_node.is_strict_mode(), m_function_node.might_need_arguments_object(), m_function_node.is_arrow_function());
|
2021-06-05 15:14:09 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void Return::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-05 15:53:36 +02:00
|
|
|
{
|
2021-06-07 20:58:36 -07:00
|
|
|
interpreter.do_return(interpreter.accumulator().value_or(js_undefined()));
|
2021-06-05 15:53:36 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void Increment::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-09 11:40:38 +02:00
|
|
|
{
|
2021-10-16 21:42:32 +03:00
|
|
|
auto old_value_or_error = interpreter.accumulator().to_numeric(interpreter.global_object());
|
|
|
|
if (old_value_or_error.is_error())
|
2021-06-09 11:40:38 +02:00
|
|
|
return;
|
2021-10-16 21:42:32 +03:00
|
|
|
auto old_value = old_value_or_error.release_value();
|
2021-06-09 11:40:38 +02:00
|
|
|
|
|
|
|
if (old_value.is_number())
|
|
|
|
interpreter.accumulator() = Value(old_value.as_double() + 1);
|
|
|
|
else
|
|
|
|
interpreter.accumulator() = js_bigint(interpreter.vm().heap(), old_value.as_bigint().big_integer().plus(Crypto::SignedBigInteger { 1 }));
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void Decrement::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-09 11:40:38 +02:00
|
|
|
{
|
2021-10-16 21:42:32 +03:00
|
|
|
auto old_value_or_error = interpreter.accumulator().to_numeric(interpreter.global_object());
|
|
|
|
if (old_value_or_error.is_error())
|
2021-06-09 11:40:38 +02:00
|
|
|
return;
|
2021-10-16 21:42:32 +03:00
|
|
|
auto old_value = old_value_or_error.release_value();
|
2021-06-09 11:40:38 +02:00
|
|
|
|
|
|
|
if (old_value.is_number())
|
|
|
|
interpreter.accumulator() = Value(old_value.as_double() - 1);
|
|
|
|
else
|
|
|
|
interpreter.accumulator() = js_bigint(interpreter.vm().heap(), old_value.as_bigint().big_integer().minus(Crypto::SignedBigInteger { 1 }));
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void Throw::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-09 18:18:56 +02:00
|
|
|
{
|
|
|
|
interpreter.vm().throw_exception(interpreter.global_object(), interpreter.accumulator());
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void EnterUnwindContext::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-10 15:04:38 +02:00
|
|
|
{
|
|
|
|
interpreter.enter_unwind_context(m_handler_target, m_finalizer_target);
|
2021-06-13 20:39:40 +04:30
|
|
|
interpreter.jump(m_entry_point);
|
2021-06-10 15:04:38 +02:00
|
|
|
}
|
|
|
|
|
2021-06-13 20:40:20 +04:30
|
|
|
void EnterUnwindContext::replace_references_impl(BasicBlock const& from, BasicBlock const& to)
|
|
|
|
{
|
|
|
|
if (&m_entry_point.block() == &from)
|
|
|
|
m_entry_point = Label { to };
|
|
|
|
if (m_handler_target.has_value() && &m_handler_target->block() == &from)
|
|
|
|
m_handler_target = Label { to };
|
|
|
|
if (m_finalizer_target.has_value() && &m_finalizer_target->block() == &from)
|
|
|
|
m_finalizer_target = Label { to };
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void LeaveUnwindContext::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-10 15:04:38 +02:00
|
|
|
{
|
|
|
|
interpreter.leave_unwind_context();
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void ContinuePendingUnwind::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-10 15:04:38 +02:00
|
|
|
{
|
|
|
|
interpreter.continue_pending_unwind(m_resume_target);
|
|
|
|
}
|
|
|
|
|
2021-06-13 20:40:20 +04:30
|
|
|
void ContinuePendingUnwind::replace_references_impl(BasicBlock const& from, BasicBlock const& to)
|
|
|
|
{
|
|
|
|
if (&m_resume_target.block() == &from)
|
|
|
|
m_resume_target = Label { to };
|
|
|
|
}
|
|
|
|
|
2021-07-01 12:24:46 +02:00
|
|
|
void PushDeclarativeEnvironment::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-10 22:12:21 +02:00
|
|
|
{
|
2021-09-22 12:44:56 +02:00
|
|
|
auto* environment = interpreter.vm().heap().allocate<DeclarativeEnvironment>(interpreter.global_object(), interpreter.vm().lexical_environment());
|
2021-07-01 12:24:46 +02:00
|
|
|
interpreter.vm().running_execution_context().lexical_environment = environment;
|
|
|
|
interpreter.vm().running_execution_context().variable_environment = environment;
|
2021-06-10 22:12:21 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void Yield::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-11 01:38:30 +04:30
|
|
|
{
|
|
|
|
auto yielded_value = interpreter.accumulator().value_or(js_undefined());
|
2021-06-16 20:52:30 +01:00
|
|
|
auto object = JS::Object::create(interpreter.global_object(), nullptr);
|
2021-07-06 01:15:50 +03:00
|
|
|
object->define_direct_property("result", yielded_value, JS::default_attributes);
|
2021-06-11 01:38:30 +04:30
|
|
|
if (m_continuation_label.has_value())
|
2021-07-06 01:15:50 +03:00
|
|
|
object->define_direct_property("continuation", Value(static_cast<double>(reinterpret_cast<u64>(&m_continuation_label->block()))), JS::default_attributes);
|
2021-06-11 01:38:30 +04:30
|
|
|
else
|
2021-07-06 01:15:50 +03:00
|
|
|
object->define_direct_property("continuation", Value(0), JS::default_attributes);
|
2021-06-11 01:38:30 +04:30
|
|
|
interpreter.do_return(object);
|
|
|
|
}
|
|
|
|
|
2021-06-13 20:40:20 +04:30
|
|
|
void Yield::replace_references_impl(BasicBlock const& from, BasicBlock const& to)
|
|
|
|
{
|
|
|
|
if (m_continuation_label.has_value() && &m_continuation_label->block() == &from)
|
|
|
|
m_continuation_label = Label { to };
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void GetByValue::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-11 00:35:25 +02:00
|
|
|
{
|
2021-10-12 19:24:57 +01:00
|
|
|
auto object_or_error = interpreter.reg(m_base).to_object(interpreter.global_object());
|
|
|
|
if (object_or_error.is_error())
|
|
|
|
return;
|
|
|
|
auto* object = object_or_error.release_value();
|
2021-10-16 22:20:23 +03:00
|
|
|
auto property_key_or_error = interpreter.accumulator().to_property_key(interpreter.global_object());
|
|
|
|
if (property_key_or_error.is_error())
|
2021-10-12 19:24:57 +01:00
|
|
|
return;
|
2021-10-16 22:20:23 +03:00
|
|
|
auto value_or_error = object->get(property_key_or_error.release_value());
|
2021-10-12 19:24:57 +01:00
|
|
|
if (value_or_error.is_error())
|
|
|
|
return;
|
|
|
|
interpreter.accumulator() = value_or_error.release_value();
|
2021-06-11 00:35:25 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
void PutByValue::execute_impl(Bytecode::Interpreter& interpreter) const
|
2021-06-11 00:35:25 +02:00
|
|
|
{
|
2021-10-12 19:24:57 +01:00
|
|
|
auto object_or_error = interpreter.reg(m_base).to_object(interpreter.global_object());
|
|
|
|
if (object_or_error.is_error())
|
|
|
|
return;
|
|
|
|
auto* object = object_or_error.release_value();
|
2021-10-16 22:20:23 +03:00
|
|
|
auto property_key_or_error = interpreter.reg(m_property).to_property_key(interpreter.global_object());
|
|
|
|
if (property_key_or_error.is_error())
|
2021-10-12 19:24:57 +01:00
|
|
|
return;
|
2021-10-16 22:20:23 +03:00
|
|
|
MUST(object->set(property_key_or_error.release_value(), interpreter.accumulator(), Object::ShouldThrowExceptions::Yes));
|
2021-06-11 00:35:25 +02:00
|
|
|
}
|
|
|
|
|
2021-06-13 13:40:48 -07:00
|
|
|
void GetIterator::execute_impl(Bytecode::Interpreter& interpreter) const
|
|
|
|
{
|
2021-10-20 08:24:54 -04:00
|
|
|
auto iterator_or_error = get_iterator(interpreter.global_object(), interpreter.accumulator());
|
|
|
|
if (iterator_or_error.is_error())
|
|
|
|
return;
|
|
|
|
interpreter.accumulator() = iterator_or_error.release_value();
|
2021-06-13 13:40:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void IteratorNext::execute_impl(Bytecode::Interpreter& interpreter) const
|
|
|
|
{
|
2021-10-12 19:24:57 +01:00
|
|
|
auto object_or_error = interpreter.accumulator().to_object(interpreter.global_object());
|
|
|
|
if (object_or_error.is_error())
|
|
|
|
return;
|
|
|
|
auto* object = object_or_error.release_value();
|
2021-10-20 08:44:30 -04:00
|
|
|
|
|
|
|
auto iterator_result_or_error = iterator_next(*object);
|
|
|
|
if (iterator_result_or_error.is_error())
|
|
|
|
return;
|
|
|
|
auto* iterator_result = iterator_result_or_error.release_value();
|
|
|
|
|
|
|
|
interpreter.accumulator() = iterator_result;
|
2021-06-13 13:40:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void IteratorResultDone::execute_impl(Bytecode::Interpreter& interpreter) const
|
|
|
|
{
|
2021-10-12 19:24:57 +01:00
|
|
|
auto iterator_result_or_error = interpreter.accumulator().to_object(interpreter.global_object());
|
|
|
|
if (iterator_result_or_error.is_error())
|
|
|
|
return;
|
|
|
|
auto* iterator_result = iterator_result_or_error.release_value();
|
2021-10-20 09:00:37 -04:00
|
|
|
|
|
|
|
auto complete_or_error = iterator_complete(interpreter.global_object(), *iterator_result);
|
|
|
|
if (complete_or_error.is_error())
|
|
|
|
return;
|
|
|
|
auto complete = complete_or_error.release_value();
|
|
|
|
|
|
|
|
interpreter.accumulator() = Value(complete);
|
2021-06-13 13:40:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void IteratorResultValue::execute_impl(Bytecode::Interpreter& interpreter) const
|
|
|
|
{
|
2021-10-12 19:24:57 +01:00
|
|
|
auto iterator_result_or_error = interpreter.accumulator().to_object(interpreter.global_object());
|
|
|
|
if (iterator_result_or_error.is_error())
|
|
|
|
return;
|
|
|
|
auto* iterator_result = iterator_result_or_error.release_value();
|
|
|
|
interpreter.accumulator() = iterator_value(interpreter.global_object(), *iterator_result);
|
2021-06-13 13:40:48 -07:00
|
|
|
}
|
|
|
|
|
2021-06-30 15:42:13 -03:00
|
|
|
void NewClass::execute_impl(Bytecode::Interpreter&) const
|
|
|
|
{
|
2021-07-01 17:45:45 +02:00
|
|
|
(void)m_class_expression;
|
2021-06-30 15:42:13 -03:00
|
|
|
TODO();
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String Load::to_string_impl(Bytecode::Executable const&) const
|
2021-06-03 10:46:30 +02:00
|
|
|
{
|
2021-06-09 11:06:11 +02:00
|
|
|
return String::formatted("Load {}", m_src);
|
2021-06-03 10:46:30 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String LoadImmediate::to_string_impl(Bytecode::Executable const&) const
|
2021-06-07 22:05:09 +02:00
|
|
|
{
|
2021-06-09 11:06:11 +02:00
|
|
|
return String::formatted("LoadImmediate {}", m_value);
|
2021-06-07 20:58:36 -07:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String Store::to_string_impl(Bytecode::Executable const&) const
|
2021-06-07 20:58:36 -07:00
|
|
|
{
|
2021-06-09 11:06:11 +02:00
|
|
|
return String::formatted("Store {}", m_dst);
|
2021-06-07 22:05:09 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String NewBigInt::to_string_impl(Bytecode::Executable const&) const
|
2021-06-08 07:59:25 +02:00
|
|
|
{
|
2021-06-29 17:51:52 +03:00
|
|
|
return String::formatted("NewBigInt \"{}\"", m_bigint.to_base(10));
|
2021-06-08 07:59:25 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String NewArray::to_string_impl(Bytecode::Executable const&) const
|
2021-06-08 23:06:52 +02:00
|
|
|
{
|
|
|
|
StringBuilder builder;
|
|
|
|
builder.append("NewArray");
|
|
|
|
if (m_element_count != 0) {
|
2021-06-09 11:06:11 +02:00
|
|
|
builder.append(" [");
|
2021-06-08 23:06:52 +02:00
|
|
|
for (size_t i = 0; i < m_element_count; ++i) {
|
|
|
|
builder.appendff("{}", m_elements[i]);
|
|
|
|
if (i != m_element_count - 1)
|
|
|
|
builder.append(',');
|
|
|
|
}
|
|
|
|
builder.append(']');
|
|
|
|
}
|
|
|
|
return builder.to_string();
|
|
|
|
}
|
|
|
|
|
2021-06-13 14:06:26 -07:00
|
|
|
String IteratorToArray::to_string_impl(const Bytecode::Executable&) const
|
|
|
|
{
|
|
|
|
return "IteratorToArray";
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String NewString::to_string_impl(Bytecode::Executable const& executable) const
|
2021-06-03 18:26:32 +02:00
|
|
|
{
|
2021-06-09 10:02:01 +02:00
|
|
|
return String::formatted("NewString {} (\"{}\")", m_string, executable.string_table->get(m_string));
|
2021-06-03 18:26:32 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String NewObject::to_string_impl(Bytecode::Executable const&) const
|
2021-06-04 20:30:23 +02:00
|
|
|
{
|
2021-06-07 20:58:36 -07:00
|
|
|
return "NewObject";
|
|
|
|
}
|
|
|
|
|
2021-06-19 17:17:40 -07:00
|
|
|
String NewRegExp::to_string_impl(Bytecode::Executable const& executable) const
|
|
|
|
{
|
|
|
|
return String::formatted("NewRegExp source:{} (\"{}\") flags:{} (\"{}\")", m_source_index, executable.get_string(m_source_index), m_flags_index, executable.get_string(m_flags_index));
|
|
|
|
}
|
|
|
|
|
2021-06-13 15:30:32 -07:00
|
|
|
String CopyObjectExcludingProperties::to_string_impl(const Bytecode::Executable&) const
|
|
|
|
{
|
|
|
|
StringBuilder builder;
|
|
|
|
builder.appendff("CopyObjectExcludingProperties from:{}", m_from_object);
|
|
|
|
if (m_excluded_names_count != 0) {
|
|
|
|
builder.append(" excluding:[");
|
|
|
|
for (size_t i = 0; i < m_excluded_names_count; ++i) {
|
|
|
|
builder.appendff("{}", m_excluded_names[i]);
|
|
|
|
if (i != m_excluded_names_count - 1)
|
|
|
|
builder.append(',');
|
|
|
|
}
|
|
|
|
builder.append(']');
|
|
|
|
}
|
|
|
|
return builder.to_string();
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String ConcatString::to_string_impl(Bytecode::Executable const&) const
|
2021-06-07 20:58:36 -07:00
|
|
|
{
|
2021-06-09 11:06:11 +02:00
|
|
|
return String::formatted("ConcatString {}", m_lhs);
|
2021-06-04 20:30:23 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String GetVariable::to_string_impl(Bytecode::Executable const& executable) const
|
2021-06-03 18:26:32 +02:00
|
|
|
{
|
2021-06-09 10:02:01 +02:00
|
|
|
return String::formatted("GetVariable {} ({})", m_identifier, executable.string_table->get(m_identifier));
|
2021-06-03 18:26:32 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String SetVariable::to_string_impl(Bytecode::Executable const& executable) const
|
2021-06-03 18:26:32 +02:00
|
|
|
{
|
2021-06-09 10:02:01 +02:00
|
|
|
return String::formatted("SetVariable {} ({})", m_identifier, executable.string_table->get(m_identifier));
|
2021-06-03 18:26:32 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String PutById::to_string_impl(Bytecode::Executable const& executable) const
|
2021-06-04 20:47:07 +02:00
|
|
|
{
|
2021-06-09 10:02:01 +02:00
|
|
|
return String::formatted("PutById base:{}, property:{} ({})", m_base, m_property, executable.string_table->get(m_property));
|
2021-06-04 20:47:07 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String GetById::to_string_impl(Bytecode::Executable const& executable) const
|
2021-06-04 21:03:53 +02:00
|
|
|
{
|
2021-06-09 10:02:01 +02:00
|
|
|
return String::formatted("GetById {} ({})", m_property, executable.string_table->get(m_property));
|
2021-06-04 21:03:53 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String Jump::to_string_impl(Bytecode::Executable const&) const
|
2021-06-04 12:07:38 +02:00
|
|
|
{
|
2021-06-09 06:49:58 +04:30
|
|
|
if (m_true_target.has_value())
|
|
|
|
return String::formatted("Jump {}", *m_true_target);
|
|
|
|
return String::formatted("Jump <empty>");
|
2021-06-04 12:07:38 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String JumpConditional::to_string_impl(Bytecode::Executable const&) const
|
2021-06-04 12:20:44 +02:00
|
|
|
{
|
2021-06-09 06:49:58 +04:30
|
|
|
auto true_string = m_true_target.has_value() ? String::formatted("{}", *m_true_target) : "<empty>";
|
|
|
|
auto false_string = m_false_target.has_value() ? String::formatted("{}", *m_false_target) : "<empty>";
|
|
|
|
return String::formatted("JumpConditional true:{} false:{}", true_string, false_string);
|
2021-06-04 12:20:44 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String JumpNullish::to_string_impl(Bytecode::Executable const&) const
|
2021-06-08 02:18:47 +02:00
|
|
|
{
|
2021-06-09 06:49:58 +04:30
|
|
|
auto true_string = m_true_target.has_value() ? String::formatted("{}", *m_true_target) : "<empty>";
|
|
|
|
auto false_string = m_false_target.has_value() ? String::formatted("{}", *m_false_target) : "<empty>";
|
|
|
|
return String::formatted("JumpNullish null:{} nonnull:{}", true_string, false_string);
|
2021-06-08 02:18:47 +02:00
|
|
|
}
|
|
|
|
|
2021-06-13 12:24:40 -07:00
|
|
|
String JumpUndefined::to_string_impl(Bytecode::Executable const&) const
|
|
|
|
{
|
|
|
|
auto true_string = m_true_target.has_value() ? String::formatted("{}", *m_true_target) : "<empty>";
|
|
|
|
auto false_string = m_false_target.has_value() ? String::formatted("{}", *m_false_target) : "<empty>";
|
|
|
|
return String::formatted("JumpUndefined undefined:{} not undefined:{}", true_string, false_string);
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String Call::to_string_impl(Bytecode::Executable const&) const
|
2021-06-05 15:15:30 +02:00
|
|
|
{
|
|
|
|
StringBuilder builder;
|
2021-06-07 20:58:36 -07:00
|
|
|
builder.appendff("Call callee:{}, this:{}", m_callee, m_this_value);
|
2021-06-07 15:12:43 +02:00
|
|
|
if (m_argument_count != 0) {
|
2021-06-05 15:15:30 +02:00
|
|
|
builder.append(", arguments:[");
|
2021-06-07 15:12:43 +02:00
|
|
|
for (size_t i = 0; i < m_argument_count; ++i) {
|
2021-06-05 15:15:30 +02:00
|
|
|
builder.appendff("{}", m_arguments[i]);
|
2021-06-07 15:12:43 +02:00
|
|
|
if (i != m_argument_count - 1)
|
2021-06-05 15:15:30 +02:00
|
|
|
builder.append(',');
|
|
|
|
}
|
|
|
|
builder.append(']');
|
|
|
|
}
|
|
|
|
return builder.to_string();
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String NewFunction::to_string_impl(Bytecode::Executable const&) const
|
2021-06-05 15:14:09 +02:00
|
|
|
{
|
2021-06-10 00:49:23 +02:00
|
|
|
return "NewFunction";
|
2021-06-05 15:14:09 +02:00
|
|
|
}
|
|
|
|
|
2021-06-30 15:42:13 -03:00
|
|
|
String NewClass::to_string_impl(Bytecode::Executable const&) const
|
|
|
|
{
|
|
|
|
return "NewClass";
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String Return::to_string_impl(Bytecode::Executable const&) const
|
2021-06-05 15:53:36 +02:00
|
|
|
{
|
|
|
|
return "Return";
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String Increment::to_string_impl(Bytecode::Executable const&) const
|
2021-06-09 11:40:38 +02:00
|
|
|
{
|
|
|
|
return "Increment";
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String Decrement::to_string_impl(Bytecode::Executable const&) const
|
2021-06-09 11:40:38 +02:00
|
|
|
{
|
|
|
|
return "Decrement";
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String Throw::to_string_impl(Bytecode::Executable const&) const
|
2021-06-09 18:18:56 +02:00
|
|
|
{
|
|
|
|
return "Throw";
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String EnterUnwindContext::to_string_impl(Bytecode::Executable const&) const
|
2021-06-10 15:04:38 +02:00
|
|
|
{
|
|
|
|
auto handler_string = m_handler_target.has_value() ? String::formatted("{}", *m_handler_target) : "<empty>";
|
|
|
|
auto finalizer_string = m_finalizer_target.has_value() ? String::formatted("{}", *m_finalizer_target) : "<empty>";
|
2021-06-13 20:39:40 +04:30
|
|
|
return String::formatted("EnterUnwindContext handler:{} finalizer:{} entry:{}", handler_string, finalizer_string, m_entry_point);
|
2021-06-10 15:04:38 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String LeaveUnwindContext::to_string_impl(Bytecode::Executable const&) const
|
2021-06-10 15:04:38 +02:00
|
|
|
{
|
|
|
|
return "LeaveUnwindContext";
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String ContinuePendingUnwind::to_string_impl(Bytecode::Executable const&) const
|
2021-06-10 15:04:38 +02:00
|
|
|
{
|
|
|
|
return String::formatted("ContinuePendingUnwind resume:{}", m_resume_target);
|
|
|
|
}
|
|
|
|
|
2021-07-01 12:24:46 +02:00
|
|
|
String PushDeclarativeEnvironment::to_string_impl(const Bytecode::Executable& executable) const
|
2021-06-10 22:12:21 +02:00
|
|
|
{
|
|
|
|
StringBuilder builder;
|
2021-07-01 12:24:46 +02:00
|
|
|
builder.append("PushDeclarativeEnvironment");
|
2021-06-10 22:12:21 +02:00
|
|
|
if (!m_variables.is_empty()) {
|
|
|
|
builder.append(" {");
|
|
|
|
Vector<String> names;
|
|
|
|
for (auto& it : m_variables)
|
|
|
|
names.append(executable.get_string(it.key));
|
|
|
|
builder.join(", ", names);
|
|
|
|
builder.append("}");
|
|
|
|
}
|
|
|
|
return builder.to_string();
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String Yield::to_string_impl(Bytecode::Executable const&) const
|
2021-06-11 01:38:30 +04:30
|
|
|
{
|
|
|
|
if (m_continuation_label.has_value())
|
|
|
|
return String::formatted("Yield continuation:@{}", m_continuation_label->block().name());
|
|
|
|
return String::formatted("Yield return");
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String GetByValue::to_string_impl(const Bytecode::Executable&) const
|
2021-06-11 00:35:25 +02:00
|
|
|
{
|
|
|
|
return String::formatted("GetByValue base:{}", m_base);
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:08:12 +04:30
|
|
|
String PutByValue::to_string_impl(const Bytecode::Executable&) const
|
2021-06-11 00:35:25 +02:00
|
|
|
{
|
|
|
|
return String::formatted("PutByValue base:{}, property:{}", m_base, m_property);
|
|
|
|
}
|
|
|
|
|
2021-06-13 13:40:48 -07:00
|
|
|
String GetIterator::to_string_impl(Executable const&) const
|
|
|
|
{
|
|
|
|
return "GetIterator";
|
|
|
|
}
|
|
|
|
|
|
|
|
String IteratorNext::to_string_impl(Executable const&) const
|
|
|
|
{
|
|
|
|
return "IteratorNext";
|
|
|
|
}
|
|
|
|
|
|
|
|
String IteratorResultDone::to_string_impl(Executable const&) const
|
|
|
|
{
|
|
|
|
return "IteratorResultDone";
|
|
|
|
}
|
|
|
|
|
|
|
|
String IteratorResultValue::to_string_impl(Executable const&) const
|
|
|
|
{
|
|
|
|
return "IteratorResultValue";
|
|
|
|
}
|
|
|
|
|
2021-06-03 10:46:30 +02:00
|
|
|
}
|