mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 06:14:58 +00:00
Revert "LibJS/Bytecode: Bring back the bytecode optimization pipeline"
This reverts commit 5b29974bfa
.
This commit is contained in:
parent
b37d84be58
commit
5b69413c4b
15 changed files with 65 additions and 962 deletions
|
@ -2512,7 +2512,7 @@ Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> TryStatement::gener
|
|||
|
||||
auto& target_block = generator.make_block();
|
||||
generator.switch_to_basic_block(saved_block);
|
||||
generator.emit<Bytecode::Op::EnterUnwindContext>(Bytecode::Label { target_block }, handler_target, finalizer_target);
|
||||
generator.emit<Bytecode::Op::EnterUnwindContext>(Bytecode::Label { target_block });
|
||||
generator.start_boundary(Bytecode::Generator::BlockBoundaryType::Unwind);
|
||||
if (m_finalizer)
|
||||
generator.start_boundary(Bytecode::Generator::BlockBoundaryType::ReturnToFinally);
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include <AK/Badge.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibJS/Bytecode/Operand.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap/Handle.h>
|
||||
|
||||
|
@ -36,7 +35,7 @@ public:
|
|||
|
||||
void grow(size_t additional_size);
|
||||
|
||||
void terminate(Badge<Generator>, size_t slot_offset) { terminate(slot_offset); }
|
||||
void terminate(Badge<Generator>) { m_terminated = true; }
|
||||
bool is_terminated() const { return m_terminated; }
|
||||
|
||||
String const& name() const { return m_name; }
|
||||
|
@ -47,56 +46,14 @@ public:
|
|||
BasicBlock const* handler() const { return m_handler; }
|
||||
BasicBlock const* finalizer() const { return m_finalizer; }
|
||||
|
||||
Instruction const* terminator() const
|
||||
{
|
||||
VERIFY(m_terminated);
|
||||
return reinterpret_cast<Instruction const*>(data() + m_terminator_offset);
|
||||
}
|
||||
|
||||
template<typename OpType, typename... Args>
|
||||
void append(u32 start_offset, u32 end_offset, Args&&... args)
|
||||
{
|
||||
VERIFY(!m_terminated);
|
||||
size_t const slot_offset = size();
|
||||
grow(sizeof(OpType));
|
||||
void* slot = data() + slot_offset;
|
||||
new (slot) OpType(forward<Args>(args)...);
|
||||
if constexpr (OpType::IsTerminator)
|
||||
terminate(slot_offset);
|
||||
auto* op = static_cast<OpType*>(slot);
|
||||
op->set_source_record({ start_offset, end_offset });
|
||||
}
|
||||
|
||||
template<typename OpType, typename... Args>
|
||||
void append_with_extra_operand_slots(u32 start_offset, u32 end_offset, size_t extra_operand_slots, Args&&... args)
|
||||
{
|
||||
VERIFY(!m_terminated);
|
||||
size_t size_to_allocate = round_up_to_power_of_two(sizeof(OpType) + extra_operand_slots * sizeof(Operand), alignof(void*));
|
||||
size_t slot_offset = size();
|
||||
grow(size_to_allocate);
|
||||
void* slot = data() + slot_offset;
|
||||
new (slot) OpType(forward<Args>(args)...);
|
||||
if constexpr (OpType::IsTerminator)
|
||||
terminate(slot_offset);
|
||||
auto* op = static_cast<OpType*>(slot);
|
||||
op->set_source_record({ start_offset, end_offset });
|
||||
}
|
||||
|
||||
private:
|
||||
explicit BasicBlock(String name);
|
||||
|
||||
void terminate(size_t slot_offset)
|
||||
{
|
||||
m_terminated = true;
|
||||
m_terminator_offset = slot_offset;
|
||||
}
|
||||
|
||||
Vector<u8> m_buffer;
|
||||
BasicBlock const* m_handler { nullptr };
|
||||
BasicBlock const* m_finalizer { nullptr };
|
||||
String m_name;
|
||||
bool m_terminated { false };
|
||||
size_t m_terminator_offset { 0 };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
void* slot = m_current_basic_block->data() + slot_offset;
|
||||
new (slot) OpType(forward<Args>(args)...);
|
||||
if constexpr (OpType::IsTerminator)
|
||||
m_current_basic_block->terminate({}, slot_offset);
|
||||
m_current_basic_block->terminate({});
|
||||
auto* op = static_cast<OpType*>(slot);
|
||||
op->set_source_record({ m_current_ast_node->start_offset(), m_current_ast_node->end_offset() });
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ public:
|
|||
void* slot = m_current_basic_block->data() + slot_offset;
|
||||
new (slot) OpType(forward<Args>(args)...);
|
||||
if constexpr (OpType::IsTerminator)
|
||||
m_current_basic_block->terminate({}, slot_offset);
|
||||
m_current_basic_block->terminate({});
|
||||
auto* op = static_cast<OpType*>(slot);
|
||||
op->set_source_record({ m_current_ast_node->start_offset(), m_current_ast_node->end_offset() });
|
||||
}
|
||||
|
|
|
@ -10,36 +10,6 @@
|
|||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
bool Instruction::is_terminator() const
|
||||
{
|
||||
#define __BYTECODE_OP(op) \
|
||||
case Type::op: \
|
||||
return Op::op::IsTerminator;
|
||||
|
||||
switch (type()) {
|
||||
ENUMERATE_BYTECODE_OPS(__BYTECODE_OP)
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
#undef __BYTECODE_OP
|
||||
}
|
||||
|
||||
void Instruction::replace_references(BasicBlock const& from, BasicBlock const& to)
|
||||
{
|
||||
#define __BYTECODE_OP(op) \
|
||||
case Instruction::Type::op: \
|
||||
return static_cast<Bytecode::Op::op&>(*this).replace_references_impl(from, to);
|
||||
|
||||
switch (type()) {
|
||||
ENUMERATE_BYTECODE_OPS(__BYTECODE_OP)
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
#undef __BYTECODE_OP
|
||||
}
|
||||
|
||||
void Instruction::destroy(Instruction& instruction)
|
||||
{
|
||||
#define __BYTECODE_OP(op) \
|
||||
|
|
|
@ -131,13 +131,10 @@ public:
|
|||
#undef __BYTECODE_OP
|
||||
};
|
||||
|
||||
[[nodiscard]] bool is_terminator() const;
|
||||
|
||||
Type type() const { return m_type; }
|
||||
size_t length() const { return m_length; }
|
||||
ByteString to_byte_string(Bytecode::Executable const&) const;
|
||||
ThrowCompletionOr<void> execute(Bytecode::Interpreter&) const;
|
||||
void replace_references(BasicBlock const& from, BasicBlock const& to);
|
||||
static void destroy(Instruction&);
|
||||
|
||||
// FIXME: Find a better way to organize this information
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <LibJS/Bytecode/Interpreter.h>
|
||||
#include <LibJS/Bytecode/Label.h>
|
||||
#include <LibJS/Bytecode/Op.h>
|
||||
#include <LibJS/Bytecode/PassManager.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/BigInt.h>
|
||||
|
@ -569,25 +568,6 @@ void Interpreter::enter_object_environment(Object& object)
|
|||
vm().running_execution_context().lexical_environment = new_object_environment(object, true, old_environment);
|
||||
}
|
||||
|
||||
static PassManager& optimization_pipeline()
|
||||
{
|
||||
static auto s_optimization_pipeline = [] {
|
||||
auto pm = make<PassManager>();
|
||||
pm->add<Passes::GenerateCFG>();
|
||||
pm->add<Passes::UnifySameBlocks>();
|
||||
pm->add<Passes::GenerateCFG>();
|
||||
pm->add<Passes::MergeBlocks>();
|
||||
pm->add<Passes::GenerateCFG>();
|
||||
pm->add<Passes::UnifySameBlocks>();
|
||||
pm->add<Passes::GenerateCFG>();
|
||||
pm->add<Passes::MergeBlocks>();
|
||||
pm->add<Passes::GenerateCFG>();
|
||||
pm->add<Passes::PlaceBlocks>();
|
||||
return pm;
|
||||
}();
|
||||
return *s_optimization_pipeline;
|
||||
}
|
||||
|
||||
ThrowCompletionOr<NonnullGCPtr<Bytecode::Executable>> compile(VM& vm, ASTNode const& node, ReadonlySpan<FunctionParameter> parameters, FunctionKind kind, DeprecatedFlyString const& name)
|
||||
{
|
||||
auto executable_result = Bytecode::Generator::generate(vm, node, parameters, kind);
|
||||
|
@ -597,13 +577,6 @@ ThrowCompletionOr<NonnullGCPtr<Bytecode::Executable>> compile(VM& vm, ASTNode co
|
|||
auto bytecode_executable = executable_result.release_value();
|
||||
bytecode_executable->name = name;
|
||||
|
||||
auto& passes = optimization_pipeline();
|
||||
passes.perform(*bytecode_executable);
|
||||
if constexpr (JS_BYTECODE_DEBUG) {
|
||||
dbgln("Optimisation passes took {}us", passes.elapsed());
|
||||
dbgln("Compiled Bytecode::Block for function '{}':", name);
|
||||
}
|
||||
|
||||
if (Bytecode::g_dump_bytecode)
|
||||
bytecode_executable->dump();
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
namespace JS::Bytecode {
|
||||
|
||||
class InstructionStreamIterator;
|
||||
class PassManager;
|
||||
|
||||
struct CallFrame {
|
||||
static NonnullOwnPtr<CallFrame> create(size_t register_count);
|
||||
|
|
|
@ -42,7 +42,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand src() const { return m_src; }
|
||||
|
@ -78,29 +77,28 @@ private:
|
|||
O(StrictlyInequals, strict_inequals) \
|
||||
O(StrictlyEquals, strict_equals)
|
||||
|
||||
#define JS_DECLARE_COMMON_BINARY_OP(OpTitleCase, op_snake_case) \
|
||||
class OpTitleCase final : public Instruction { \
|
||||
public: \
|
||||
explicit OpTitleCase(Operand dst, Operand lhs, Operand rhs) \
|
||||
: Instruction(Type::OpTitleCase, sizeof(*this)) \
|
||||
, m_dst(dst) \
|
||||
, m_lhs(lhs) \
|
||||
, m_rhs(rhs) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const; \
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const; \
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { } \
|
||||
\
|
||||
Operand dst() const { return m_dst; } \
|
||||
Operand lhs() const { return m_lhs; } \
|
||||
Operand rhs() const { return m_rhs; } \
|
||||
\
|
||||
private: \
|
||||
Operand m_dst; \
|
||||
Operand m_lhs; \
|
||||
Operand m_rhs; \
|
||||
#define JS_DECLARE_COMMON_BINARY_OP(OpTitleCase, op_snake_case) \
|
||||
class OpTitleCase final : public Instruction { \
|
||||
public: \
|
||||
explicit OpTitleCase(Operand dst, Operand lhs, Operand rhs) \
|
||||
: Instruction(Type::OpTitleCase, sizeof(*this)) \
|
||||
, m_dst(dst) \
|
||||
, m_lhs(lhs) \
|
||||
, m_rhs(rhs) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const; \
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const; \
|
||||
\
|
||||
Operand dst() const { return m_dst; } \
|
||||
Operand lhs() const { return m_lhs; } \
|
||||
Operand rhs() const { return m_rhs; } \
|
||||
\
|
||||
private: \
|
||||
Operand m_dst; \
|
||||
Operand m_lhs; \
|
||||
Operand m_rhs; \
|
||||
};
|
||||
|
||||
JS_ENUMERATE_COMMON_BINARY_OPS_WITHOUT_FAST_PATH(JS_DECLARE_COMMON_BINARY_OP)
|
||||
|
@ -114,26 +112,25 @@ JS_ENUMERATE_COMMON_BINARY_OPS_WITH_FAST_PATH(JS_DECLARE_COMMON_BINARY_OP)
|
|||
O(UnaryMinus, unary_minus) \
|
||||
O(Typeof, typeof_)
|
||||
|
||||
#define JS_DECLARE_COMMON_UNARY_OP(OpTitleCase, op_snake_case) \
|
||||
class OpTitleCase final : public Instruction { \
|
||||
public: \
|
||||
OpTitleCase(Operand dst, Operand src) \
|
||||
: Instruction(Type::OpTitleCase, sizeof(*this)) \
|
||||
, m_dst(dst) \
|
||||
, m_src(src) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const; \
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const; \
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { } \
|
||||
\
|
||||
Operand dst() const { return m_dst; } \
|
||||
Operand src() const { return m_src; } \
|
||||
\
|
||||
private: \
|
||||
Operand m_dst; \
|
||||
Operand m_src; \
|
||||
#define JS_DECLARE_COMMON_UNARY_OP(OpTitleCase, op_snake_case) \
|
||||
class OpTitleCase final : public Instruction { \
|
||||
public: \
|
||||
OpTitleCase(Operand dst, Operand src) \
|
||||
: Instruction(Type::OpTitleCase, sizeof(*this)) \
|
||||
, m_dst(dst) \
|
||||
, m_src(src) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const; \
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const; \
|
||||
\
|
||||
Operand dst() const { return m_dst; } \
|
||||
Operand src() const { return m_src; } \
|
||||
\
|
||||
private: \
|
||||
Operand m_dst; \
|
||||
Operand m_src; \
|
||||
};
|
||||
|
||||
JS_ENUMERATE_COMMON_UNARY_OPS(JS_DECLARE_COMMON_UNARY_OP)
|
||||
|
@ -149,7 +146,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
|
||||
|
@ -170,7 +166,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
StringTableIndex source_index() const { return m_source_index; }
|
||||
|
@ -187,26 +182,25 @@ private:
|
|||
#define JS_ENUMERATE_NEW_BUILTIN_ERROR_OPS(O) \
|
||||
O(TypeError)
|
||||
|
||||
#define JS_DECLARE_NEW_BUILTIN_ERROR_OP(ErrorName) \
|
||||
class New##ErrorName final : public Instruction { \
|
||||
public: \
|
||||
New##ErrorName(Operand dst, StringTableIndex error_string) \
|
||||
: Instruction(Type::New##ErrorName, sizeof(*this)) \
|
||||
, m_dst(dst) \
|
||||
, m_error_string(error_string) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const; \
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const; \
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { } \
|
||||
\
|
||||
Operand dst() const { return m_dst; } \
|
||||
StringTableIndex error_string() const { return m_error_string; } \
|
||||
\
|
||||
private: \
|
||||
Operand m_dst; \
|
||||
StringTableIndex m_error_string; \
|
||||
#define JS_DECLARE_NEW_BUILTIN_ERROR_OP(ErrorName) \
|
||||
class New##ErrorName final : public Instruction { \
|
||||
public: \
|
||||
New##ErrorName(Operand dst, StringTableIndex error_string) \
|
||||
: Instruction(Type::New##ErrorName, sizeof(*this)) \
|
||||
, m_dst(dst) \
|
||||
, m_error_string(error_string) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const; \
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const; \
|
||||
\
|
||||
Operand dst() const { return m_dst; } \
|
||||
StringTableIndex error_string() const { return m_error_string; } \
|
||||
\
|
||||
private: \
|
||||
Operand m_dst; \
|
||||
StringTableIndex m_error_string; \
|
||||
};
|
||||
|
||||
JS_ENUMERATE_NEW_BUILTIN_ERROR_OPS(JS_DECLARE_NEW_BUILTIN_ERROR_OP)
|
||||
|
@ -227,7 +221,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
size_t length_impl(size_t excluded_names_count) const
|
||||
{
|
||||
|
@ -267,7 +260,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
|
||||
|
@ -314,7 +306,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
ReadonlySpan<Value> elements() const { return { m_elements, m_element_count }; }
|
||||
|
@ -337,7 +328,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand src() const { return m_src; }
|
||||
|
@ -361,7 +351,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand specifier() const { return m_specifier; }
|
||||
|
@ -384,7 +373,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand iterator() const { return m_iterator; }
|
||||
|
@ -405,7 +393,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand src() const { return m_src; }
|
||||
|
@ -429,7 +416,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
};
|
||||
|
||||
class EnterObjectEnvironment final : public Instruction {
|
||||
|
@ -442,7 +428,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand object() const { return m_object; }
|
||||
|
||||
|
@ -460,7 +445,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
|
||||
|
@ -482,7 +466,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
IdentifierTableIndex identifier() const { return m_identifier; }
|
||||
EnvironmentMode mode() const { return m_mode; }
|
||||
|
@ -516,7 +499,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
IdentifierTableIndex identifier() const { return m_identifier; }
|
||||
Operand src() const { return m_src; }
|
||||
|
@ -543,7 +525,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
size_t index() const { return m_index; }
|
||||
Operand dst() const { return Operand(Operand::Type::Local, m_index); }
|
||||
|
@ -567,7 +548,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
IdentifierTableIndex identifier() const { return m_identifier; }
|
||||
u32 cache_index() const { return m_cache_index; }
|
||||
|
@ -593,7 +573,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
IdentifierTableIndex identifier() const { return m_identifier; }
|
||||
|
@ -617,7 +596,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
IdentifierTableIndex identifier() const { return m_identifier; }
|
||||
|
@ -640,7 +618,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
IdentifierTableIndex identifier() const { return m_identifier; }
|
||||
|
@ -663,7 +640,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand base() const { return m_base; }
|
||||
|
@ -691,7 +667,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand base() const { return m_base; }
|
||||
|
@ -719,7 +694,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand base() const { return m_base; }
|
||||
|
@ -743,7 +717,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand base() const { return m_base; }
|
||||
|
@ -778,7 +751,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand base() const { return m_base; }
|
||||
IdentifierTableIndex property() const { return m_property; }
|
||||
|
@ -809,7 +781,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand base() const { return m_base; }
|
||||
Operand this_value() const { return m_this_value; }
|
||||
|
@ -840,7 +811,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand base() const { return m_base; }
|
||||
IdentifierTableIndex property() const { return m_property; }
|
||||
|
@ -865,7 +835,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand base() const { return m_base; }
|
||||
|
@ -890,7 +859,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand base() const { return m_base; }
|
||||
|
@ -916,7 +884,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand base() const { return m_base; }
|
||||
|
@ -941,7 +908,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand base() const { return m_base; }
|
||||
|
@ -968,7 +934,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand base() const { return m_base; }
|
||||
Operand property() const { return m_property; }
|
||||
|
@ -996,7 +961,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand base() const { return m_base; }
|
||||
Operand property() const { return m_property; }
|
||||
|
@ -1024,7 +988,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand base() const { return m_base; }
|
||||
|
@ -1054,7 +1017,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
private:
|
||||
Operand m_dst;
|
||||
|
@ -1090,13 +1052,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void 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 };
|
||||
}
|
||||
|
||||
auto& true_target() const { return m_true_target; }
|
||||
auto& false_target() const { return m_false_target; }
|
||||
|
@ -1196,7 +1151,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
private:
|
||||
Operand m_dst;
|
||||
|
@ -1231,7 +1185,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
private:
|
||||
Operand m_dst;
|
||||
|
@ -1254,7 +1207,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand arguments() const { return m_arguments; }
|
||||
|
@ -1279,7 +1231,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Optional<Operand> const& super_class() const { return m_super_class; }
|
||||
|
@ -1306,7 +1257,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
FunctionExpression const& function_node() const { return m_function_node; }
|
||||
|
@ -1330,7 +1280,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
ScopeNode const& scope_node() const { return m_scope_node; }
|
||||
|
||||
|
@ -1350,7 +1299,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Optional<Operand> const& value() const { return m_value; }
|
||||
|
||||
|
@ -1368,7 +1316,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
|
||||
|
@ -1387,7 +1334,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand src() const { return m_src; }
|
||||
|
@ -1407,7 +1353,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
|
||||
|
@ -1426,7 +1371,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand src() const { return m_src; }
|
||||
|
@ -1448,7 +1392,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand src() const { return m_src; }
|
||||
|
||||
|
@ -1466,7 +1409,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand src() const { return m_src; }
|
||||
|
||||
|
@ -1484,7 +1426,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand src() const { return m_src; }
|
||||
|
||||
|
@ -1502,7 +1443,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand src() const { return m_src; }
|
||||
|
||||
|
@ -1514,34 +1454,19 @@ class EnterUnwindContext final : public Instruction {
|
|||
public:
|
||||
constexpr static bool IsTerminator = true;
|
||||
|
||||
EnterUnwindContext(Label entry_point, Optional<Label> handler, Optional<Label> finalizer)
|
||||
EnterUnwindContext(Label entry_point)
|
||||
: Instruction(Type::EnterUnwindContext, sizeof(*this))
|
||||
, m_entry_point(move(entry_point))
|
||||
, m_handler(move(handler))
|
||||
, m_finalizer(move(finalizer))
|
||||
{
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const& from, BasicBlock const& to)
|
||||
{
|
||||
if (&m_entry_point.block() == &from)
|
||||
m_entry_point = Label { to };
|
||||
if (m_handler.has_value() && &m_handler->block() == &from)
|
||||
m_handler = Label { to };
|
||||
if (m_finalizer.has_value() && &m_finalizer->block() == &from)
|
||||
m_finalizer = Label { to };
|
||||
}
|
||||
|
||||
auto& entry_point() const { return m_entry_point; }
|
||||
auto& handler() const { return m_handler; }
|
||||
auto& finalizer() const { return m_finalizer; }
|
||||
|
||||
private:
|
||||
Label m_entry_point;
|
||||
Optional<Label> m_handler;
|
||||
Optional<Label> m_finalizer;
|
||||
};
|
||||
|
||||
class ScheduleJump final : public Instruction {
|
||||
|
@ -1567,11 +1492,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const& from, BasicBlock const& to)
|
||||
{
|
||||
if (&m_target.block() == &from)
|
||||
m_target = Label { to };
|
||||
}
|
||||
|
||||
private:
|
||||
Label m_target;
|
||||
|
@ -1586,7 +1506,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
};
|
||||
|
||||
class LeaveUnwindContext final : public Instruction {
|
||||
|
@ -1598,7 +1517,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
};
|
||||
|
||||
class ContinuePendingUnwind final : public Instruction {
|
||||
|
@ -1613,11 +1531,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const& from, BasicBlock const& to)
|
||||
{
|
||||
if (&m_resume_target.block() == &from)
|
||||
m_resume_target = Label { to };
|
||||
}
|
||||
|
||||
auto& resume_target() const { return m_resume_target; }
|
||||
|
||||
|
@ -1644,11 +1557,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void 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 };
|
||||
}
|
||||
|
||||
auto& continuation() const { return m_continuation_label; }
|
||||
Operand value() const { return m_value; }
|
||||
|
@ -1671,11 +1579,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const& from, BasicBlock const& to)
|
||||
{
|
||||
if (&m_continuation_label.block() == &from)
|
||||
m_continuation_label = Label { to };
|
||||
}
|
||||
|
||||
auto& continuation() const { return m_continuation_label; }
|
||||
Operand argument() const { return m_argument; }
|
||||
|
@ -1697,7 +1600,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand iterable() const { return m_iterable; }
|
||||
|
@ -1720,7 +1622,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand object() const { return m_object; }
|
||||
Operand iterator_record() const { return m_iterator_record; }
|
||||
|
@ -1741,7 +1642,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand next_method() const { return m_next_method; }
|
||||
Operand iterator_record() const { return m_iterator_record; }
|
||||
|
@ -1763,7 +1663,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand object() const { return m_object; }
|
||||
|
@ -1786,7 +1685,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand object() const { return m_object; }
|
||||
|
@ -1808,7 +1706,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand iterator_record() const { return m_iterator_record; }
|
||||
Completion::Type completion_type() const { return m_completion_type; }
|
||||
|
@ -1832,7 +1729,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand iterator_record() const { return m_iterator_record; }
|
||||
Completion::Type completion_type() const { return m_completion_type; }
|
||||
|
@ -1855,7 +1751,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
Operand iterator_record() const { return m_iterator_record; }
|
||||
|
@ -1875,7 +1770,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
|
||||
|
@ -1893,7 +1787,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
|
||||
|
@ -1911,7 +1804,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
|
||||
|
@ -1929,7 +1821,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
|
||||
|
@ -1948,7 +1839,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand dst() const { return m_dst; }
|
||||
IdentifierTableIndex identifier() const { return m_identifier; }
|
||||
|
@ -1970,7 +1860,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
Operand value() const { return m_value; }
|
||||
|
||||
|
@ -1989,7 +1878,6 @@ public:
|
|||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
|
||||
private:
|
||||
StringView m_text;
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Bytecode/PassManager.h>
|
||||
|
||||
namespace JS::Bytecode::Passes {
|
||||
|
||||
void DumpCFG::perform(PassPipelineExecutable& executable)
|
||||
{
|
||||
started();
|
||||
|
||||
VERIFY(executable.cfg.has_value());
|
||||
outln(m_file, "CFG Dump for {} basic blocks:", executable.executable.basic_blocks.size());
|
||||
for (auto& entry : executable.cfg.value()) {
|
||||
for (auto& value : entry.value)
|
||||
outln(m_file, "{} -> {}", entry.key->name(), value->name());
|
||||
}
|
||||
outln(m_file);
|
||||
|
||||
finished();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,220 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/TemporaryChange.h>
|
||||
#include <LibJS/Bytecode/PassManager.h>
|
||||
|
||||
namespace JS::Bytecode::Passes {
|
||||
|
||||
struct UnwindFrame {
|
||||
BasicBlock const* handler;
|
||||
BasicBlock const* finalizer;
|
||||
Vector<BasicBlock const*> finalizer_targets;
|
||||
};
|
||||
|
||||
static HashTable<BasicBlock const*> seen_blocks;
|
||||
static Vector<UnwindFrame> unwind_frames;
|
||||
|
||||
static BasicBlock const* next_handler_or_finalizer()
|
||||
{
|
||||
return unwind_frames.last().handler ?: unwind_frames.last().finalizer;
|
||||
}
|
||||
|
||||
static void generate_cfg_for_block(BasicBlock const& current_block, PassPipelineExecutable& executable)
|
||||
{
|
||||
seen_blocks.set(¤t_block);
|
||||
|
||||
auto enter_label = [&](Label const& label, BasicBlock const& entering_block) {
|
||||
executable.cfg->ensure(&entering_block).set(&label.block());
|
||||
executable.inverted_cfg->ensure(&label.block()).set(&entering_block);
|
||||
|
||||
// The finalizers and handlers of an unwind context are handled separately
|
||||
if (!seen_blocks.contains(&label.block())
|
||||
&& &label.block() != unwind_frames.last().handler
|
||||
&& &label.block() != unwind_frames.last().finalizer)
|
||||
generate_cfg_for_block(label.block(), executable);
|
||||
};
|
||||
|
||||
if (auto const* block = next_handler_or_finalizer())
|
||||
enter_label(Label { *block }, current_block);
|
||||
|
||||
for (InstructionStreamIterator it { current_block.instruction_stream() }; !it.at_end(); ++it) {
|
||||
auto const& instruction = *it;
|
||||
|
||||
if (instruction.type() == Instruction::Type::LeaveUnwindContext) {
|
||||
if (unwind_frames.last().finalizer && unwind_frames.last().finalizer != ¤t_block)
|
||||
dbgln("FIXME: Popping finalizer from the unwind context from outside the finalizer");
|
||||
unwind_frames.take_last();
|
||||
|
||||
if (auto const* block = next_handler_or_finalizer())
|
||||
enter_label(Label { *block }, current_block);
|
||||
}
|
||||
|
||||
if (!instruction.is_terminator())
|
||||
continue;
|
||||
|
||||
using enum Instruction::Type;
|
||||
switch (instruction.type()) {
|
||||
case Jump: {
|
||||
auto true_target = *static_cast<Op::Jump const&>(instruction).true_target();
|
||||
enter_label(true_target, current_block);
|
||||
return;
|
||||
}
|
||||
case JumpIf:
|
||||
case JumpNullish:
|
||||
case JumpUndefined: {
|
||||
// FIXME: It would be nice if we could avoid this copy, if we know that the unwind context stays the same in both paths
|
||||
// Or with a COW capable Vector alternative
|
||||
// Note: We might partially unwind here, so we need to make a copy of
|
||||
// the current context to assure that the falsy code path has the same one
|
||||
{
|
||||
TemporaryChange saved_context { unwind_frames, unwind_frames };
|
||||
|
||||
auto true_target = *static_cast<Op::Jump const&>(instruction).true_target();
|
||||
enter_label(true_target, current_block);
|
||||
}
|
||||
|
||||
auto false_target = *static_cast<Op::Jump const&>(instruction).false_target();
|
||||
enter_label(false_target, current_block);
|
||||
return;
|
||||
}
|
||||
case Yield: {
|
||||
auto continuation = static_cast<Op::Yield const&>(instruction).continuation();
|
||||
if (continuation.has_value()) {
|
||||
executable.exported_blocks->set(&continuation->block());
|
||||
enter_label(*continuation, current_block);
|
||||
} else if (auto const* finalizer = unwind_frames.last().finalizer) {
|
||||
enter_label(Label { *finalizer }, current_block);
|
||||
unwind_frames.last().finalizer_targets.append(nullptr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case Await: {
|
||||
auto const& continuation = static_cast<Op::Await const&>(instruction).continuation();
|
||||
executable.exported_blocks->set(&continuation.block());
|
||||
enter_label(continuation, current_block);
|
||||
return;
|
||||
}
|
||||
case EnterUnwindContext: {
|
||||
auto entry_point = static_cast<Op::EnterUnwindContext const&>(instruction).entry_point();
|
||||
auto handler_target = static_cast<Op::EnterUnwindContext const&>(instruction).handler();
|
||||
auto finalizer_target = static_cast<Op::EnterUnwindContext const&>(instruction).finalizer();
|
||||
|
||||
// We keep the frame alive here on the stack, to save some allocation size
|
||||
UnwindFrame frame {
|
||||
.handler = handler_target.has_value() ? &handler_target->block() : nullptr,
|
||||
.finalizer = finalizer_target.has_value() ? &finalizer_target->block() : nullptr,
|
||||
.finalizer_targets = {}
|
||||
};
|
||||
|
||||
unwind_frames.append(frame);
|
||||
|
||||
{
|
||||
// This will enter the handler and finalizer when needed.
|
||||
TemporaryChange saved_context { unwind_frames, unwind_frames };
|
||||
enter_label(entry_point, current_block);
|
||||
}
|
||||
frame.handler = nullptr;
|
||||
if (handler_target.has_value()) {
|
||||
// We manually generate the CFG, because we previously skiped it
|
||||
TemporaryChange saved_context { unwind_frames, unwind_frames };
|
||||
generate_cfg_for_block(handler_target->block(), executable);
|
||||
}
|
||||
|
||||
if (finalizer_target.has_value()) {
|
||||
// We manually generate the CFG, because we previously halted before entering it
|
||||
generate_cfg_for_block(finalizer_target->block(), executable);
|
||||
|
||||
// We previously halted execution when we would enter the finalizer,
|
||||
// So we now have to visit all possible targets
|
||||
// This mainly affects the ScheduleJump instruction
|
||||
for (auto const* block : frame.finalizer_targets) {
|
||||
if (block == nullptr) {
|
||||
// This signals a `return`, which we do not handle specially, so we skip
|
||||
continue;
|
||||
}
|
||||
if (!seen_blocks.contains(block))
|
||||
generate_cfg_for_block(*block, executable);
|
||||
}
|
||||
} else {
|
||||
unwind_frames.take_last();
|
||||
VERIFY(frame.finalizer_targets.is_empty());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
case ContinuePendingUnwind: {
|
||||
auto resume_target = static_cast<Op::ContinuePendingUnwind const&>(instruction).resume_target();
|
||||
enter_label(resume_target, current_block);
|
||||
// Note: We already mark these possible control flow changes further up, but when we get
|
||||
// get better error awareness, being explicit here will be required
|
||||
if (auto const* handler = unwind_frames.last().handler)
|
||||
enter_label(Label { *handler }, current_block);
|
||||
else if (auto const* finalizer = unwind_frames.last().finalizer)
|
||||
enter_label(Label { *finalizer }, current_block);
|
||||
|
||||
return;
|
||||
}
|
||||
case Throw:
|
||||
// Note: We technically register that we enter the handler in the prelude,
|
||||
// but lets be correct and mark it again,
|
||||
// this will be useful once we have more info on which instruction can
|
||||
// actually fail
|
||||
if (auto const* handler = unwind_frames.last().handler) {
|
||||
enter_label(Label { *handler }, current_block);
|
||||
} else if (auto const* finalizer = unwind_frames.last().finalizer) {
|
||||
enter_label(Label { *finalizer }, current_block);
|
||||
// Note: This error might bubble through the finalizer to the next handler/finalizer,
|
||||
// This is currently marked in the general path
|
||||
}
|
||||
return;
|
||||
case Return:
|
||||
if (auto const* finalizer = unwind_frames.last().finalizer) {
|
||||
enter_label(Label { *finalizer }, current_block);
|
||||
unwind_frames.last().finalizer_targets.append(nullptr);
|
||||
}
|
||||
return;
|
||||
case ScheduleJump: {
|
||||
enter_label(Label { *unwind_frames.last().finalizer }, current_block);
|
||||
|
||||
unwind_frames.last().finalizer_targets.append(
|
||||
&static_cast<Op::ScheduleJump const&>(instruction).target().block());
|
||||
return;
|
||||
}
|
||||
case End:
|
||||
return;
|
||||
default:
|
||||
dbgln("Unhandled terminator instruction: `{}`", instruction.to_byte_string(executable.executable));
|
||||
VERIFY_NOT_REACHED();
|
||||
};
|
||||
}
|
||||
|
||||
// We have left the block, but not through a designated terminator,
|
||||
// so before we return, we need to check if we still need to go through a finalizer
|
||||
if (auto const* finalizer = unwind_frames.last().finalizer)
|
||||
enter_label(Label { *finalizer }, current_block);
|
||||
}
|
||||
|
||||
void GenerateCFG::perform(PassPipelineExecutable& executable)
|
||||
{
|
||||
started();
|
||||
|
||||
executable.cfg = HashMap<BasicBlock const*, HashTable<BasicBlock const*>> {};
|
||||
executable.inverted_cfg = HashMap<BasicBlock const*, HashTable<BasicBlock const*>> {};
|
||||
executable.exported_blocks = HashTable<BasicBlock const*> {};
|
||||
|
||||
seen_blocks.clear();
|
||||
unwind_frames.clear();
|
||||
UnwindFrame top_level_frame = {};
|
||||
|
||||
unwind_frames.append(top_level_frame);
|
||||
|
||||
generate_cfg_for_block(*executable.executable.basic_blocks.first(), executable);
|
||||
|
||||
finished();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,177 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Bytecode/PassManager.h>
|
||||
|
||||
namespace JS::Bytecode::Passes {
|
||||
|
||||
void MergeBlocks::perform(PassPipelineExecutable& executable)
|
||||
{
|
||||
started();
|
||||
|
||||
VERIFY(executable.cfg.has_value());
|
||||
VERIFY(executable.inverted_cfg.has_value());
|
||||
auto cfg = executable.cfg.release_value();
|
||||
auto inverted_cfg = executable.inverted_cfg.release_value();
|
||||
|
||||
// Figure out which blocks can be merged
|
||||
HashTable<BasicBlock const*> blocks_to_merge;
|
||||
HashMap<BasicBlock const*, BasicBlock const*> blocks_to_replace;
|
||||
Vector<BasicBlock const*> blocks_to_remove;
|
||||
Vector<size_t> boundaries;
|
||||
|
||||
for (auto& entry : cfg) {
|
||||
if (entry.value.size() != 1)
|
||||
continue;
|
||||
|
||||
if (executable.exported_blocks->contains(*entry.value.begin()))
|
||||
continue;
|
||||
|
||||
if (!entry.key->is_terminated())
|
||||
continue;
|
||||
|
||||
if (entry.key->terminator()->type() != Instruction::Type::Jump)
|
||||
continue;
|
||||
|
||||
{
|
||||
InstructionStreamIterator it { entry.key->instruction_stream() };
|
||||
auto& first_instruction = *it;
|
||||
if (first_instruction.type() == Instruction::Type::Jump) {
|
||||
auto const* replacing_block = &static_cast<Op::Jump const&>(first_instruction).true_target()->block();
|
||||
if (replacing_block != entry.key) {
|
||||
blocks_to_replace.set(entry.key, replacing_block);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (auto cfg_iter = inverted_cfg.find(*entry.value.begin()); cfg_iter != inverted_cfg.end()) {
|
||||
auto& predecessor_entry = cfg_iter->value;
|
||||
if (predecessor_entry.size() != 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
// The two blocks are safe to merge.
|
||||
blocks_to_merge.set(entry.key);
|
||||
}
|
||||
|
||||
for (auto& entry : blocks_to_replace) {
|
||||
auto const* replacement = entry.value;
|
||||
for (;;) {
|
||||
auto lookup = blocks_to_replace.get(replacement);
|
||||
if (!lookup.has_value())
|
||||
break;
|
||||
if (replacement == *lookup)
|
||||
break;
|
||||
replacement = *lookup;
|
||||
}
|
||||
entry.value = replacement;
|
||||
}
|
||||
|
||||
auto replace_blocks = [&](auto& blocks, auto& replacement) {
|
||||
Optional<size_t> first_successor_position;
|
||||
for (auto& entry : blocks) {
|
||||
blocks_to_remove.append(entry);
|
||||
auto it = executable.executable.basic_blocks.find_if([entry](auto& block) { return entry == block; });
|
||||
VERIFY(!it.is_end());
|
||||
if (!first_successor_position.has_value())
|
||||
first_successor_position = it.index();
|
||||
}
|
||||
for (auto& block : executable.executable.basic_blocks) {
|
||||
InstructionStreamIterator it { block->instruction_stream() };
|
||||
while (!it.at_end()) {
|
||||
auto& instruction = *it;
|
||||
++it;
|
||||
for (auto& entry : blocks)
|
||||
const_cast<Instruction&>(instruction).replace_references(*entry, replacement);
|
||||
}
|
||||
}
|
||||
return first_successor_position;
|
||||
};
|
||||
|
||||
for (auto& entry : blocks_to_replace) {
|
||||
AK::Array candidates { entry.key };
|
||||
(void)replace_blocks(candidates, *entry.value);
|
||||
}
|
||||
|
||||
while (!blocks_to_merge.is_empty()) {
|
||||
auto it = blocks_to_merge.begin();
|
||||
auto const* current_block = *it;
|
||||
blocks_to_merge.remove(it);
|
||||
|
||||
Vector<BasicBlock const*> successors { current_block };
|
||||
for (;;) {
|
||||
auto const* last = successors.last();
|
||||
auto entry = cfg.find(last);
|
||||
if (entry == cfg.end())
|
||||
break;
|
||||
auto const* successor = *entry->value.begin();
|
||||
successors.append(successor);
|
||||
|
||||
if (!blocks_to_merge.remove(successor))
|
||||
break;
|
||||
}
|
||||
|
||||
auto blocks_to_merge_copy = blocks_to_merge;
|
||||
// We need to do the following multiple times, due to it not being
|
||||
// guaranteed, that the blocks are in sequential order
|
||||
bool did_prepend = true;
|
||||
while (did_prepend) {
|
||||
did_prepend = false;
|
||||
for (auto const* last : blocks_to_merge) {
|
||||
auto entry = cfg.find(last);
|
||||
if (entry == cfg.end())
|
||||
continue;
|
||||
auto const* successor = *entry->value.begin();
|
||||
if (successor == successors.first()) {
|
||||
successors.prepend(last);
|
||||
blocks_to_merge_copy.remove(last);
|
||||
did_prepend = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blocks_to_merge = move(blocks_to_merge_copy);
|
||||
|
||||
StringBuilder builder;
|
||||
builder.append("merge"sv);
|
||||
for (auto& entry : successors) {
|
||||
builder.append('.');
|
||||
builder.append(entry->name());
|
||||
}
|
||||
|
||||
auto new_block = BasicBlock::create(MUST(builder.to_string()));
|
||||
auto& block = *new_block;
|
||||
auto first_successor_position = replace_blocks(successors, *new_block);
|
||||
VERIFY(first_successor_position.has_value());
|
||||
|
||||
size_t last_successor_index = successors.size() - 1;
|
||||
for (size_t i = 0; i < successors.size(); ++i) {
|
||||
auto& entry = successors[i];
|
||||
InstructionStreamIterator it { entry->instruction_stream() };
|
||||
while (!it.at_end()) {
|
||||
auto& instruction = *it;
|
||||
++it;
|
||||
if (instruction.is_terminator() && last_successor_index != i)
|
||||
break;
|
||||
// FIXME: Use a single memcpy to copy the whole block at once.
|
||||
auto instruction_size = instruction.length();
|
||||
size_t slot_offset = block.size();
|
||||
block.grow(instruction_size);
|
||||
auto* next_slot = block.data() + slot_offset;
|
||||
memcpy(next_slot, &instruction, instruction_size);
|
||||
}
|
||||
}
|
||||
|
||||
executable.executable.basic_blocks.insert(*first_successor_position, move(new_block));
|
||||
}
|
||||
|
||||
executable.executable.basic_blocks.remove_all_matching([&blocks_to_remove](auto& candidate) { return blocks_to_remove.contains_slow(candidate.ptr()); });
|
||||
|
||||
finished();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Bytecode/PassManager.h>
|
||||
|
||||
namespace JS::Bytecode::Passes {
|
||||
|
||||
void PlaceBlocks::perform(PassPipelineExecutable& executable)
|
||||
{
|
||||
started();
|
||||
|
||||
VERIFY(executable.cfg.has_value());
|
||||
auto cfg = executable.cfg.release_value();
|
||||
|
||||
Vector<BasicBlock&> replaced_blocks;
|
||||
HashTable<BasicBlock const*> reachable_blocks;
|
||||
|
||||
// Visit the blocks in CFG order
|
||||
Function<void(BasicBlock const*)> visit = [&](auto* block) {
|
||||
if (reachable_blocks.contains(block))
|
||||
return;
|
||||
|
||||
reachable_blocks.set(block);
|
||||
replaced_blocks.append(*const_cast<BasicBlock*>(block));
|
||||
|
||||
auto children = cfg.find(block);
|
||||
if (children == cfg.end())
|
||||
return;
|
||||
|
||||
for (auto& entry : children->value)
|
||||
visit(entry);
|
||||
};
|
||||
|
||||
// Make sure to visit the entry block first
|
||||
visit(executable.executable.basic_blocks.first());
|
||||
|
||||
for (auto& entry : cfg)
|
||||
visit(entry.key);
|
||||
|
||||
// Put the unreferenced blocks back in at the end
|
||||
for (auto& entry : static_cast<Vector<NonnullOwnPtr<BasicBlock>>&>(executable.executable.basic_blocks)) {
|
||||
if (reachable_blocks.contains(entry.ptr()))
|
||||
(void)entry.leak_ptr();
|
||||
else
|
||||
replaced_blocks.append(*entry.leak_ptr()); // Don't try to do DCE here.
|
||||
}
|
||||
|
||||
executable.executable.basic_blocks.clear();
|
||||
for (auto& block : replaced_blocks)
|
||||
executable.executable.basic_blocks.append(adopt_own(block));
|
||||
|
||||
finished();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Bytecode/PassManager.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace JS::Bytecode::Passes {
|
||||
|
||||
void UnifySameBlocks::perform(PassPipelineExecutable& executable)
|
||||
{
|
||||
started();
|
||||
|
||||
VERIFY(executable.cfg.has_value());
|
||||
VERIFY(executable.inverted_cfg.has_value());
|
||||
auto cfg = executable.cfg.release_value();
|
||||
auto inverted_cfg = executable.inverted_cfg.release_value();
|
||||
|
||||
HashMap<BasicBlock const*, BasicBlock const*> equal_blocks;
|
||||
|
||||
for (size_t i = 0; i < executable.executable.basic_blocks.size(); ++i) {
|
||||
auto& block = executable.executable.basic_blocks[i];
|
||||
auto block_bytes = block->instruction_stream();
|
||||
for (auto& candidate_block : executable.executable.basic_blocks.span().slice(i + 1)) {
|
||||
if (equal_blocks.contains(&*candidate_block))
|
||||
continue;
|
||||
// FIXME: This can probably be relaxed a bit...
|
||||
if (candidate_block->size() != block->size())
|
||||
continue;
|
||||
if (candidate_block->finalizer() != block->finalizer())
|
||||
continue;
|
||||
if (candidate_block->handler() != block->handler())
|
||||
continue;
|
||||
|
||||
auto candidate_bytes = candidate_block->instruction_stream();
|
||||
if (memcmp(candidate_bytes.data(), block_bytes.data(), candidate_block->size()) == 0)
|
||||
equal_blocks.set(candidate_block.ptr(), block);
|
||||
}
|
||||
}
|
||||
|
||||
auto replace_blocks = [&](auto& match, auto& replacement) {
|
||||
Optional<size_t> first_successor_position;
|
||||
auto it = executable.executable.basic_blocks.find_if([match](auto& block) { return match == block; });
|
||||
VERIFY(!it.is_end());
|
||||
executable.executable.basic_blocks.remove(it.index());
|
||||
if (!first_successor_position.has_value())
|
||||
first_successor_position = it.index();
|
||||
|
||||
for (auto& block : executable.executable.basic_blocks) {
|
||||
InstructionStreamIterator it { block->instruction_stream() };
|
||||
while (!it.at_end()) {
|
||||
auto& instruction = *it;
|
||||
++it;
|
||||
const_cast<Instruction&>(instruction).replace_references(*match, replacement);
|
||||
}
|
||||
}
|
||||
return first_successor_position;
|
||||
};
|
||||
|
||||
for (auto& entry : equal_blocks)
|
||||
(void)replace_blocks(entry.key, *entry.value);
|
||||
|
||||
finished();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,127 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibCore/ElapsedTimer.h>
|
||||
#include <LibJS/Bytecode/BasicBlock.h>
|
||||
#include <LibJS/Bytecode/Generator.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
struct PassPipelineExecutable {
|
||||
Executable& executable;
|
||||
Optional<HashMap<BasicBlock const*, HashTable<BasicBlock const*>>> cfg {};
|
||||
Optional<HashMap<BasicBlock const*, HashTable<BasicBlock const*>>> inverted_cfg {};
|
||||
Optional<HashTable<BasicBlock const*>> exported_blocks {};
|
||||
};
|
||||
|
||||
class Pass {
|
||||
public:
|
||||
Pass() = default;
|
||||
virtual ~Pass() = default;
|
||||
|
||||
virtual void perform(PassPipelineExecutable&) = 0;
|
||||
void started()
|
||||
{
|
||||
m_timer.start();
|
||||
}
|
||||
void finished()
|
||||
{
|
||||
m_time_difference = m_timer.elapsed_time();
|
||||
}
|
||||
|
||||
u64 elapsed() const { return m_time_difference.to_microseconds(); }
|
||||
|
||||
protected:
|
||||
Core::ElapsedTimer m_timer;
|
||||
Duration m_time_difference {};
|
||||
};
|
||||
|
||||
class PassManager : public Pass {
|
||||
public:
|
||||
PassManager() = default;
|
||||
~PassManager() override = default;
|
||||
|
||||
void add(NonnullOwnPtr<Pass> pass) { m_passes.append(move(pass)); }
|
||||
|
||||
template<typename PassT, typename... Args>
|
||||
void add(Args&&... args) { m_passes.append(make<PassT>(forward<Args>(args)...)); }
|
||||
|
||||
void perform(Executable& executable)
|
||||
{
|
||||
PassPipelineExecutable pipeline_executable { executable };
|
||||
perform(pipeline_executable);
|
||||
}
|
||||
|
||||
virtual void perform(PassPipelineExecutable& executable) override
|
||||
{
|
||||
started();
|
||||
for (auto& pass : m_passes)
|
||||
pass->perform(executable);
|
||||
finished();
|
||||
}
|
||||
|
||||
private:
|
||||
Vector<NonnullOwnPtr<Pass>> m_passes;
|
||||
};
|
||||
|
||||
namespace Passes {
|
||||
|
||||
class GenerateCFG : public Pass {
|
||||
public:
|
||||
GenerateCFG() = default;
|
||||
~GenerateCFG() override = default;
|
||||
|
||||
private:
|
||||
virtual void perform(PassPipelineExecutable&) override;
|
||||
};
|
||||
|
||||
class MergeBlocks : public Pass {
|
||||
public:
|
||||
MergeBlocks() = default;
|
||||
~MergeBlocks() override = default;
|
||||
|
||||
private:
|
||||
virtual void perform(PassPipelineExecutable&) override;
|
||||
};
|
||||
|
||||
class PlaceBlocks : public Pass {
|
||||
public:
|
||||
PlaceBlocks() = default;
|
||||
~PlaceBlocks() override = default;
|
||||
|
||||
private:
|
||||
virtual void perform(PassPipelineExecutable&) override;
|
||||
};
|
||||
|
||||
class UnifySameBlocks : public Pass {
|
||||
public:
|
||||
UnifySameBlocks() = default;
|
||||
~UnifySameBlocks() override = default;
|
||||
|
||||
private:
|
||||
virtual void perform(PassPipelineExecutable&) override;
|
||||
};
|
||||
|
||||
class DumpCFG : public Pass {
|
||||
public:
|
||||
DumpCFG(FILE* file)
|
||||
: m_file(file)
|
||||
{
|
||||
}
|
||||
|
||||
~DumpCFG() override = default;
|
||||
|
||||
private:
|
||||
virtual void perform(PassPipelineExecutable&) override;
|
||||
|
||||
FILE* m_file { nullptr };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -9,11 +9,6 @@ set(SOURCES
|
|||
Bytecode/IdentifierTable.cpp
|
||||
Bytecode/Instruction.cpp
|
||||
Bytecode/Interpreter.cpp
|
||||
Bytecode/Pass/DumpCFG.cpp
|
||||
Bytecode/Pass/GenerateCFG.cpp
|
||||
Bytecode/Pass/MergeBlocks.cpp
|
||||
Bytecode/Pass/PlaceBlocks.cpp
|
||||
Bytecode/Pass/UnifySameBlocks.cpp
|
||||
Bytecode/RegexTable.cpp
|
||||
Bytecode/StringTable.cpp
|
||||
Console.cpp
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue