1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 05:38:11 +00:00

LibJS: Generate bytecode for entering nested lexical environments

This adds a new PushLexicalEnvironment instruction that creates a new
LexicalEnvironment and pushes it on the VM's scope stack.

There is no corresponding PopLexicalEnvironment instruction yet,
so this will behave incorrectly with let/const scopes for example.
This commit is contained in:
Andreas Kling 2021-06-10 22:12:21 +02:00
parent d560ee118d
commit c3c68399b5
4 changed files with 92 additions and 1 deletions

View file

@ -11,6 +11,8 @@
#include <LibJS/Bytecode/Instruction.h>
#include <LibJS/Bytecode/Op.h>
#include <LibJS/Bytecode/Register.h>
#include <LibJS/Bytecode/StringTable.h>
#include <LibJS/Runtime/ScopeObject.h>
namespace JS {
@ -27,6 +29,41 @@ void ScopeNode::generate_bytecode(Bytecode::Generator& generator) const
generator.emit<Bytecode::Op::SetVariable>(generator.intern_string(function.name()));
}
HashMap<u32, Variable> scope_variables_with_declaration_kind;
bool is_program_node = is<Program>(*this);
for (auto& declaration : variables()) {
for (auto& declarator : declaration.declarations()) {
if (is_program_node && declaration.declaration_kind() == DeclarationKind::Var) {
declarator.target().visit(
[&](const NonnullRefPtr<Identifier>& id) {
generator.emit<Bytecode::Op::LoadImmediate>(js_undefined());
generator.emit<Bytecode::Op::PutById>(Bytecode::Register::global_object(), generator.intern_string(id->string()));
},
[&](const NonnullRefPtr<BindingPattern>& binding) {
binding->for_each_assigned_name([&](const auto& name) {
generator.emit<Bytecode::Op::LoadImmediate>(js_undefined());
generator.emit<Bytecode::Op::PutById>(Bytecode::Register::global_object(), generator.intern_string(name));
});
});
} else {
declarator.target().visit(
[&](const NonnullRefPtr<Identifier>& id) {
scope_variables_with_declaration_kind.set((size_t)generator.intern_string(id->string()).value(), { js_undefined(), declaration.declaration_kind() });
},
[&](const NonnullRefPtr<BindingPattern>& binding) {
binding->for_each_assigned_name([&](const auto& name) {
scope_variables_with_declaration_kind.set((size_t)generator.intern_string(name).value(), { js_undefined(), declaration.declaration_kind() });
});
});
}
}
}
if (!scope_variables_with_declaration_kind.is_empty()) {
generator.emit<Bytecode::Op::PushLexicalEnvironment>(move(scope_variables_with_declaration_kind));
}
for (auto& child : children()) {
child.generate_bytecode(generator);
if (generator.is_current_block_terminated())
@ -560,8 +597,21 @@ void FunctionDeclaration::generate_bytecode(Bytecode::Generator&) const
{
}
void VariableDeclaration::generate_bytecode(Bytecode::Generator&) const
void VariableDeclaration::generate_bytecode(Bytecode::Generator& generator) const
{
for (auto& declarator : m_declarations) {
if (declarator.init())
declarator.init()->generate_bytecode(generator);
else
generator.emit<Bytecode::Op::LoadImmediate>(js_undefined());
declarator.target().visit(
[&](const NonnullRefPtr<Identifier>& id) {
generator.emit<Bytecode::Op::SetVariable>(generator.intern_string(id->string()));
},
[&](const NonnullRefPtr<BindingPattern>&) {
TODO();
});
}
}
void CallExpression::generate_bytecode(Bytecode::Generator& generator) const