[dart2js] Update SSA/Codegen inlining metrics.

Add several more inlining metrics to SSA:
- getters (ellisions vs. inlines)
- setters (ellisions vs. inlines)
- intercepted length calls
- if conditions
- is checks
- late sentinel checks

After digging these are all the opportunities for optimization that I saw that I thought might be affected by changes in global inference. Open to feedback on whether any of these are unnecessary or if there's any other things worth tracking.

Change-Id: I70ff279a797f71b39b2bc02c00fbb3f6e149cb2a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/255202
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 7fdd154..3b1632d 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -5137,9 +5137,11 @@
         _typeInferenceMap.resultTypeOfSelector(selector, receiverType);
     HInvokeDynamic invoke;
     if (selector.isGetter) {
+      _metrics.countGettersTotal.add();
       invoke = HInvokeDynamicGetter(selector, receiverType, element, inputs,
           isIntercepted, resultType, sourceInformation);
     } else if (selector.isSetter) {
+      _metrics.countSettersTotal.add();
       invoke = HInvokeDynamicSetter(selector, receiverType, element, inputs,
           isIntercepted, resultType, sourceInformation);
     } else if (selector.isClosureCall) {
@@ -5840,9 +5842,9 @@
         providedArguments, typeArguments, currentNode, sourceInformation,
         instanceType: instanceType);
     if (inlined) {
-      _metrics.countInlinesDone.add();
+      _metrics.countMethodInlined.add();
     } else {
-      _metrics.countInlinesSkipped.add();
+      _metrics.countMethodNotInlined.add();
     }
     return inlined;
   }
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 3e7e544..c2cd1ce 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -175,6 +175,13 @@
 class _CodegenMetrics extends MetricsBase {
   int countHIf = 0;
   int countHIfConstant = 0;
+  int countHIsTest = 0;
+  int countHIsTestSimple = 0;
+  int countHIsLateSentinel = 0;
+  int countHGetLength = 0;
+  int countHIndex = 0;
+  int countHFieldGet = 0;
+  int countSingleTargetInstanceCalls = 0;
   final countHInterceptor = CountMetric('count.HInterceptor');
   final countHInterceptorGet = CountMetric('count.HInterceptor.getInterceptor');
   final countHInterceptorOneshot = CountMetric('count.HInterceptor.oneShot');
@@ -193,6 +200,14 @@
   Iterable<Metric> get secondary => [
         CountMetric('count.HIf')..add(countHIf),
         CountMetric('count.HIf.constant')..add(countHIfConstant),
+        CountMetric('count.HIsTest')..add(countHIsTest),
+        CountMetric('count.HIsTestSimple')..add(countHIsTestSimple),
+        CountMetric('count.HIsLateSentinel')..add(countHIsLateSentinel),
+        CountMetric('count.HGetLength')..add(countHGetLength),
+        CountMetric('count.HIndex')..add(countHIndex),
+        CountMetric('count.HFieldGet')..add(countHFieldGet),
+        CountMetric('count.SingleTargetInstance')
+          ..add(countSingleTargetInstanceCalls),
         countHInterceptor,
         countHInterceptorGet,
         countHInterceptorConditionalConstant,
@@ -1884,6 +1899,7 @@
 
   @override
   visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
+    _updateInvokeMetrics(node);
     use(node.receiver);
     js.Expression object = pop();
     String methodName;
@@ -2074,8 +2090,13 @@
     }
   }
 
+  void _updateInvokeMetrics(HInvokeDynamic node) {
+    if (node.element != null) _metrics.countSingleTargetInstanceCalls++;
+  }
+
   @override
   visitInvokeDynamicSetter(HInvokeDynamicSetter node) {
+    _updateInvokeMetrics(node);
     use(node.receiver);
     js.Name name = _namer.invocationName(node.selector);
     push(js
@@ -2086,6 +2107,7 @@
 
   @override
   visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
+    _updateInvokeMetrics(node);
     use(node.receiver);
     js.Name name = _namer.invocationName(node.selector);
     push(js
@@ -2260,6 +2282,7 @@
 
   @override
   visitFieldGet(HFieldGet node) {
+    _metrics.countHFieldGet++;
     use(node.receiver);
     push(_loadField(pop(), node.element, node.sourceInformation));
   }
@@ -2281,6 +2304,7 @@
 
   @override
   visitGetLength(HGetLength node) {
+    _metrics.countHGetLength++;
     use(node.receiver);
     push(js.PropertyAccess.field(pop(), 'length')
         .withSourceInformation(node.sourceInformation));
@@ -2908,6 +2932,7 @@
 
   @override
   void visitIndex(HIndex node) {
+    _metrics.countHIndex++;
     use(node.receiver);
     js.Expression receiver = pop();
     use(node.index);
@@ -3119,6 +3144,7 @@
 
   @override
   visitIsTest(HIsTest node) {
+    _metrics.countHIsTest++;
     _registry.registerTypeUse(TypeUse.isCheck(node.dartType));
 
     use(node.typeInput);
@@ -3135,6 +3161,7 @@
 
   @override
   visitIsTestSimple(HIsTestSimple node) {
+    _metrics.countHIsTestSimple++;
     _emitIsTestSimple(node);
   }
 
@@ -3400,6 +3427,8 @@
   }
 
   @override
-  visitIsLateSentinel(HIsLateSentinel node) =>
-      _emitIsLateSentinel(node.inputs.single, node.sourceInformation);
+  visitIsLateSentinel(HIsLateSentinel node) {
+    _metrics.countHIsLateSentinel;
+    _emitIsLateSentinel(node.inputs.single, node.sourceInformation);
+  }
 }
diff --git a/pkg/compiler/lib/src/ssa/metrics.dart b/pkg/compiler/lib/src/ssa/metrics.dart
index 2cdf618..8ef1158 100644
--- a/pkg/compiler/lib/src/ssa/metrics.dart
+++ b/pkg/compiler/lib/src/ssa/metrics.dart
@@ -1,11 +1,25 @@
 import '../common/metrics.dart';
 
 class SsaMetrics extends MetricsBase {
-  final countInlinesDone = CountMetric('count.inlines.done');
-  final countInlinesSkipped = CountMetric('count.inlines.skipped');
-  final countInlineConstantsDone = CountMetric('count.inlineConstants.done');
-  final countInlineConstantsSkipped =
-      CountMetric('count.inlineConstants.skipped');
+  final countMethodInlined = CountMetric('count.method.inlined');
+  final countMethodNotInlined = CountMetric('count.method.notInlined');
+  final countSpecializations = CountMetric('count.specializations');
+  final countOperationFolded = CountMetric('count.operation.folded');
+  final countLengthOptimized = CountMetric('count.length.optimized');
+  final countFieldGetFolded = CountMetric('count.fieldGet.folded');
+  final countIndexFolded = CountMetric('count.index.folded');
+  final countGetLengthFolded = CountMetric('count.getLength.folded');
+  final countGettersTotal = CountMetric('count.getters.total');
+  final countGettersInlined = CountMetric('count.getters.inlined');
+  final countGettersElided = CountMetric('count.getters.elided');
+  final countSettersTotal = CountMetric('count.setters.total');
+  final countSettersInlined = CountMetric('count.setters.inlined');
+  final countSettersElided = CountMetric('count.setters.elided');
+  final countConditionDecided = CountMetric('count.if.decided');
+  final countIsTestDecided = CountMetric('count.isTest.decided');
+  final countIsTestSimplified = CountMetric('count.isTest.simplified');
+  final countLateSentinelCheckDecided =
+      CountMetric('count.lateSentinel.decided');
 
   @override
   String get namespace => 'ssa';
@@ -15,9 +29,22 @@
 
   @override
   Iterable<Metric> get secondary => [
-        countInlinesDone,
-        countInlinesSkipped,
-        countInlineConstantsDone,
-        countInlineConstantsSkipped
+        countMethodInlined,
+        countMethodNotInlined,
+        countSpecializations,
+        countLengthOptimized,
+        countFieldGetFolded,
+        countIndexFolded,
+        countGetLengthFolded,
+        countGettersTotal,
+        countGettersInlined,
+        countGettersElided,
+        countSettersTotal,
+        countSettersInlined,
+        countSettersElided,
+        countConditionDecided,
+        countIsTestDecided,
+        countIsTestSimplified,
+        countLateSentinelCheckDecided
       ];
 }
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index faad0f8..a8b11e0 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -656,13 +656,17 @@
       HInstruction instruction = node.inputs.length == 2
           ? foldUnary(operation, node.inputs[1])
           : foldBinary(operation, node.inputs[1], node.inputs[2]);
-      if (instruction != null) return instruction;
+      if (instruction != null) {
+        _metrics.countOperationFolded.add();
+        return instruction;
+      }
     }
 
     // Try converting the instruction to a builtin instruction.
     HInstruction instruction = node.specializer.tryConvertToBuiltin(node,
         _graph, _globalInferenceResults, commonElements, _closedWorld, _log);
     if (instruction != null) {
+      _metrics.countSpecializations.add();
       return instruction;
     }
 
@@ -736,7 +740,10 @@
     } else if (selector.isGetter) {
       if (commonElements.appliesToJsIndexableLength(selector)) {
         HInstruction optimized = tryOptimizeLengthInterceptedGetter(node);
-        if (optimized != null) return optimized;
+        if (optimized != null) {
+          _metrics.countLengthOptimized.add();
+          return optimized;
+        }
       }
     }
 
@@ -1274,8 +1281,10 @@
     HInstruction value = node.inputs[0];
     AbstractBool isLateSentinel = value.isLateSentinel(_abstractValueDomain);
     if (isLateSentinel.isDefinitelyTrue) {
+      _metrics.countLateSentinelCheckDecided.add();
       return _graph.addConstantBool(true, _closedWorld);
     } else if (isLateSentinel.isDefinitelyFalse) {
+      _metrics.countLateSentinelCheckDecided.add();
       return _graph.addConstantBool(false, _closedWorld);
     }
 
@@ -1320,9 +1329,11 @@
     AbstractBool isTruthy =
         _abstractValueDomain.isTruthy(condition.instructionType);
     if (isTruthy.isDefinitelyTrue) {
+      _metrics.countConditionDecided.add();
       return _replaceHIfCondition(
           node, _graph.addConstantBool(true, _closedWorld));
     } else if (isTruthy.isDefinitelyFalse) {
+      _metrics.countConditionDecided.add();
       return _replaceHIfCondition(
           node, _graph.addConstantBool(false, _closedWorld));
     }
@@ -1443,12 +1454,11 @@
       if (constant is ConstructedConstantValue) {
         ConstantValue value = constant.fields[node.element];
         if (value != null) {
-          _metrics.countInlineConstantsDone.add();
+          _metrics.countFieldGetFolded.add();
           return _graph.addConstant(value, _closedWorld);
         }
       }
     }
-    _metrics.countInlineConstantsSkipped.add();
 
     return node;
   }
@@ -1460,12 +1470,14 @@
     if (receiver.isConstantList()) {
       HConstant constantReceiver = receiver;
       ListConstantValue constant = constantReceiver.constant;
+      _metrics.countGetLengthFolded.add();
       return _graph.addConstantInt(constant.length, _closedWorld);
     }
 
     if (receiver.isConstantString()) {
       HConstant constantReceiver = receiver;
       StringConstantValue constant = constantReceiver.constant;
+      _metrics.countGetLengthFolded.add();
       return _graph.addConstantInt(constant.length, _closedWorld);
     }
 
@@ -1474,6 +1486,7 @@
       int /*?*/ length = _abstractValueDomain.getContainerLength(receiverType);
       if (length != null) {
         HInstruction constant = _graph.addConstantInt(length, _closedWorld);
+        _metrics.countGetLengthFolded.add();
         if (_abstractValueDomain.isNull(receiverType).isPotentiallyTrue) {
           // If the container can be null, we update all uses of the length
           // access to use the constant instead, but keep the length access in
@@ -1510,6 +1523,7 @@
         // be able to do with the broader type of [lengthInput].  We should
         // insert a HTypeKnown witnessed by the allocation to narrow the
         // lengthInput.
+        _metrics.countGetLengthFolded.add();
         return lengthInput;
       }
     }
@@ -1518,6 +1532,7 @@
         isFixedLength(receiver.instructionType, _closedWorld)) {
       // The input type has changed to fixed-length so change to an unassignable
       // HGetLength to allow more GVN optimizations.
+      _metrics.countGetLengthFolded.add();
       return HGetLength(receiver, node.instructionType, isAssignable: false);
     }
     return node;
@@ -1532,6 +1547,7 @@
         ConstantValue foldedValue =
             constant_system.index.fold(receiver.constant, index.constant);
         if (foldedValue != null) {
+          _metrics.countIndexFolded.add();
           return _graph.addConstant(foldedValue, _closedWorld);
         }
       }
@@ -1581,11 +1597,13 @@
         ConstantValue constant = fieldData.constantValue;
         HConstant result = _graph.addConstant(constant, _closedWorld,
             sourceInformation: node.sourceInformation);
+        _metrics.countGettersElided.add();
         _log?.registerConstantFieldGet(node, field, result);
         return result;
       } else {
         receiver = maybeGuardWithNullCheck(receiver, node, field);
         HFieldGet result = _directFieldGet(receiver, field, node);
+        _metrics.countGettersInlined.add();
         _log?.registerFieldGet(node, result);
         return result;
       }
@@ -1658,12 +1676,14 @@
       HInstruction assignField() {
         if (_closedWorld.fieldAnalysis.getFieldData(field).isElided) {
           _log?.registerFieldSet(node);
+          _metrics.countSettersElided.add();
           return value;
         } else {
           HFieldSet result =
               HFieldSet(_abstractValueDomain, field, receiver, value)
                 ..sourceInformation = node.sourceInformation;
           _log?.registerFieldSet(node, result);
+          _metrics.countSettersInlined.add();
           return result;
         }
       }
@@ -2101,9 +2121,11 @@
 
     AbstractBool result = node.evaluate(_closedWorld, _options);
     if (result.isDefinitelyFalse) {
+      _metrics.countIsTestDecided.add();
       return _graph.addConstantBool(false, _closedWorld);
     }
     if (result.isDefinitelyTrue) {
+      _metrics.countIsTestDecided.add();
       return _graph.addConstantBool(true, _closedWorld);
     }
 
@@ -2124,6 +2146,7 @@
     if (specialization != null) {
       AbstractValueWithPrecision checkedType = _abstractValueDomain
           .createFromStaticType(node.dartType, nullable: false);
+      _metrics.countIsTestSimplified.add();
       return HIsTestSimple(node.dartType, checkedType, specialization,
           node.checkedInput, _abstractValueDomain.boolType);
     }
@@ -2137,9 +2160,11 @@
   HInstruction visitIsTestSimple(HIsTestSimple node) {
     AbstractBool result = node.evaluate(_closedWorld, _options);
     if (result.isDefinitelyFalse) {
+      _metrics.countIsTestDecided.add();
       return _graph.addConstantBool(false, _closedWorld);
     }
     if (result.isDefinitelyTrue) {
+      _metrics.countIsTestDecided.add();
       return _graph.addConstantBool(true, _closedWorld);
     }
     return node;