mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 09:14:58 +00:00
LibJS: Add file & line number to bytecode VM stack traces :^)
This works by adding source start/end offset to every bytecode instruction. In the future we can make this more efficient by keeping a map of bytecode ranges to source ranges in the Executable instead, but let's just get traces working first. Co-Authored-By: Andrew Kaster <akaster@serenityos.org>
This commit is contained in:
parent
0b66656ca9
commit
1c06111cbd
16 changed files with 157 additions and 26 deletions
|
@ -29,6 +29,7 @@ Bytecode::CodeGenerationErrorOr<void> ASTNode::generate_bytecode(Bytecode::Gener
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ScopeNode::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
bool did_create_lexical_environment = false;
|
||||
|
||||
if (is<BlockStatement>(*this)) {
|
||||
|
@ -61,11 +62,13 @@ Bytecode::CodeGenerationErrorOr<void> EmptyStatement::generate_bytecode(Bytecode
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ExpressionStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
return m_expression->generate_bytecode(generator);
|
||||
}
|
||||
|
||||
Bytecode::CodeGenerationErrorOr<void> BinaryExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
if (m_op == BinaryOp::In && is<PrivateIdentifier>(*m_lhs)) {
|
||||
auto const& private_identifier = static_cast<PrivateIdentifier const&>(*m_lhs).string();
|
||||
TRY(m_rhs->generate_bytecode(generator));
|
||||
|
@ -154,6 +157,7 @@ Bytecode::CodeGenerationErrorOr<void> BinaryExpression::generate_bytecode(Byteco
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> LogicalExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
TRY(m_lhs->generate_bytecode(generator));
|
||||
|
||||
// lhs
|
||||
|
@ -198,6 +202,7 @@ Bytecode::CodeGenerationErrorOr<void> LogicalExpression::generate_bytecode(Bytec
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> UnaryExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
if (m_op == UnaryOp::Delete)
|
||||
return generator.emit_delete_reference(m_lhs);
|
||||
|
||||
|
@ -245,24 +250,28 @@ Bytecode::CodeGenerationErrorOr<void> UnaryExpression::generate_bytecode(Bytecod
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> NumericLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
generator.emit<Bytecode::Op::LoadImmediate>(m_value);
|
||||
return {};
|
||||
}
|
||||
|
||||
Bytecode::CodeGenerationErrorOr<void> BooleanLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
generator.emit<Bytecode::Op::LoadImmediate>(Value(m_value));
|
||||
return {};
|
||||
}
|
||||
|
||||
Bytecode::CodeGenerationErrorOr<void> NullLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
generator.emit<Bytecode::Op::LoadImmediate>(js_null());
|
||||
return {};
|
||||
}
|
||||
|
||||
Bytecode::CodeGenerationErrorOr<void> BigIntLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
// 1. Return the NumericValue of NumericLiteral as defined in 12.8.3.
|
||||
auto integer = [&] {
|
||||
if (m_value[0] == '0' && m_value.length() >= 3)
|
||||
|
@ -281,12 +290,14 @@ Bytecode::CodeGenerationErrorOr<void> BigIntLiteral::generate_bytecode(Bytecode:
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> StringLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
generator.emit<Bytecode::Op::NewString>(generator.intern_string(m_value));
|
||||
return {};
|
||||
}
|
||||
|
||||
Bytecode::CodeGenerationErrorOr<void> RegExpLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
auto source_index = generator.intern_string(m_pattern);
|
||||
auto flags_index = generator.intern_string(m_flags);
|
||||
auto regex_index = generator.intern_regex(Bytecode::ParsedRegex {
|
||||
|
@ -300,6 +311,7 @@ Bytecode::CodeGenerationErrorOr<void> RegExpLiteral::generate_bytecode(Bytecode:
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> Identifier::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
if (is_global()) {
|
||||
generator.emit<Bytecode::Op::GetGlobal>(generator.intern_identifier(m_string), generator.next_global_variable_cache());
|
||||
} else if (is_local()) {
|
||||
|
@ -354,6 +366,7 @@ static Bytecode::CodeGenerationErrorOr<void> arguments_to_array_for_call(Bytecod
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> SuperCall::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
if (m_is_synthetic == IsPartOfSyntheticConstructor::Yes) {
|
||||
// NOTE: This is the case where we have a fake constructor(...args) { super(...args); } which
|
||||
// shouldn't call @@iterator of %Array.prototype%.
|
||||
|
@ -375,6 +388,7 @@ static Bytecode::CodeGenerationErrorOr<void> generate_binding_pattern_bytecode(B
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
if (m_op == AssignmentOp::Assignment) {
|
||||
// AssignmentExpression : LeftHandSideExpression = AssignmentExpression
|
||||
return m_lhs.visit(
|
||||
|
@ -621,6 +635,7 @@ Bytecode::CodeGenerationErrorOr<void> AssignmentExpression::generate_bytecode(By
|
|||
// LabelledStatement : LabelIdentifier : LabelledItem
|
||||
Bytecode::CodeGenerationErrorOr<void> LabelledStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
// Return ? LabelledEvaluation of this LabelledStatement with argument « ».
|
||||
return generate_labelled_evaluation(generator, {});
|
||||
}
|
||||
|
@ -629,6 +644,7 @@ Bytecode::CodeGenerationErrorOr<void> LabelledStatement::generate_bytecode(Bytec
|
|||
// LabelledStatement : LabelIdentifier : LabelledItem
|
||||
Bytecode::CodeGenerationErrorOr<void> LabelledStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector<DeprecatedFlyString> const& label_set) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
// Convert the m_labelled_item NNRP to a reference early so we don't have to do it every single time we want to use it.
|
||||
auto const& labelled_item = *m_labelled_item;
|
||||
|
||||
|
@ -687,11 +703,13 @@ Bytecode::CodeGenerationErrorOr<void> IterationStatement::generate_labelled_eval
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> WhileStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
return generate_labelled_evaluation(generator, {});
|
||||
}
|
||||
|
||||
Bytecode::CodeGenerationErrorOr<void> WhileStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector<DeprecatedFlyString> const& label_set) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
// test
|
||||
// jump if_false (true) end (false) body
|
||||
// body
|
||||
|
@ -742,11 +760,13 @@ Bytecode::CodeGenerationErrorOr<void> WhileStatement::generate_labelled_evaluati
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> DoWhileStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
return generate_labelled_evaluation(generator, {});
|
||||
}
|
||||
|
||||
Bytecode::CodeGenerationErrorOr<void> DoWhileStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector<DeprecatedFlyString> const& label_set) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
// jump always (true) body
|
||||
// test
|
||||
// jump if_false (true) end (false) body
|
||||
|
@ -798,11 +818,13 @@ Bytecode::CodeGenerationErrorOr<void> DoWhileStatement::generate_labelled_evalua
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ForStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
return generate_labelled_evaluation(generator, {});
|
||||
}
|
||||
|
||||
Bytecode::CodeGenerationErrorOr<void> ForStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector<DeprecatedFlyString> const& label_set) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
// init
|
||||
// jump always (true) test
|
||||
// test
|
||||
|
@ -938,6 +960,7 @@ Bytecode::CodeGenerationErrorOr<void> ForStatement::generate_labelled_evaluation
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ObjectExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
generator.emit<Bytecode::Op::NewObject>();
|
||||
if (m_properties.is_empty())
|
||||
return {};
|
||||
|
@ -999,6 +1022,7 @@ Bytecode::CodeGenerationErrorOr<void> ObjectExpression::generate_bytecode(Byteco
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ArrayExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
if (m_elements.is_empty()) {
|
||||
generator.emit<Bytecode::Op::NewArray>();
|
||||
return {};
|
||||
|
@ -1048,12 +1072,14 @@ Bytecode::CodeGenerationErrorOr<void> ArrayExpression::generate_bytecode(Bytecod
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> MemberExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
return generator.emit_load_from_reference(*this);
|
||||
}
|
||||
|
||||
Bytecode::CodeGenerationErrorOr<void> FunctionDeclaration::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
if (m_is_hoisted) {
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
auto index = generator.intern_identifier(name());
|
||||
generator.emit<Bytecode::Op::GetVariable>(index);
|
||||
generator.emit<Bytecode::Op::SetVariable>(index, Bytecode::Op::SetVariable::InitializationMode::Set, Bytecode::Op::EnvironmentMode::Var);
|
||||
|
@ -1063,6 +1089,7 @@ Bytecode::CodeGenerationErrorOr<void> FunctionDeclaration::generate_bytecode(Byt
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> FunctionExpression::generate_bytecode_with_lhs_name(Bytecode::Generator& generator, Optional<Bytecode::IdentifierTableIndex> lhs_name) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
bool has_name = !name().is_empty();
|
||||
Optional<Bytecode::IdentifierTableIndex> name_identifier;
|
||||
|
||||
|
@ -1085,6 +1112,7 @@ Bytecode::CodeGenerationErrorOr<void> FunctionExpression::generate_bytecode_with
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> FunctionExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
return generate_bytecode_with_lhs_name(generator, {});
|
||||
}
|
||||
|
||||
|
@ -1427,6 +1455,7 @@ static Bytecode::CodeGenerationErrorOr<void> assign_accumulator_to_variable_decl
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> VariableDeclaration::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
// The completion value of a VariableDeclaration is empty, but there might already be a non-empty
|
||||
// completion value in the accumulator. We need to save it and restore it after the declaration executed.
|
||||
auto saved_accumulator = generator.allocate_register();
|
||||
|
@ -1511,6 +1540,7 @@ static Bytecode::CodeGenerationErrorOr<void> generate_optional_chain(Bytecode::G
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> CallExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
auto callee_reg = generator.allocate_register();
|
||||
auto this_reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::LoadImmediate>(js_undefined());
|
||||
|
@ -1587,6 +1617,7 @@ static void generate_await(Bytecode::Generator& generator, Bytecode::Register re
|
|||
// https://tc39.es/ecma262/#sec-return-statement-runtime-semantics-evaluation
|
||||
Bytecode::CodeGenerationErrorOr<void> ReturnStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
if (m_argument) {
|
||||
// ReturnStatement : return Expression ;
|
||||
// 1. Let exprRef be ? Evaluation of Expression.
|
||||
|
@ -1699,6 +1730,7 @@ static void generate_yield(Bytecode::Generator& generator, Bytecode::Label conti
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> YieldExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
VERIFY(generator.is_in_generator_function());
|
||||
|
||||
auto received_completion_register = generator.allocate_register();
|
||||
|
@ -2039,6 +2071,7 @@ Bytecode::CodeGenerationErrorOr<void> YieldExpression::generate_bytecode(Bytecod
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> IfStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
// test
|
||||
// jump if_true (true) true (false) false
|
||||
// true
|
||||
|
@ -2081,6 +2114,7 @@ Bytecode::CodeGenerationErrorOr<void> IfStatement::generate_bytecode(Bytecode::G
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ContinueStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
// FIXME: Handle finally blocks in a graceful manner
|
||||
// We need to execute the finally block, but tell it to resume
|
||||
// execution at the designated block
|
||||
|
@ -2100,6 +2134,7 @@ Bytecode::CodeGenerationErrorOr<void> DebuggerStatement::generate_bytecode(Bytec
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ConditionalExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
// test
|
||||
// jump if_true (true) true (false) false
|
||||
// true
|
||||
|
@ -2135,6 +2170,7 @@ Bytecode::CodeGenerationErrorOr<void> ConditionalExpression::generate_bytecode(B
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> SequenceExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
for (auto& expression : m_expressions)
|
||||
TRY(expression->generate_bytecode(generator));
|
||||
|
||||
|
@ -2143,6 +2179,7 @@ Bytecode::CodeGenerationErrorOr<void> SequenceExpression::generate_bytecode(Byte
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> TemplateLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
auto string_reg = generator.allocate_register();
|
||||
|
||||
for (size_t i = 0; i < m_expressions.size(); i++) {
|
||||
|
@ -2160,6 +2197,7 @@ Bytecode::CodeGenerationErrorOr<void> TemplateLiteral::generate_bytecode(Bytecod
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> TaggedTemplateLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
TRY(m_tag->generate_bytecode(generator));
|
||||
auto tag_reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::Store>(tag_reg);
|
||||
|
@ -2252,6 +2290,7 @@ Bytecode::CodeGenerationErrorOr<void> TaggedTemplateLiteral::generate_bytecode(B
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> UpdateExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
TRY(generator.emit_load_from_reference(*m_argument));
|
||||
|
||||
Optional<Bytecode::Register> previous_value_for_postfix_reg;
|
||||
|
@ -2275,6 +2314,7 @@ Bytecode::CodeGenerationErrorOr<void> UpdateExpression::generate_bytecode(Byteco
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ThrowStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
TRY(m_argument->generate_bytecode(generator));
|
||||
generator.perform_needed_unwinds<Bytecode::Op::Throw>();
|
||||
generator.emit<Bytecode::Op::Throw>();
|
||||
|
@ -2283,6 +2323,7 @@ Bytecode::CodeGenerationErrorOr<void> ThrowStatement::generate_bytecode(Bytecode
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> BreakStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
// FIXME: Handle finally blocks in a graceful manner
|
||||
// We need to execute the finally block, but tell it to resume
|
||||
// execution at the designated block
|
||||
|
@ -2297,6 +2338,7 @@ Bytecode::CodeGenerationErrorOr<void> BreakStatement::generate_bytecode(Bytecode
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> TryStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
auto& saved_block = generator.current_block();
|
||||
|
||||
Optional<Bytecode::Label> handler_target;
|
||||
|
@ -2397,11 +2439,13 @@ Bytecode::CodeGenerationErrorOr<void> TryStatement::generate_bytecode(Bytecode::
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> SwitchStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
return generate_labelled_evaluation(generator, {});
|
||||
}
|
||||
|
||||
Bytecode::CodeGenerationErrorOr<void> SwitchStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector<DeprecatedFlyString> const& label_set) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
auto discriminant_reg = generator.allocate_register();
|
||||
TRY(m_discriminant->generate_bytecode(generator));
|
||||
generator.emit<Bytecode::Op::Store>(discriminant_reg);
|
||||
|
@ -2484,6 +2528,7 @@ Bytecode::CodeGenerationErrorOr<void> SuperExpression::generate_bytecode(Bytecod
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ClassDeclaration::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
auto accumulator_backup_reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::Store>(accumulator_backup_reg);
|
||||
|
||||
|
@ -2516,6 +2561,7 @@ Bytecode::CodeGenerationErrorOr<void> ClassExpression::generate_bytecode_with_lh
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ClassExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
return generate_bytecode_with_lhs_name(generator, {});
|
||||
}
|
||||
|
||||
|
@ -2528,6 +2574,7 @@ Bytecode::CodeGenerationErrorOr<void> SpreadExpression::generate_bytecode(Byteco
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ThisExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
generator.emit<Bytecode::Op::ResolveThisBinding>();
|
||||
return {};
|
||||
}
|
||||
|
@ -2564,6 +2611,7 @@ static void generate_await(Bytecode::Generator& generator, Bytecode::Register re
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> AwaitExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
TRY(m_argument->generate_bytecode(generator));
|
||||
|
||||
auto received_completion_register = generator.allocate_register();
|
||||
|
@ -2579,6 +2627,7 @@ Bytecode::CodeGenerationErrorOr<void> AwaitExpression::generate_bytecode(Bytecod
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> WithStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
TRY(m_object->generate_bytecode(generator));
|
||||
generator.emit<Bytecode::Op::EnterObjectEnvironment>();
|
||||
|
||||
|
@ -2934,6 +2983,7 @@ static Bytecode::CodeGenerationErrorOr<void> for_in_of_body_evaluation(Bytecode:
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ForInStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
return generate_labelled_evaluation(generator, {});
|
||||
}
|
||||
|
||||
|
@ -2952,6 +3002,7 @@ Bytecode::CodeGenerationErrorOr<void> ForInStatement::generate_labelled_evaluati
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ForOfStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
return generate_labelled_evaluation(generator, {});
|
||||
}
|
||||
|
||||
|
@ -2969,6 +3020,7 @@ Bytecode::CodeGenerationErrorOr<void> ForOfStatement::generate_labelled_evaluati
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ForAwaitOfStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
return generate_labelled_evaluation(generator, {});
|
||||
}
|
||||
|
||||
|
@ -2987,6 +3039,7 @@ Bytecode::CodeGenerationErrorOr<void> ForAwaitOfStatement::generate_labelled_eva
|
|||
// 13.3.12.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-meta-properties-runtime-semantics-evaluation
|
||||
Bytecode::CodeGenerationErrorOr<void> MetaProperty::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
// NewTarget : new . target
|
||||
if (m_type == MetaProperty::Type::NewTarget) {
|
||||
// 1. Return GetNewTarget().
|
||||
|
@ -3005,6 +3058,7 @@ Bytecode::CodeGenerationErrorOr<void> MetaProperty::generate_bytecode(Bytecode::
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ClassFieldInitializerStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
TRY(generator.emit_named_evaluation_if_anonymous_function(*m_expression, generator.intern_identifier(m_class_field_identifier_name)));
|
||||
generator.perform_needed_unwinds<Bytecode::Op::Return>();
|
||||
generator.emit<Bytecode::Op::Return>();
|
||||
|
@ -3084,6 +3138,7 @@ static Bytecode::CodeGenerationErrorOr<void> generate_optional_chain(Bytecode::G
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> OptionalChain::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
auto current_base_register = generator.allocate_register();
|
||||
auto current_value_register = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::LoadImmediate>(js_undefined());
|
||||
|
@ -3093,6 +3148,7 @@ Bytecode::CodeGenerationErrorOr<void> OptionalChain::generate_bytecode(Bytecode:
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ImportCall::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
TRY(m_specifier->generate_bytecode(generator));
|
||||
auto specifier_reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::Store>(specifier_reg);
|
||||
|
@ -3111,6 +3167,7 @@ Bytecode::CodeGenerationErrorOr<void> ImportCall::generate_bytecode(Bytecode::Ge
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ExportStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
if (!is_default_export()) {
|
||||
if (m_statement) {
|
||||
return m_statement->generate_bytecode(generator);
|
||||
|
|
|
@ -26,6 +26,11 @@ struct GlobalVariableCache : public PropertyLookupCache {
|
|||
u64 environment_serial_number { 0 };
|
||||
};
|
||||
|
||||
struct SourceRecord {
|
||||
u32 source_start_offset {};
|
||||
u32 source_end_offset {};
|
||||
};
|
||||
|
||||
struct Executable {
|
||||
DeprecatedFlyString name;
|
||||
Vector<PropertyLookupCache> property_lookup_caches;
|
||||
|
@ -34,6 +39,7 @@ struct Executable {
|
|||
NonnullOwnPtr<StringTable> string_table;
|
||||
NonnullOwnPtr<IdentifierTable> identifier_table;
|
||||
NonnullOwnPtr<RegexTable> regex_table;
|
||||
NonnullRefPtr<SourceCode const> source_code;
|
||||
size_t number_of_registers { 0 };
|
||||
bool is_strict_mode { false };
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ CodeGenerationErrorOr<NonnullOwnPtr<Executable>> Generator::generate(ASTNode con
|
|||
{
|
||||
Generator generator;
|
||||
generator.switch_to_basic_block(generator.make_block());
|
||||
SourceLocationScope scope(generator, node);
|
||||
generator.m_enclosing_function_kind = enclosing_function_kind;
|
||||
if (generator.is_in_generator_or_async_function()) {
|
||||
// Immediately yield with no value.
|
||||
|
@ -69,6 +70,7 @@ CodeGenerationErrorOr<NonnullOwnPtr<Executable>> Generator::generate(ASTNode con
|
|||
.string_table = move(generator.m_string_table),
|
||||
.identifier_table = move(generator.m_identifier_table),
|
||||
.regex_table = move(generator.m_regex_table),
|
||||
.source_code = node.source_code(),
|
||||
.number_of_registers = generator.m_next_register,
|
||||
.is_strict_mode = is_strict_mode,
|
||||
});
|
||||
|
@ -92,6 +94,18 @@ Register Generator::allocate_register()
|
|||
return Register { m_next_register++ };
|
||||
}
|
||||
|
||||
Generator::SourceLocationScope::SourceLocationScope(Generator& generator, ASTNode const& node)
|
||||
: m_generator(generator)
|
||||
, m_previous_node(m_generator.m_current_ast_node)
|
||||
{
|
||||
m_generator.m_current_ast_node = &node;
|
||||
}
|
||||
|
||||
Generator::SourceLocationScope::~SourceLocationScope()
|
||||
{
|
||||
m_generator.m_current_ast_node = m_previous_node;
|
||||
}
|
||||
|
||||
Label Generator::nearest_continuable_scope() const
|
||||
{
|
||||
return m_continuable_scopes.last().bytecode_target;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/SinglyLinkedList.h>
|
||||
#include <LibJS/AST.h>
|
||||
#include <LibJS/Bytecode/BasicBlock.h>
|
||||
#include <LibJS/Bytecode/CodeGenerationError.h>
|
||||
#include <LibJS/Bytecode/Executable.h>
|
||||
|
@ -45,6 +46,16 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
class SourceLocationScope {
|
||||
public:
|
||||
SourceLocationScope(Generator&, ASTNode const& node);
|
||||
~SourceLocationScope();
|
||||
|
||||
private:
|
||||
Generator& m_generator;
|
||||
ASTNode const* m_previous_node { nullptr };
|
||||
};
|
||||
|
||||
template<typename OpType, typename... Args>
|
||||
OpType& emit(Args&&... args)
|
||||
{
|
||||
|
@ -58,7 +69,9 @@ public:
|
|||
new (slot) OpType(forward<Args>(args)...);
|
||||
if constexpr (OpType::IsTerminator)
|
||||
m_current_basic_block->terminate({}, static_cast<Instruction const*>(slot));
|
||||
return *static_cast<OpType*>(slot);
|
||||
auto* op = static_cast<OpType*>(slot);
|
||||
op->set_source_record({ m_current_ast_node->start_offset(), m_current_ast_node->end_offset() });
|
||||
return *op;
|
||||
}
|
||||
|
||||
template<typename OpType, typename... Args>
|
||||
|
@ -77,7 +90,9 @@ public:
|
|||
new (slot) OpType(forward<Args>(args)...);
|
||||
if constexpr (OpType::IsTerminator)
|
||||
m_current_basic_block->terminate({}, static_cast<Instruction const*>(slot));
|
||||
return *static_cast<OpType*>(slot);
|
||||
auto* op = static_cast<OpType*>(slot);
|
||||
op->set_source_record({ m_current_ast_node->start_offset(), m_current_ast_node->end_offset() });
|
||||
return *op;
|
||||
}
|
||||
|
||||
CodeGenerationErrorOr<void> emit_load_from_reference(JS::ASTNode const&);
|
||||
|
@ -231,6 +246,7 @@ private:
|
|||
};
|
||||
|
||||
BasicBlock* m_current_basic_block { nullptr };
|
||||
ASTNode const* m_current_ast_node { nullptr };
|
||||
Vector<NonnullOwnPtr<BasicBlock>> m_root_basic_blocks;
|
||||
NonnullOwnPtr<StringTable> m_string_table;
|
||||
NonnullOwnPtr<IdentifierTable> m_identifier_table;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Bytecode/Executable.h>
|
||||
#include <LibJS/Bytecode/Instruction.h>
|
||||
#include <LibJS/Bytecode/Op.h>
|
||||
|
||||
|
@ -25,4 +26,20 @@ void Instruction::destroy(Instruction& instruction)
|
|||
#undef __BYTECODE_OP
|
||||
}
|
||||
|
||||
UnrealizedSourceRange InstructionStreamIterator::source_range() const
|
||||
{
|
||||
VERIFY(m_executable);
|
||||
auto record = dereference().source_record();
|
||||
return {
|
||||
.source_code = m_executable->source_code,
|
||||
.start_offset = record.source_start_offset,
|
||||
.end_offset = record.source_end_offset,
|
||||
};
|
||||
}
|
||||
|
||||
RefPtr<SourceCode> InstructionStreamIterator::source_code() const
|
||||
{
|
||||
return m_executable ? m_executable->source_code.ptr() : nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
|
||||
#include <AK/Forward.h>
|
||||
#include <AK/Span.h>
|
||||
#include <LibJS/Bytecode/Executable.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/SourceRange.h>
|
||||
|
||||
#define ENUMERATE_BYTECODE_OPS(O) \
|
||||
O(Add) \
|
||||
|
@ -137,6 +139,10 @@ public:
|
|||
ThrowCompletionOr<void> execute(Bytecode::Interpreter&) const;
|
||||
static void destroy(Instruction&);
|
||||
|
||||
// FIXME: Find a better way to organize this information
|
||||
void set_source_record(SourceRecord rec) { m_source_record = rec; }
|
||||
SourceRecord source_record() const { return m_source_record; }
|
||||
|
||||
protected:
|
||||
explicit Instruction(Type type)
|
||||
: m_type(type)
|
||||
|
@ -144,13 +150,15 @@ protected:
|
|||
}
|
||||
|
||||
private:
|
||||
SourceRecord m_source_record {};
|
||||
Type m_type {};
|
||||
};
|
||||
|
||||
class InstructionStreamIterator {
|
||||
public:
|
||||
explicit InstructionStreamIterator(ReadonlyBytes bytes)
|
||||
InstructionStreamIterator(ReadonlyBytes bytes, Executable const* executable = nullptr)
|
||||
: m_bytes(bytes)
|
||||
, m_executable(executable)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -170,11 +178,15 @@ public:
|
|||
m_offset += dereference().length();
|
||||
}
|
||||
|
||||
UnrealizedSourceRange source_range() const;
|
||||
RefPtr<SourceCode> source_code() const;
|
||||
|
||||
private:
|
||||
Instruction const& dereference() const { return *reinterpret_cast<Instruction const*>(m_bytes.data() + offset()); }
|
||||
|
||||
ReadonlyBytes m_bytes;
|
||||
size_t m_offset { 0 };
|
||||
Executable const* m_executable { nullptr };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -173,6 +173,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Realm& realm, Execu
|
|||
TemporaryChange restore_saved_jump { m_scheduled_jump, static_cast<BasicBlock const*>(nullptr) };
|
||||
TemporaryChange restore_saved_exception { m_saved_exception, {} };
|
||||
|
||||
VERIFY(!vm().execution_context_stack().is_empty());
|
||||
bool pushed_execution_context = false;
|
||||
ExecutionContext execution_context(vm().heap());
|
||||
if (vm().execution_context_stack().is_empty() || !vm().running_execution_context().lexical_environment) {
|
||||
|
@ -198,8 +199,9 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Realm& realm, Execu
|
|||
TemporaryChange restore_this_value { m_this_value, {} };
|
||||
|
||||
for (;;) {
|
||||
Bytecode::InstructionStreamIterator pc(m_current_block->instruction_stream());
|
||||
TemporaryChange temp_change { m_pc, &pc };
|
||||
auto pc = InstructionStreamIterator { m_current_block->instruction_stream(), m_current_executable };
|
||||
TemporaryChange temp_change { m_pc, Optional<InstructionStreamIterator&>(pc) };
|
||||
TemporaryChange context_change { vm().running_execution_context().instruction_stream_iterator, Optional<InstructionStreamIterator&>(pc) };
|
||||
|
||||
// FIXME: This is getting kinda spaghetti-y
|
||||
bool will_jump = false;
|
||||
|
@ -369,14 +371,10 @@ ThrowCompletionOr<void> Interpreter::continue_pending_unwind(Label const& resume
|
|||
return {};
|
||||
}
|
||||
|
||||
size_t Interpreter::pc() const
|
||||
{
|
||||
return m_pc ? m_pc->offset() : 0;
|
||||
}
|
||||
|
||||
DeprecatedString Interpreter::debug_position() const
|
||||
{
|
||||
return DeprecatedString::formatted("{}:{:2}:{:4x}", m_current_executable->name, m_current_block->name(), pc());
|
||||
auto offset = m_pc.has_value() ? m_pc->offset() : 0;
|
||||
return DeprecatedString::formatted("{}:{:2}:{:4x}", m_current_executable->name, m_current_block->name(), offset);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<NonnullOwnPtr<Bytecode::Executable>> compile(VM& vm, ASTNode const& node, FunctionKind kind, DeprecatedFlyString const& name)
|
||||
|
|
|
@ -87,7 +87,7 @@ public:
|
|||
Executable& current_executable() { return *m_current_executable; }
|
||||
Executable const& current_executable() const { return *m_current_executable; }
|
||||
BasicBlock const& current_block() const { return *m_current_block; }
|
||||
size_t pc() const;
|
||||
auto& instruction_stream_iterator() const { return m_pc; }
|
||||
DeprecatedString debug_position() const;
|
||||
|
||||
Optional<Value>& this_value() { return m_this_value; }
|
||||
|
@ -121,7 +121,7 @@ private:
|
|||
Optional<Value> m_saved_exception;
|
||||
Executable* m_current_executable { nullptr };
|
||||
BasicBlock const* m_current_block { nullptr };
|
||||
InstructionStreamIterator* m_pc { nullptr };
|
||||
Optional<InstructionStreamIterator&> m_pc {};
|
||||
};
|
||||
|
||||
extern bool g_dump_bytecode;
|
||||
|
|
|
@ -152,6 +152,7 @@ ThrowCompletionOr<Value> ECMAScriptFunctionObject::internal_call(Value this_argu
|
|||
|
||||
// Non-standard
|
||||
callee_context.arguments.extend(move(arguments_list));
|
||||
callee_context.instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
|
||||
|
||||
// 2. Let calleeContext be PrepareForOrdinaryCall(F, undefined).
|
||||
// NOTE: We throw if the end of the native stack is reached, so unlike in the spec this _does_ need an exception check.
|
||||
|
@ -221,6 +222,7 @@ ThrowCompletionOr<NonnullGCPtr<Object>> ECMAScriptFunctionObject::internal_const
|
|||
|
||||
// Non-standard
|
||||
callee_context.arguments.extend(move(arguments_list));
|
||||
callee_context.instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
|
||||
|
||||
// 4. Let calleeContext be PrepareForOrdinaryCall(F, newTarget).
|
||||
// NOTE: We throw if the end of the native stack is reached, so unlike in the spec this _does_ need an exception check.
|
||||
|
|
|
@ -83,9 +83,12 @@ void Error::populate_stack()
|
|||
if (function_name.is_empty())
|
||||
function_name = "<unknown>"sv;
|
||||
|
||||
UnrealizedSourceRange range = {};
|
||||
if (context->instruction_stream_iterator.has_value())
|
||||
range = context->instruction_stream_iterator->source_range();
|
||||
TracebackFrame frame {
|
||||
.function_name = move(function_name),
|
||||
.source_range_storage = context->source_range,
|
||||
.source_range_storage = range,
|
||||
};
|
||||
|
||||
m_traceback.append(move(frame));
|
||||
|
|
|
@ -33,7 +33,7 @@ ExecutionContext ExecutionContext::copy() const
|
|||
copy.lexical_environment = lexical_environment;
|
||||
copy.variable_environment = variable_environment;
|
||||
copy.private_environment = private_environment;
|
||||
copy.source_range = source_range;
|
||||
copy.instruction_stream_iterator = instruction_stream_iterator;
|
||||
copy.function_name = function_name;
|
||||
copy.this_value = this_value;
|
||||
copy.is_strict_mode = is_strict_mode;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <AK/DeprecatedFlyString.h>
|
||||
#include <AK/WeakPtr.h>
|
||||
#include <LibJS/Bytecode/Instruction.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap/MarkedVector.h>
|
||||
#include <LibJS/Module.h>
|
||||
|
@ -43,7 +44,7 @@ public:
|
|||
// Non-standard: This points at something that owns this ExecutionContext, in case it needs to be protected from GC.
|
||||
GCPtr<Cell> context_owner;
|
||||
|
||||
UnrealizedSourceRange source_range;
|
||||
Optional<Bytecode::InstructionStreamIterator&> instruction_stream_iterator;
|
||||
DeprecatedFlyString function_name;
|
||||
Value this_value;
|
||||
MarkedVector<Value> arguments;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include <LibJS/AST.h>
|
||||
#include <LibJS/Bytecode/Interpreter.h>
|
||||
#include <LibJS/Runtime/FunctionEnvironment.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
|
@ -128,9 +129,9 @@ ThrowCompletionOr<Value> NativeFunction::internal_call(Value this_argument, Mark
|
|||
// Note: This is already the default value.
|
||||
|
||||
// 8. Perform any necessary implementation-defined initialization of calleeContext.
|
||||
|
||||
callee_context.this_value = this_argument;
|
||||
callee_context.arguments.extend(move(arguments_list));
|
||||
callee_context.instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
|
||||
|
||||
callee_context.lexical_environment = caller_context.lexical_environment;
|
||||
callee_context.variable_environment = caller_context.variable_environment;
|
||||
|
@ -192,8 +193,8 @@ ThrowCompletionOr<NonnullGCPtr<Object>> NativeFunction::internal_construct(Marke
|
|||
// Note: This is already the default value.
|
||||
|
||||
// 8. Perform any necessary implementation-defined initialization of calleeContext.
|
||||
|
||||
callee_context.arguments.extend(move(arguments_list));
|
||||
callee_context.instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
|
||||
|
||||
callee_context.lexical_environment = caller_context.lexical_environment;
|
||||
callee_context.variable_environment = caller_context.variable_environment;
|
||||
|
|
|
@ -746,8 +746,8 @@ void VM::dump_backtrace() const
|
|||
{
|
||||
for (ssize_t i = m_execution_context_stack.size() - 1; i >= 0; --i) {
|
||||
auto& frame = m_execution_context_stack[i];
|
||||
if (frame->source_range.source_code) {
|
||||
auto source_range = frame->source_range.realize();
|
||||
if (frame->instruction_stream_iterator->source_code()) {
|
||||
auto source_range = frame->instruction_stream_iterator->source_range().realize();
|
||||
dbgln("-> {} @ {}:{},{}", frame->function_name, source_range.filename(), source_range.start.line, source_range.start.column);
|
||||
} else {
|
||||
dbgln("-> {}", frame->function_name);
|
||||
|
|
|
@ -3,15 +3,14 @@ const stackGetter = stackDescriptor.get;
|
|||
const stackSetter = stackDescriptor.set;
|
||||
|
||||
describe("getter - normal behavior", () => {
|
||||
test.xfail("basic functionality", () => {
|
||||
test("basic functionality", () => {
|
||||
const stackFrames = [
|
||||
/^ at .*Error \(.*\/Error\.prototype\.stack\.js:\d+:\d+\)$/,
|
||||
/^ at .+\/Error\/Error\.prototype\.stack\.js:\d+:\d+$/,
|
||||
/^ at test \(.+\/test-common.js:\d+:\d+\)$/,
|
||||
/^ at (.+\/test-common.js:\d+:\d+)/,
|
||||
/^ at .+\/Error\/Error\.prototype\.stack\.js:6:73$/,
|
||||
/^ at .+\/Error\/Error\.prototype\.stack\.js:6:9$/,
|
||||
/^ at describe \(.+\/test-common\.js:\d+:\d+\)$/,
|
||||
/^ at .+\/Error\/Error\.prototype\.stack\.js:5:38$/,
|
||||
/^ at .+\/Error\/Error\.prototype\.stack\.js:5:9$/,
|
||||
];
|
||||
const values = [
|
||||
{
|
||||
|
|
|
@ -268,8 +268,13 @@ static ErrorOr<bool> parse_and_run(JS::Realm& realm, StringView source, StringVi
|
|||
warnln(" -> {}", traceback_frame.function_name);
|
||||
warnln(" {} more calls", repetitions);
|
||||
} else {
|
||||
for (size_t j = 0; j < repetitions + 1; ++j)
|
||||
warnln(" -> {}", traceback_frame.function_name);
|
||||
for (size_t j = 0; j < repetitions + 1; ++j) {
|
||||
warnln(" -> {} ({}:{},{})",
|
||||
traceback_frame.function_name,
|
||||
traceback_frame.source_range().code->filename(),
|
||||
traceback_frame.source_range().start.line,
|
||||
traceback_frame.source_range().start.column);
|
||||
}
|
||||
}
|
||||
repetitions = 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue