summaryrefslogtreecommitdiff
path: root/Userland/Libraries
diff options
context:
space:
mode:
authorMatthew Olsson <matthewcolsson@gmail.com>2021-06-13 12:24:40 -0700
committerAndreas Kling <kling@serenityos.org>2021-06-19 09:38:26 +0200
commitf39ab2e60aa136f2a5d164109a27465654ea6f13 (patch)
tree9a9fa01ca0122299b904f90c3892f6da28c8f2f5 /Userland/Libraries
parent3ee627909affafdd8d51df8272e32a7d55f3ca9d (diff)
downloadserenity-f39ab2e60aa136f2a5d164109a27465654ea6f13.zip
LibJS: Add JumpUndefined bytecode
Diffstat (limited to 'Userland/Libraries')
-rw-r--r--Userland/Libraries/LibJS/Bytecode/Instruction.h1
-rw-r--r--Userland/Libraries/LibJS/Bytecode/Op.cpp18
-rw-r--r--Userland/Libraries/LibJS/Bytecode/Op.h11
-rw-r--r--Userland/Libraries/LibJS/Bytecode/Pass/GenerateCFG.cpp2
4 files changed, 31 insertions, 1 deletions
diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h
index ac0e8de028..e3ca74d91d 100644
--- a/Userland/Libraries/LibJS/Bytecode/Instruction.h
+++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h
@@ -40,6 +40,7 @@
O(Jump) \
O(JumpConditional) \
O(JumpNullish) \
+ O(JumpUndefined) \
O(Call) \
O(NewFunction) \
O(Return) \
diff --git a/Userland/Libraries/LibJS/Bytecode/Op.cpp b/Userland/Libraries/LibJS/Bytecode/Op.cpp
index 6dfe48a42e..607878882a 100644
--- a/Userland/Libraries/LibJS/Bytecode/Op.cpp
+++ b/Userland/Libraries/LibJS/Bytecode/Op.cpp
@@ -195,6 +195,17 @@ void JumpNullish::execute_impl(Bytecode::Interpreter& interpreter) const
interpreter.jump(m_false_target.value());
}
+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());
+}
+
void Call::execute_impl(Bytecode::Interpreter& interpreter) const
{
auto callee = interpreter.reg(m_callee);
@@ -439,6 +450,13 @@ String JumpNullish::to_string_impl(Bytecode::Executable const&) const
return String::formatted("JumpNullish null:{} nonnull:{}", true_string, false_string);
}
+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);
+}
+
String Call::to_string_impl(Bytecode::Executable const&) const
{
StringBuilder builder;
diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h
index 653b9d1889..af93adb28b 100644
--- a/Userland/Libraries/LibJS/Bytecode/Op.h
+++ b/Userland/Libraries/LibJS/Bytecode/Op.h
@@ -377,6 +377,17 @@ public:
String to_string_impl(Bytecode::Executable const&) const;
};
+class JumpUndefined final : public Jump {
+public:
+ explicit JumpUndefined(Optional<Label> true_target = {}, Optional<Label> false_target = {})
+ : Jump(Type::JumpUndefined, move(true_target), move(false_target))
+ {
+ }
+
+ void execute_impl(Bytecode::Interpreter&) const;
+ String to_string_impl(Bytecode::Executable const&) const;
+};
+
// NOTE: This instruction is variable-width depending on the number of arguments!
class Call final : public Instruction {
public:
diff --git a/Userland/Libraries/LibJS/Bytecode/Pass/GenerateCFG.cpp b/Userland/Libraries/LibJS/Bytecode/Pass/GenerateCFG.cpp
index 167e3c6052..e6cafc443d 100644
--- a/Userland/Libraries/LibJS/Bytecode/Pass/GenerateCFG.cpp
+++ b/Userland/Libraries/LibJS/Bytecode/Pass/GenerateCFG.cpp
@@ -58,7 +58,7 @@ void GenerateCFG::perform(PassPipelineExecutable& executable)
continue;
}
- if (instruction.type() == Instruction::Type::JumpConditional || instruction.type() == Instruction::Type::JumpNullish) {
+ if (instruction.type() == Instruction::Type::JumpConditional || instruction.type() == Instruction::Type::JumpNullish || instruction.type() == Instruction::Type::JumpUndefined) {
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();