Skip to content

Commit cfbb69a

Browse files
committed
LibJS: Support more assignment expressions in the bytecode VM
Use the new reference get/put helpers in BytecodeGenerator to support assignment expressions other than just plain assignment.
1 parent 72736f9 commit cfbb69a

File tree

1 file changed

+85
-112
lines changed

1 file changed

+85
-112
lines changed

Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp

Lines changed: 85 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -253,132 +253,105 @@ void AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) con
253253
{
254254
// FIXME: Implement this for BindingPatterns too.
255255
auto& lhs = m_lhs.get<NonnullRefPtr<Expression>>();
256-
if (is<Identifier>(*lhs)) {
257-
auto& identifier = static_cast<Identifier const&>(*lhs);
258256

259-
if (m_op == AssignmentOp::Assignment) {
260-
m_rhs->generate_bytecode(generator);
261-
generator.emit<Bytecode::Op::SetVariable>(generator.intern_identifier(identifier.string()));
262-
return;
263-
}
264-
265-
lhs->generate_bytecode(generator);
266-
267-
Bytecode::BasicBlock* rhs_block_ptr { nullptr };
268-
Bytecode::BasicBlock* end_block_ptr { nullptr };
269-
270-
// Logical assignments short circuit.
271-
if (m_op == AssignmentOp::AndAssignment) { // &&=
272-
rhs_block_ptr = &generator.make_block();
273-
end_block_ptr = &generator.make_block();
257+
if (m_op == AssignmentOp::Assignment) {
258+
m_rhs->generate_bytecode(generator);
259+
generator.emit_store_to_reference(lhs);
260+
return;
261+
}
274262

275-
generator.emit<Bytecode::Op::JumpConditional>().set_targets(
276-
Bytecode::Label { *rhs_block_ptr },
277-
Bytecode::Label { *end_block_ptr });
278-
} else if (m_op == AssignmentOp::OrAssignment) { // ||=
279-
rhs_block_ptr = &generator.make_block();
280-
end_block_ptr = &generator.make_block();
263+
generator.emit_load_from_reference(lhs);
281264

282-
generator.emit<Bytecode::Op::JumpConditional>().set_targets(
283-
Bytecode::Label { *end_block_ptr },
284-
Bytecode::Label { *rhs_block_ptr });
285-
} else if (m_op == AssignmentOp::NullishAssignment) { // ??=
286-
rhs_block_ptr = &generator.make_block();
287-
end_block_ptr = &generator.make_block();
288-
289-
generator.emit<Bytecode::Op::JumpNullish>().set_targets(
290-
Bytecode::Label { *rhs_block_ptr },
291-
Bytecode::Label { *end_block_ptr });
292-
}
265+
Bytecode::BasicBlock* rhs_block_ptr { nullptr };
266+
Bytecode::BasicBlock* end_block_ptr { nullptr };
293267

294-
if (rhs_block_ptr)
295-
generator.switch_to_basic_block(*rhs_block_ptr);
268+
// Logical assignments short circuit.
269+
if (m_op == AssignmentOp::AndAssignment) { // &&=
270+
rhs_block_ptr = &generator.make_block();
271+
end_block_ptr = &generator.make_block();
296272

297-
// lhs_reg is a part of the rhs_block because the store isn't necessary
298-
// if the logical assignment condition fails.
299-
auto lhs_reg = generator.allocate_register();
300-
generator.emit<Bytecode::Op::Store>(lhs_reg);
301-
m_rhs->generate_bytecode(generator);
273+
generator.emit<Bytecode::Op::JumpConditional>().set_targets(
274+
Bytecode::Label { *rhs_block_ptr },
275+
Bytecode::Label { *end_block_ptr });
276+
} else if (m_op == AssignmentOp::OrAssignment) { // ||=
277+
rhs_block_ptr = &generator.make_block();
278+
end_block_ptr = &generator.make_block();
302279

303-
switch (m_op) {
304-
case AssignmentOp::AdditionAssignment:
305-
generator.emit<Bytecode::Op::Add>(lhs_reg);
306-
break;
307-
case AssignmentOp::SubtractionAssignment:
308-
generator.emit<Bytecode::Op::Sub>(lhs_reg);
309-
break;
310-
case AssignmentOp::MultiplicationAssignment:
311-
generator.emit<Bytecode::Op::Mul>(lhs_reg);
312-
break;
313-
case AssignmentOp::DivisionAssignment:
314-
generator.emit<Bytecode::Op::Div>(lhs_reg);
315-
break;
316-
case AssignmentOp::ModuloAssignment:
317-
generator.emit<Bytecode::Op::Mod>(lhs_reg);
318-
break;
319-
case AssignmentOp::ExponentiationAssignment:
320-
generator.emit<Bytecode::Op::Exp>(lhs_reg);
321-
break;
322-
case AssignmentOp::BitwiseAndAssignment:
323-
generator.emit<Bytecode::Op::BitwiseAnd>(lhs_reg);
324-
break;
325-
case AssignmentOp::BitwiseOrAssignment:
326-
generator.emit<Bytecode::Op::BitwiseOr>(lhs_reg);
327-
break;
328-
case AssignmentOp::BitwiseXorAssignment:
329-
generator.emit<Bytecode::Op::BitwiseXor>(lhs_reg);
330-
break;
331-
case AssignmentOp::LeftShiftAssignment:
332-
generator.emit<Bytecode::Op::LeftShift>(lhs_reg);
333-
break;
334-
case AssignmentOp::RightShiftAssignment:
335-
generator.emit<Bytecode::Op::RightShift>(lhs_reg);
336-
break;
337-
case AssignmentOp::UnsignedRightShiftAssignment:
338-
generator.emit<Bytecode::Op::UnsignedRightShift>(lhs_reg);
339-
break;
340-
case AssignmentOp::AndAssignment:
341-
case AssignmentOp::OrAssignment:
342-
case AssignmentOp::NullishAssignment:
343-
break; // These are handled above.
344-
default:
345-
TODO();
346-
}
280+
generator.emit<Bytecode::Op::JumpConditional>().set_targets(
281+
Bytecode::Label { *end_block_ptr },
282+
Bytecode::Label { *rhs_block_ptr });
283+
} else if (m_op == AssignmentOp::NullishAssignment) { // ??=
284+
rhs_block_ptr = &generator.make_block();
285+
end_block_ptr = &generator.make_block();
347286

348-
generator.emit<Bytecode::Op::SetVariable>(generator.intern_identifier(identifier.string()));
287+
generator.emit<Bytecode::Op::JumpNullish>().set_targets(
288+
Bytecode::Label { *rhs_block_ptr },
289+
Bytecode::Label { *end_block_ptr });
290+
}
349291

350-
if (end_block_ptr) {
351-
generator.emit<Bytecode::Op::Jump>().set_targets(
352-
Bytecode::Label { *end_block_ptr },
353-
{});
292+
if (rhs_block_ptr)
293+
generator.switch_to_basic_block(*rhs_block_ptr);
354294

355-
generator.switch_to_basic_block(*end_block_ptr);
356-
}
295+
// lhs_reg is a part of the rhs_block because the store isn't necessary
296+
// if the logical assignment condition fails.
297+
auto lhs_reg = generator.allocate_register();
298+
generator.emit<Bytecode::Op::Store>(lhs_reg);
299+
m_rhs->generate_bytecode(generator);
357300

358-
return;
301+
switch (m_op) {
302+
case AssignmentOp::AdditionAssignment:
303+
generator.emit<Bytecode::Op::Add>(lhs_reg);
304+
break;
305+
case AssignmentOp::SubtractionAssignment:
306+
generator.emit<Bytecode::Op::Sub>(lhs_reg);
307+
break;
308+
case AssignmentOp::MultiplicationAssignment:
309+
generator.emit<Bytecode::Op::Mul>(lhs_reg);
310+
break;
311+
case AssignmentOp::DivisionAssignment:
312+
generator.emit<Bytecode::Op::Div>(lhs_reg);
313+
break;
314+
case AssignmentOp::ModuloAssignment:
315+
generator.emit<Bytecode::Op::Mod>(lhs_reg);
316+
break;
317+
case AssignmentOp::ExponentiationAssignment:
318+
generator.emit<Bytecode::Op::Exp>(lhs_reg);
319+
break;
320+
case AssignmentOp::BitwiseAndAssignment:
321+
generator.emit<Bytecode::Op::BitwiseAnd>(lhs_reg);
322+
break;
323+
case AssignmentOp::BitwiseOrAssignment:
324+
generator.emit<Bytecode::Op::BitwiseOr>(lhs_reg);
325+
break;
326+
case AssignmentOp::BitwiseXorAssignment:
327+
generator.emit<Bytecode::Op::BitwiseXor>(lhs_reg);
328+
break;
329+
case AssignmentOp::LeftShiftAssignment:
330+
generator.emit<Bytecode::Op::LeftShift>(lhs_reg);
331+
break;
332+
case AssignmentOp::RightShiftAssignment:
333+
generator.emit<Bytecode::Op::RightShift>(lhs_reg);
334+
break;
335+
case AssignmentOp::UnsignedRightShiftAssignment:
336+
generator.emit<Bytecode::Op::UnsignedRightShift>(lhs_reg);
337+
break;
338+
case AssignmentOp::AndAssignment:
339+
case AssignmentOp::OrAssignment:
340+
case AssignmentOp::NullishAssignment:
341+
break; // These are handled above.
342+
default:
343+
TODO();
359344
}
360345

361-
if (is<MemberExpression>(*lhs)) {
362-
auto& expression = static_cast<MemberExpression const&>(*lhs);
363-
expression.object().generate_bytecode(generator);
364-
auto object_reg = generator.allocate_register();
365-
generator.emit<Bytecode::Op::Store>(object_reg);
346+
generator.emit_store_to_reference(lhs);
366347

367-
if (expression.is_computed()) {
368-
expression.property().generate_bytecode(generator);
369-
auto property_reg = generator.allocate_register();
370-
generator.emit<Bytecode::Op::Store>(property_reg);
371-
m_rhs->generate_bytecode(generator);
372-
generator.emit<Bytecode::Op::PutByValue>(object_reg, property_reg);
373-
} else {
374-
m_rhs->generate_bytecode(generator);
375-
auto identifier_table_ref = generator.intern_identifier(verify_cast<Identifier>(expression.property()).string());
376-
generator.emit<Bytecode::Op::PutById>(object_reg, identifier_table_ref);
377-
}
378-
return;
379-
}
348+
if (end_block_ptr) {
349+
generator.emit<Bytecode::Op::Jump>().set_targets(
350+
Bytecode::Label { *end_block_ptr },
351+
{});
380352

381-
TODO();
353+
generator.switch_to_basic_block(*end_block_ptr);
354+
}
382355
}
383356

384357
void WhileStatement::generate_bytecode(Bytecode::Generator& generator) const

0 commit comments

Comments
 (0)