| OLD | NEW | 
|---|
| 1 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file | 
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a | 
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. | 
| 4 | 4 | 
| 5 part of ssa; | 5 part of ssa; | 
| 6 | 6 | 
| 7 abstract class OptimizationPhase { | 7 abstract class OptimizationPhase { | 
| 8   String get name; | 8   String get name; | 
| 9   void visitGraph(HGraph graph); | 9   void visitGraph(HGraph graph); | 
| 10 } | 10 } | 
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 104 /// of identifying gvn-able lengths and mis-identifies some unions of fixed | 104 /// of identifying gvn-able lengths and mis-identifies some unions of fixed | 
| 105 /// length indexables (see TODO) as not fixed length. | 105 /// length indexables (see TODO) as not fixed length. | 
| 106 bool isFixedLength(mask, Compiler compiler) { | 106 bool isFixedLength(mask, Compiler compiler) { | 
| 107   ClassWorld classWorld = compiler.world; | 107   ClassWorld classWorld = compiler.world; | 
| 108   JavaScriptBackend backend = compiler.backend; | 108   JavaScriptBackend backend = compiler.backend; | 
| 109   if (mask.isContainer && mask.length != null) { | 109   if (mask.isContainer && mask.length != null) { | 
| 110     // A container on which we have inferred the length. | 110     // A container on which we have inferred the length. | 
| 111     return true; | 111     return true; | 
| 112   } | 112   } | 
| 113   // TODO(sra): Recognize any combination of fixed length indexables. | 113   // TODO(sra): Recognize any combination of fixed length indexables. | 
| 114   if (mask.containsOnly(backend.jsFixedArrayClass) || | 114   if (mask.containsOnly(backend.helpers.jsFixedArrayClass) || | 
| 115       mask.containsOnly(backend.jsUnmodifiableArrayClass) || | 115       mask.containsOnly(backend.helpers.jsUnmodifiableArrayClass) || | 
| 116       mask.containsOnlyString(classWorld) || | 116       mask.containsOnlyString(classWorld) || | 
| 117       backend.isTypedArray(mask)) { | 117       backend.isTypedArray(mask)) { | 
| 118     return true; | 118     return true; | 
| 119   } | 119   } | 
| 120   return false; | 120   return false; | 
| 121 } | 121 } | 
| 122 | 122 | 
| 123 /** | 123 /** | 
| 124  * If both inputs to known operations are available execute the operation at | 124  * If both inputs to known operations are available execute the operation at | 
| 125  * compile-time. | 125  * compile-time. | 
| (...skipping 14 matching lines...) Expand all  Loading... | 
| 140   Compiler get compiler => backend.compiler; | 140   Compiler get compiler => backend.compiler; | 
| 141   final SsaOptimizerTask optimizer; | 141   final SsaOptimizerTask optimizer; | 
| 142 | 142 | 
| 143   SsaInstructionSimplifier(this.constantSystem, | 143   SsaInstructionSimplifier(this.constantSystem, | 
| 144                            this.backend, | 144                            this.backend, | 
| 145                            this.optimizer, | 145                            this.optimizer, | 
| 146                            this.work); | 146                            this.work); | 
| 147 | 147 | 
| 148   CoreClasses get coreClasses => compiler.coreClasses; | 148   CoreClasses get coreClasses => compiler.coreClasses; | 
| 149 | 149 | 
|  | 150   BackendHelpers get helpers => backend.helpers; | 
|  | 151 | 
| 150   void visitGraph(HGraph visitee) { | 152   void visitGraph(HGraph visitee) { | 
| 151     graph = visitee; | 153     graph = visitee; | 
| 152     visitDominatorTree(visitee); | 154     visitDominatorTree(visitee); | 
| 153   } | 155   } | 
| 154 | 156 | 
| 155   visitBasicBlock(HBasicBlock block) { | 157   visitBasicBlock(HBasicBlock block) { | 
| 156     HInstruction instruction = block.first; | 158     HInstruction instruction = block.first; | 
| 157     while (instruction != null) { | 159     while (instruction != null) { | 
| 158       HInstruction next = instruction.next; | 160       HInstruction next = instruction.next; | 
| 159       HInstruction replacement = instruction.accept(this); | 161       HInstruction replacement = instruction.accept(this); | 
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 245 | 247 | 
| 246     // If the code is unreachable, remove the HBoolify.  This can happen when | 248     // If the code is unreachable, remove the HBoolify.  This can happen when | 
| 247     // there is a throw expression in a short-circuit conditional.  Removing the | 249     // there is a throw expression in a short-circuit conditional.  Removing the | 
| 248     // unreachable HBoolify makes it easier to reconstruct the short-circuit | 250     // unreachable HBoolify makes it easier to reconstruct the short-circuit | 
| 249     // operation. | 251     // operation. | 
| 250     if (input.instructionType.isEmpty && !input.instructionType.isNullable) | 252     if (input.instructionType.isEmpty && !input.instructionType.isNullable) | 
| 251       return input; | 253       return input; | 
| 252 | 254 | 
| 253     // All values that cannot be 'true' are boolified to false. | 255     // All values that cannot be 'true' are boolified to false. | 
| 254     TypeMask mask = input.instructionType; | 256     TypeMask mask = input.instructionType; | 
| 255     if (!mask.contains(backend.jsBoolClass, compiler.world)) { | 257     if (!mask.contains(helpers.jsBoolClass, compiler.world)) { | 
| 256       return graph.addConstantBool(false, compiler); | 258       return graph.addConstantBool(false, compiler); | 
| 257     } | 259     } | 
| 258     return node; | 260     return node; | 
| 259   } | 261   } | 
| 260 | 262 | 
| 261   HInstruction visitNot(HNot node) { | 263   HInstruction visitNot(HNot node) { | 
| 262     List<HInstruction> inputs = node.inputs; | 264     List<HInstruction> inputs = node.inputs; | 
| 263     assert(inputs.length == 1); | 265     assert(inputs.length == 1); | 
| 264     HInstruction input = inputs[0]; | 266     HInstruction input = inputs[0]; | 
| 265     if (input is HConstant) { | 267     if (input is HConstant) { | 
| (...skipping 26 matching lines...) Expand all  Loading... | 
| 292     if (actualReceiver.isIndexablePrimitive(compiler)) { | 294     if (actualReceiver.isIndexablePrimitive(compiler)) { | 
| 293       if (actualReceiver.isConstantString()) { | 295       if (actualReceiver.isConstantString()) { | 
| 294         HConstant constantInput = actualReceiver; | 296         HConstant constantInput = actualReceiver; | 
| 295         StringConstantValue constant = constantInput.constant; | 297         StringConstantValue constant = constantInput.constant; | 
| 296         return graph.addConstantInt(constant.length, compiler); | 298         return graph.addConstantInt(constant.length, compiler); | 
| 297       } else if (actualReceiver.isConstantList()) { | 299       } else if (actualReceiver.isConstantList()) { | 
| 298         HConstant constantInput = actualReceiver; | 300         HConstant constantInput = actualReceiver; | 
| 299         ListConstantValue constant = constantInput.constant; | 301         ListConstantValue constant = constantInput.constant; | 
| 300         return graph.addConstantInt(constant.length, compiler); | 302         return graph.addConstantInt(constant.length, compiler); | 
| 301       } | 303       } | 
| 302       Element element = backend.jsIndexableLength; | 304       Element element = helpers.jsIndexableLength; | 
| 303       bool isFixed = isFixedLength(actualReceiver.instructionType, compiler); | 305       bool isFixed = isFixedLength(actualReceiver.instructionType, compiler); | 
| 304       TypeMask actualType = node.instructionType; | 306       TypeMask actualType = node.instructionType; | 
| 305       ClassWorld classWorld = compiler.world; | 307       ClassWorld classWorld = compiler.world; | 
| 306       TypeMask resultType = backend.positiveIntType; | 308       TypeMask resultType = backend.positiveIntType; | 
| 307       // If we already have computed a more specific type, keep that type. | 309       // If we already have computed a more specific type, keep that type. | 
| 308       if (HInstruction.isInstanceOf( | 310       if (HInstruction.isInstanceOf( | 
| 309               actualType, backend.jsUInt31Class, classWorld)) { | 311               actualType, helpers.jsUInt31Class, classWorld)) { | 
| 310         resultType = backend.uint31Type; | 312         resultType = backend.uint31Type; | 
| 311       } else if (HInstruction.isInstanceOf( | 313       } else if (HInstruction.isInstanceOf( | 
| 312               actualType, backend.jsUInt32Class, classWorld)) { | 314               actualType, helpers.jsUInt32Class, classWorld)) { | 
| 313         resultType = backend.uint32Type; | 315         resultType = backend.uint32Type; | 
| 314       } | 316       } | 
| 315       HFieldGet result = new HFieldGet( | 317       HFieldGet result = new HFieldGet( | 
| 316           element, actualReceiver, resultType, | 318           element, actualReceiver, resultType, | 
| 317           isAssignable: !isFixed); | 319           isAssignable: !isFixed); | 
| 318       return result; | 320       return result; | 
| 319     } else if (actualReceiver.isConstantMap()) { | 321     } else if (actualReceiver.isConstantMap()) { | 
| 320       HConstant constantInput = actualReceiver; | 322       HConstant constantInput = actualReceiver; | 
| 321       MapConstantValue constant = constantInput.constant; | 323       MapConstantValue constant = constantInput.constant; | 
| 322       return graph.addConstantInt(constant.length, compiler); | 324       return graph.addConstantInt(constant.length, compiler); | 
| (...skipping 23 matching lines...) Expand all  Loading... | 
| 346     World world = compiler.world; | 348     World world = compiler.world; | 
| 347 | 349 | 
| 348     bool applies(Element element) { | 350     bool applies(Element element) { | 
| 349       return selector.applies(element, world) && | 351       return selector.applies(element, world) && | 
| 350              (mask == null || mask.canHit(element, selector, world)); | 352              (mask == null || mask.canHit(element, selector, world)); | 
| 351     } | 353     } | 
| 352 | 354 | 
| 353     if (selector.isCall || selector.isOperator) { | 355     if (selector.isCall || selector.isOperator) { | 
| 354       Element target; | 356       Element target; | 
| 355       if (input.isExtendableArray(compiler)) { | 357       if (input.isExtendableArray(compiler)) { | 
| 356         if (applies(backend.jsArrayRemoveLast)) { | 358         if (applies(helpers.jsArrayRemoveLast)) { | 
| 357           target = backend.jsArrayRemoveLast; | 359           target = helpers.jsArrayRemoveLast; | 
| 358         } else if (applies(backend.jsArrayAdd)) { | 360         } else if (applies(helpers.jsArrayAdd)) { | 
| 359           // The codegen special cases array calls, but does not | 361           // The codegen special cases array calls, but does not | 
| 360           // inline argument type checks. | 362           // inline argument type checks. | 
| 361           if (!compiler.enableTypeAssertions) { | 363           if (!compiler.enableTypeAssertions) { | 
| 362             target = backend.jsArrayAdd; | 364             target = helpers.jsArrayAdd; | 
| 363           } | 365           } | 
| 364         } | 366         } | 
| 365       } else if (input.isStringOrNull(compiler)) { | 367       } else if (input.isStringOrNull(compiler)) { | 
| 366         if (applies(backend.jsStringSplit)) { | 368         if (applies(helpers.jsStringSplit)) { | 
| 367           HInstruction argument = node.inputs[2]; | 369           HInstruction argument = node.inputs[2]; | 
| 368           if (argument.isString(compiler)) { | 370           if (argument.isString(compiler)) { | 
| 369             target = backend.jsStringSplit; | 371             target = helpers.jsStringSplit; | 
| 370           } | 372           } | 
| 371         } else if (applies(backend.jsStringOperatorAdd)) { | 373         } else if (applies(helpers.jsStringOperatorAdd)) { | 
| 372           // `operator+` is turned into a JavaScript '+' so we need to | 374           // `operator+` is turned into a JavaScript '+' so we need to | 
| 373           // make sure the receiver and the argument are not null. | 375           // make sure the receiver and the argument are not null. | 
| 374           // TODO(sra): Do this via [node.specializer]. | 376           // TODO(sra): Do this via [node.specializer]. | 
| 375           HInstruction argument = node.inputs[2]; | 377           HInstruction argument = node.inputs[2]; | 
| 376           if (argument.isString(compiler) | 378           if (argument.isString(compiler) | 
| 377               && !input.canBeNull()) { | 379               && !input.canBeNull()) { | 
| 378             return new HStringConcat(input, argument, null, | 380             return new HStringConcat(input, argument, null, | 
| 379                                      node.instructionType); | 381                                      node.instructionType); | 
| 380           } | 382           } | 
| 381         } else if (applies(backend.jsStringToString) | 383         } else if (applies(helpers.jsStringToString) | 
| 382                    && !input.canBeNull()) { | 384                    && !input.canBeNull()) { | 
| 383           return input; | 385           return input; | 
| 384         } | 386         } | 
| 385       } | 387       } | 
| 386       if (target != null) { | 388       if (target != null) { | 
| 387         // TODO(ngeoffray): There is a strong dependency between codegen | 389         // TODO(ngeoffray): There is a strong dependency between codegen | 
| 388         // and this optimization that the dynamic invoke does not need an | 390         // and this optimization that the dynamic invoke does not need an | 
| 389         // interceptor. We currently need to keep a | 391         // interceptor. We currently need to keep a | 
| 390         // HInvokeDynamicMethod and not create a HForeign because | 392         // HInvokeDynamicMethod and not create a HForeign because | 
| 391         // HForeign is too opaque for the SsaCheckInserter (that adds a | 393         // HForeign is too opaque for the SsaCheckInserter (that adds a | 
| 392         // bounds check on removeLast). Once we start inlining, the | 394         // bounds check on removeLast). Once we start inlining, the | 
| 393         // bounds check will become explicit, so we won't need this | 395         // bounds check will become explicit, so we won't need this | 
| 394         // optimization. | 396         // optimization. | 
| 395         HInvokeDynamicMethod result = new HInvokeDynamicMethod( | 397         HInvokeDynamicMethod result = new HInvokeDynamicMethod( | 
| 396             node.selector, node.mask, | 398             node.selector, node.mask, | 
| 397             node.inputs.sublist(1), node.instructionType); | 399             node.inputs.sublist(1), node.instructionType); | 
| 398         result.element = target; | 400         result.element = target; | 
| 399         return result; | 401         return result; | 
| 400       } | 402       } | 
| 401     } else if (selector.isGetter) { | 403     } else if (selector.isGetter) { | 
| 402       if (selector.applies(backend.jsIndexableLength, world)) { | 404       if (selector.applies(helpers.jsIndexableLength, world)) { | 
| 403         HInstruction optimized = tryOptimizeLengthInterceptedGetter(node); | 405         HInstruction optimized = tryOptimizeLengthInterceptedGetter(node); | 
| 404         if (optimized != null) return optimized; | 406         if (optimized != null) return optimized; | 
| 405       } | 407       } | 
| 406     } | 408     } | 
| 407 | 409 | 
| 408     return node; | 410     return node; | 
| 409   } | 411   } | 
| 410 | 412 | 
| 411   HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 413   HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 
| 412     propagateConstantValueToUses(node); | 414     propagateConstantValueToUses(node); | 
| (...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 776 | 778 | 
| 777   VariableElement findConcreteFieldForDynamicAccess(HInstruction receiver, | 779   VariableElement findConcreteFieldForDynamicAccess(HInstruction receiver, | 
| 778                                                     Selector selector) { | 780                                                     Selector selector) { | 
| 779     TypeMask receiverType = receiver.instructionType; | 781     TypeMask receiverType = receiver.instructionType; | 
| 780     return compiler.world.locateSingleField(selector, receiverType); | 782     return compiler.world.locateSingleField(selector, receiverType); | 
| 781   } | 783   } | 
| 782 | 784 | 
| 783   HInstruction visitFieldGet(HFieldGet node) { | 785   HInstruction visitFieldGet(HFieldGet node) { | 
| 784     if (node.isNullCheck) return node; | 786     if (node.isNullCheck) return node; | 
| 785     var receiver = node.receiver; | 787     var receiver = node.receiver; | 
| 786     if (node.element == backend.jsIndexableLength) { | 788     if (node.element == helpers.jsIndexableLength) { | 
| 787       JavaScriptItemCompilationContext context = work.compilationContext; | 789       JavaScriptItemCompilationContext context = work.compilationContext; | 
| 788       if (context.allocatedFixedLists.contains(receiver)) { | 790       if (context.allocatedFixedLists.contains(receiver)) { | 
| 789         // TODO(ngeoffray): checking if the second input is an integer | 791         // TODO(ngeoffray): checking if the second input is an integer | 
| 790         // should not be necessary but it currently makes it easier for | 792         // should not be necessary but it currently makes it easier for | 
| 791         // other optimizations to reason about a fixed length constructor | 793         // other optimizations to reason about a fixed length constructor | 
| 792         // that we know takes an int. | 794         // that we know takes an int. | 
| 793         if (receiver.inputs[0].isInteger(compiler)) { | 795         if (receiver.inputs[0].isInteger(compiler)) { | 
| 794           return receiver.inputs[0]; | 796           return receiver.inputs[0]; | 
| 795         } | 797         } | 
| 796       } else if (receiver.isConstantList() || receiver.isConstantString()) { | 798       } else if (receiver.isConstantList() || receiver.isConstantString()) { | 
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 998   final bool trustPrimitives; | 1000   final bool trustPrimitives; | 
| 999   final JavaScriptBackend backend; | 1001   final JavaScriptBackend backend; | 
| 1000   final String name = "SsaCheckInserter"; | 1002   final String name = "SsaCheckInserter"; | 
| 1001   HGraph graph; | 1003   HGraph graph; | 
| 1002 | 1004 | 
| 1003   SsaCheckInserter(this.trustPrimitives, | 1005   SsaCheckInserter(this.trustPrimitives, | 
| 1004                    this.backend, | 1006                    this.backend, | 
| 1005                    this.work, | 1007                    this.work, | 
| 1006                    this.boundsChecked); | 1008                    this.boundsChecked); | 
| 1007 | 1009 | 
|  | 1010   BackendHelpers get helpers => backend.helpers; | 
|  | 1011 | 
| 1008   void visitGraph(HGraph graph) { | 1012   void visitGraph(HGraph graph) { | 
| 1009     this.graph = graph; | 1013     this.graph = graph; | 
| 1010 | 1014 | 
| 1011     // In --trust-primitives mode we don't add bounds checks.  This is better | 1015     // In --trust-primitives mode we don't add bounds checks.  This is better | 
| 1012     // than trying to remove them later as the limit expression would become | 1016     // than trying to remove them later as the limit expression would become | 
| 1013     // dead and require DCE. | 1017     // dead and require DCE. | 
| 1014     if (trustPrimitives) return; | 1018     if (trustPrimitives) return; | 
| 1015 | 1019 | 
| 1016     visitDominatorTree(graph); | 1020     visitDominatorTree(graph); | 
| 1017   } | 1021   } | 
| 1018 | 1022 | 
| 1019   void visitBasicBlock(HBasicBlock block) { | 1023   void visitBasicBlock(HBasicBlock block) { | 
| 1020     HInstruction instruction = block.first; | 1024     HInstruction instruction = block.first; | 
| 1021     while (instruction != null) { | 1025     while (instruction != null) { | 
| 1022       HInstruction next = instruction.next; | 1026       HInstruction next = instruction.next; | 
| 1023       instruction = instruction.accept(this); | 1027       instruction = instruction.accept(this); | 
| 1024       instruction = next; | 1028       instruction = next; | 
| 1025     } | 1029     } | 
| 1026   } | 1030   } | 
| 1027 | 1031 | 
| 1028   HBoundsCheck insertBoundsCheck(HInstruction indexNode, | 1032   HBoundsCheck insertBoundsCheck(HInstruction indexNode, | 
| 1029                                  HInstruction array, | 1033                                  HInstruction array, | 
| 1030                                  HInstruction indexArgument) { | 1034                                  HInstruction indexArgument) { | 
| 1031     Compiler compiler = backend.compiler; | 1035     Compiler compiler = backend.compiler; | 
| 1032     HFieldGet length = new HFieldGet( | 1036     HFieldGet length = new HFieldGet( | 
| 1033         backend.jsIndexableLength, array, backend.positiveIntType, | 1037         helpers.jsIndexableLength, array, backend.positiveIntType, | 
| 1034         isAssignable: !isFixedLength(array.instructionType, compiler)); | 1038         isAssignable: !isFixedLength(array.instructionType, compiler)); | 
| 1035     indexNode.block.addBefore(indexNode, length); | 1039     indexNode.block.addBefore(indexNode, length); | 
| 1036 | 1040 | 
| 1037     TypeMask type = indexArgument.isPositiveInteger(compiler) | 1041     TypeMask type = indexArgument.isPositiveInteger(compiler) | 
| 1038         ? indexArgument.instructionType | 1042         ? indexArgument.instructionType | 
| 1039         : backend.positiveIntType; | 1043         : backend.positiveIntType; | 
| 1040     HBoundsCheck check = new HBoundsCheck( | 1044     HBoundsCheck check = new HBoundsCheck( | 
| 1041         indexArgument, length, array, type); | 1045         indexArgument, length, array, type); | 
| 1042     indexNode.block.addBefore(indexNode, check); | 1046     indexNode.block.addBefore(indexNode, check); | 
| 1043     // If the index input to the bounds check was not known to be an integer | 1047     // If the index input to the bounds check was not known to be an integer | 
| (...skipping 18 matching lines...) Expand all  Loading... | 
| 1062 | 1066 | 
| 1063   void visitIndexAssign(HIndexAssign node) { | 1067   void visitIndexAssign(HIndexAssign node) { | 
| 1064     if (boundsChecked.contains(node)) return; | 1068     if (boundsChecked.contains(node)) return; | 
| 1065     HInstruction index = node.index; | 1069     HInstruction index = node.index; | 
| 1066     index = insertBoundsCheck(node, node.receiver, index); | 1070     index = insertBoundsCheck(node, node.receiver, index); | 
| 1067   } | 1071   } | 
| 1068 | 1072 | 
| 1069   void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 1073   void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 
| 1070     Element element = node.element; | 1074     Element element = node.element; | 
| 1071     if (node.isInterceptedCall) return; | 1075     if (node.isInterceptedCall) return; | 
| 1072     if (element != backend.jsArrayRemoveLast) return; | 1076     if (element != helpers.jsArrayRemoveLast) return; | 
| 1073     if (boundsChecked.contains(node)) return; | 1077     if (boundsChecked.contains(node)) return; | 
| 1074     // `0` is the index we want to check, but we want to report `-1`, as if we | 1078     // `0` is the index we want to check, but we want to report `-1`, as if we | 
| 1075     // executed `a[a.length-1]` | 1079     // executed `a[a.length-1]` | 
| 1076     HBoundsCheck check = insertBoundsCheck( | 1080     HBoundsCheck check = insertBoundsCheck( | 
| 1077         node, node.receiver, graph.addConstantInt(0, backend.compiler)); | 1081         node, node.receiver, graph.addConstantInt(0, backend.compiler)); | 
| 1078     HInstruction minusOne = graph.addConstantInt(-1, backend.compiler); | 1082     HInstruction minusOne = graph.addConstantInt(-1, backend.compiler); | 
| 1079     check.inputs.add(minusOne); | 1083     check.inputs.add(minusOne); | 
| 1080     minusOne.usedBy.add(check); | 1084     minusOne.usedBy.add(check); | 
| 1081   } | 1085   } | 
| 1082 } | 1086 } | 
| (...skipping 1315 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 2398 | 2402 | 
| 2399     keyedValues.forEach((receiver, values) { | 2403     keyedValues.forEach((receiver, values) { | 
| 2400       result.keyedValues[receiver] = | 2404       result.keyedValues[receiver] = | 
| 2401           new Map<HInstruction, HInstruction>.from(values); | 2405           new Map<HInstruction, HInstruction>.from(values); | 
| 2402     }); | 2406     }); | 
| 2403 | 2407 | 
| 2404     result.nonEscapingReceivers.addAll(nonEscapingReceivers); | 2408     result.nonEscapingReceivers.addAll(nonEscapingReceivers); | 
| 2405     return result; | 2409     return result; | 
| 2406   } | 2410   } | 
| 2407 } | 2411 } | 
| OLD | NEW | 
|---|