1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 04:47:35 +00:00

LibJS: Make ASTNode::generate_bytecode() fallible

Instead of crashing on the spot, return a descriptive error that will
eventually continue its days as a javascript "InternalError" exception.
This should make random crashes with BC less likely.
This commit is contained in:
Ali Mohammad Pur 2022-02-12 19:54:08 +03:30 committed by Linus Groh
parent 3a5f7cb524
commit 75aa900b83
10 changed files with 378 additions and 233 deletions

View file

@ -23,7 +23,7 @@ Generator::~Generator()
{
}
NonnullOwnPtr<Executable> Generator::generate(ASTNode const& node, FunctionKind enclosing_function_kind)
CodeGenerationErrorOr<NonnullOwnPtr<Executable>> Generator::generate(ASTNode const& node, FunctionKind enclosing_function_kind)
{
Generator generator;
generator.switch_to_basic_block(generator.make_block());
@ -34,7 +34,7 @@ NonnullOwnPtr<Executable> Generator::generate(ASTNode const& node, FunctionKind
generator.emit<Bytecode::Op::Yield>(Label { start_block });
generator.switch_to_basic_block(start_block);
}
node.generate_bytecode(generator);
TRY(node.generate_bytecode(generator));
if (generator.is_in_generator_or_async_function()) {
// Terminate all unterminated blocks with yield return
for (auto& block : generator.m_root_basic_blocks) {
@ -99,38 +99,43 @@ void Generator::end_breakable_scope()
m_breakable_scopes.take_last();
}
void Generator::emit_load_from_reference(JS::ASTNode const& node)
CodeGenerationErrorOr<void> Generator::emit_load_from_reference(JS::ASTNode const& node)
{
if (is<Identifier>(node)) {
auto& identifier = static_cast<Identifier const&>(node);
emit<Bytecode::Op::GetVariable>(intern_identifier(identifier.string()));
return;
return {};
}
if (is<MemberExpression>(node)) {
auto& expression = static_cast<MemberExpression const&>(node);
expression.object().generate_bytecode(*this);
TRY(expression.object().generate_bytecode(*this));
auto object_reg = allocate_register();
emit<Bytecode::Op::Store>(object_reg);
if (expression.is_computed()) {
expression.property().generate_bytecode(*this);
TRY(expression.property().generate_bytecode(*this));
emit<Bytecode::Op::GetByValue>(object_reg);
} else {
} else if (expression.property().is_identifier()) {
auto identifier_table_ref = intern_identifier(verify_cast<Identifier>(expression.property()).string());
emit<Bytecode::Op::GetById>(identifier_table_ref);
} else {
return CodeGenerationError {
&expression,
"Unimplemented non-computed member expression"sv
};
}
return;
return {};
}
VERIFY_NOT_REACHED();
}
void Generator::emit_store_to_reference(JS::ASTNode const& node)
CodeGenerationErrorOr<void> Generator::emit_store_to_reference(JS::ASTNode const& node)
{
if (is<Identifier>(node)) {
auto& identifier = static_cast<Identifier const&>(node);
emit<Bytecode::Op::SetVariable>(intern_identifier(identifier.string()));
return;
return {};
}
if (is<MemberExpression>(node)) {
// NOTE: The value is in the accumulator, so we have to store that away first.
@ -138,25 +143,36 @@ void Generator::emit_store_to_reference(JS::ASTNode const& node)
emit<Bytecode::Op::Store>(value_reg);
auto& expression = static_cast<MemberExpression const&>(node);
expression.object().generate_bytecode(*this);
TRY(expression.object().generate_bytecode(*this));
auto object_reg = allocate_register();
emit<Bytecode::Op::Store>(object_reg);
if (expression.is_computed()) {
expression.property().generate_bytecode(*this);
TRY(expression.property().generate_bytecode(*this));
auto property_reg = allocate_register();
emit<Bytecode::Op::Store>(property_reg);
emit<Bytecode::Op::Load>(value_reg);
emit<Bytecode::Op::PutByValue>(object_reg, property_reg);
} else {
} else if (expression.property().is_identifier()) {
emit<Bytecode::Op::Load>(value_reg);
auto identifier_table_ref = intern_identifier(verify_cast<Identifier>(expression.property()).string());
emit<Bytecode::Op::PutById>(object_reg, identifier_table_ref);
} else {
return CodeGenerationError {
&expression,
"Unimplemented non-computed member expression"sv
};
}
return;
return {};
}
VERIFY_NOT_REACHED();
}
String CodeGenerationError::to_string()
{
return String::formatted("CodeGenerationError in {}: {}", failing_node ? failing_node->class_name() : "<unknown node>", reason_literal);
}
}