Skip to content

Commit 003589d

Browse files
committed
LibJS: Generate C++ bytecode instruction classes from a definition file
This commit adds a new Bytecode.def file that describes all the LibJS bytecode instructions. From this, we are able to generate the full declarations for all C++ bytecode instruction classes, as well as their serialization code. Note that some of the bytecode compiler was updated since instructions no longer have default constructor arguments. The big immediate benefit here is that we lose a couple thousand lines of hand-written C++ code. Going forward, this also allows us to do more tooling for the bytecode VM, now that we have an authoritative description of its instructions. Key things to know about: - Instructions can inherit from one another. At the moment, everything simply inherits from the base "Instruction". - @Terminator means the instruction terminates a basic block. - @nothrow means the instruction cannot throw. This affects how the interpreter interacts with it. - Variable-length instructions are automatically supported. Just put an array of something as the last field of the instruction. - The m_length field is magical. If present, it will be populated with the full length of the instruction. This is used for variable-length instructions.
1 parent 84443e1 commit 003589d

File tree

12 files changed

+1975
-4198
lines changed

12 files changed

+1975
-4198
lines changed

Libraries/LibJS/Bytecode/ASTCodegen.cpp

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ static Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> arguments_to_arr
495495
{
496496
auto dst = generator.allocate_register();
497497
if (arguments.is_empty()) {
498-
generator.emit<Bytecode::Op::NewArray>(dst);
498+
generator.emit<Bytecode::Op::NewArray>(dst, ReadonlySpan<ScopedOperand> {});
499499
return dst;
500500
}
501501

@@ -512,9 +512,9 @@ static Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> arguments_to_arr
512512
}
513513

514514
if (first_spread.index() != 0)
515-
generator.emit_with_extra_operand_slots<Bytecode::Op::NewArray>(args.size(), dst, args);
515+
generator.emit_with_extra_operand_slots<Bytecode::Op::NewArray>(args.size(), dst, args.span());
516516
else
517-
generator.emit<Bytecode::Op::NewArray>(dst);
517+
generator.emit<Bytecode::Op::NewArray>(dst, ReadonlySpan<ScopedOperand> {});
518518

519519
if (first_spread != arguments.end()) {
520520
for (auto it = first_spread; it != arguments.end(); ++it) {
@@ -1034,7 +1034,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> ForStatement::generate_
10341034
if (identifier.is_local())
10351035
return;
10361036
auto index = generator.intern_identifier(identifier.string());
1037-
generator.emit<Bytecode::Op::CreateVariable>(index, Bytecode::Op::EnvironmentMode::Lexical, is_const);
1037+
generator.emit<Bytecode::Op::CreateVariable>(index, Bytecode::Op::EnvironmentMode::Lexical, is_const, false, false);
10381038
if (!is_const) {
10391039
per_iteration_bindings.append(index);
10401040
}
@@ -1067,7 +1067,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> ForStatement::generate_
10671067
generator.begin_variable_scope();
10681068

10691069
for (size_t i = 0; i < per_iteration_bindings.size(); ++i) {
1070-
generator.emit<Bytecode::Op::CreateVariable>(per_iteration_bindings[i], Bytecode::Op::EnvironmentMode::Lexical, false);
1070+
generator.emit<Bytecode::Op::CreateVariable>(per_iteration_bindings[i], Bytecode::Op::EnvironmentMode::Lexical, false, false, false);
10711071
generator.emit<Bytecode::Op::InitializeLexicalBinding>(per_iteration_bindings[i], registers[i]);
10721072
}
10731073
};
@@ -1206,7 +1206,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> ArrayExpression::genera
12061206
Bytecode::Generator::SourceLocationScope scope(generator, *this);
12071207
if (m_elements.is_empty()) {
12081208
auto dst = choose_dst(generator, preferred_dst);
1209-
generator.emit<Bytecode::Op::NewArray>(dst);
1209+
generator.emit<Bytecode::Op::NewArray>(dst, ReadonlySpan<ScopedOperand> {});
12101210
return dst;
12111211
}
12121212

@@ -1242,7 +1242,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> ArrayExpression::genera
12421242
if (first_spread.index() != 0) {
12431243
generator.emit_with_extra_operand_slots<Bytecode::Op::NewArray>(args.size(), dst, args);
12441244
} else {
1245-
generator.emit<Bytecode::Op::NewArray>(dst);
1245+
generator.emit<Bytecode::Op::NewArray>(dst, ReadonlySpan<ScopedOperand> {});
12461246
}
12471247

12481248
if (first_spread != m_elements.end()) {
@@ -1288,7 +1288,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> FunctionExpression::gen
12881288
generator.begin_variable_scope();
12891289

12901290
name_identifier = generator.intern_identifier(name());
1291-
generator.emit<Bytecode::Op::CreateVariable>(*name_identifier, Bytecode::Op::EnvironmentMode::Lexical, true);
1291+
generator.emit<Bytecode::Op::CreateVariable>(*name_identifier, Bytecode::Op::EnvironmentMode::Lexical, true, false, false);
12921292
}
12931293

12941294
auto new_function = choose_dst(generator, preferred_dst);
@@ -1437,7 +1437,7 @@ static Bytecode::CodeGenerationErrorOr<void> generate_array_binding_pattern_byte
14371437
auto iterator_object = generator.allocate_register();
14381438
auto iterator_next_method = generator.allocate_register();
14391439
auto iterator_done_property = generator.allocate_register();
1440-
generator.emit<Bytecode::Op::GetIterator>(iterator_object, iterator_next_method, iterator_done_property, input_array);
1440+
generator.emit<Bytecode::Op::GetIterator>(iterator_object, iterator_next_method, iterator_done_property, input_array, IteratorHint::Sync);
14411441
bool first = true;
14421442

14431443
auto assign_value_to_alias = [&](auto& alias, ScopedOperand value) {
@@ -1485,7 +1485,7 @@ static Bytecode::CodeGenerationErrorOr<void> generate_array_binding_pattern_byte
14851485
value = generator.allocate_register();
14861486

14871487
generator.switch_to_basic_block(if_exhausted_block);
1488-
generator.emit<Bytecode::Op::NewArray>(value);
1488+
generator.emit<Bytecode::Op::NewArray>(value, ReadonlySpan<ScopedOperand> {});
14891489
generator.emit<Bytecode::Op::Jump>(Bytecode::Label { continuation_block });
14901490

14911491
generator.switch_to_basic_block(if_not_exhausted_block);
@@ -1801,32 +1801,32 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> CallExpression::generat
18011801
dst,
18021802
callee,
18031803
this_value,
1804-
argument_operands,
18051804
builtin.value(),
1806-
expression_string_index);
1805+
expression_string_index,
1806+
argument_operands);
18071807
} else if (call_type == Op::CallType::Construct) {
18081808
generator.emit_with_extra_operand_slots<Bytecode::Op::CallConstruct>(
18091809
argument_operands.size(),
18101810
dst,
18111811
callee,
1812-
argument_operands,
1813-
expression_string_index);
1812+
expression_string_index,
1813+
argument_operands);
18141814
} else if (call_type == Op::CallType::DirectEval) {
18151815
generator.emit_with_extra_operand_slots<Bytecode::Op::CallDirectEval>(
18161816
argument_operands.size(),
18171817
dst,
18181818
callee,
18191819
this_value,
1820-
argument_operands,
1821-
expression_string_index);
1820+
expression_string_index,
1821+
argument_operands);
18221822
} else {
18231823
generator.emit_with_extra_operand_slots<Bytecode::Op::Call>(
18241824
argument_operands.size(),
18251825
dst,
18261826
callee,
18271827
this_value,
1828-
argument_operands,
1829-
expression_string_index);
1828+
expression_string_index,
1829+
argument_operands);
18301830
}
18311831
}
18321832

@@ -2023,7 +2023,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> YieldExpression::genera
20232023
auto array = generator.allocate_register();
20242024
generator.emit_with_extra_operand_slots<Bytecode::Op::NewArray>(1, array, ReadonlySpan<ScopedOperand> { &received_completion_value, 1 });
20252025
auto inner_result = generator.allocate_register();
2026-
generator.emit<Bytecode::Op::CallWithArgumentArray>(inner_result, next_method, iterator, array);
2026+
generator.emit<Bytecode::Op::CallWithArgumentArray>(inner_result, next_method, iterator, array, OptionalNone {});
20272027

20282028
// ii. If generatorKind is async, set innerResult to ? Await(innerResult).
20292029
if (generator.is_in_async_generator_function()) {
@@ -2112,7 +2112,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> YieldExpression::genera
21122112
// 1. Let innerResult be ? Call(throw, iterator, « received.[[Value]] »).
21132113
auto received_value_array = generator.allocate_register();
21142114
generator.emit_with_extra_operand_slots<Bytecode::Op::NewArray>(1, received_value_array, ReadonlySpan<ScopedOperand> { &received_completion_value, 1 });
2115-
generator.emit<Bytecode::Op::CallWithArgumentArray>(inner_result, throw_method, iterator, received_value_array);
2115+
generator.emit<Bytecode::Op::CallWithArgumentArray>(inner_result, throw_method, iterator, received_value_array, OptionalNone {});
21162116

21172117
// 2. If generatorKind is async, set innerResult to ? Await(innerResult).
21182118
if (generator.is_in_async_generator_function()) {
@@ -2209,7 +2209,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> YieldExpression::genera
22092209
auto call_array = generator.allocate_register();
22102210
generator.emit_with_extra_operand_slots<Bytecode::Op::NewArray>(1, call_array, ReadonlySpan<ScopedOperand> { &received_completion_value, 1 });
22112211
auto inner_return_result = generator.allocate_register();
2212-
generator.emit<Bytecode::Op::CallWithArgumentArray>(inner_return_result, return_method, iterator, call_array);
2212+
generator.emit<Bytecode::Op::CallWithArgumentArray>(inner_return_result, return_method, iterator, call_array, OptionalNone {});
22132213

22142214
// v. If generatorKind is async, set innerReturnResult to ? Await(innerReturnResult).
22152215
if (generator.is_in_async_generator_function()) {
@@ -2508,7 +2508,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> TaggedTemplateLiteral::
25082508

25092509
auto strings_array = generator.allocate_register();
25102510
if (string_regs.is_empty()) {
2511-
generator.emit<Bytecode::Op::NewArray>(strings_array);
2511+
generator.emit<Bytecode::Op::NewArray>(strings_array, ReadonlySpan<ScopedOperand> {});
25122512
} else {
25132513
generator.emit_with_extra_operand_slots<Bytecode::Op::NewArray>(string_regs.size(), strings_array, string_regs);
25142514
}
@@ -2532,7 +2532,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> TaggedTemplateLiteral::
25322532

25332533
auto raw_strings_array = generator.allocate_register();
25342534
if (raw_string_regs.is_empty()) {
2535-
generator.emit<Bytecode::Op::NewArray>(raw_strings_array);
2535+
generator.emit<Bytecode::Op::NewArray>(raw_strings_array, ReadonlySpan<ScopedOperand> {});
25362536
} else {
25372537
generator.emit_with_extra_operand_slots<Bytecode::Op::NewArray>(raw_string_regs.size(), raw_strings_array, raw_string_regs);
25382538
}
@@ -2543,10 +2543,10 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> TaggedTemplateLiteral::
25432543
if (!argument_regs.is_empty())
25442544
generator.emit_with_extra_operand_slots<Bytecode::Op::NewArray>(argument_regs.size(), arguments, argument_regs);
25452545
else
2546-
generator.emit<Bytecode::Op::NewArray>(arguments);
2546+
generator.emit<Bytecode::Op::NewArray>(arguments, ReadonlySpan<ScopedOperand> {});
25472547

25482548
auto dst = choose_dst(generator, preferred_dst);
2549-
generator.emit<Bytecode::Op::CallWithArgumentArray>(dst, tag, this_value, arguments);
2549+
generator.emit<Bytecode::Op::CallWithArgumentArray>(dst, tag, this_value, arguments, OptionalNone {});
25502550
return dst;
25512551
}
25522552

@@ -2665,7 +2665,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> TryStatement::generate_
26652665
generator.begin_variable_scope();
26662666
did_create_variable_scope_for_catch_clause = true;
26672667
auto parameter_identifier = generator.intern_identifier(parameter->string());
2668-
generator.emit<Bytecode::Op::CreateVariable>(parameter_identifier, Bytecode::Op::EnvironmentMode::Lexical, false);
2668+
generator.emit<Bytecode::Op::CreateVariable>(parameter_identifier, Bytecode::Op::EnvironmentMode::Lexical, false, false, false);
26692669
generator.emit<Bytecode::Op::InitializeLexicalBinding>(parameter_identifier, caught_value);
26702670
}
26712671
return {};
@@ -2683,7 +2683,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> TryStatement::generate_
26832683
if (identifier.is_local())
26842684
return;
26852685
auto parameter_identifier = generator.intern_identifier(identifier.string());
2686-
generator.emit<Bytecode::Op::CreateVariable>(parameter_identifier, Bytecode::Op::EnvironmentMode::Lexical, false);
2686+
generator.emit<Bytecode::Op::CreateVariable>(parameter_identifier, Bytecode::Op::EnvironmentMode::Lexical, false, false, false);
26872687
}));
26882688

26892689
TRY(binding_pattern->generate_bytecode(generator, Bytecode::Op::BindingInitializationMode::Initialize, caught_value));
@@ -2885,12 +2885,12 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> ClassDeclaration::gener
28852885
Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> ClassExpression::generate_bytecode_with_lhs_name(Bytecode::Generator& generator, Optional<Bytecode::IdentifierTableIndex> lhs_name, Optional<ScopedOperand> preferred_dst) const
28862886
{
28872887
// NOTE: Step 2 is not a part of NewClass instruction because it is assumed to be done before super class expression evaluation
2888-
generator.emit<Bytecode::Op::CreateLexicalEnvironment>();
2888+
generator.emit<Bytecode::Op::CreateLexicalEnvironment>(OptionalNone {}, 0);
28892889

28902890
if (has_name() || !lhs_name.has_value()) {
28912891
// NOTE: Step 3.a is not a part of NewClass instruction because it is assumed to be done before super class expression evaluation
28922892
auto interned_index = generator.intern_identifier(name());
2893-
generator.emit<Bytecode::Op::CreateVariable>(interned_index, Bytecode::Op::EnvironmentMode::Lexical, true);
2893+
generator.emit<Bytecode::Op::CreateVariable>(interned_index, Bytecode::Op::EnvironmentMode::Lexical, true, false, false);
28942894
}
28952895

28962896
Optional<ScopedOperand> super_class;
@@ -3098,7 +3098,7 @@ static Bytecode::CodeGenerationErrorOr<ForInOfHeadEvaluationResult> for_in_of_he
30983098
return;
30993099
// i. Perform ! newEnv.CreateMutableBinding(name, false).
31003100
auto interned_identifier = generator.intern_identifier(identifier.string());
3101-
generator.emit<Bytecode::Op::CreateVariable>(interned_identifier, Bytecode::Op::EnvironmentMode::Lexical, false);
3101+
generator.emit<Bytecode::Op::CreateVariable>(interned_identifier, Bytecode::Op::EnvironmentMode::Lexical, false, false, false);
31023102
}));
31033103
// d. Set the running execution context's LexicalEnvironment to newEnv.
31043104
// NOTE: Done by CreateLexicalEnvironment.
@@ -3298,7 +3298,7 @@ static Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> for_in_of_body_e
32983298
// b. Else,
32993299
else {
33003300
// i. Perform ! environment.CreateMutableBinding(name, false).
3301-
generator.emit<Bytecode::Op::CreateVariable>(interned_identifier, Bytecode::Op::EnvironmentMode::Lexical, false);
3301+
generator.emit<Bytecode::Op::CreateVariable>(interned_identifier, Bytecode::Op::EnvironmentMode::Lexical, false, false, false);
33023302
}
33033303
}));
33043304
// 3. Return unused.
@@ -3512,7 +3512,7 @@ static Bytecode::CodeGenerationErrorOr<void> generate_optional_chain(Bytecode::G
35123512
TRY(reference.visit(
35133513
[&](OptionalChain::Call const& call) -> Bytecode::CodeGenerationErrorOr<void> {
35143514
auto arguments = TRY(arguments_to_array_for_call(generator, call.arguments)).value();
3515-
generator.emit<Bytecode::Op::CallWithArgumentArray>(current_value, current_value, current_base, arguments);
3515+
generator.emit<Bytecode::Op::CallWithArgumentArray>(current_value, current_value, current_base, arguments, OptionalNone {});
35163516
generator.emit_mov(current_base, generator.add_constant(js_undefined()));
35173517
return {};
35183518
},

0 commit comments

Comments
 (0)