[dart2js] Migrate ssa/codegen.dart

Migrate the cycle codegen.dart, codegen_helpers.dart and variable_allocator.dart

Change-Id: I89b2b59736bd8024fe5a65bba4bbb60f3379b700
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/268863
Commit-Queue: Stephen Adams <sra@google.com>
Reviewed-by: Nate Biggs <natebiggs@google.com>
This commit is contained in:
Stephen Adams
2022-11-16 21:32:00 +00:00
committed by Commit Queue
parent 8e70a02f05
commit 58c15eeeeb
8 changed files with 443 additions and 428 deletions
@@ -106,7 +106,7 @@ class SpecializedChecks {
return null;
}
static MemberEntity? findAsCheck(DartType dartType,
static FunctionEntity? findAsCheck(DartType dartType,
JCommonElements commonElements, bool useLegacySubtyping) {
if (dartType is InterfaceType) {
if (dartType.typeArguments.isNotEmpty) return null;
@@ -147,7 +147,7 @@ class SpecializedChecks {
/// String nullable: false legacy: true String yes
/// String nullable: false legacy: false String no
///
static MemberEntity? _findAsCheck(
static FunctionEntity? _findAsCheck(
ClassEntity element, JCommonElements commonElements,
{required bool nullable, required bool legacy}) {
if (element == commonElements.jsStringClass ||
File diff suppressed because it is too large Load Diff
+85 -94
View File
@@ -2,8 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// @dart = 2.10
import '../constants/values.dart';
import '../elements/entities.dart';
import '../inferrer/abstract_value_domain.dart';
@@ -30,11 +28,11 @@ bool canUseAliasedSuperMember(MemberEntity member, Selector selector) {
///
/// - Combine read/modify/write sequences into HReadModifyWrite instructions to
/// simplify codegen of expressions like `a.x += y`.
class SsaInstructionSelection extends HBaseVisitor<HInstruction /*?*/ >
class SsaInstructionSelection extends HBaseVisitor<HInstruction?>
with CodegenPhase {
final JClosedWorld _closedWorld;
final CompilerOptions _options;
HGraph graph;
late final HGraph graph;
SsaInstructionSelection(this._options, this._closedWorld);
@@ -49,10 +47,10 @@ class SsaInstructionSelection extends HBaseVisitor<HInstruction /*?*/ >
@override
void visitBasicBlock(HBasicBlock block) {
HInstruction instruction = block.first;
HInstruction? instruction = block.first;
while (instruction != null) {
HInstruction next = instruction.next;
HInstruction replacement = instruction.accept(this);
HInstruction? next = instruction.next;
HInstruction? replacement = instruction.accept(this);
if (replacement != instruction && replacement != null) {
block.rewrite(instruction, replacement);
@@ -84,7 +82,7 @@ class SsaInstructionSelection extends HBaseVisitor<HInstruction /*?*/ >
@override
HInstruction visitNullCheck(HNullCheck node) {
// If we remove this NullCheck, does the program behave the same?
HInstruction faultingInstruction = _followingSameFaultInstruction(node);
HInstruction? faultingInstruction = _followingSameFaultInstruction(node);
if (faultingInstruction != null) {
// Force [faultingInstruction] to appear in same source location as
// [node]. This avoids the source-mapped stack trace containing an
@@ -103,13 +101,13 @@ class SsaInstructionSelection extends HBaseVisitor<HInstruction /*?*/ >
/// Searches the instructions following [nullCheck] to see if the first
/// instruction with an effect or exception will fault on a `null` input just
/// like the [nullCheck].
HInstruction _followingSameFaultInstruction(HNullCheck nullCheck) {
HInstruction current = nullCheck.next;
HInstruction? _followingSameFaultInstruction(HNullCheck nullCheck) {
HInstruction? current = nullCheck.next;
do {
// The instructionType of [nullCheck] is not nullable (since it is the
// (not) null check!) This means that if we do need to check the type, we
// should test against nullCheck.checkedInput, not the direct input.
if (current.getDartReceiver(_closedWorld) == nullCheck) {
if (current!.getDartReceiver(_closedWorld) == nullCheck) {
if (current is HFieldGet) return current;
if (current is HFieldSet) return current;
if (current is HGetLength) return current;
@@ -148,13 +146,13 @@ class SsaInstructionSelection extends HBaseVisitor<HInstruction /*?*/ >
return null;
}
HInstruction next = current.next;
HInstruction? next = current.next;
if (next == null) {
// We do not merge blocks in our SSA graph, so if this block just jumps
// to a single successor, visit the successor, avoiding back-edges.
HBasicBlock successor;
HBasicBlock? successor;
if (current is HGoto) {
successor = current.block.successors.single;
successor = current.block!.successors.single;
} else if (current is HIf) {
// We also leave HIf nodes in place when one branch is dead.
HInstruction condition = current.inputs.first;
@@ -164,7 +162,7 @@ class SsaInstructionSelection extends HBaseVisitor<HInstruction /*?*/ >
: current.elseBlock;
}
}
if (successor != null && successor.id > current.block.id) {
if (successor != null && successor.id > current.block!.id) {
next = successor.first;
}
}
@@ -182,7 +180,7 @@ class SsaInstructionSelection extends HBaseVisitor<HInstruction /*?*/ >
/// Returns the single JavaScript comparison (`==` or `===`) if that
/// implements `identical(left, right)`, or returns `null` if the more complex
/// ternary `left == null ? right == null : left === right` is required.
String simpleOp(HInstruction left, HInstruction right) {
String? simpleOp(HInstruction left, HInstruction right) {
AbstractValue leftType = left.instructionType;
AbstractValue rightType = right.instructionType;
if (_abstractValueDomain.isNull(leftType).isDefinitelyFalse) {
@@ -225,12 +223,12 @@ class SsaInstructionSelection extends HBaseVisitor<HInstruction /*?*/ >
.isPotentiallyTrue;
@override
HInstruction visitFieldSet(HFieldSet setter) {
HInstruction? visitFieldSet(HFieldSet setter) {
// Pattern match
// t1 = x.f; t2 = t1 + 1; x.f = t2; use(t2) --> ++x.f
// t1 = x.f; t2 = t1 op y; x.f = t2; use(t2) --> x.f op= y
// t1 = x.f; t2 = t1 + 1; x.f = t2; use(t1) --> x.f++
HBasicBlock block = setter.block;
HBasicBlock block = setter.block!;
HInstruction op = setter.value;
HInstruction receiver = setter.receiver;
@@ -249,12 +247,12 @@ class SsaInstructionSelection extends HBaseVisitor<HInstruction /*?*/ >
return false;
}
HInstruction noMatchingRead() {
HInstruction? noMatchingRead() {
// If we have other HFieldSet optimizations, they go here.
return null;
}
HInstruction replaceOp(HInstruction replacement, HInstruction getter) {
HInstruction? replaceOp(HInstruction replacement, HInstruction getter) {
block.addBefore(setter, replacement);
block.remove(setter);
block.rewrite(op, replacement);
@@ -263,10 +261,8 @@ class SsaInstructionSelection extends HBaseVisitor<HInstruction /*?*/ >
return null;
}
HInstruction plusOrMinus(String assignOp, String incrementOp) {
HInvokeBinary binary = op;
HInstruction left = binary.left;
HInstruction right = binary.right;
HInstruction? plusOrMinus(String assignOp, String incrementOp,
HInstruction left, HInstruction right) {
if (isMatchingRead(left)) {
if (left.usedBy.length == 1) {
if (right is HConstant && right.constant.isOne) {
@@ -294,7 +290,7 @@ class SsaInstructionSelection extends HBaseVisitor<HInstruction /*?*/ >
return noMatchingRead();
}
HInstruction simple(
HInstruction? simple(
String assignOp, HInstruction left, HInstruction right) {
if (isMatchingRead(left)) {
if (left.usedBy.length == 1) {
@@ -306,31 +302,26 @@ class SsaInstructionSelection extends HBaseVisitor<HInstruction /*?*/ >
return noMatchingRead();
}
HInstruction simpleBinary(String assignOp) {
HInvokeBinary binary = op;
return simple(assignOp, binary.left, binary.right);
}
HInstruction bitop(String assignOp) {
HInstruction? bitop(String assignOp, HInvokeBinary binary) {
// HBitAnd, HBitOr etc. are more difficult because HBitAnd(a.x, y)
// sometimes needs to be forced to unsigned: a.x = (a.x & y) >>> 0.
if (op.isUInt31(_abstractValueDomain).isDefinitelyTrue) {
return simpleBinary(assignOp);
return simple(assignOp, binary.left, binary.right);
}
return noMatchingRead();
}
if (op is HAdd) return plusOrMinus('+', '++');
if (op is HSubtract) return plusOrMinus('-', '--');
if (op is HAdd) return plusOrMinus('+', '++', op.left, op.right);
if (op is HSubtract) return plusOrMinus('-', '--', op.left, op.right);
if (op is HStringConcat) return simple('+', op.left, op.right);
if (op is HMultiply) return simpleBinary('*');
if (op is HDivide) return simpleBinary('/');
if (op is HMultiply) return simple('*', op.left, op.right);
if (op is HDivide) return simple('/', op.left, op.right);
if (op is HBitAnd) return bitop('&');
if (op is HBitOr) return bitop('|');
if (op is HBitXor) return bitop('^');
if (op is HBitAnd) return bitop('&', op);
if (op is HBitOr) return bitop('|', op);
if (op is HBitXor) return bitop('^', op);
return noMatchingRead();
}
@@ -349,8 +340,8 @@ class SsaInstructionSelection extends HBaseVisitor<HInstruction /*?*/ >
!_intercepted(operand1.instructionType)) {
if (test.usedBy.length == 1 && condition.usedBy.length == 1) {
node.changeUse(condition, operand1);
condition.block.remove(condition);
test.block.remove(test);
condition.block!.remove(condition);
test.block!.remove(test);
}
}
}
@@ -362,9 +353,9 @@ class SsaInstructionSelection extends HBaseVisitor<HInstruction /*?*/ >
if (operand2.isNull(_abstractValueDomain).isDefinitelyTrue &&
!_intercepted(operand1.instructionType)) {
var not = HNot(operand1, _abstractValueDomain.boolType);
node.block.addBefore(node, not);
node.block!.addBefore(node, not);
node.changeUse(condition, not);
condition.block.remove(condition);
condition.block!.remove(condition);
}
}
return node;
@@ -383,9 +374,9 @@ class SsaTypeKnownRemover extends HBaseVisitor<void> with CodegenPhase {
@override
void visitBasicBlock(HBasicBlock block) {
HInstruction instruction = block.last;
HInstruction? instruction = block.last;
while (instruction != null) {
HInstruction previous = instruction.previous;
HInstruction? previous = instruction.previous;
instruction.accept(this);
instruction = previous;
}
@@ -393,8 +384,8 @@ class SsaTypeKnownRemover extends HBaseVisitor<void> with CodegenPhase {
@override
void visitTypeKnown(HTypeKnown instruction) {
instruction.block.rewrite(instruction, instruction.checkedInput);
instruction.block.remove(instruction);
instruction.block!.rewrite(instruction, instruction.checkedInput);
instruction.block!.remove(instruction);
}
@override
@@ -419,9 +410,9 @@ class SsaTrustedPrimitiveCheckRemover extends HBaseVisitor<void>
@override
void visitBasicBlock(HBasicBlock block) {
HInstruction instruction = block.first;
HInstruction? instruction = block.first;
while (instruction != null) {
HInstruction next = instruction.next;
HInstruction? next = instruction.next;
instruction.accept(this);
instruction = next;
}
@@ -429,14 +420,14 @@ class SsaTrustedPrimitiveCheckRemover extends HBaseVisitor<void>
@override
void visitPrimitiveCheck(HPrimitiveCheck instruction) {
instruction.block.rewrite(instruction, instruction.checkedInput);
instruction.block.remove(instruction);
instruction.block!.rewrite(instruction, instruction.checkedInput);
instruction.block!.remove(instruction);
}
@override
void visitBoolConversion(HBoolConversion instruction) {
instruction.block.rewrite(instruction, instruction.checkedInput);
instruction.block.remove(instruction);
instruction.block!.rewrite(instruction, instruction.checkedInput);
instruction.block!.remove(instruction);
}
}
@@ -453,9 +444,9 @@ class SsaTrustedLateCheckRemover extends HBaseVisitor<void> with CodegenPhase {
@override
void visitBasicBlock(HBasicBlock block) {
HInstruction instruction = block.first;
HInstruction? instruction = block.first;
while (instruction != null) {
HInstruction next = instruction.next;
HInstruction? next = instruction.next;
instruction.accept(this);
instruction = next;
}
@@ -465,14 +456,14 @@ class SsaTrustedLateCheckRemover extends HBaseVisitor<void> with CodegenPhase {
void visitLateCheck(HLateCheck instruction) {
if (!instruction.isTrusted) return;
final inputs = instruction.inputs.toList();
instruction.block.rewrite(instruction, instruction.checkedInput);
instruction.block.remove(instruction);
instruction.block!.rewrite(instruction, instruction.checkedInput);
instruction.block!.remove(instruction);
// TODO(sra): There might be a unused name.
// Remove pure unused inputs.
for (HInstruction input in inputs) {
if (input.usedBy.isNotEmpty) continue;
HBasicBlock block = input.block;
HBasicBlock? block = input.block;
if (block == null) continue; // Already removed.
if (input.isPure(_abstractValueDomain)) {
// Special cases that are removed properly by other phases.
@@ -497,7 +488,7 @@ class SsaTrustedLateCheckRemover extends HBaseVisitor<void> with CodegenPhase {
/// b.y = v;
/// -->
/// b.y = a.x = v;
class SsaAssignmentChaining extends HBaseVisitor<HInstruction /*?*/ >
class SsaAssignmentChaining extends HBaseVisitor<HInstruction?>
with CodegenPhase {
final JClosedWorld _closedWorld;
@@ -508,35 +499,34 @@ class SsaAssignmentChaining extends HBaseVisitor<HInstruction /*?*/ >
@override
void visitGraph(HGraph graph) {
//this.graph = graph;
visitDominatorTree(graph);
}
@override
void visitBasicBlock(HBasicBlock block) {
HInstruction instruction = block.first;
HInstruction? instruction = block.first;
while (instruction != null) {
instruction = instruction.accept(this);
instruction = instruction.accept<HInstruction?>(this);
}
}
/// Returns the next instruction.
@override
HInstruction visitInstruction(HInstruction node) {
HInstruction? visitInstruction(HInstruction node) {
return node.next;
}
@override
HInstruction visitFieldSet(HFieldSet setter) {
HInstruction? visitFieldSet(HFieldSet setter) {
return tryChainAssignment(setter, setter.value);
}
@override
HInstruction visitStaticStore(HStaticStore store) {
HInstruction? visitStaticStore(HStaticStore store) {
return tryChainAssignment(store, store.inputs.single);
}
HInstruction tryChainAssignment(HInstruction setter, HInstruction value) {
HInstruction? tryChainAssignment(HInstruction setter, HInstruction value) {
// Try to use result of field or static assignment
//
// t1 = v; x.f = t1; ... t1 ...
@@ -551,7 +541,7 @@ class SsaAssignmentChaining extends HBaseVisitor<HInstruction /*?*/ >
// the number of references to [value].
HInstruction chain = setter;
setter.instructionType = value.instructionType;
for (HInstruction current = setter.next;;) {
for (HInstruction? current = setter.next;;) {
if (current is HFieldSet) {
HFieldSet nextSetter = current;
if (nextSetter.value == value && nextSetter.receiver != value) {
@@ -579,7 +569,7 @@ class SsaAssignmentChaining extends HBaseVisitor<HInstruction /*?*/ >
break;
}
final HInstruction next = chain.next;
final HInstruction? next = chain.next;
if (value.usedBy.length <= 1) return next; // setter is only remaining use.
@@ -597,7 +587,7 @@ class SsaAssignmentChaining extends HBaseVisitor<HInstruction /*?*/ >
// assignment.
// TODO(sra): Better analysis to permit phis that are part of a
// forwards-only tree.
if (use.block.id < chain.block.id) return next;
if (use.block!.id < chain.block!.id) return next;
if (use.usedBy.any((node) => node is HPhi)) return next;
// A forward phi often has a new name. We want to avoid [value] having a
@@ -670,12 +660,12 @@ class SsaInstructionMerger extends HBaseVisitor<void> with CodegenPhase {
/// List of [HInstruction] that the instruction merger expects in
/// order when visiting the inputs of an instruction.
List<HInstruction> expectedInputs;
List<HInstruction>? expectedInputs;
/// Set of pure [HInstruction] that the instruction merger expects to
/// find. The order of pure instructions do not matter, as they will
/// not be affected by side effects.
Set<HInstruction> pureInputs;
Set<HInstruction>? pureInputs;
Set<HInstruction> generateAtUseSite;
void markAsGenerateAtUseSite(HInstruction instruction) {
@@ -708,7 +698,7 @@ class SsaInstructionMerger extends HBaseVisitor<void> with CodegenPhase {
// Move it closer to [user], so that instructions in
// between do not prevent making it generate at use site.
input.moveBefore(user);
pureInputs.add(input);
pureInputs!.add(input);
// Previous computations done on [input] are now invalid
// because we moved [input] to another place. So all
// non code motion invariant instructions need
@@ -723,7 +713,7 @@ class SsaInstructionMerger extends HBaseVisitor<void> with CodegenPhase {
input.accept(this);
}
} else {
expectedInputs.add(input);
expectedInputs!.add(input);
}
}
}
@@ -889,8 +879,8 @@ class SsaInstructionMerger extends HBaseVisitor<void> with CodegenPhase {
// Return true if it is found, or false if not.
bool findInInputsAndPopNonMatching(HInstruction instruction) {
assert(!isEffectivelyPure(instruction));
while (!expectedInputs.isEmpty) {
HInstruction nextInput = expectedInputs.removeLast();
while (!expectedInputs!.isEmpty) {
HInstruction nextInput = expectedInputs!.removeLast();
assert(!generateAtUseSite.contains(nextInput));
assert(nextInput.usedBy.length == 1);
if (identical(nextInput, instruction)) {
@@ -900,8 +890,8 @@ class SsaInstructionMerger extends HBaseVisitor<void> with CodegenPhase {
return false;
}
block.last.accept(this);
for (HInstruction instruction = block.last.previous;
block.last!.accept(this);
for (HInstruction? instruction = block.last!.previous;
instruction != null;
instruction = instruction.previous) {
if (generateAtUseSite.contains(instruction)) {
@@ -912,7 +902,7 @@ class SsaInstructionMerger extends HBaseVisitor<void> with CodegenPhase {
continue;
}
if (isEffectivelyPure(instruction)) {
if (pureInputs.contains(instruction)) {
if (pureInputs!.contains(instruction)) {
tryGenerateAtUseSite(instruction);
} else {
// If the input is not in the [pureInputs] set, it has not
@@ -961,6 +951,7 @@ class SsaInstructionMerger extends HBaseVisitor<void> with CodegenPhase {
// f(bar(), t3);
// use(t3);
//
final expectedInputs = this.expectedInputs!;
int oldLength = expectedInputs.length;
instruction.accept(this);
if (oldLength != 0 && oldLength != expectedInputs.length) {
@@ -978,7 +969,7 @@ class SsaInstructionMerger extends HBaseVisitor<void> with CodegenPhase {
// expected input.
tryGenerateAtUseSite(instruction);
} else {
assert(expectedInputs.isEmpty);
assert(expectedInputs!.isEmpty);
}
instruction.accept(this);
}
@@ -1000,7 +991,7 @@ class SsaInstructionMerger extends HBaseVisitor<void> with CodegenPhase {
/// using these operators instead of nested ifs and boolean variables.
class SsaConditionMerger extends HGraphVisitor with CodegenPhase {
Set<HInstruction> generateAtUseSite;
Set<HInstruction> controlFlowOperators;
Set<HIf> controlFlowOperators;
void markAsGenerateAtUseSite(HInstruction instruction) {
assert(!instruction.isJsStatement());
@@ -1027,16 +1018,16 @@ class SsaConditionMerger extends HGraphVisitor with CodegenPhase {
// before the control flow instruction, or the last instruction,
// then we will have to emit a statement for that last instruction.
if (instruction != block.last &&
!identical(instruction, block.last.previous)) return true;
!identical(instruction, block.last!.previous)) return true;
// If one of the instructions in the block until [instruction] is
// not generated at use site, then we will have to emit a
// statement for it.
// TODO(ngeoffray): we could generate a comma separated
// list of expressions.
for (HInstruction temp = block.first;
for (HInstruction? temp = block.first;
!identical(temp, instruction);
temp = temp.next) {
temp = temp!.next) {
if (!generateAtUseSite.contains(temp)) return true;
}
@@ -1059,8 +1050,8 @@ class SsaConditionMerger extends HGraphVisitor with CodegenPhase {
@override
void visitBasicBlock(HBasicBlock block) {
if (block.last is! HIf) return;
HIf startIf = block.last;
HBasicBlock end = startIf.joinBlock;
HIf startIf = block.last as HIf;
HBasicBlock? end = startIf.joinBlock;
// We check that the structure is the following:
// If
@@ -1096,7 +1087,7 @@ class SsaConditionMerger extends HGraphVisitor with CodegenPhase {
HBasicBlock elseBlock = startIf.elseBlock;
if (!identical(end.predecessors[1], elseBlock)) return;
HPhi phi = end.phis.first;
HPhi phi = end.phis.first as HPhi;
// This useless phi should have been removed. Do not generate-at-use if
// there is no use. See #48383.
if (phi.usedBy.isEmpty) return;
@@ -1118,16 +1109,16 @@ class SsaConditionMerger extends HGraphVisitor with CodegenPhase {
// have any statement and its join block is [end], we can emit a
// sequence of control flow operation.
if (controlFlowOperators.contains(thenBlock.last)) {
HIf otherIf = thenBlock.last;
HIf otherIf = thenBlock.last as HIf;
if (!identical(otherIf.joinBlock, end)) {
// This could be a join block that just feeds into our join block.
HBasicBlock otherJoin = otherIf.joinBlock;
HBasicBlock otherJoin = otherIf.joinBlock!;
if (otherJoin.first != otherJoin.last) return;
if (otherJoin.successors.length != 1) return;
if (otherJoin.successors[0] != end) return;
if (otherJoin.phis.isEmpty) return;
if (!identical(otherJoin.phis.first, otherJoin.phis.last)) return;
HPhi otherPhi = otherJoin.phis.first;
HPhi otherPhi = otherJoin.phis.first as HPhi;
if (thenInput != otherPhi) return;
if (elseInput != otherPhi.inputs[1]) return;
}
@@ -1143,9 +1134,9 @@ class SsaConditionMerger extends HGraphVisitor with CodegenPhase {
controlFlowOperators.add(startIf);
// Find the next non-HGoto instruction following the phi.
HInstruction nextInstruction = phi.block.first;
HInstruction? nextInstruction = phi.block!.first;
while (nextInstruction is HGoto) {
nextInstruction = nextInstruction.block.successors[0].first;
nextInstruction = nextInstruction.block!.successors[0].first;
}
// If the operation is only used by the first instruction
@@ -1190,9 +1181,9 @@ class SsaShareRegionConstants extends HBaseVisitor<void> with CodegenPhase {
@override
void visitBasicBlock(HBasicBlock block) {
HInstruction instruction = block.first;
HInstruction? instruction = block.first;
while (instruction != null) {
HInstruction next = instruction.next;
HInstruction? next = instruction.next;
instruction.accept(this);
instruction = next;
}
@@ -1214,7 +1205,7 @@ class SsaShareRegionConstants extends HBaseVisitor<void> with CodegenPhase {
// entry, not the use of `this`.
reference.sourceInformation = node.sourceInformation;
reference.sourceElement = _ExpressionName(name);
node.block.addAfter(node, reference);
node.block!.addAfter(node, reference);
for (HInstruction user in users) {
if (cacheable(user)) {
user.changeUse(node, reference);
+5 -25
View File
@@ -768,6 +768,9 @@ class HBasicBlock extends HInstructionList {
static const int STATUS_CLOSED = 2;
int status = STATUS_NEW;
// TODO(48820): Can we make the Phi list better typed? As it stands, the
// first/last fields and the next/previous fields of the HPhi nodes are all
// typed as HInstruction, requiring downcasts to HPhi/HPhi?
HInstructionList phis = HInstructionList();
HLoopInformation? loopInformation = null;
@@ -3417,7 +3420,7 @@ class HLazyStatic extends HInstruction {
}
class HStaticStore extends HInstruction {
MemberEntity element;
FieldEntity element;
HStaticStore(AbstractValueDomain domain, this.element, HInstruction value)
: super([value], domain.emptyType) {
sideEffects.clearAllSideEffects();
@@ -4036,7 +4039,6 @@ abstract class HStatementInformationVisitor {
}
abstract class HExpressionInformationVisitor {
bool visitAndOrInfo(HAndOrBlockInformation info);
bool visitSubExpressionInfo(HSubExpressionBlockInformation info);
}
@@ -4184,28 +4186,6 @@ class HIfBlockInformation implements HStatementInformation {
visitor.visitIfInfo(this);
}
class HAndOrBlockInformation implements HExpressionInformation {
final bool isAnd;
final HExpressionInformation left;
final HExpressionInformation right;
HAndOrBlockInformation(this.isAnd, this.left, this.right);
@override
HBasicBlock get start => left.start;
@override
HBasicBlock get end => right.end;
// We don't currently use HAndOrBlockInformation.
@override
HInstruction? get conditionExpression {
return null;
}
@override
bool accept(HExpressionInformationVisitor visitor) =>
visitor.visitAndOrInfo(this);
}
class HTryBlockInformation implements HStatementInformation {
final HStatementInformation? body;
final HLocalValue? catchVariable;
@@ -4494,7 +4474,7 @@ class HAsCheckSimple extends HCheck {
final DartType dartType;
final AbstractValueWithPrecision checkedType;
final bool isTypeError;
final MemberEntity method;
final FunctionEntity method;
HAsCheckSimple(HInstruction checked, this.dartType, this.checkedType,
this.isTypeError, this.method, AbstractValue type)
@@ -2,8 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// @dart = 2.10
import '../common.dart';
import '../js_backend/namer.dart' show ModularNamer;
import 'codegen.dart' show CodegenPhase;
@@ -28,7 +26,9 @@ class LiveInterval {
/// The id where the instruction is defined.
int start;
final List<LiveRange> ranges;
LiveInterval() : ranges = [];
LiveInterval()
: start = -1,
ranges = [];
// We want [HCheck] instructions to have the same name as the
// instruction it checks, so both instructions should share the same
@@ -73,7 +73,7 @@ class LiveInterval {
class LiveEnvironment {
/// The instruction id where the basic block starts. See
/// [SsaLiveIntervalBuilder.instructionId].
int startId;
int startId = -1;
/// The instruction id where the basic block ends.
final int endId;
@@ -101,7 +101,7 @@ class LiveEnvironment {
void remove(HInstruction instruction, int id) {
LiveInterval interval =
liveIntervals.putIfAbsent(instruction, () => LiveInterval());
int lastId = liveInstructions[instruction];
int? lastId = liveInstructions[instruction];
// If [lastId] is null, then this instruction is not being used.
interval.add(LiveRange(id, lastId ?? id));
// The instruction is defined at [id].
@@ -159,7 +159,7 @@ class LiveEnvironment {
/// instruction, and computes the liveIns of each basic block.
class SsaLiveIntervalBuilder extends HBaseVisitor<void> with CodegenPhase {
final Set<HInstruction> generateAtUseSite;
final Set<HInstruction> controlFlowOperators;
final Set<HIf> controlFlowOperators;
/// A counter to assign start and end ids to live ranges. The initial
/// value is not relevant. Note that instructionId goes downward to ease
@@ -181,14 +181,14 @@ class SsaLiveIntervalBuilder extends HBaseVisitor<void> with CodegenPhase {
SsaLiveIntervalBuilder(this.generateAtUseSite, this.controlFlowOperators) {
for (HIf ifNode in controlFlowOperators) {
_phiToCondition[ifNode.joinBlock.phis.first] = ifNode.condition;
_phiToCondition[ifNode.joinBlock!.phis.first!] = ifNode.condition;
}
}
@override
void visitGraph(HGraph graph) {
visitPostDominatorTree(graph);
if (!liveInstructions[graph.entry].isEmpty) {
if (!liveInstructions[graph.entry]!.isEmpty) {
failedAt(CURRENT_ELEMENT_SPANNABLE, 'LiveIntervalBuilder.');
}
}
@@ -196,7 +196,7 @@ class SsaLiveIntervalBuilder extends HBaseVisitor<void> with CodegenPhase {
void markInputsAsLiveInEnvironment(
HInstruction instruction, LiveEnvironment environment) {
if (instruction is HPhi) {
HInstruction condition = _phiToCondition[instruction];
HInstruction? condition = _phiToCondition[instruction];
if (condition != null) {
markAsLiveInEnvironment(condition, environment);
}
@@ -223,9 +223,8 @@ class SsaLiveIntervalBuilder extends HBaseVisitor<void> with CodegenPhase {
// When looking for the checkedInstructionOrNonGenerateAtUseSite of t3 we must
// return t2.
HInstruction checkedInstructionOrNonGenerateAtUseSite(HCheck check) {
dynamic checked = check.checkedInput;
HInstruction checked = check.checkedInput;
while (checked is HCheck) {
// ignore: avoid_dynamic_calls
HInstruction next = checked.checkedInput;
if (generateAtUseSite.contains(next)) break;
checked = next;
@@ -265,7 +264,7 @@ class SsaLiveIntervalBuilder extends HBaseVisitor<void> with CodegenPhase {
// Unconditionally force the live ranges of the HCheck to
// be the live ranges of the instruction it is checking.
liveIntervals[instruction] =
LiveInterval.forCheck(instructionId, liveIntervals[checked]);
LiveInterval.forCheck(instructionId, liveIntervals[checked]!);
}
}
}
@@ -278,7 +277,7 @@ class SsaLiveIntervalBuilder extends HBaseVisitor<void> with CodegenPhase {
// the inputs of the phis of the successor that flow from this block.
for (int i = 0; i < block.successors.length; i++) {
HBasicBlock successor = block.successors[i];
LiveEnvironment successorEnv = liveInstructions[successor];
LiveEnvironment? successorEnv = liveInstructions[successor];
if (successorEnv != null) {
environment.mergeWith(successorEnv);
} else {
@@ -286,14 +285,14 @@ class SsaLiveIntervalBuilder extends HBaseVisitor<void> with CodegenPhase {
}
int index = successor.predecessors.indexOf(block);
for (HPhi phi = successor.phis.first; phi != null; phi = phi.next) {
for (var phi = successor.phis.first; phi != null; phi = phi.next) {
markAsLiveInEnvironment(phi.inputs[index], environment);
}
}
// Iterate over all instructions to remove an instruction from the
// environment and add its inputs.
HInstruction instruction = block.last;
HInstruction? instruction = block.last;
while (instruction != null) {
if (!generateAtUseSite.contains(instruction)) {
removeFromEnvironment(instruction, environment);
@@ -305,7 +304,7 @@ class SsaLiveIntervalBuilder extends HBaseVisitor<void> with CodegenPhase {
// We just remove the phis from the environment. The inputs of the
// phis will be put in the environment of the predecessors.
for (HPhi phi = block.phis.first; phi != null; phi = phi.next) {
for (var phi = block.phis.first; phi != null; phi = phi.next) {
if (!generateAtUseSite.contains(phi)) {
environment.remove(phi, instructionId);
}
@@ -325,8 +324,8 @@ class SsaLiveIntervalBuilder extends HBaseVisitor<void> with CodegenPhase {
}
void updateLoopMarker(HBasicBlock header) {
LiveEnvironment env = liveInstructions[header];
int lastId = env.loopMarkers[header];
LiveEnvironment env = liveInstructions[header]!;
int lastId = env.loopMarkers[header]!;
// Update all instructions that are liveIns in [header] to have a
// range that covers the loop.
env.liveInstructions.forEach((HInstruction instruction, int id) {
@@ -411,11 +410,11 @@ class VariableNames {
int get numberOfVariables => allUsedNames.length;
String getName(HInstruction instruction) {
String? getName(HInstruction? instruction) {
return ownName[instruction];
}
CopyHandler getCopyHandler(HBasicBlock block) {
CopyHandler? getCopyHandler(HBasicBlock block) {
return copyHandlers[block];
}
@@ -423,7 +422,7 @@ class VariableNames {
allUsedNames.add(name);
}
bool hasName(HInstruction instruction) => ownName.containsKey(instruction);
bool hasName(HInstruction? instruction) => ownName.containsKey(instruction);
void addCopy(HBasicBlock block, HInstruction source, HPhi destination) {
CopyHandler handler = copyHandlers.putIfAbsent(block, () => CopyHandler());
@@ -453,7 +452,7 @@ class VariableNamer {
// All liveIns instructions must have a name at this point, so we
// add them to the list of used names.
environment.liveInstructions.forEach((HInstruction instruction, int index) {
String name = names.getName(instruction);
String? name = names.getName(instruction);
if (name != null) {
usedNames.add(name);
names.addNameUsed(name);
@@ -480,7 +479,7 @@ class VariableNamer {
return name;
}
HPhi firstPhiUserWithElement(HInstruction instruction) {
HPhi? firstPhiUserWithElement(HInstruction instruction) {
for (HInstruction user in instruction.usedBy) {
if (user is HPhi && user.sourceElement != null) {
return user;
@@ -490,7 +489,7 @@ class VariableNamer {
}
String allocateName(HInstruction instruction) {
String name;
String? name;
if (instruction is HCheck) {
// Special case this instruction to use the name of its
// input if it has one.
@@ -503,8 +502,8 @@ class VariableNamer {
}
if (instruction.sourceElement != null) {
if (instruction.sourceElement.name != null) {
name = allocateWithHint(instruction.sourceElement.name);
if (instruction.sourceElement!.name != null) {
name = allocateWithHint(instruction.sourceElement!.name!);
} else {
// Source element is synthesized and has no name.
name = allocateTemporary();
@@ -513,9 +512,10 @@ class VariableNamer {
// We could not find an element for the instruction. If the
// instruction is used by a phi, try to use the name of the phi.
// Otherwise, just allocate a temporary name.
HPhi phi = firstPhiUserWithElement(instruction);
if (phi != null && phi.sourceElement.name != null) {
name = allocateWithHint(phi.sourceElement.name);
HPhi? phi = firstPhiUserWithElement(instruction);
final phiName = phi?.sourceElement?.name;
if (phiName != null) {
name = allocateWithHint(phiName);
} else {
name = allocateTemporary();
}
@@ -532,7 +532,7 @@ class VariableNamer {
/// Frees [instruction]'s name so it can be used for other instructions.
void freeName(HInstruction instruction) {
String ownName = names.ownName[instruction];
String? ownName = names.ownName[instruction];
if (ownName != null) {
// We check if we have already looked for temporary names
// because if we haven't, chances are the temporary we allocate
@@ -576,7 +576,7 @@ class SsaVariableAllocator extends HBaseVisitor<void> with CodegenPhase {
@override
void visitBasicBlock(HBasicBlock block) {
VariableNamer variableNamer =
VariableNamer(liveInstructions[block], names, _namer);
VariableNamer(liveInstructions[block]!, names, _namer);
block.forEachPhi((HPhi phi) {
handlePhi(phi, variableNamer);
@@ -599,8 +599,8 @@ class SsaVariableAllocator extends HBaseVisitor<void> with CodegenPhase {
/// Returns whether [instruction] dies at the instruction [at].
bool diesAt(HInstruction instruction, HInstruction at) {
LiveInterval atInterval = liveIntervals[at];
LiveInterval instructionInterval = liveIntervals[instruction];
LiveInterval atInterval = liveIntervals[at]!;
LiveInterval instructionInterval = liveIntervals[instruction]!;
int start = atInterval.start;
return instructionInterval.diesAt(start);
}
@@ -642,7 +642,7 @@ class SsaVariableAllocator extends HBaseVisitor<void> with CodegenPhase {
for (int i = 0; i < phi.inputs.length; i++) {
HInstruction input = phi.inputs[i];
HBasicBlock predecessor = phi.block.predecessors[i];
HBasicBlock predecessor = phi.block!.predecessors[i];
// A [HTypeKnown] instruction never has a name, but its checked
// input might, therefore we need to do a copy instead of an
// assignment.
+1 -1
View File
@@ -496,7 +496,7 @@ class StaticUse {
/// Direct invocation of a method [element] with the given [callStructure].
factory StaticUse.directInvoke(FunctionEntity element,
CallStructure callStructure, List<DartType> typeArguments) {
CallStructure callStructure, List<DartType>? typeArguments) {
assert(
element.isInstanceMember,
failedAt(element,
+24 -5
View File
@@ -805,7 +805,11 @@ class For extends Loop {
final Expression? condition;
final Expression? update;
For(this.init, this.condition, this.update, Statement body) : super(body);
For(this.init, this.condition, this.update, Statement body,
{JavaScriptNodeSourceInformation? sourceInformation})
: super(body) {
_sourceInformation = sourceInformation;
}
@override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitFor(this);
@@ -840,7 +844,11 @@ class ForIn extends Loop {
final Expression leftHandSide;
final Expression object;
ForIn(this.leftHandSide, this.object, Statement body) : super(body);
ForIn(this.leftHandSide, this.object, Statement body,
{JavaScriptNodeSourceInformation? sourceInformation})
: super(body) {
_sourceInformation = sourceInformation;
}
@override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitForIn(this);
@@ -870,7 +878,11 @@ class ForIn extends Loop {
class While extends Loop {
final Expression condition;
While(this.condition, Statement body) : super(body);
While(this.condition, Statement body,
{JavaScriptNodeSourceInformation? sourceInformation})
: super(body) {
_sourceInformation = sourceInformation;
}
@override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitWhile(this);
@@ -898,7 +910,11 @@ class While extends Loop {
class Do extends Loop {
final Expression condition;
Do(Statement body, this.condition) : super(body);
Do(Statement body, this.condition,
{JavaScriptNodeSourceInformation? sourceInformation})
: super(body) {
_sourceInformation = sourceInformation;
}
@override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitDo(this);
@@ -1509,7 +1525,10 @@ class VariableInitialization extends Expression {
// The initializing value can be missing, e.g. for `a` in `var a, b=1;`.
final Expression? value;
VariableInitialization(this.declaration, this.value);
VariableInitialization(this.declaration, this.value,
{JavaScriptNodeSourceInformation? sourceInformation}) {
_sourceInformation = sourceInformation;
}
@override
int get precedenceLevel => ASSIGNMENT;
+10
View File
@@ -134,6 +134,16 @@ class Template {
}
throw ArgumentError.value(arguments, 'arguments', 'Must be a List or Map');
}
// TODO(sra): We should rather make the return type of `instantiate` be what
// we need, either by making Template be generic or have Expression and
// Statement subclasses that override `instantiate`. Checking is likely still
// required since the argument can be the result (e.g. "#").
Expression instantiateExpression(Object arguments) =>
instantiate(arguments) as Expression;
Statement instantiateStatement(Object arguments) =>
instantiate(arguments) as Statement;
}
/// An Instantiator is a Function that generates a JS AST tree or List of