diff --git a/pkg/compiler/lib/src/js_backend/specialized_checks.dart b/pkg/compiler/lib/src/js_backend/specialized_checks.dart index 76b6cba7ab3..f86b47f8068 100644 --- a/pkg/compiler/lib/src/js_backend/specialized_checks.dart +++ b/pkg/compiler/lib/src/js_backend/specialized_checks.dart @@ -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 || diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart index 05e4603e8ea..ec6aac0f518 100644 --- a/pkg/compiler/lib/src/ssa/codegen.dart +++ b/pkg/compiler/lib/src/ssa/codegen.dart @@ -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 'dart:math' as math; import 'dart:collection' show Queue; @@ -58,8 +56,7 @@ class SsaCodeGeneratorTask extends CompilerTask { final _CodegenMetrics _metrics = _CodegenMetrics(); SsaCodeGeneratorTask( - Measurer measurer, this._options, this.sourceInformationStrategy) - : super(measurer); + Measurer super.measurer, this._options, this.sourceInformationStrategy); @override String get name => 'SSA code generator'; @@ -73,7 +70,7 @@ class SsaCodeGeneratorTask extends CompilerTask { return js.Fun(parameters, body, asyncModifier: asyncModifier) .withSourceInformation(sourceInformationStrategy .createBuilderForContext(element) - .buildDeclaration(element)); + .buildDeclaration(element)) as js.Fun; } if (needsAsyncRewrite) { @@ -101,13 +98,13 @@ class SsaCodeGeneratorTask extends CompilerTask { if (member is FieldEntity) { code = generateLazyInitializer( member, graph, codegen, closedWorld, registry, namer, emitter); - } else { + } else if (member is FunctionEntity) { code = generateMethod( member, graph, codegen, closedWorld, registry, namer, emitter); + } else { + failedAt(member, 'Cannot generate JavaScript for $member'); } - if (code != null) { - codegen.tracer.traceJavaScriptText('JavaScript', code.debugPrint); - } + codegen.tracer.traceJavaScriptText('JavaScript', code.debugPrint); return code; } @@ -120,7 +117,7 @@ class SsaCodeGeneratorTask extends CompilerTask { ModularNamer namer, ModularEmitter emitter) { return measure(() { - SourceInformation sourceInformation = sourceInformationStrategy + SourceInformation? sourceInformation = sourceInformationStrategy .createBuilderForContext(field) .buildDeclaration(field); SsaCodeGenerator codeGenerator = SsaCodeGenerator( @@ -246,12 +243,17 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { final _CodegenMetrics _metrics; final Set generateAtUseSite = {}; - final Set controlFlowOperators = {}; + final Set controlFlowOperators = {}; final Set breakAction = {}; final Set continueAction = {}; final Set implicitContinueAction = {}; final List parameters = []; + // Using a Block as the current container allows a statement tree to be + // constructed that contains the block, and then have the block filled in + // later. + // TODO(sra): It would be cleaner if the [js.Block] could be unmodifiable but + // that would require deferring the construction of the containing AST. js.Block currentContainer = js.Block.empty(); js.Block get body => currentContainer; List expressionStack = []; @@ -259,7 +261,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { /// Contains the names of the instructions, as well as the parallel /// copies to perform on block transitioning. - VariableNames variableNames; + late VariableNames variableNames; /// `true` when we need to generate a `var` declaration at function entry, /// `false` if we can generate a `var` declaration at first assignment in the @@ -275,17 +277,17 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { /// Set of variables and parameters that have already been declared. final Set declaredLocals = {}; - HGraph currentGraph; + late HGraph currentGraph; // Records a block-information that is being handled specially. // Used to break bad recursion. - HBlockInformation currentBlockInformation; + HBlockInformation? currentBlockInformation; // The subgraph is used to delimit traversal for some constructions, e.g., // if branches. - SubGraph subGraph; + SubGraph? subGraph; // Pending blocks than need to be visited as part of current subgraph. - Queue blockQueue; + Queue? blockQueue; SsaCodeGenerator( this._codegenTask, @@ -331,16 +333,18 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { // of bits. int bitWidth(HInstruction instruction) { const int MAX = 32; - int constant(HInstruction instruction) { - if (instruction is HConstant && instruction.isConstantInteger()) { - IntConstantValue constant = instruction.constant; - return constant.intValue.toInt(); + int? constant(HInstruction instruction) { + if (instruction is HConstant) { + ConstantValue constant = instruction.constant; + if (constant is IntConstantValue) { + return constant.intValue.toInt(); + } } return null; } if (instruction.isConstantInteger()) { - int value = constant(instruction); + int value = constant(instruction)!; if (value < 0) return MAX; if (value > ((1 << 31) - 1)) return MAX; return value.bitLength; @@ -348,21 +352,25 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { if (instruction is HBitAnd) { return math.min(bitWidth(instruction.left), bitWidth(instruction.right)); } - if (instruction is HBitOr || instruction is HBitXor) { - HBinaryBitOp bitOp = instruction; - int leftWidth = bitWidth(bitOp.left); + if (instruction is HBitOr) { + int leftWidth = bitWidth(instruction.left); if (leftWidth == MAX) return MAX; - return math.max(leftWidth, bitWidth(bitOp.right)); + return math.max(leftWidth, bitWidth(instruction.right)); + } + if (instruction is HBitXor) { + int leftWidth = bitWidth(instruction.left); + if (leftWidth == MAX) return MAX; + return math.max(leftWidth, bitWidth(instruction.right)); } if (instruction is HShiftLeft) { - int shiftCount = constant(instruction.right); + int? shiftCount = constant(instruction.right); if (shiftCount == null || shiftCount < 0 || shiftCount > 31) return MAX; int leftWidth = bitWidth(instruction.left); int width = leftWidth + shiftCount; return math.min(width, MAX); } if (instruction is HShiftRight) { - int shiftCount = constant(instruction.right); + int? shiftCount = constant(instruction.right); if (shiftCount == null || shiftCount < 0 || shiftCount > 31) return MAX; int leftWidth = bitWidth(instruction.left); if (leftWidth >= MAX) return MAX; @@ -400,14 +408,14 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { /// If the [instruction] is not `null` it will be used to attach the position /// to the [expression]. pushExpressionAsStatement( - js.Expression expression, SourceInformation sourceInformation) { + js.Expression expression, SourceInformation? sourceInformation) { pushStatement(js.ExpressionStatement(expression) .withSourceInformation(sourceInformation)); } /// If the [instruction] is not `null` it will be used to attach the position /// to the [expression]. - push(js.Expression /*!*/ expression) { + push(js.Expression expression) { expressionStack.add(expression); } @@ -448,7 +456,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { shouldGroupVarDeclarations = allocator.names.numberOfVariables > 1; } - void handleDelayedVariableDeclarations(SourceInformation sourceInformation) { + void handleDelayedVariableDeclarations(SourceInformation? sourceInformation) { // Create 'var' list at the start of function. Move assignment statements // from the top of the body into the variable initializers. if (collectedVariableDeclarations.isEmpty) return; @@ -469,9 +477,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { js.Expression value = expression.value; if (_safeInInitializer(value) && collectedVariableDeclarations.remove(name)) { - var initialization = - js.VariableInitialization(js.VariableDeclaration(name), value) - .withSourceInformation(expression.sourceInformation); + var initialization = js.VariableInitialization( + js.VariableDeclaration(name), value, + sourceInformation: expression.sourceInformation); declarations.add(initialization); ++nextStatement; continue; @@ -506,12 +514,14 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { handleDelayedVariableDeclarations(graph.sourceInformation); } - void visitSubGraph(SubGraph newSubGraph) { - SubGraph oldSubGraph = subGraph; - Queue oldBlockQueue = blockQueue; + void visitSubGraph(SubGraph? newSubGraph) { + final oldSubGraph = subGraph; + final oldBlockQueue = blockQueue; + subGraph = newSubGraph; - blockQueue = Queue(); - enterSubGraph(subGraph.start); + blockQueue = Queue(); + enterSubGraph(subGraph!.start); + blockQueue = oldBlockQueue; subGraph = oldSubGraph; } @@ -529,8 +539,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { // here. If we start using the other HExpressionInformation types too, // this code should be generalized. assert(info is HSubExpressionBlockInformation); + info as HSubExpressionBlockInformation; HSubExpressionBlockInformation expressionInfo = info; - SubGraph limits = expressionInfo.subExpression; + SubGraph limits = expressionInfo.subExpression!; // Start assuming that we can generate declarations. If we find a // counter-example, we degrade our assumption to either expression or @@ -540,7 +551,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { int result = TYPE_DECLARATION; HBasicBlock basicBlock = limits.start; do { - HInstruction current = basicBlock.first; + HInstruction current = basicBlock.first!; while (current != basicBlock.last) { // E.g, bounds check. if (current.isControlFlow()) { @@ -551,7 +562,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { if (current.usedBy.isEmpty || current is HFieldSet) { result = TYPE_EXPRESSION; } - current = current.next; + current = current.next!; } if (current is HGoto) { basicBlock = basicBlock.successors[0]; @@ -578,27 +589,30 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { return !identical(expressionType(info), TYPE_STATEMENT); } - bool isJSCondition(HExpressionInformation info) { - HSubExpressionBlockInformation graph = info; - SubExpression limits = graph.subExpression; + bool isJSCondition(HExpressionInformation? info) { + // Currently we only handle sub-expression graphs. + info as HSubExpressionBlockInformation; + + SubExpression? limits = info.subExpression; return !identical(expressionType(info), TYPE_STATEMENT) && - (limits.end.last is HConditionalBranch); + (limits!.end.last is HConditionalBranch); } /// Generate statements from block information. /// If the block information contains expressions, generate only /// assignments, and if it ends in a conditional branch, don't generate /// the condition. - void generateStatements(HBlockInformation block) { + void generateStatements(HBlockInformation? block) { if (block is HStatementInformation) { block.accept(this); + } else if (block is HSubExpressionBlockInformation) { + visitSubGraph(block.subExpression); } else { - HSubExpressionBlockInformation expression = block; - visitSubGraph(expression.subExpression); + failedAt(CURRENT_ELEMENT_SPANNABLE, 'Unexpected block: $block'); } } - js.Block generateStatementsInNewBlock(HBlockInformation block) { + js.Block generateStatementsInNewBlock(HBlockInformation? block) { js.Block result = js.Block.empty(); js.Block oldContainer = currentContainer; currentContainer = result; @@ -623,9 +637,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } /// Generate expressions from block information. - js.Expression generateExpression(HExpressionInformation expression) { + js.Expression? generateExpression(HExpressionInformation expression) { // Currently we only handle sub-expression graphs. - assert(expression is HSubExpressionBlockInformation); + expression as HSubExpressionBlockInformation; bool oldIsGeneratingExpression = isGeneratingExpression; isGeneratingExpression = true; @@ -654,13 +668,10 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { List visitArguments(List inputs, {int start = HInvoke.ARGUMENTS_OFFSET}) { assert(inputs.length >= start); - List result = - List.filled(inputs.length - start, null); - for (int i = start; i < inputs.length; i++) { - use(inputs[i]); - result[i - start] = pop(); - } - return result; + return List.generate(inputs.length - start, (i) { + use(inputs[i + start]); + return pop(); + }, growable: false); } bool isVariableDeclared(String variableName) { @@ -669,7 +680,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } js.Expression generateExpressionAssignment(String variableName, - js.Expression value, SourceInformation sourceInformation) { + js.Expression value, SourceInformation? sourceInformation) { // TODO(johnniwinther): Introduce a DeferredVariableUse to handle this // in the SSA codegen or let the JS printer handle it fully and remove it // here. @@ -703,7 +714,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } void assignVariable(String variableName, js.Expression value, - SourceInformation sourceInformation) { + SourceInformation? sourceInformation) { if (isGeneratingExpression) { // If we are in an expression then we can't declare the variable here. // We have no choice, but to use it and then declare it separately. @@ -749,7 +760,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { instruction is HBoolConversion || instruction is HNullCheck || instruction is HLateReadCheck) { - String inputName = variableNames.getName(instruction.checkedInput); + String? inputName = variableNames.getName(instruction.checkedInput); if (variableNames.getName(instruction) == inputName) { needsAssignment = false; } @@ -763,7 +774,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { !instruction.isControlFlow() && variableNames.hasName(instruction)) { visitExpression(instruction); - assignVariable(variableNames.getName(instruction), pop(), + assignVariable(variableNames.getName(instruction)!, pop(), instruction.sourceInformation); return; } @@ -804,7 +815,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { use(skipGenerateAtUseCheckInputs(check)); } else { assert(variableNames.hasName(argument)); - push(js.VariableUse(variableNames.getName(argument))); + push(js.VariableUse(variableNames.getName(argument)!)); } } @@ -864,16 +875,16 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } if (isExpression) { - push(generateExpression(info.expression)); + push(generateExpression(info.expression)!); } else { - use(info.expression.conditionExpression); + use(info.expression.conditionExpression!); } js.Expression key = pop(); bool handledDefault = false; List cases = []; - HSwitch switchInstruction = info.expression.end.last; + HSwitch switchInstruction = info.expression.end.last as HSwitch; List inputs = switchInstruction.inputs; - List successors = switchInstruction.block.successors; + List successors = switchInstruction.block!.successors; js.Block oldContainer = currentContainer; for (int inputIndex = 1, statementIndex = 0; @@ -944,30 +955,23 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { return false; } - @override - bool visitAndOrInfo(HAndOrBlockInformation info) { - return false; - } - @override bool visitTryInfo(HTryBlockInformation info) { js.Block body = generateStatementsInNewBlock(info.body); - js.Catch catchPart = null; - js.Block finallyPart = null; + js.Catch? catchPart = null; + js.Block? finallyPart = null; if (info.catchBlock != null) { void register(ClassEntity classElement) { - if (classElement != null) { - _registry - // ignore:deprecated_member_use_from_same_package - .registerInstantiatedClass(classElement); - } + _registry + // ignore:deprecated_member_use_from_same_package + .registerInstantiatedClass(classElement); } register(_commonElements.jsPlainJavaScriptObjectClass); register(_commonElements.jsUnknownJavaScriptObjectClass); - HLocalValue exception = info.catchVariable; - String name = variableNames.getName(exception); + HLocalValue? exception = info.catchVariable; + String name = variableNames.getName(exception)!; js.VariableDeclaration decl = js.VariableDeclaration(name); js.Block catchBlock = generateStatementsInNewBlock(info.catchBlock); catchPart = js.Catch(decl, catchBlock); @@ -980,9 +984,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } void visitBodyIgnoreLabels(HLoopBlockInformation info) { - if (info.body.start.isLabeledBlock()) { - HBlockInformation oldInfo = currentBlockInformation; - currentBlockInformation = info.body.start.blockFlow.body; + if (info.body!.start.isLabeledBlock()) { + HBlockInformation? oldInfo = currentBlockInformation; + currentBlockInformation = info.body!.start.blockFlow!.body; generateStatements(info.body); currentBlockInformation = oldInfo; } else { @@ -992,10 +996,10 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { @override bool visitLoopInfo(HLoopBlockInformation info) { - HExpressionInformation condition = info.condition; + HExpressionInformation? condition = info.condition; bool isConditionExpression = isJSCondition(condition); - js.Loop loop; + late js.Loop loop; switch (info.kind) { // Treat all three "test-first" loops the same way. @@ -1003,7 +1007,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { case HLoopBlockInformation.WHILE_LOOP: case HLoopBlockInformation.FOR_IN_LOOP: case HLoopBlockInformation.SWITCH_CONTINUE_LOOP: - HBlockInformation initialization = info.initializer; + HExpressionInformation? initialization = info.initializer; int initializationType = TYPE_STATEMENT; if (initialization != null) { initializationType = expressionType(initialization); @@ -1018,17 +1022,17 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { js.Block oldContainer = currentContainer; js.Block avoidContainer = js.Block.empty(); currentContainer = avoidContainer; - assignPhisOfSuccessors(condition.end.successors.last); + assignPhisOfSuccessors(condition!.end.successors.last); bool hasPhiUpdates = !avoidContainer.statements.isEmpty; currentContainer = oldContainer; if (isConditionExpression && !hasPhiUpdates && info.updates != null && - isJSExpression(info.updates)) { + isJSExpression(info.updates!)) { // If we have an updates graph, and it's expressible as an // expression, generate a for-loop. - js.Expression jsInitialization = null; + js.Expression? jsInitialization = null; if (initialization != null) { int delayedVariablesCount = collectedVariableDeclarations.length; jsInitialization = generateExpression(initialization); @@ -1040,30 +1044,30 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { // expressions and see if they are all assignments that can be // converted into declarations. - List assignments; + List? assignments; bool allSimpleAssignments(js.Expression expression) { if (expression is js.Assignment) { js.Assignment assignment = expression; if (assignment.leftHandSide is js.VariableUse && !assignment.isCompound) { - assignments ??= []; - assignments.add(expression); + (assignments ??= []).add(expression); return true; } - } else if (expression.isCommaOperator) { - js.Binary binary = expression; - return allSimpleAssignments(binary.left) && - allSimpleAssignments(binary.right); + } else if (expression is js.Binary && + expression.isCommaOperator) { + return allSimpleAssignments(expression.left) && + allSimpleAssignments(expression.right); } return false; } - if (allSimpleAssignments(jsInitialization)) { + if (jsInitialization != null && + allSimpleAssignments(jsInitialization)) { List inits = []; - for (js.Assignment assignment in assignments) { - String id = (assignment.leftHandSide as js.VariableUse).name; - js.Node declaration = js.VariableDeclaration(id); + for (js.Assignment assignment in assignments!) { + final id = (assignment.leftHandSide as js.VariableUse).name; + final declaration = js.VariableDeclaration(id); inits.add( js.VariableInitialization(declaration, assignment.value)); collectedVariableDeclarations.remove(id); @@ -1073,29 +1077,29 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } } } - js.Expression jsCondition = generateExpression(condition); - js.Expression jsUpdates = generateExpression(info.updates); + js.Expression? jsCondition = generateExpression(condition); + js.Expression? jsUpdates = generateExpression(info.updates!); // The body might be labeled. Ignore this when recursing on the // subgraph. // TODO(lrn): Remove this extra labeling when handling all loops // using subgraphs. oldContainer = currentContainer; - js.Statement body = js.Block.empty(); + js.Block body = js.Block.empty(); currentContainer = body; visitBodyIgnoreLabels(info); currentContainer = oldContainer; - body = unwrapStatement(body); - loop = js.For(jsInitialization, jsCondition, jsUpdates, body) - .withSourceInformation(info.sourceInformation); + loop = js.For( + jsInitialization, jsCondition, jsUpdates, unwrapStatement(body), + sourceInformation: info.sourceInformation); } else { // We have either no update graph, or it's too complex to // put in an expression. if (initialization != null) { generateStatements(initialization); } - js.Expression jsCondition; + js.Expression? jsCondition; js.Block oldContainer = currentContainer; - js.Statement body = js.Block.empty(); + js.Block body = js.Block.empty(); if (isConditionExpression && !hasPhiUpdates) { jsCondition = generateExpression(condition); currentContainer = body; @@ -1103,7 +1107,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { jsCondition = newLiteralBool(true, info.sourceInformation); currentContainer = body; generateStatements(condition); - use(condition.conditionExpression); + use(condition.conditionExpression!); js.Expression ifTest = js.Prefix("!", pop()); js.Statement jsBreak = js.Break(null); js.Statement exitLoop; @@ -1122,9 +1126,8 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { visitBodyIgnoreLabels(info); } currentContainer = oldContainer; - body = unwrapStatement(body); - loop = js.While(jsCondition, body) - .withSourceInformation(info.sourceInformation); + loop = js.While(jsCondition!, unwrapStatement(body), + sourceInformation: info.sourceInformation); } break; case HLoopBlockInformation.DO_WHILE_LOOP: @@ -1136,7 +1139,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { js.Block oldContainer = currentContainer; js.Block exitAvoidContainer = js.Block.empty(); currentContainer = exitAvoidContainer; - assignPhisOfSuccessors(condition.end.successors.last); + assignPhisOfSuccessors(condition!.end.successors.last); bool hasExitPhiUpdates = !exitAvoidContainer.statements.isEmpty; currentContainer = oldContainer; @@ -1163,20 +1166,21 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { if (info.updates != null) { generateStatements(info.updates); } + js.Expression? jsCondition; if (isConditionExpression) { - push(generateExpression(condition)); + jsCondition = generateExpression(condition); } else { generateStatements(condition); - use(condition.conditionExpression); + use(condition.conditionExpression!); + jsCondition = pop(); } - js.Expression jsCondition = pop(); if (jsCondition == null) { // If the condition is dead code, we turn the do-while into // a simpler while because we will never reach the condition // at the end of the loop anyway. loop = js.While(newLiteralBool(true, info.sourceInformation), - unwrapStatement(body)) - .withSourceInformation(info.sourceInformation); + unwrapStatement(body), + sourceInformation: info.sourceInformation); } else { if (hasPhiUpdates || hasExitPhiUpdates) { updateBody.statements.add(js.Continue(null)); @@ -1191,19 +1195,19 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { body.statements.add(js.If(jsCondition, updateBody, exitLoop)); jsCondition = newLiteralBool(true, info.sourceInformation); } - loop = js.Do(unwrapStatement(body), jsCondition) - .withSourceInformation(info.sourceInformation); + loop = js.Do(unwrapStatement(body), jsCondition, + sourceInformation: info.sourceInformation); } currentContainer = oldContainer; break; default: - failedAt(condition.conditionExpression, + failedAt(condition!.conditionExpression!, 'Unexpected loop kind: ${info.kind}.'); } js.Statement result = loop; if (info.kind == HLoopBlockInformation.SWITCH_CONTINUE_LOOP) { String continueLabelString = - _namer.implicitContinueLabelName(info.target); + _namer.implicitContinueLabelName(info.target!); result = js.LabeledStatement(continueLabelString, result); } pushStatement(wrapIntoLabels(result, info.labels)); @@ -1236,7 +1240,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { // For handling unlabeled continues from the body of a loop. // TODO(lrn): Consider recording whether the target is in fact // a target of an unlabeled continue, and not generate this if it isn't. - JumpTarget target = labeledBlockInfo.target; + JumpTarget target = labeledBlockInfo.target!; String labelName = _namer.implicitContinueLabelName(target); result = js.LabeledStatement(labelName, result); implicitContinueAction.add(target); @@ -1249,7 +1253,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } } } - JumpTarget target = labeledBlockInfo.target; + JumpTarget target = labeledBlockInfo.target!; if (target.isSwitch) { // This is an extra block around a switch that is generated // as a nested if/else chain. We add an extra break target @@ -1266,7 +1270,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { while (!continueOverrides.isEmpty) { continueAction.remove(continueOverrides.head); implicitContinueAction.remove(continueOverrides.head); - continueOverrides = continueOverrides.tail; + continueOverrides = continueOverrides.tail!; } } else { breakAction.remove(labeledBlockInfo.target); @@ -1280,7 +1284,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { // Wraps a loop body in a block to make continues have a target to break // to (if necessary). void wrapLoopBodyForContinue(HLoopBlockInformation info) { - JumpTarget target = info.target; + JumpTarget? target = info.target; if (target != null && target.isContinueTarget) { js.Block oldContainer = currentContainer; js.Block body = js.Block.empty(); @@ -1295,9 +1299,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } String labelName = _namer.implicitContinueLabelName(target); result = js.LabeledStatement(labelName, result); - implicitContinueAction.add(info.target); + implicitContinueAction.add(target); visitBodyIgnoreLabels(info); - implicitContinueAction.remove(info.target); + implicitContinueAction.remove(target); for (LabelDefinition label in info.labels) { if (label.isContinueTarget) { continueAction.remove(label); @@ -1321,13 +1325,13 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { // "if" and its condition). if (identical(info, currentBlockInformation)) return false; - HBlockInformation oldBlockInformation = currentBlockInformation; + HBlockInformation? oldBlockInformation = currentBlockInformation; currentBlockInformation = info; bool success = info.accept(this); currentBlockInformation = oldBlockInformation; if (success) { - HBasicBlock continuation = block.continuation; + HBasicBlock? continuation = block.continuation; if (continuation != null) { continueSubGraph(continuation); } @@ -1336,17 +1340,16 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } void enterSubGraph(HBasicBlock node) { - assert(blockQueue.isEmpty); - assert(node != null); + assert(blockQueue!.isEmpty); continueSubGraph(node); - while (blockQueue.isNotEmpty) { - node = blockQueue.removeFirst(); + while (blockQueue!.isNotEmpty) { + node = blockQueue!.removeFirst(); assert(node.isLive); - assert(subGraph.contains(node)); + assert(subGraph!.contains(node)); // If this node has block-structure based information attached, // try using that to traverse from here. - if (node.blockFlow != null && handleBlockFlow(node.blockFlow)) { + if (node.blockFlow != null && handleBlockFlow(node.blockFlow!)) { continue; } @@ -1357,12 +1360,12 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { void continueSubGraph(HBasicBlock node) { if (!node.isLive) return; // Don't follow edges out of the current sub-graph. - if (!subGraph.contains(node)) return; - blockQueue.add(node); + if (!subGraph!.contains(node)) return; + blockQueue!.add(node); } void emitAssignment( - String destination, String source, SourceInformation sourceInformation) { + String destination, String source, SourceInformation? sourceInformation) { assignVariable(destination, js.VariableUse(source), sourceInformation); } @@ -1372,15 +1375,15 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { Iterable> instructionCopies, String tempName, void doAssignment( - String target, String source, SourceInformation sourceInformation)) { - Map sourceInformationMap = {}; + String target, String source, SourceInformation? sourceInformation)) { + Map sourceInformationMap = {}; // Map the instructions to strings. Iterable> copies = instructionCopies.map((Copy copy) { - String sourceName = variableNames.getName(copy.source); + String sourceName = variableNames.getName(copy.source)!; sourceInformationMap[sourceName] = copy.source.sourceInformation; - String destinationName = variableNames.getName(copy.destination); + String destinationName = variableNames.getName(copy.destination)!; sourceInformationMap[sourceName] = copy.destination.sourceInformation; return Copy(sourceName, destinationName); }); @@ -1428,10 +1431,10 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { while (!worklist.isEmpty) { while (!ready.isEmpty) { String destination = ready.removeLast(); - String source = initialValue[destination]; + String source = initialValue[destination]!; // Since [source] might have been updated, use the current // location of [source] - String copy = currentLocation[source]; + String copy = currentLocation[source]!; doAssignment(destination, copy, sourceInformationMap[copy] ?? sourceInformationMap[destination]); // Now [destination] is the current location of [source]. @@ -1461,14 +1464,14 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } void assignPhisOfSuccessors(HBasicBlock node) { - CopyHandler handler = variableNames.getCopyHandler(node); + CopyHandler? handler = variableNames.getCopyHandler(node); if (handler == null) return; sequentializeCopies( handler.copies, variableNames.getSwapTemp(), emitAssignment); for (Copy copy in handler.assignments) { - String name = variableNames.getName(copy.destination); + String name = variableNames.getName(copy.destination)!; use(copy.source); assignVariable(name, pop(), copy.source.sourceInformation ?? copy.destination.sourceInformation); @@ -1476,19 +1479,19 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } void iterateBasicBlock(HBasicBlock node) { - HInstruction instruction = node.first; + HInstruction instruction = node.first!; while (!identical(instruction, node.last)) { if (!isGenerateAtUseSite(instruction)) { define(instruction); } - instruction = instruction.next; + instruction = instruction.next!; } assignPhisOfSuccessors(node); visit(instruction); } void handleInvokeBinary( - HInvokeBinary node, String op, SourceInformation sourceInformation) { + HInvokeBinary node, String op, SourceInformation? sourceInformation) { use(node.left); js.Expression jsLeft = pop(); use(node.right); @@ -1534,9 +1537,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } void emitIdentityComparison( - HIdentity instruction, SourceInformation sourceInformation, + HIdentity instruction, SourceInformation? sourceInformation, {bool inverse = false}) { - String op = instruction.singleComparisonOp; + String? op = instruction.singleComparisonOp; HInstruction left = instruction.left; HInstruction right = instruction.right; if (op != null) { @@ -1636,7 +1639,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { @override visitGoto(HGoto node) { - HBasicBlock block = node.block; + HBasicBlock block = node.block!; assert(block.successors.length == 1); List dominated = block.dominatedBlocks; // With the exception of the entry-node which dominates its successor @@ -1657,7 +1660,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { @override visitLoopBranch(HLoopBranch node) { - assert(node.block == subGraph.end); + assert(node.block == subGraph!.end); // We are generating code for a loop condition. // If we are generating the subgraph as an expression, the // condition will be generated as the expression. @@ -1670,9 +1673,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { @override visitBreak(HBreak node) { - assert(node.block.successors.length == 1); + assert(node.block!.successors.length == 1); if (node.label != null) { - LabelDefinition label = node.label; + LabelDefinition label = node.label!; if (breakAction.contains(label.target)) { implicitBreakWithLabel(label.target); } else { @@ -1697,9 +1700,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { @override visitContinue(HContinue node) { - assert(node.block.successors.length == 1); + assert(node.block!.successors.length == 1); if (node.label != null) { - LabelDefinition label = node.label; + LabelDefinition label = node.label!; if (continueAction.contains(label)) { continueAsBreak(label); } else { @@ -1742,7 +1745,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { bool tryControlFlowOperation(HIf node) { if (!controlFlowOperators.contains(node)) return false; - HPhi phi = node.joinBlock.phis.first; + HPhi phi = node.joinBlock!.phis.first as HPhi; bool atUseSite = isGenerateAtUseSite(phi); // Don't generate a conditional operator in this situation: // i = condition ? bar() : i; @@ -1755,20 +1758,20 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { return false; } if (!atUseSite) define(phi); - continueSubGraph(node.joinBlock); + continueSubGraph(node.joinBlock!); return true; } void generateIf(HIf node, HIfBlockInformation info) { - HStatementInformation thenGraph = info.thenGraph; - HStatementInformation elseGraph = info.elseGraph; + HStatementInformation? thenGraph = info.thenGraph; + HStatementInformation? elseGraph = info.elseGraph; HInstruction condition = node.inputs.single; js.Expression test; js.Statement thenPart; js.Statement elsePart; - HBasicBlock thenBlock = node.block.successors[0]; + HBasicBlock thenBlock = node.block!.successors[0]; // If we believe we will generate S1 as empty, instead of // // if (e) S1; else S2; @@ -1782,7 +1785,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { if (isGenerateAtUseSite(condition) && thenBlock.successors.length == 1 && thenBlock.successors.single == node.joinBlock && - node.joinBlock.phis.isEmpty && + node.joinBlock!.phis.isEmpty && thenBlock.first is HGoto) { generateNot(condition, condition.sourceInformation); test = pop(); @@ -1815,7 +1818,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { return js.ExpressionStatement(test); } test = js.Prefix('!', test); - var temp = thenPart; + js.Statement temp = thenPart; thenPart = elsePart; elsePart = temp; } @@ -1836,15 +1839,15 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { visitIf(HIf node) { _metrics.countHIf++; HInstruction condition = node.inputs[0]; - if (condition.isConstant()) _metrics.countHIfConstant++; + if (condition is HConstant) _metrics.countHIfConstant++; if (tryControlFlowOperation(node)) return; - HIfBlockInformation info = node.blockInformation.body; + HIfBlockInformation info = + node.blockInformation!.body as HIfBlockInformation; - if (condition.isConstant()) { - HConstant constant = condition; - if (constant.constant is TrueConstantValue) { + if (condition is HConstant) { + if (condition.constant is TrueConstantValue) { generateStatements(info.thenGraph); } else { generateStatements(info.elseGraph); @@ -1853,7 +1856,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { generateIf(node, info); } - HBasicBlock joinBlock = node.joinBlock; + HBasicBlock? joinBlock = node.joinBlock; if (joinBlock != null && !identical(joinBlock.dominator, node.block)) { // The join block is dominated by a block in one of the branches. // The subgraph traversal never reached it, so we visit it here @@ -1865,7 +1868,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { // branches, and is not the join block. // Depending on how the then/else branches terminate // (e.g., return/throw/break) there can be any number of these. - List dominated = node.block.dominatedBlocks; + List dominated = node.block!.dominatedBlocks; for (int i = 2; i < dominated.length; i++) { continueSubGraph(dominated[i]); } @@ -1885,8 +1888,8 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } else { _metrics.countHInterceptorGet.add(); assert(node.inputs.length == 1); - _registry.registerSpecializedGetInterceptor(node.interceptedClasses); - js.Name name = _namer.nameForGetInterceptor(node.interceptedClasses); + _registry.registerSpecializedGetInterceptor(node.interceptedClasses!); + js.Name name = _namer.nameForGetInterceptor(node.interceptedClasses!); js.Expression isolate = _namer.readGlobalObjectForInterceptors(); use(node.receiver); List arguments = [pop()]; @@ -1902,9 +1905,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { _updateInvokeMetrics(node); use(node.receiver); js.Expression object = pop(); - String methodName; + String? methodName; List arguments = visitArguments(node.inputs); - MemberEntity target = node.element; + MemberEntity? target = node.element; // TODO(herhut): The namer should return the appropriate backend name here. if (target != null && !node.isInterceptedCall) { @@ -1936,20 +1939,23 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { @override void visitInvokeConstructorBody(HInvokeConstructorBody node) { + final element = node.element as ConstructorBodyEntity; use(node.inputs[0]); js.Expression object = pop(); - js.Name methodName = _namer.instanceMethodName(node.element); + js.Name methodName = _namer.instanceMethodName(element); List arguments = visitArguments(node.inputs); push(js .propertyCall(object, methodName, arguments) .withSourceInformation(node.sourceInformation)); _registry.registerStaticUse(StaticUse.constructorBodyInvoke( - node.element, CallStructure.unnamed(arguments.length))); + element, CallStructure.unnamed(arguments.length))); } @override void visitInvokeGeneratorBody(HInvokeGeneratorBody node) { - JGeneratorBody element = node.element; + // TODO(sra): Refactor HInvokeGeneratorBody so that `node.element` has this + // type. + JGeneratorBody element = node.element as JGeneratorBody; if (element.isInstanceMember) { use(node.inputs[0]); js.Expression object = pop(); @@ -1965,7 +1971,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { js.Call(pop(), arguments, sourceInformation: node.sourceInformation)); } - _registry.registerStaticUse(StaticUse.generatorBodyInvoke(node.element)); + _registry.registerStaticUse(StaticUse.generatorBodyInvoke(element)); } @override @@ -1999,7 +2005,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { // [node.element] will be enqueued. We're not using the receiver // type because our optimizations might end up in a state where the // invoke dynamic knows more than the receiver. - ClassEntity enclosing = node.element.enclosingClass; + ClassEntity enclosing = node.element!.enclosingClass!; if (_closedWorld.classHierarchy.isInstantiated(enclosing)) { return _abstractValueDomain.createNonNullExact(enclosing); } else { @@ -2014,7 +2020,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { return _abstractValueDomain.createNonNullSubtype(enclosing); } } - return mask ?? _abstractValueDomain.dynamicType; + return mask; } void registerMethodInvoke(HInvokeDynamic node) { @@ -2023,7 +2029,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { // If we don't know what we're calling or if we are calling a getter, // we need to register that fact that we may be calling a closure // with the same arguments. - MemberEntity target = node.element; + MemberEntity? target = node.element; if ((target == null || target.isGetter) && // TODO(johnniwinther): Remove this when kernel adds an `isFunctionCall` // flag to [ir.MethodInvocation]. Currently we can't tell the difference @@ -2046,6 +2052,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { failedAt(node, '$selector does not apply to $target')); assert(!selector.isGetter && !selector.isSetter, "Unexpected direct invocation selector: $selector."); + target as FunctionEntity; // TODO(sra): Make node.element have this type. _registry.registerStaticUse(StaticUse.directInvoke( target, selector.callStructure, node.typeArguments)); } else { @@ -2057,12 +2064,13 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } void registerSetter(HInvokeDynamic node, {bool needsCheck = false}) { - if (node.element is FieldEntity && !needsCheck) { + final element = node.element; + if (element is FieldEntity && !needsCheck) { // This is a dynamic update which we have found to have a single // target but for some reason haven't inlined. We are _still_ accessing // the target dynamically but we don't need to enqueue more than target // for this to work. - _registry.registerStaticUse(StaticUse.directSet(node.element)); + _registry.registerStaticUse(StaticUse.directSet(element)); } else { Selector selector = node.selector; AbstractValue mask = @@ -2073,14 +2081,14 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } void registerGetter(HInvokeDynamic node) { - if (node.element != null && - (node.element.isGetter || node.element is FieldEntity)) { + final element = node.element; + if (element != null && (element.isGetter || element is FieldEntity)) { // This is a dynamic read which we have found to have a single target but // for some reason haven't inlined. We are _still_ accessing the target // dynamically but we don't need to enqueue more than target for this to // work. The test above excludes non-getter functions since the element // represents two targets - a tearoff getter and the torn-off method. - _registry.registerStaticUse(StaticUse.directGet(node.element)); + _registry.registerStaticUse(StaticUse.directGet(element)); } else { Selector selector = node.selector; AbstractValue mask = @@ -2132,7 +2140,11 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { @override visitInvokeStatic(HInvokeStatic node) { - MemberEntity element = node.element; + // TODO(48820): Refactor HInvokeStatic so that the element has static type + // FunctionEntity (`element` can be a FieldEntity in subclass HInvokeSuper, + // so possibly make HInvokeSuper and HInvokeStatic extend a common + // superclass, or have a different node for super-field accesses). + FunctionEntity element = node.element as FunctionEntity; node.instantiatedTypes?.forEach(_registry.registerInstantiation); List arguments = visitArguments(node.inputs, start: 0); @@ -2198,23 +2210,25 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { @override visitInvokeSuper(HInvokeSuper node) { MemberEntity superElement = node.element; - ClassEntity superClass = superElement.enclosingClass; Selector selector = node.selector; bool useAliasedSuper = canUseAliasedSuperMember(superElement, selector); if (selector.isGetter) { if (superElement is FieldEntity || superElement.isGetter) { _registry.registerStaticUse(StaticUse.superGet(superElement)); } else { - _registry.registerStaticUse(StaticUse.superTearOff(node.element)); + superElement as FunctionEntity; // Not a field so must be a function. + _registry.registerStaticUse(StaticUse.superTearOff(superElement)); } } else if (selector.isSetter) { if (superElement is FieldEntity) { _registry.registerStaticUse(StaticUse.superFieldSet(superElement)); } else { assert(superElement.isSetter); + superElement as FunctionEntity; // Not a field so must be a function. _registry.registerStaticUse(StaticUse.superSetterSet(superElement)); } } else { + superElement as FunctionEntity; // Not a field so must be a function. if (useAliasedSuper) { _registry.registerStaticUse(StaticUse.superInvoke( superElement, CallStructure.unnamed(node.inputs.length))); @@ -2229,7 +2243,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { js.Name fieldName = _namer.instanceFieldPropertyName(superElement); use(node.getDartReceiver(_closedWorld)); js.PropertyAccess access = js.PropertyAccess(pop(), fieldName) - .withSourceInformation(node.sourceInformation); + .withSourceInformation(node.sourceInformation) as js.PropertyAccess; if (node.isSetter) { use(node.value); push(js.Assignment(access, pop()) @@ -2237,7 +2251,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } else { push(access); } - } else { + } else if (superElement is FunctionEntity) { if (!useAliasedSuper) { js.Name methodName; if (selector.isGetter && !superElement.isGetter) { @@ -2255,6 +2269,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { methodName = _namer.instanceMethodName(superElement); } + ClassEntity superClass = superElement.enclosingClass!; push(js.js('#.#.call(#)', [ _emitter.prototypeAccess(superClass), methodName, @@ -2269,11 +2284,13 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { ]) // Skip receiver argument. .withSourceInformation(node.sourceInformation)); } + } else { + failedAt(node, 'node.element must be FieldEntity or FunctionEntity'); } } js.Expression _loadField(js.Expression receiver, FieldEntity field, - SourceInformation sourceInformation) { + SourceInformation? sourceInformation) { _registry.registerStaticUse(StaticUse.fieldGet(field)); js.Name name = _namer.instanceFieldPropertyName(field); return js.PropertyAccess(receiver, name) @@ -2347,7 +2364,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { visitLocalSet(HLocalSet node) { use(node.value); assignVariable( - variableNames.getName(node.receiver), pop(), node.sourceInformation); + variableNames.getName(node.receiver)!, pop(), node.sourceInformation); } @override @@ -2357,7 +2374,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { assert(_nativeData.isNativeMember(target), 'non-native target: $node'); - String targetName = _nativeData.hasFixedBackendName(target) + String? targetName = _nativeData.hasFixedBackendName(target) ? _nativeData.getFixedBackendName(target) : target.name; @@ -2387,23 +2404,23 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } js.Expression expression = js.js .uncachedExpressionTemplate(template) - .instantiate(templateInputs); + .instantiateExpression(templateInputs); push(expression.withSourceInformation(node.sourceInformation)); _registry.registerNativeMethod(target); } if (_nativeData.isJsInteropMember(target)) { if (target.isStatic || target.isTopLevel || target is ConstructorEntity) { - String path = _nativeData.getFixedBackendMethodPath(target); + String path = _nativeData.getFixedBackendMethodPath(target)!; js.Expression pathExpression = - js.js.uncachedExpressionTemplate(path).instantiate([]); + js.js.uncachedExpressionTemplate(path).instantiateExpression([]); invokeWithJavaScriptReceiver(pathExpression); return; } } if (_nativeData.isNativeMember(target)) { - _registry.registerNativeBehavior(node.nativeBehavior); + _registry.registerNativeBehavior(node.nativeBehavior!); if (target.isInstanceMember) { HInstruction receiver = inputs.first; use(receiver); @@ -2412,8 +2429,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } if (target.isStatic || target.isTopLevel) { var arguments = visitArguments(inputs, start: 0); - js.Expression targetExpression = - js.js.uncachedExpressionTemplate(targetName).instantiate([]); + js.Expression targetExpression = js.js + .uncachedExpressionTemplate(targetName!) + .instantiateExpression([]); js.Expression expression; if (target.isGetter) { expression = targetExpression; @@ -2434,7 +2452,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } void registerForeignTypes(HForeign node) { - NativeBehavior nativeBehavior = node.nativeBehavior; + NativeBehavior? nativeBehavior = node.nativeBehavior; if (nativeBehavior == null) return; _registry.registerNativeBehavior(nativeBehavior); } @@ -2449,7 +2467,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { interpolatedExpressions.add(pop()); } pushStatement(node.codeTemplate - .instantiate(interpolatedExpressions) + .instantiateStatement(interpolatedExpressions) .withSourceInformation(node.sourceInformation)); } else { List interpolatedExpressions = []; @@ -2458,7 +2476,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { interpolatedExpressions.add(pop()); } push(node.codeTemplate - .instantiate(interpolatedExpressions) + .instantiateExpression(interpolatedExpressions) .withSourceInformation(node.sourceInformation)); } @@ -2481,9 +2499,10 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { .registerInstantiatedClass(node.element); } node.instantiatedTypes?.forEach(_registry.registerInstantiation); - if (node.callMethod != null) { - _registry?.registerStaticUse(StaticUse.implicitInvoke(node.callMethod)); - _registry?.registerInstantiatedClosure(node.callMethod); + final callMethod = node.callMethod; + if (callMethod != null) { + _registry.registerStaticUse(StaticUse.implicitInvoke(callMethod)); + _registry.registerInstantiatedClosure(callMethod); } } @@ -2493,7 +2512,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } js.Expression newLiteralBool( - bool value, SourceInformation sourceInformation) { + bool value, SourceInformation? sourceInformation) { if (_options.enableMinification) { // Use !0 for true, !1 for false. return js.Prefix("!", js.LiteralNumber(value ? "0" : "1")) @@ -2504,7 +2523,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } void generateConstant( - ConstantValue constant, SourceInformation sourceInformation) { + ConstantValue constant, SourceInformation? sourceInformation) { js.Expression expression = _emitter.constantReference(constant); if (!constant.isDummy) { // TODO(johnniwinther): Support source information on synthetic constants. @@ -2543,15 +2562,11 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { ">": "<=", ">=": "<" }; - return inverse ? inverseOperator[op] : op; + return inverse ? inverseOperator[op]! : op; } - void generateNot(HInstruction input, SourceInformation sourceInformation) { - bool canGenerateOptimizedComparison(HInstruction instruction) { - if (instruction is! HRelational) return false; - - HRelational relational = instruction; - + void generateNot(HInstruction input, SourceInformation? sourceInformation) { + bool canGenerateOptimizedComparison(HRelational relational) { HInstruction left = relational.left; HInstruction right = relational.right; if (left.isStringOrNull(_abstractValueDomain).isDefinitelyTrue && @@ -2576,9 +2591,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { emitIdentityComparison(input, sourceInformation, inverse: true); } else if (input is HIsLateSentinel) { _emitIsLateSentinel(input, sourceInformation, inverse: true); - } else if (canGenerateOptimizedComparison(input)) { - HRelational relational = input; - constant_system.BinaryOperation operation = relational.operation(); + } else if (input is HRelational && + canGenerateOptimizedComparison(input)) { + constant_system.BinaryOperation operation = input.operation(); String op = mapRelationalOperator(operation.name, true); handleInvokeBinary(input, op, sourceInformation); } else { @@ -2594,7 +2609,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { @override visitParameterValue(HParameterValue node) { assert(!isGenerateAtUseSite(node)); - String name = variableNames.getName(node); + String name = variableNames.getName(node)!; parameters.add(js.Parameter(name)); declaredLocals.add(name); } @@ -2602,7 +2617,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { @override visitLocalValue(HLocalValue node) { assert(!isGenerateAtUseSite(node)); - String name = variableNames.getName(node); + String name = variableNames.getName(node)!; collectedVariableDeclarations.add(name); } @@ -2611,9 +2626,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { // This method is only called for phis that are generated at use // site. A phi can be generated at use site only if it is the // result of a control flow operation. - HBasicBlock ifBlock = node.block.dominator; + HBasicBlock ifBlock = node.block!.dominator!; assert(controlFlowOperators.contains(ifBlock.last)); - HInstruction input = ifBlock.last.inputs[0]; + HInstruction input = ifBlock.last!.inputs[0]; if (input.isConstantFalse()) { use(node.inputs[1]); } else if (input.isConstantTrue()) { @@ -2656,7 +2671,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { @override visitThrow(HThrow node) { - SourceInformation sourceInformation = node.sourceInformation; + SourceInformation? sourceInformation = node.sourceInformation; if (node.isRethrow) { use(node.inputs[0]); pushStatement(js.Throw(pop()).withSourceInformation(sourceInformation)); @@ -2720,8 +2735,8 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { // TODO(sra): Better analysis of possible NaN input. bool indexCanBeNaN = !_isDefinitelyNotNaN(index); - js.Expression under; - js.Expression over; + js.Expression? under; + js.Expression? over; if (index.isInteger(_abstractValueDomain).isPotentiallyFalse) { // Combined domain check and low bound check. `a >>> 0 !== a` is true for @@ -2758,7 +2773,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { assert(over != null || under != null); js.Expression underOver; if (under == null) { - underOver = over; + underOver = over!; } else if (over == null) { underOver = under; } else { @@ -2775,15 +2790,14 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { // Generate the call to the 'throw' helper in a block in case it needs // multiple statements. - js.Statement thenBody = js.Block.empty(); + js.Block thenBody = js.Block.empty(); js.Block oldContainer = currentContainer; currentContainer = thenBody; _pushThrowWithHelper(_commonElements.throwIndexOutOfRangeException, [node.array, node.reportedIndex], sourceInformation: node.sourceInformation); currentContainer = oldContainer; - thenBody = unwrapStatement(thenBody); - pushStatement(js.If.noElse(underOver, thenBody) + pushStatement(js.If.noElse(underOver, unwrapStatement(thenBody)) .withSourceInformation(node.sourceInformation)); } @@ -2803,7 +2817,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } void _pushThrowWithHelper(FunctionEntity helper, List inputs, - {SourceInformation sourceInformation}) { + {SourceInformation? sourceInformation}) { List arguments = []; for (final input in inputs) { use(input); @@ -2817,12 +2831,12 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } void _pushCallStatic(FunctionEntity target, List arguments, - SourceInformation sourceInformation) { + SourceInformation? sourceInformation) { _registry.registerStaticUse(StaticUse.staticInvoke( target, CallStructure.unnamed(arguments.length))); js.Expression jsTarget = _emitter.staticFunctionAccess(target); - js.Call call = js.Call(jsTarget, List.of(arguments, growable: false)) - .withSourceInformation(sourceInformation); + js.Call call = js.Call(jsTarget, List.of(arguments, growable: false), + sourceInformation: sourceInformation); push(call); } @@ -2841,17 +2855,19 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { @override void visitStatic(HStatic node) { MemberEntity element = node.element; - assert(element.isFunction || element is FieldEntity); - if (element.isFunction) { + if (element is FunctionEntity) { + // TODO(sra): Static tear-offs should be constants. push(_emitter .staticClosureAccess(element) .withSourceInformation(node.sourceInformation)); _registry.registerStaticUse(StaticUse.staticTearOff(element)); - } else { + } else if (element is FieldEntity) { push(_emitter .staticFieldAccess(element) .withSourceInformation(node.sourceInformation)); _registry.registerStaticUse(StaticUse.staticGet(element)); + } else { + failedAt(node, 'HStatic must be a FieldEntity or FunctionEntity'); } } @@ -2868,7 +2884,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { @override void visitStaticStore(HStaticStore node) { _registry.registerStaticUse(StaticUse.staticSet(node.element)); - js.Node variable = _emitter.staticFieldAccess(node.element); + js.Expression variable = _emitter.staticFieldAccess(node.element); use(node.inputs[0]); push(js.Assignment(variable, pop()) .withSourceInformation(node.sourceInformation)); @@ -2953,7 +2969,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } void checkTypeOf(HInstruction input, String cmp, String typeName, - SourceInformation sourceInformation) { + SourceInformation? sourceInformation) { use(input); js.Expression typeOf = js.Prefix("typeof", pop()); push(js.Binary(cmp, typeOf, js.string(typeName)) @@ -2961,12 +2977,12 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { } void checkNum( - HInstruction input, String cmp, SourceInformation sourceInformation) { + HInstruction input, String cmp, SourceInformation? sourceInformation) { return checkTypeOf(input, cmp, 'number', sourceInformation); } void checkBool( - HInstruction input, String cmp, SourceInformation sourceInformation) { + HInstruction input, String cmp, SourceInformation? sourceInformation) { return checkTypeOf(input, cmp, 'boolean', sourceInformation); } @@ -2974,27 +2990,25 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { void visitPrimitiveCheck(HPrimitiveCheck node) { js.Expression test = _generateReceiverOrArgumentTypeTest(node); js.Block oldContainer = currentContainer; - js.Statement body = js.Block.empty(); - currentContainer = body; + js.Block body = currentContainer = js.Block.empty(); + final sourceInformation = node.sourceInformation; if (node.isArgumentTypeCheck) { use(node.checkedInput); _pushCallStatic(_commonElements.throwIllegalArgumentException, [pop()], node.sourceInformation); - pushStatement( - js.Return(pop()).withSourceInformation(node.sourceInformation)); + pushStatement(js.Return(pop()).withSourceInformation(sourceInformation)); } else if (node.isReceiverTypeCheck) { use(node.checkedInput); js.Name methodName = - _namer.invocationName(node.receiverTypeCheckSelector); + _namer.invocationName(node.receiverTypeCheckSelector!); js.Expression call = js.propertyCall( - pop(), methodName, []).withSourceInformation(node.sourceInformation); - pushStatement( - js.Return(call).withSourceInformation(node.sourceInformation)); + pop(), methodName, []).withSourceInformation(sourceInformation); + pushStatement(js.Return(call).withSourceInformation(sourceInformation)); } currentContainer = oldContainer; - body = unwrapStatement(body); + final then = unwrapStatement(body); pushStatement( - js.If.noElse(test, body).withSourceInformation(node.sourceInformation)); + js.If.noElse(test, then).withSourceInformation(sourceInformation)); } js.Expression _generateReceiverOrArgumentTypeTest(HPrimitiveCheck node) { @@ -3027,7 +3041,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { _registry.registerStaticUse(staticUse); use(node.checkedInput); List arguments = [pop()]; - push(js.Call(_emitter.staticFunctionAccess(staticUse.element), arguments) + push(js.Call( + _emitter.staticFunctionAccess(staticUse.element as FunctionEntity), + arguments) .withSourceInformation(node.sourceInformation)); } @@ -3177,7 +3193,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { js.Expression typeof(String type) => js.Binary(relation, js.Prefix('typeof', value), js.string(type)); - js.Expression isTest(MemberEntity helper) { + js.Expression isTest(FunctionEntity helper) { _registry.registerStaticUse( StaticUse.staticInvoke(helper, CallStructure.ONE_ARG)); js.Expression test = @@ -3185,13 +3201,12 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { return handleNegative(test); } - js.Expression test; + late js.Expression test; switch (node.specialization) { case IsTestSpecialization.isNull: case IsTestSpecialization.notNull: // These cases should be lowered using [HIdentity] during optimization. failedAt(node, 'Missing lowering'); - break; case IsTestSpecialization.string: test = typeof("string"); @@ -3220,7 +3235,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { (dartType is LegacyType && !dartType.baseType.isObject && dartType.baseType is! NeverType)); - InterfaceType type = dartType.withoutNullability; + InterfaceType type = dartType.withoutNullability as InterfaceType; _registry.registerTypeUse(TypeUse.constructorReference(type)); test = handleNegative(js.js('# instanceof #', [value, _emitter.constructorAccess(type.element)])); @@ -3247,7 +3262,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { @override visitAsCheckSimple(HAsCheckSimple node) { use(node.checkedInput); - MemberEntity method = node.method; + FunctionEntity method = node.method; _registry.registerStaticUse( StaticUse.staticInvoke(method, CallStructure.ONE_ARG)); js.Expression methodAccess = _emitter.staticFunctionAccess(method); @@ -3307,7 +3322,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { // in [receiverMask]. // TODO(sra): Store the context class on the HInstanceEnvironment. This // would allow the subtype classes to be iterated. - ClassEntity receiverClass = + ClassEntity? receiverClass = _abstractValueDomain.getExactClass(receiverMask); if (receiverClass != null) { if (_closedWorld.rtiNeed.classNeedsTypeArguments(receiverClass)) { @@ -3343,9 +3358,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { TypeRecipe typeExpression = node.typeExpression; if (envStructure is FullTypeEnvironmentStructure && typeExpression is TypeExpressionRecipe) { - if (typeExpression.type is TypeVariableType) { - TypeVariableType type = typeExpression.type; - int index = indexTypeVariable( + final type = typeExpression.type; + if (type is TypeVariableType) { + int? index = indexTypeVariable( _closedWorld, _rtiSubstitutions, envStructure, type); if (index != null) { assert(index >= 1); @@ -3382,7 +3397,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { _registry.registerTypeUse(TypeUse.namedTypeVariableNewRti(typeVariable)); } - MemberEntity method = _commonElements.rtiEvalMethod; + final method = _commonElements.rtiEvalMethod; Selector selector = Selector.fromElement(method); js.Name methodLiteral = _namer.invocationName(selector); push(js.js('#.#(#)', [ @@ -3404,7 +3419,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { use(node.inputs[1]); js.Expression extensions = pop(); - MemberEntity method = _commonElements.rtiBindMethod; + final method = _commonElements.rtiBindMethod; Selector selector = Selector.fromElement(method); js.Name methodLiteral = _namer.invocationName(selector); push(js.js('#.#(#)', [ @@ -3417,7 +3432,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { StaticUse.directInvoke(method, selector.callStructure, null)); } - _emitIsLateSentinel(HInstruction input, SourceInformation sourceInformation, + _emitIsLateSentinel(HInstruction input, SourceInformation? sourceInformation, {inverse = false}) { use(input); js.Expression value = pop(); @@ -3429,7 +3444,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { @override visitIsLateSentinel(HIsLateSentinel node) { - _metrics.countHIsLateSentinel; + _metrics.countHIsLateSentinel++; _emitIsLateSentinel(node.inputs.single, node.sourceInformation); } } diff --git a/pkg/compiler/lib/src/ssa/codegen_helpers.dart b/pkg/compiler/lib/src/ssa/codegen_helpers.dart index 93d9c743252..3edf57170cf 100644 --- a/pkg/compiler/lib/src/ssa/codegen_helpers.dart +++ b/pkg/compiler/lib/src/ssa/codegen_helpers.dart @@ -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 +class SsaInstructionSelection extends HBaseVisitor 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 @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 @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 /// 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 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 : 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 /// 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 .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 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 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 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 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 !_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 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 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 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 @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 @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 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 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 with CodegenPhase { /// b.y = v; /// --> /// b.y = a.x = v; -class SsaAssignmentChaining extends HBaseVisitor +class SsaAssignmentChaining extends HBaseVisitor with CodegenPhase { final JClosedWorld _closedWorld; @@ -508,35 +499,34 @@ class SsaAssignmentChaining extends HBaseVisitor @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(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 // 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 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 // 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 with CodegenPhase { /// List of [HInstruction] that the instruction merger expects in /// order when visiting the inputs of an instruction. - List expectedInputs; + List? 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 pureInputs; + Set? pureInputs; Set generateAtUseSite; void markAsGenerateAtUseSite(HInstruction instruction) { @@ -708,7 +698,7 @@ class SsaInstructionMerger extends HBaseVisitor 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 with CodegenPhase { input.accept(this); } } else { - expectedInputs.add(input); + expectedInputs!.add(input); } } } @@ -889,8 +879,8 @@ class SsaInstructionMerger extends HBaseVisitor 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 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 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 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 with CodegenPhase { // expected input. tryGenerateAtUseSite(instruction); } else { - assert(expectedInputs.isEmpty); + assert(expectedInputs!.isEmpty); } instruction.accept(this); } @@ -1000,7 +991,7 @@ class SsaInstructionMerger extends HBaseVisitor with CodegenPhase { /// using these operators instead of nested ifs and boolean variables. class SsaConditionMerger extends HGraphVisitor with CodegenPhase { Set generateAtUseSite; - Set controlFlowOperators; + Set 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 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 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); diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart index 79b2ca099ef..c60d9d124c2 100644 --- a/pkg/compiler/lib/src/ssa/nodes.dart +++ b/pkg/compiler/lib/src/ssa/nodes.dart @@ -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) diff --git a/pkg/compiler/lib/src/ssa/variable_allocator.dart b/pkg/compiler/lib/src/ssa/variable_allocator.dart index acfeb33f5ef..413f223bb20 100644 --- a/pkg/compiler/lib/src/ssa/variable_allocator.dart +++ b/pkg/compiler/lib/src/ssa/variable_allocator.dart @@ -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 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 with CodegenPhase { final Set generateAtUseSite; - final Set controlFlowOperators; + final Set 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 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 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 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 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 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 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 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 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 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 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 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. diff --git a/pkg/compiler/lib/src/universe/use.dart b/pkg/compiler/lib/src/universe/use.dart index feb5aa88ad6..a1cc26071c2 100644 --- a/pkg/compiler/lib/src/universe/use.dart +++ b/pkg/compiler/lib/src/universe/use.dart @@ -496,7 +496,7 @@ class StaticUse { /// Direct invocation of a method [element] with the given [callStructure]. factory StaticUse.directInvoke(FunctionEntity element, - CallStructure callStructure, List typeArguments) { + CallStructure callStructure, List? typeArguments) { assert( element.isInstanceMember, failedAt(element, diff --git a/pkg/js_ast/lib/src/nodes.dart b/pkg/js_ast/lib/src/nodes.dart index fb2c4809d6a..264dfb8bf09 100644 --- a/pkg/js_ast/lib/src/nodes.dart +++ b/pkg/js_ast/lib/src/nodes.dart @@ -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(NodeVisitor 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(NodeVisitor 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(NodeVisitor 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(NodeVisitor 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; diff --git a/pkg/js_ast/lib/src/template.dart b/pkg/js_ast/lib/src/template.dart index 208c575436d..0da617b36fb 100644 --- a/pkg/js_ast/lib/src/template.dart +++ b/pkg/js_ast/lib/src/template.dart @@ -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