Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: pkg/compiler/lib/src/ssa/optimize.dart

Issue 2777163002: Make codegen and optimizations depend more directly on data objects. (Closed)
Patch Set: Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; 5 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
6 import '../common/names.dart' show Selectors; 6 import '../common/names.dart' show Selectors;
7 import '../common/tasks.dart' show CompilerTask; 7 import '../common/tasks.dart' show CompilerTask;
8 import '../compiler.dart' show Compiler; 8 import '../compiler.dart' show Compiler;
9 import '../constants/constant_system.dart'; 9 import '../constants/constant_system.dart';
10 import '../constants/values.dart'; 10 import '../constants/values.dart';
11 import '../common_elements.dart' show CommonElements; 11 import '../common_elements.dart' show CommonElements;
12 import '../elements/elements.dart' 12 import '../elements/elements.dart'
13 show ClassElement, FieldElement, MethodElement; 13 show ClassElement, FieldElement, MethodElement;
14 import '../elements/entities.dart'; 14 import '../elements/entities.dart';
15 import '../elements/resolution_types.dart'; 15 import '../elements/resolution_types.dart';
16 import '../js/js.dart' as js; 16 import '../js/js.dart' as js;
17 import '../js_backend/backend_helpers.dart' show BackendHelpers; 17 import '../js_backend/backend_helpers.dart' show BackendHelpers;
18 import '../js_backend/js_backend.dart'; 18 import '../js_backend/js_backend.dart';
19 import '../js_backend/interceptor_data.dart' show InterceptorData;
20 import '../js_backend/native_data.dart' show NativeData;
19 import '../native/native.dart' as native; 21 import '../native/native.dart' as native;
22 import '../options.dart';
20 import '../tree/dartstring.dart' as ast; 23 import '../tree/dartstring.dart' as ast;
21 import '../types/types.dart'; 24 import '../types/types.dart';
22 import '../universe/selector.dart' show Selector; 25 import '../universe/selector.dart' show Selector;
23 import '../universe/side_effects.dart' show SideEffects; 26 import '../universe/side_effects.dart' show SideEffects;
24 import '../util/util.dart'; 27 import '../util/util.dart';
25 import '../world.dart' show ClosedWorld; 28 import '../world.dart' show ClosedWorld;
26 import 'interceptor_simplifier.dart'; 29 import 'interceptor_simplifier.dart';
27 import 'nodes.dart'; 30 import 'nodes.dart';
28 import 'types.dart'; 31 import 'types.dart';
29 import 'types_propagation.dart'; 32 import 'types_propagation.dart';
30 import 'value_range_analyzer.dart'; 33 import 'value_range_analyzer.dart';
31 import 'value_set.dart'; 34 import 'value_set.dart';
32 35
33 abstract class OptimizationPhase { 36 abstract class OptimizationPhase {
34 String get name; 37 String get name;
35 void visitGraph(HGraph graph); 38 void visitGraph(HGraph graph);
36 } 39 }
37 40
38 class SsaOptimizerTask extends CompilerTask { 41 class SsaOptimizerTask extends CompilerTask {
39 final JavaScriptBackend backend; 42 final JavaScriptBackend _backend;
40 43
41 Map<HInstruction, Range> ranges = <HInstruction, Range>{}; 44 Map<HInstruction, Range> ranges = <HInstruction, Range>{};
42 45
43 SsaOptimizerTask(JavaScriptBackend backend) 46 SsaOptimizerTask(this._backend) : super(_backend.compiler.measurer);
44 : this.backend = backend,
45 super(backend.compiler.measurer);
46 47
47 String get name => 'SSA optimizer'; 48 String get name => 'SSA optimizer';
48 49
49 Compiler get compiler => backend.compiler; 50 Compiler get _compiler => _backend.compiler;
51
52 GlobalTypeInferenceResults get _results => _compiler.globalInference.results;
53
54 BackendHelpers get _helpers => _backend.helpers;
55
56 CompilerOptions get _options => _compiler.options;
57
58 RuntimeTypesSubstitutions get _rtiSubstitutions => _backend.rtiSubstitutions;
59
60 InterceptorData get _interceptorData => _backend.interceptorData;
50 61
51 void optimize(CodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) { 62 void optimize(CodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) {
52 void runPhase(OptimizationPhase phase) { 63 void runPhase(OptimizationPhase phase) {
53 measureSubtask(phase.name, () => phase.visitGraph(graph)); 64 measureSubtask(phase.name, () => phase.visitGraph(graph));
54 backend.tracer.traceGraph(phase.name, graph); 65 _backend.tracer.traceGraph(phase.name, graph);
55 assert(graph.isValid()); 66 assert(graph.isValid());
56 } 67 }
57 68
58 bool trustPrimitives = compiler.options.trustPrimitives; 69 bool trustPrimitives = _options.trustPrimitives;
59 CodegenRegistry registry = work.registry; 70 CodegenRegistry registry = work.registry;
60 Set<HInstruction> boundsChecked = new Set<HInstruction>(); 71 Set<HInstruction> boundsChecked = new Set<HInstruction>();
61 SsaCodeMotion codeMotion; 72 SsaCodeMotion codeMotion;
62 SsaLoadElimination loadElimination; 73 SsaLoadElimination loadElimination;
63 measure(() { 74 measure(() {
64 List<OptimizationPhase> phases = <OptimizationPhase>[ 75 List<OptimizationPhase> phases = <OptimizationPhase>[
65 // Run trivial instruction simplification first to optimize 76 // Run trivial instruction simplification first to optimize
66 // some patterns useful for type conversion. 77 // some patterns useful for type conversion.
67 new SsaInstructionSimplifier(backend, closedWorld, this, registry), 78 new SsaInstructionSimplifier(_results, _options, _helpers,
79 _rtiSubstitutions, closedWorld, registry),
68 new SsaTypeConversionInserter(closedWorld), 80 new SsaTypeConversionInserter(closedWorld),
69 new SsaRedundantPhiEliminator(), 81 new SsaRedundantPhiEliminator(),
70 new SsaDeadPhiEliminator(), 82 new SsaDeadPhiEliminator(),
71 new SsaTypePropagator(compiler, closedWorld), 83 new SsaTypePropagator(_results, _options, _helpers, closedWorld),
72 // After type propagation, more instructions can be 84 // After type propagation, more instructions can be
73 // simplified. 85 // simplified.
74 new SsaInstructionSimplifier(backend, closedWorld, this, registry), 86 new SsaInstructionSimplifier(_results, _options, _helpers,
87 _rtiSubstitutions, closedWorld, registry),
75 new SsaCheckInserter( 88 new SsaCheckInserter(
76 trustPrimitives, backend, closedWorld, boundsChecked), 89 trustPrimitives, _helpers, closedWorld, boundsChecked),
77 new SsaInstructionSimplifier(backend, closedWorld, this, registry), 90 new SsaInstructionSimplifier(_results, _options, _helpers,
91 _rtiSubstitutions, closedWorld, registry),
78 new SsaCheckInserter( 92 new SsaCheckInserter(
79 trustPrimitives, backend, closedWorld, boundsChecked), 93 trustPrimitives, _helpers, closedWorld, boundsChecked),
80 new SsaTypePropagator(compiler, closedWorld), 94 new SsaTypePropagator(_results, _options, _helpers, closedWorld),
81 // Run a dead code eliminator before LICM because dead 95 // Run a dead code eliminator before LICM because dead
82 // interceptors are often in the way of LICM'able instructions. 96 // interceptors are often in the way of LICM'able instructions.
83 new SsaDeadCodeEliminator(closedWorld, this), 97 new SsaDeadCodeEliminator(closedWorld, this),
84 new SsaGlobalValueNumberer(), 98 new SsaGlobalValueNumberer(),
85 // After GVN, some instructions might need their type to be 99 // After GVN, some instructions might need their type to be
86 // updated because they now have different inputs. 100 // updated because they now have different inputs.
87 new SsaTypePropagator(compiler, closedWorld), 101 new SsaTypePropagator(_results, _options, _helpers, closedWorld),
88 codeMotion = new SsaCodeMotion(), 102 codeMotion = new SsaCodeMotion(),
89 loadElimination = 103 loadElimination =
90 new SsaLoadElimination(backend, compiler, closedWorld), 104 new SsaLoadElimination(_helpers, _compiler, closedWorld),
91 new SsaRedundantPhiEliminator(), 105 new SsaRedundantPhiEliminator(),
92 new SsaDeadPhiEliminator(), 106 new SsaDeadPhiEliminator(),
93 // After GVN and load elimination the same value may be used in code 107 // After GVN and load elimination the same value may be used in code
94 // controlled by a test on the value, so redo 'conversion insertion' to 108 // controlled by a test on the value, so redo 'conversion insertion' to
95 // learn from the refined type. 109 // learn from the refined type.
96 new SsaTypeConversionInserter(closedWorld), 110 new SsaTypeConversionInserter(closedWorld),
97 new SsaTypePropagator(compiler, closedWorld), 111 new SsaTypePropagator(_results, _options, _helpers, closedWorld),
98 new SsaValueRangeAnalyzer(backend.helpers, closedWorld, this), 112 new SsaValueRangeAnalyzer(_helpers, closedWorld, this),
99 // Previous optimizations may have generated new 113 // Previous optimizations may have generated new
100 // opportunities for instruction simplification. 114 // opportunities for instruction simplification.
101 new SsaInstructionSimplifier(backend, closedWorld, this, registry), 115 new SsaInstructionSimplifier(_results, _options, _helpers,
116 _rtiSubstitutions, closedWorld, registry),
102 new SsaCheckInserter( 117 new SsaCheckInserter(
103 trustPrimitives, backend, closedWorld, boundsChecked), 118 trustPrimitives, _helpers, closedWorld, boundsChecked),
104 ]; 119 ];
105 phases.forEach(runPhase); 120 phases.forEach(runPhase);
106 121
107 // Simplifying interceptors is not strictly just an optimization, it is 122 // Simplifying interceptors is not strictly just an optimization, it is
108 // required for implementation correctness because the code generator 123 // required for implementation correctness because the code generator
109 // assumes it is always performed. 124 // assumes it is always performed.
110 runPhase(new SsaSimplifyInterceptors( 125 runPhase(new SsaSimplifyInterceptors(closedWorld, _helpers,
111 compiler, closedWorld, work.element.enclosingClass)); 126 _interceptorData, work.element.enclosingClass));
112 127
113 SsaDeadCodeEliminator dce = new SsaDeadCodeEliminator(closedWorld, this); 128 SsaDeadCodeEliminator dce = new SsaDeadCodeEliminator(closedWorld, this);
114 runPhase(dce); 129 runPhase(dce);
115 if (codeMotion.movedCode || 130 if (codeMotion.movedCode ||
116 dce.eliminatedSideEffects || 131 dce.eliminatedSideEffects ||
117 loadElimination.newGvnCandidates) { 132 loadElimination.newGvnCandidates) {
118 phases = <OptimizationPhase>[ 133 phases = <OptimizationPhase>[
119 new SsaTypePropagator(compiler, closedWorld), 134 new SsaTypePropagator(_results, _options, _helpers, closedWorld),
120 new SsaGlobalValueNumberer(), 135 new SsaGlobalValueNumberer(),
121 new SsaCodeMotion(), 136 new SsaCodeMotion(),
122 new SsaValueRangeAnalyzer(backend.helpers, closedWorld, this), 137 new SsaValueRangeAnalyzer(_helpers, closedWorld, this),
123 new SsaInstructionSimplifier(backend, closedWorld, this, registry), 138 new SsaInstructionSimplifier(_results, _options, _helpers,
139 _rtiSubstitutions, closedWorld, registry),
124 new SsaCheckInserter( 140 new SsaCheckInserter(
125 trustPrimitives, backend, closedWorld, boundsChecked), 141 trustPrimitives, _helpers, closedWorld, boundsChecked),
126 new SsaSimplifyInterceptors( 142 new SsaSimplifyInterceptors(closedWorld, _helpers, _interceptorData,
127 compiler, closedWorld, work.element.enclosingClass), 143 work.element.enclosingClass),
128 new SsaDeadCodeEliminator(closedWorld, this), 144 new SsaDeadCodeEliminator(closedWorld, this),
129 ]; 145 ];
130 } else { 146 } else {
131 phases = <OptimizationPhase>[ 147 phases = <OptimizationPhase>[
132 new SsaTypePropagator(compiler, closedWorld), 148 new SsaTypePropagator(_results, _options, _helpers, closedWorld),
133 // Run the simplifier to remove unneeded type checks inserted by 149 // Run the simplifier to remove unneeded type checks inserted by
134 // type propagation. 150 // type propagation.
135 new SsaInstructionSimplifier(backend, closedWorld, this, registry), 151 new SsaInstructionSimplifier(_results, _options, _helpers,
152 _rtiSubstitutions, closedWorld, registry),
136 ]; 153 ];
137 } 154 }
138 phases.forEach(runPhase); 155 phases.forEach(runPhase);
139 }); 156 });
140 } 157 }
141 } 158 }
142 159
143 /// Returns `true` if [mask] represents only types that have a length that 160 /// Returns `true` if [mask] represents only types that have a length that
144 /// cannot change. The current implementation is conservative for the purpose 161 /// cannot change. The current implementation is conservative for the purpose
145 /// of identifying gvn-able lengths and mis-identifies some unions of fixed 162 /// of identifying gvn-able lengths and mis-identifies some unions of fixed
(...skipping 18 matching lines...) Expand all
164 * compile-time. 181 * compile-time.
165 */ 182 */
166 class SsaInstructionSimplifier extends HBaseVisitor 183 class SsaInstructionSimplifier extends HBaseVisitor
167 implements OptimizationPhase { 184 implements OptimizationPhase {
168 // We don't produce constant-folded strings longer than this unless they have 185 // We don't produce constant-folded strings longer than this unless they have
169 // a single use. This protects against exponentially large constant folded 186 // a single use. This protects against exponentially large constant folded
170 // strings. 187 // strings.
171 static const MAX_SHARED_CONSTANT_FOLDED_STRING_LENGTH = 512; 188 static const MAX_SHARED_CONSTANT_FOLDED_STRING_LENGTH = 512;
172 189
173 final String name = "SsaInstructionSimplifier"; 190 final String name = "SsaInstructionSimplifier";
174 final JavaScriptBackend backend; 191 final GlobalTypeInferenceResults _globalInferenceResults;
175 final ClosedWorld closedWorld; 192 final CompilerOptions _options;
176 final CodegenRegistry registry; 193 final BackendHelpers _helpers;
177 HGraph graph; 194 final RuntimeTypesSubstitutions _rtiSubstitutions;
178 Compiler get compiler => backend.compiler; 195 final ClosedWorld _closedWorld;
179 final SsaOptimizerTask optimizer; 196 final CodegenRegistry _registry;
197 HGraph _graph;
180 198
181 SsaInstructionSimplifier( 199 SsaInstructionSimplifier(this._globalInferenceResults, this._options,
182 this.backend, this.closedWorld, this.optimizer, this.registry); 200 this._helpers, this._rtiSubstitutions, this._closedWorld, this._registry);
183 201
184 CommonElements get commonElements => closedWorld.commonElements; 202 CommonElements get commonElements => _closedWorld.commonElements;
185 203
186 BackendHelpers get helpers => backend.helpers; 204 ConstantSystem get constantSystem => _closedWorld.constantSystem;
187 205
188 ConstantSystem get constantSystem => closedWorld.constantSystem; 206 NativeData get _nativeData => _closedWorld.nativeData;
189
190 GlobalTypeInferenceResults get globalInferenceResults =>
191 compiler.globalInference.results;
192 207
193 void visitGraph(HGraph visitee) { 208 void visitGraph(HGraph visitee) {
194 graph = visitee; 209 _graph = visitee;
195 visitDominatorTree(visitee); 210 visitDominatorTree(visitee);
196 } 211 }
197 212
198 visitBasicBlock(HBasicBlock block) { 213 visitBasicBlock(HBasicBlock block) {
199 HInstruction instruction = block.first; 214 HInstruction instruction = block.first;
200 while (instruction != null) { 215 while (instruction != null) {
201 HInstruction next = instruction.next; 216 HInstruction next = instruction.next;
202 HInstruction replacement = instruction.accept(this); 217 HInstruction replacement = instruction.accept(this);
203 if (replacement != instruction) { 218 if (replacement != instruction) {
204 block.rewrite(instruction, replacement); 219 block.rewrite(instruction, replacement);
205 220
206 // The intersection of double and int return conflicting, and 221 // The intersection of double and int return conflicting, and
207 // because of our number implementation for JavaScript, it 222 // because of our number implementation for JavaScript, it
208 // might be that an operation thought to return double, can be 223 // might be that an operation thought to return double, can be
209 // simplified to an int. For example: 224 // simplified to an int. For example:
210 // `2.5 * 10`. 225 // `2.5 * 10`.
211 if (!(replacement.isNumberOrNull(closedWorld) && 226 if (!(replacement.isNumberOrNull(_closedWorld) &&
212 instruction.isNumberOrNull(closedWorld))) { 227 instruction.isNumberOrNull(_closedWorld))) {
213 // If we can replace [instruction] with [replacement], then 228 // If we can replace [instruction] with [replacement], then
214 // [replacement]'s type can be narrowed. 229 // [replacement]'s type can be narrowed.
215 TypeMask newType = replacement.instructionType 230 TypeMask newType = replacement.instructionType
216 .intersection(instruction.instructionType, closedWorld); 231 .intersection(instruction.instructionType, _closedWorld);
217 replacement.instructionType = newType; 232 replacement.instructionType = newType;
218 } 233 }
219 234
220 // If the replacement instruction does not know its 235 // If the replacement instruction does not know its
221 // source element, use the source element of the 236 // source element, use the source element of the
222 // instruction. 237 // instruction.
223 if (replacement.sourceElement == null) { 238 if (replacement.sourceElement == null) {
224 replacement.sourceElement = instruction.sourceElement; 239 replacement.sourceElement = instruction.sourceElement;
225 } 240 }
226 if (replacement.sourceInformation == null) { 241 if (replacement.sourceInformation == null) {
(...skipping 26 matching lines...) Expand all
253 } 268 }
254 // TODO(het): consider supporting other values (short strings?) 269 // TODO(het): consider supporting other values (short strings?)
255 } 270 }
256 return null; 271 return null;
257 } 272 }
258 273
259 void propagateConstantValueToUses(HInstruction node) { 274 void propagateConstantValueToUses(HInstruction node) {
260 if (node.usedBy.isEmpty) return; 275 if (node.usedBy.isEmpty) return;
261 ConstantValue value = getConstantFromType(node); 276 ConstantValue value = getConstantFromType(node);
262 if (value != null) { 277 if (value != null) {
263 HConstant constant = graph.addConstant(value, closedWorld); 278 HConstant constant = _graph.addConstant(value, _closedWorld);
264 for (HInstruction user in node.usedBy.toList()) { 279 for (HInstruction user in node.usedBy.toList()) {
265 user.changeUse(node, constant); 280 user.changeUse(node, constant);
266 } 281 }
267 } 282 }
268 } 283 }
269 284
270 HInstruction visitParameterValue(HParameterValue node) { 285 HInstruction visitParameterValue(HParameterValue node) {
271 // [HParameterValue]s are either the value of the parameter (in fully SSA 286 // [HParameterValue]s are either the value of the parameter (in fully SSA
272 // converted code), or the mutable variable containing the value (in 287 // converted code), or the mutable variable containing the value (in
273 // incompletely SSA converted code, e.g. methods containing exceptions). 288 // incompletely SSA converted code, e.g. methods containing exceptions).
(...skipping 15 matching lines...) Expand all
289 } 304 }
290 305
291 propagateConstantValueToUses(node); 306 propagateConstantValueToUses(node);
292 return node; 307 return node;
293 } 308 }
294 309
295 HInstruction visitBoolify(HBoolify node) { 310 HInstruction visitBoolify(HBoolify node) {
296 List<HInstruction> inputs = node.inputs; 311 List<HInstruction> inputs = node.inputs;
297 assert(inputs.length == 1); 312 assert(inputs.length == 1);
298 HInstruction input = inputs[0]; 313 HInstruction input = inputs[0];
299 if (input.isBoolean(closedWorld)) return input; 314 if (input.isBoolean(_closedWorld)) return input;
300 315
301 // If the code is unreachable, remove the HBoolify. This can happen when 316 // If the code is unreachable, remove the HBoolify. This can happen when
302 // there is a throw expression in a short-circuit conditional. Removing the 317 // there is a throw expression in a short-circuit conditional. Removing the
303 // unreachable HBoolify makes it easier to reconstruct the short-circuit 318 // unreachable HBoolify makes it easier to reconstruct the short-circuit
304 // operation. 319 // operation.
305 if (input.instructionType.isEmpty) return input; 320 if (input.instructionType.isEmpty) return input;
306 321
307 // All values that cannot be 'true' are boolified to false. 322 // All values that cannot be 'true' are boolified to false.
308 TypeMask mask = input.instructionType; 323 TypeMask mask = input.instructionType;
309 if (!mask.contains(helpers.jsBoolClass, closedWorld)) { 324 if (!mask.contains(_helpers.jsBoolClass, _closedWorld)) {
310 return graph.addConstantBool(false, closedWorld); 325 return _graph.addConstantBool(false, _closedWorld);
311 } 326 }
312 return node; 327 return node;
313 } 328 }
314 329
315 HInstruction visitNot(HNot node) { 330 HInstruction visitNot(HNot node) {
316 List<HInstruction> inputs = node.inputs; 331 List<HInstruction> inputs = node.inputs;
317 assert(inputs.length == 1); 332 assert(inputs.length == 1);
318 HInstruction input = inputs[0]; 333 HInstruction input = inputs[0];
319 if (input is HConstant) { 334 if (input is HConstant) {
320 HConstant constant = input; 335 HConstant constant = input;
321 bool isTrue = constant.constant.isTrue; 336 bool isTrue = constant.constant.isTrue;
322 return graph.addConstantBool(!isTrue, closedWorld); 337 return _graph.addConstantBool(!isTrue, _closedWorld);
323 } else if (input is HNot) { 338 } else if (input is HNot) {
324 return input.inputs[0]; 339 return input.inputs[0];
325 } 340 }
326 return node; 341 return node;
327 } 342 }
328 343
329 HInstruction visitInvokeUnary(HInvokeUnary node) { 344 HInstruction visitInvokeUnary(HInvokeUnary node) {
330 HInstruction folded = 345 HInstruction folded =
331 foldUnary(node.operation(constantSystem), node.operand); 346 foldUnary(node.operation(constantSystem), node.operand);
332 return folded != null ? folded : node; 347 return folded != null ? folded : node;
333 } 348 }
334 349
335 HInstruction foldUnary(UnaryOperation operation, HInstruction operand) { 350 HInstruction foldUnary(UnaryOperation operation, HInstruction operand) {
336 if (operand is HConstant) { 351 if (operand is HConstant) {
337 HConstant receiver = operand; 352 HConstant receiver = operand;
338 ConstantValue folded = operation.fold(receiver.constant); 353 ConstantValue folded = operation.fold(receiver.constant);
339 if (folded != null) return graph.addConstant(folded, closedWorld); 354 if (folded != null) return _graph.addConstant(folded, _closedWorld);
340 } 355 }
341 return null; 356 return null;
342 } 357 }
343 358
344 HInstruction tryOptimizeLengthInterceptedGetter(HInvokeDynamic node) { 359 HInstruction tryOptimizeLengthInterceptedGetter(HInvokeDynamic node) {
345 HInstruction actualReceiver = node.inputs[1]; 360 HInstruction actualReceiver = node.inputs[1];
346 if (actualReceiver.isIndexablePrimitive(closedWorld)) { 361 if (actualReceiver.isIndexablePrimitive(_closedWorld)) {
347 if (actualReceiver.isConstantString()) { 362 if (actualReceiver.isConstantString()) {
348 HConstant constantInput = actualReceiver; 363 HConstant constantInput = actualReceiver;
349 StringConstantValue constant = constantInput.constant; 364 StringConstantValue constant = constantInput.constant;
350 return graph.addConstantInt(constant.length, closedWorld); 365 return _graph.addConstantInt(constant.length, _closedWorld);
351 } else if (actualReceiver.isConstantList()) { 366 } else if (actualReceiver.isConstantList()) {
352 HConstant constantInput = actualReceiver; 367 HConstant constantInput = actualReceiver;
353 ListConstantValue constant = constantInput.constant; 368 ListConstantValue constant = constantInput.constant;
354 return graph.addConstantInt(constant.length, closedWorld); 369 return _graph.addConstantInt(constant.length, _closedWorld);
355 } 370 }
356 bool isFixed = isFixedLength(actualReceiver.instructionType, closedWorld); 371 bool isFixed =
372 isFixedLength(actualReceiver.instructionType, _closedWorld);
357 TypeMask actualType = node.instructionType; 373 TypeMask actualType = node.instructionType;
358 TypeMask resultType = closedWorld.commonMasks.positiveIntType; 374 TypeMask resultType = _closedWorld.commonMasks.positiveIntType;
359 // If we already have computed a more specific type, keep that type. 375 // If we already have computed a more specific type, keep that type.
360 if (HInstruction.isInstanceOf( 376 if (HInstruction.isInstanceOf(
361 actualType, helpers.jsUInt31Class, closedWorld)) { 377 actualType, _helpers.jsUInt31Class, _closedWorld)) {
362 resultType = closedWorld.commonMasks.uint31Type; 378 resultType = _closedWorld.commonMasks.uint31Type;
363 } else if (HInstruction.isInstanceOf( 379 } else if (HInstruction.isInstanceOf(
364 actualType, helpers.jsUInt32Class, closedWorld)) { 380 actualType, _helpers.jsUInt32Class, _closedWorld)) {
365 resultType = closedWorld.commonMasks.uint32Type; 381 resultType = _closedWorld.commonMasks.uint32Type;
366 } 382 }
367 HGetLength result = 383 HGetLength result =
368 new HGetLength(actualReceiver, resultType, isAssignable: !isFixed); 384 new HGetLength(actualReceiver, resultType, isAssignable: !isFixed);
369 return result; 385 return result;
370 } else if (actualReceiver.isConstantMap()) { 386 } else if (actualReceiver.isConstantMap()) {
371 HConstant constantInput = actualReceiver; 387 HConstant constantInput = actualReceiver;
372 MapConstantValue constant = constantInput.constant; 388 MapConstantValue constant = constantInput.constant;
373 return graph.addConstantInt(constant.length, closedWorld); 389 return _graph.addConstantInt(constant.length, _closedWorld);
374 } 390 }
375 return null; 391 return null;
376 } 392 }
377 393
378 HInstruction handleInterceptedCall(HInvokeDynamic node) { 394 HInstruction handleInterceptedCall(HInvokeDynamic node) {
379 // Try constant folding the instruction. 395 // Try constant folding the instruction.
380 Operation operation = node.specializer.operation(constantSystem); 396 Operation operation = node.specializer.operation(constantSystem);
381 if (operation != null) { 397 if (operation != null) {
382 HInstruction instruction = node.inputs.length == 2 398 HInstruction instruction = node.inputs.length == 2
383 ? foldUnary(operation, node.inputs[1]) 399 ? foldUnary(operation, node.inputs[1])
384 : foldBinary(operation, node.inputs[1], node.inputs[2]); 400 : foldBinary(operation, node.inputs[1], node.inputs[2]);
385 if (instruction != null) return instruction; 401 if (instruction != null) return instruction;
386 } 402 }
387 403
388 // Try converting the instruction to a builtin instruction. 404 // Try converting the instruction to a builtin instruction.
389 HInstruction instruction = 405 HInstruction instruction = node.specializer.tryConvertToBuiltin(
390 node.specializer.tryConvertToBuiltin(node, compiler, closedWorld); 406 node, _globalInferenceResults, _options, _helpers, _closedWorld);
391 if (instruction != null) return instruction; 407 if (instruction != null) return instruction;
392 408
393 Selector selector = node.selector; 409 Selector selector = node.selector;
394 TypeMask mask = node.mask; 410 TypeMask mask = node.mask;
395 HInstruction input = node.inputs[1]; 411 HInstruction input = node.inputs[1];
396 412
397 bool applies(MemberEntity element) { 413 bool applies(MemberEntity element) {
398 return selector.applies(element) && 414 return selector.applies(element) &&
399 (mask == null || mask.canHit(element, selector, closedWorld)); 415 (mask == null || mask.canHit(element, selector, _closedWorld));
400 } 416 }
401 417
402 if (selector.isCall || selector.isOperator) { 418 if (selector.isCall || selector.isOperator) {
403 FunctionEntity target; 419 FunctionEntity target;
404 if (input.isExtendableArray(closedWorld)) { 420 if (input.isExtendableArray(_closedWorld)) {
405 if (applies(helpers.jsArrayRemoveLast)) { 421 if (applies(_helpers.jsArrayRemoveLast)) {
406 target = helpers.jsArrayRemoveLast; 422 target = _helpers.jsArrayRemoveLast;
407 } else if (applies(helpers.jsArrayAdd)) { 423 } else if (applies(_helpers.jsArrayAdd)) {
408 // The codegen special cases array calls, but does not 424 // The codegen special cases array calls, but does not
409 // inline argument type checks. 425 // inline argument type checks.
410 if (!compiler.options.enableTypeAssertions) { 426 if (!_options.enableTypeAssertions) {
411 target = helpers.jsArrayAdd; 427 target = _helpers.jsArrayAdd;
412 } 428 }
413 } 429 }
414 } else if (input.isStringOrNull(closedWorld)) { 430 } else if (input.isStringOrNull(_closedWorld)) {
415 if (applies(helpers.jsStringSplit)) { 431 if (applies(_helpers.jsStringSplit)) {
416 HInstruction argument = node.inputs[2]; 432 HInstruction argument = node.inputs[2];
417 if (argument.isString(closedWorld)) { 433 if (argument.isString(_closedWorld)) {
418 target = helpers.jsStringSplit; 434 target = _helpers.jsStringSplit;
419 } 435 }
420 } else if (applies(helpers.jsStringOperatorAdd)) { 436 } else if (applies(_helpers.jsStringOperatorAdd)) {
421 // `operator+` is turned into a JavaScript '+' so we need to 437 // `operator+` is turned into a JavaScript '+' so we need to
422 // make sure the receiver and the argument are not null. 438 // make sure the receiver and the argument are not null.
423 // TODO(sra): Do this via [node.specializer]. 439 // TODO(sra): Do this via [node.specializer].
424 HInstruction argument = node.inputs[2]; 440 HInstruction argument = node.inputs[2];
425 if (argument.isString(closedWorld) && !input.canBeNull()) { 441 if (argument.isString(_closedWorld) && !input.canBeNull()) {
426 return new HStringConcat(input, argument, node.instructionType); 442 return new HStringConcat(input, argument, node.instructionType);
427 } 443 }
428 } else if (applies(helpers.jsStringToString) && !input.canBeNull()) { 444 } else if (applies(_helpers.jsStringToString) && !input.canBeNull()) {
429 return input; 445 return input;
430 } 446 }
431 } 447 }
432 if (target != null) { 448 if (target != null) {
433 // TODO(ngeoffray): There is a strong dependency between codegen 449 // TODO(ngeoffray): There is a strong dependency between codegen
434 // and this optimization that the dynamic invoke does not need an 450 // and this optimization that the dynamic invoke does not need an
435 // interceptor. We currently need to keep a 451 // interceptor. We currently need to keep a
436 // HInvokeDynamicMethod and not create a HForeign because 452 // HInvokeDynamicMethod and not create a HForeign because
437 // HForeign is too opaque for the SsaCheckInserter (that adds a 453 // HForeign is too opaque for the SsaCheckInserter (that adds a
438 // bounds check on removeLast). Once we start inlining, the 454 // bounds check on removeLast). Once we start inlining, the
439 // bounds check will become explicit, so we won't need this 455 // bounds check will become explicit, so we won't need this
440 // optimization. 456 // optimization.
441 HInvokeDynamicMethod result = new HInvokeDynamicMethod(node.selector, 457 HInvokeDynamicMethod result = new HInvokeDynamicMethod(node.selector,
442 node.mask, node.inputs.sublist(1), node.instructionType); 458 node.mask, node.inputs.sublist(1), node.instructionType);
443 result.element = target; 459 result.element = target;
444 return result; 460 return result;
445 } 461 }
446 } else if (selector.isGetter) { 462 } else if (selector.isGetter) {
447 if (selector.applies(helpers.jsIndexableLength)) { 463 if (selector.applies(_helpers.jsIndexableLength)) {
448 HInstruction optimized = tryOptimizeLengthInterceptedGetter(node); 464 HInstruction optimized = tryOptimizeLengthInterceptedGetter(node);
449 if (optimized != null) return optimized; 465 if (optimized != null) return optimized;
450 } 466 }
451 } 467 }
452 468
453 return node; 469 return node;
454 } 470 }
455 471
456 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { 472 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
457 propagateConstantValueToUses(node); 473 propagateConstantValueToUses(node);
458 if (node.isInterceptedCall) { 474 if (node.isInterceptedCall) {
459 HInstruction folded = handleInterceptedCall(node); 475 HInstruction folded = handleInterceptedCall(node);
460 if (folded != node) return folded; 476 if (folded != node) return folded;
461 } 477 }
462 478
463 TypeMask receiverType = node.getDartReceiver(closedWorld).instructionType; 479 TypeMask receiverType = node.getDartReceiver(_closedWorld).instructionType;
464 MemberEntity element = 480 MemberEntity element =
465 closedWorld.locateSingleElement(node.selector, receiverType); 481 _closedWorld.locateSingleElement(node.selector, receiverType);
466 // TODO(ngeoffray): Also fold if it's a getter or variable. 482 // TODO(ngeoffray): Also fold if it's a getter or variable.
467 if (element != null && 483 if (element != null &&
468 element.isFunction 484 element.isFunction
469 // If we found out that the only target is an implicitly called 485 // If we found out that the only target is an implicitly called
470 // [:noSuchMethod:] we just ignore it. 486 // [:noSuchMethod:] we just ignore it.
471 && 487 &&
472 node.selector.applies(element)) { 488 node.selector.applies(element)) {
473 MethodElement method = element; 489 MethodElement method = element;
474 490
475 if (backend.nativeData.isNativeMember(method)) { 491 if (_nativeData.isNativeMember(method)) {
476 HInstruction folded = tryInlineNativeMethod(node, method); 492 HInstruction folded = tryInlineNativeMethod(node, method);
477 if (folded != null) return folded; 493 if (folded != null) return folded;
478 } else { 494 } else {
479 // TODO(ngeoffray): If the method has optional parameters, 495 // TODO(ngeoffray): If the method has optional parameters,
480 // we should pass the default values. 496 // we should pass the default values.
481 ResolutionFunctionType type = method.type; 497 ResolutionFunctionType type = method.type;
482 int optionalParameterCount = 498 int optionalParameterCount =
483 type.optionalParameterTypes.length + type.namedParameters.length; 499 type.optionalParameterTypes.length + type.namedParameters.length;
484 if (optionalParameterCount == 0 || 500 if (optionalParameterCount == 0 ||
485 type.parameterTypes.length + optionalParameterCount == 501 type.parameterTypes.length + optionalParameterCount ==
486 node.selector.argumentCount) { 502 node.selector.argumentCount) {
487 node.element = method; 503 node.element = method;
488 } 504 }
489 } 505 }
490 return node; 506 return node;
491 } 507 }
492 508
493 // Replace method calls through fields with a closure call on the value of 509 // Replace method calls through fields with a closure call on the value of
494 // the field. This usually removes the demand for the call-through stub and 510 // the field. This usually removes the demand for the call-through stub and
495 // makes the field load available to further optimization, e.g. LICM. 511 // makes the field load available to further optimization, e.g. LICM.
496 512
497 if (element != null && 513 if (element != null &&
498 element.isField && 514 element.isField &&
499 element.name == node.selector.name) { 515 element.name == node.selector.name) {
500 FieldEntity field = element; 516 FieldEntity field = element;
501 if (!backend.nativeData.isNativeMember(field) && 517 if (!_nativeData.isNativeMember(field) &&
502 !node.isCallOnInterceptor(closedWorld)) { 518 !node.isCallOnInterceptor(_closedWorld)) {
503 HInstruction receiver = node.getDartReceiver(closedWorld); 519 HInstruction receiver = node.getDartReceiver(_closedWorld);
504 TypeMask type = TypeMaskFactory.inferredTypeForElement( 520 TypeMask type = TypeMaskFactory.inferredTypeForElement(
505 field as Entity, globalInferenceResults); 521 field as Entity, _globalInferenceResults);
506 HInstruction load = new HFieldGet(field, receiver, type); 522 HInstruction load = new HFieldGet(field, receiver, type);
507 node.block.addBefore(node, load); 523 node.block.addBefore(node, load);
508 Selector callSelector = new Selector.callClosureFrom(node.selector); 524 Selector callSelector = new Selector.callClosureFrom(node.selector);
509 List<HInstruction> inputs = <HInstruction>[load] 525 List<HInstruction> inputs = <HInstruction>[load]
510 ..addAll(node.inputs.skip(node.isInterceptedCall ? 2 : 1)); 526 ..addAll(node.inputs.skip(node.isInterceptedCall ? 2 : 1));
511 HInstruction closureCall = 527 HInstruction closureCall =
512 new HInvokeClosure(callSelector, inputs, node.instructionType) 528 new HInvokeClosure(callSelector, inputs, node.instructionType)
513 ..sourceInformation = node.sourceInformation; 529 ..sourceInformation = node.sourceInformation;
514 node.block.addAfter(load, closureCall); 530 node.block.addAfter(load, closureCall);
515 return closureCall; 531 return closureCall;
(...skipping 25 matching lines...) Expand all
541 if (type.namedParameters.isNotEmpty) return null; 557 if (type.namedParameters.isNotEmpty) return null;
542 558
543 // Return types on native methods don't need to be checked, since the 559 // Return types on native methods don't need to be checked, since the
544 // declaration has to be truthful. 560 // declaration has to be truthful.
545 561
546 // The call site might omit optional arguments. The inlined code must 562 // The call site might omit optional arguments. The inlined code must
547 // preserve the number of arguments, so check only the actual arguments. 563 // preserve the number of arguments, so check only the actual arguments.
548 564
549 List<HInstruction> inputs = node.inputs.sublist(1); 565 List<HInstruction> inputs = node.inputs.sublist(1);
550 bool canInline = true; 566 bool canInline = true;
551 if (compiler.options.enableTypeAssertions && inputs.length > 1) { 567 if (_options.enableTypeAssertions && inputs.length > 1) {
552 // TODO(sra): Check if [input] is guaranteed to pass the parameter 568 // TODO(sra): Check if [input] is guaranteed to pass the parameter
553 // type check. Consider using a strengthened type check to avoid 569 // type check. Consider using a strengthened type check to avoid
554 // passing `null` to primitive types since the native methods usually 570 // passing `null` to primitive types since the native methods usually
555 // have non-nullable primitive parameter types. 571 // have non-nullable primitive parameter types.
556 canInline = false; 572 canInline = false;
557 } else { 573 } else {
558 int inputPosition = 1; // Skip receiver. 574 int inputPosition = 1; // Skip receiver.
559 void checkParameterType(ResolutionDartType type) { 575 void checkParameterType(ResolutionDartType type) {
560 if (inputPosition++ < inputs.length && canInline) { 576 if (inputPosition++ < inputs.length && canInline) {
561 if (type.unaliased.isFunctionType) { 577 if (type.unaliased.isFunctionType) {
562 canInline = false; 578 canInline = false;
563 } 579 }
564 } 580 }
565 } 581 }
566 582
567 type.parameterTypes.forEach(checkParameterType); 583 type.parameterTypes.forEach(checkParameterType);
568 type.optionalParameterTypes.forEach(checkParameterType); 584 type.optionalParameterTypes.forEach(checkParameterType);
569 type.namedParameterTypes.forEach(checkParameterType); 585 type.namedParameterTypes.forEach(checkParameterType);
570 } 586 }
571 587
572 if (!canInline) return null; 588 if (!canInline) return null;
573 589
574 // Strengthen instruction type from annotations to help optimize 590 // Strengthen instruction type from annotations to help optimize
575 // dependent instructions. 591 // dependent instructions.
576 native.NativeBehavior nativeBehavior = 592 native.NativeBehavior nativeBehavior =
577 backend.nativeData.getNativeMethodBehavior(method); 593 _nativeData.getNativeMethodBehavior(method);
578 TypeMask returnType = 594 TypeMask returnType =
579 TypeMaskFactory.fromNativeBehavior(nativeBehavior, closedWorld); 595 TypeMaskFactory.fromNativeBehavior(nativeBehavior, _closedWorld);
580 HInvokeDynamicMethod result = 596 HInvokeDynamicMethod result =
581 new HInvokeDynamicMethod(node.selector, node.mask, inputs, returnType); 597 new HInvokeDynamicMethod(node.selector, node.mask, inputs, returnType);
582 result.element = method; 598 result.element = method;
583 return result; 599 return result;
584 } 600 }
585 601
586 HInstruction visitBoundsCheck(HBoundsCheck node) { 602 HInstruction visitBoundsCheck(HBoundsCheck node) {
587 HInstruction index = node.index; 603 HInstruction index = node.index;
588 if (index.isInteger(closedWorld)) return node; 604 if (index.isInteger(_closedWorld)) return node;
589 if (index.isConstant()) { 605 if (index.isConstant()) {
590 HConstant constantInstruction = index; 606 HConstant constantInstruction = index;
591 assert(!constantInstruction.constant.isInt); 607 assert(!constantInstruction.constant.isInt);
592 if (!constantSystem.isInt(constantInstruction.constant)) { 608 if (!constantSystem.isInt(constantInstruction.constant)) {
593 // -0.0 is a double but will pass the runtime integer check. 609 // -0.0 is a double but will pass the runtime integer check.
594 node.staticChecks = HBoundsCheck.ALWAYS_FALSE; 610 node.staticChecks = HBoundsCheck.ALWAYS_FALSE;
595 } 611 }
596 } 612 }
597 return node; 613 return node;
598 } 614 }
599 615
600 HInstruction foldBinary( 616 HInstruction foldBinary(
601 BinaryOperation operation, HInstruction left, HInstruction right) { 617 BinaryOperation operation, HInstruction left, HInstruction right) {
602 if (left is HConstant && right is HConstant) { 618 if (left is HConstant && right is HConstant) {
603 HConstant op1 = left; 619 HConstant op1 = left;
604 HConstant op2 = right; 620 HConstant op2 = right;
605 ConstantValue folded = operation.fold(op1.constant, op2.constant); 621 ConstantValue folded = operation.fold(op1.constant, op2.constant);
606 if (folded != null) return graph.addConstant(folded, closedWorld); 622 if (folded != null) return _graph.addConstant(folded, _closedWorld);
607 } 623 }
608 return null; 624 return null;
609 } 625 }
610 626
611 HInstruction visitAdd(HAdd node) { 627 HInstruction visitAdd(HAdd node) {
612 HInstruction left = node.left; 628 HInstruction left = node.left;
613 HInstruction right = node.right; 629 HInstruction right = node.right;
614 // We can only perform this rewriting on Integer, as it is not 630 // We can only perform this rewriting on Integer, as it is not
615 // valid for -0.0. 631 // valid for -0.0.
616 if (left.isInteger(closedWorld) && right.isInteger(closedWorld)) { 632 if (left.isInteger(_closedWorld) && right.isInteger(_closedWorld)) {
617 if (left is HConstant && left.constant.isZero) return right; 633 if (left is HConstant && left.constant.isZero) return right;
618 if (right is HConstant && right.constant.isZero) return left; 634 if (right is HConstant && right.constant.isZero) return left;
619 } 635 }
620 return super.visitAdd(node); 636 return super.visitAdd(node);
621 } 637 }
622 638
623 HInstruction visitMultiply(HMultiply node) { 639 HInstruction visitMultiply(HMultiply node) {
624 HInstruction left = node.left; 640 HInstruction left = node.left;
625 HInstruction right = node.right; 641 HInstruction right = node.right;
626 if (left.isNumber(closedWorld) && right.isNumber(closedWorld)) { 642 if (left.isNumber(_closedWorld) && right.isNumber(_closedWorld)) {
627 if (left is HConstant && left.constant.isOne) return right; 643 if (left is HConstant && left.constant.isOne) return right;
628 if (right is HConstant && right.constant.isOne) return left; 644 if (right is HConstant && right.constant.isOne) return left;
629 } 645 }
630 return super.visitMultiply(node); 646 return super.visitMultiply(node);
631 } 647 }
632 648
633 HInstruction visitInvokeBinary(HInvokeBinary node) { 649 HInstruction visitInvokeBinary(HInvokeBinary node) {
634 HInstruction left = node.left; 650 HInstruction left = node.left;
635 HInstruction right = node.right; 651 HInstruction right = node.right;
636 BinaryOperation operation = node.operation(constantSystem); 652 BinaryOperation operation = node.operation(constantSystem);
(...skipping 20 matching lines...) Expand all
657 // in the remaining optimizations. 673 // in the remaining optimizations.
658 return super.visitRelational(node); 674 return super.visitRelational(node);
659 } 675 }
660 676
661 HInstruction handleIdentityCheck(HRelational node) { 677 HInstruction handleIdentityCheck(HRelational node) {
662 HInstruction left = node.left; 678 HInstruction left = node.left;
663 HInstruction right = node.right; 679 HInstruction right = node.right;
664 TypeMask leftType = left.instructionType; 680 TypeMask leftType = left.instructionType;
665 TypeMask rightType = right.instructionType; 681 TypeMask rightType = right.instructionType;
666 682
667 HInstruction makeTrue() => graph.addConstantBool(true, closedWorld); 683 HInstruction makeTrue() => _graph.addConstantBool(true, _closedWorld);
668 HInstruction makeFalse() => graph.addConstantBool(false, closedWorld); 684 HInstruction makeFalse() => _graph.addConstantBool(false, _closedWorld);
669 685
670 // Intersection of int and double return conflicting, so 686 // Intersection of int and double return conflicting, so
671 // we don't optimize on numbers to preserve the runtime semantics. 687 // we don't optimize on numbers to preserve the runtime semantics.
672 if (!(left.isNumberOrNull(closedWorld) && 688 if (!(left.isNumberOrNull(_closedWorld) &&
673 right.isNumberOrNull(closedWorld))) { 689 right.isNumberOrNull(_closedWorld))) {
674 if (leftType.isDisjoint(rightType, closedWorld)) { 690 if (leftType.isDisjoint(rightType, _closedWorld)) {
675 return makeFalse(); 691 return makeFalse();
676 } 692 }
677 } 693 }
678 694
679 if (left.isNull() && right.isNull()) { 695 if (left.isNull() && right.isNull()) {
680 return makeTrue(); 696 return makeTrue();
681 } 697 }
682 698
683 HInstruction compareConstant(HConstant constant, HInstruction input) { 699 HInstruction compareConstant(HConstant constant, HInstruction input) {
684 if (constant.constant.isTrue) { 700 if (constant.constant.isTrue) {
685 return input; 701 return input;
686 } else { 702 } else {
687 return new HNot(input, closedWorld.commonMasks.boolType); 703 return new HNot(input, _closedWorld.commonMasks.boolType);
688 } 704 }
689 } 705 }
690 706
691 if (left.isConstantBoolean() && right.isBoolean(closedWorld)) { 707 if (left.isConstantBoolean() && right.isBoolean(_closedWorld)) {
692 return compareConstant(left, right); 708 return compareConstant(left, right);
693 } 709 }
694 710
695 if (right.isConstantBoolean() && left.isBoolean(closedWorld)) { 711 if (right.isConstantBoolean() && left.isBoolean(_closedWorld)) {
696 return compareConstant(right, left); 712 return compareConstant(right, left);
697 } 713 }
698 714
699 if (identical(left.nonCheck(), right.nonCheck())) { 715 if (identical(left.nonCheck(), right.nonCheck())) {
700 // Avoid constant-folding `identical(x, x)` when `x` might be double. The 716 // Avoid constant-folding `identical(x, x)` when `x` might be double. The
701 // dart2js runtime has not always been consistent with the Dart 717 // dart2js runtime has not always been consistent with the Dart
702 // specification (section 16.0.1), which makes distinctions on NaNs and 718 // specification (section 16.0.1), which makes distinctions on NaNs and
703 // -0.0 that are hard to implement efficiently. 719 // -0.0 that are hard to implement efficiently.
704 if (left.isIntegerOrNull(closedWorld)) return makeTrue(); 720 if (left.isIntegerOrNull(_closedWorld)) return makeTrue();
705 if (!left.canBePrimitiveNumber(closedWorld)) return makeTrue(); 721 if (!left.canBePrimitiveNumber(_closedWorld)) return makeTrue();
706 } 722 }
707 723
708 return null; 724 return null;
709 } 725 }
710 726
711 HInstruction visitIdentity(HIdentity node) { 727 HInstruction visitIdentity(HIdentity node) {
712 HInstruction newInstruction = handleIdentityCheck(node); 728 HInstruction newInstruction = handleIdentityCheck(node);
713 return newInstruction == null ? super.visitIdentity(node) : newInstruction; 729 return newInstruction == null ? super.visitIdentity(node) : newInstruction;
714 } 730 }
715 731
716 void simplifyCondition( 732 void simplifyCondition(
717 HBasicBlock block, HInstruction condition, bool value) { 733 HBasicBlock block, HInstruction condition, bool value) {
718 condition.dominatedUsers(block.first).forEach((user) { 734 condition.dominatedUsers(block.first).forEach((user) {
719 HInstruction newCondition = graph.addConstantBool(value, closedWorld); 735 HInstruction newCondition = _graph.addConstantBool(value, _closedWorld);
720 user.changeUse(condition, newCondition); 736 user.changeUse(condition, newCondition);
721 }); 737 });
722 } 738 }
723 739
724 HInstruction visitIf(HIf node) { 740 HInstruction visitIf(HIf node) {
725 HInstruction condition = node.condition; 741 HInstruction condition = node.condition;
726 if (condition.isConstant()) return node; 742 if (condition.isConstant()) return node;
727 bool isNegated = condition is HNot; 743 bool isNegated = condition is HNot;
728 744
729 if (isNegated) { 745 if (isNegated) {
(...skipping 21 matching lines...) Expand all
751 767
752 if (!node.isRawCheck) { 768 if (!node.isRawCheck) {
753 return node; 769 return node;
754 } else if (type.isTypedef) { 770 } else if (type.isTypedef) {
755 return node; 771 return node;
756 } else if (type.isFunctionType) { 772 } else if (type.isFunctionType) {
757 return node; 773 return node;
758 } 774 }
759 775
760 if (type.isObject || type.treatAsDynamic) { 776 if (type.isObject || type.treatAsDynamic) {
761 return graph.addConstantBool(true, closedWorld); 777 return _graph.addConstantBool(true, _closedWorld);
762 } 778 }
763 ResolutionInterfaceType interfaceType = type; 779 ResolutionInterfaceType interfaceType = type;
764 ClassEntity element = interfaceType.element; 780 ClassEntity element = interfaceType.element;
765 HInstruction expression = node.expression; 781 HInstruction expression = node.expression;
766 if (expression.isInteger(closedWorld)) { 782 if (expression.isInteger(_closedWorld)) {
767 if (element == commonElements.intClass || 783 if (element == commonElements.intClass ||
768 element == commonElements.numClass || 784 element == commonElements.numClass ||
769 commonElements.isNumberOrStringSupertype(element)) { 785 commonElements.isNumberOrStringSupertype(element)) {
770 return graph.addConstantBool(true, closedWorld); 786 return _graph.addConstantBool(true, _closedWorld);
771 } else if (element == commonElements.doubleClass) { 787 } else if (element == commonElements.doubleClass) {
772 // We let the JS semantics decide for that check. Currently 788 // We let the JS semantics decide for that check. Currently
773 // the code we emit will always return true. 789 // the code we emit will always return true.
774 return node; 790 return node;
775 } else { 791 } else {
776 return graph.addConstantBool(false, closedWorld); 792 return _graph.addConstantBool(false, _closedWorld);
777 } 793 }
778 } else if (expression.isDouble(closedWorld)) { 794 } else if (expression.isDouble(_closedWorld)) {
779 if (element == commonElements.doubleClass || 795 if (element == commonElements.doubleClass ||
780 element == commonElements.numClass || 796 element == commonElements.numClass ||
781 commonElements.isNumberOrStringSupertype(element)) { 797 commonElements.isNumberOrStringSupertype(element)) {
782 return graph.addConstantBool(true, closedWorld); 798 return _graph.addConstantBool(true, _closedWorld);
783 } else if (element == commonElements.intClass) { 799 } else if (element == commonElements.intClass) {
784 // We let the JS semantics decide for that check. Currently 800 // We let the JS semantics decide for that check. Currently
785 // the code we emit will return true for a double that can be 801 // the code we emit will return true for a double that can be
786 // represented as a 31-bit integer and for -0.0. 802 // represented as a 31-bit integer and for -0.0.
787 return node; 803 return node;
788 } else { 804 } else {
789 return graph.addConstantBool(false, closedWorld); 805 return _graph.addConstantBool(false, _closedWorld);
790 } 806 }
791 } else if (expression.isNumber(closedWorld)) { 807 } else if (expression.isNumber(_closedWorld)) {
792 if (element == commonElements.numClass) { 808 if (element == commonElements.numClass) {
793 return graph.addConstantBool(true, closedWorld); 809 return _graph.addConstantBool(true, _closedWorld);
794 } else { 810 } else {
795 // We cannot just return false, because the expression may be of 811 // We cannot just return false, because the expression may be of
796 // type int or double. 812 // type int or double.
797 } 813 }
798 } else if (expression.canBePrimitiveNumber(closedWorld) && 814 } else if (expression.canBePrimitiveNumber(_closedWorld) &&
799 element == commonElements.intClass) { 815 element == commonElements.intClass) {
800 // We let the JS semantics decide for that check. 816 // We let the JS semantics decide for that check.
801 return node; 817 return node;
802 // We need the [:hasTypeArguments:] check because we don't have 818 // We need the [:hasTypeArguments:] check because we don't have
803 // the notion of generics in the backend. For example, [:this:] in 819 // the notion of generics in the backend. For example, [:this:] in
804 // a class [:A<T>:], is currently always considered to have the 820 // a class [:A<T>:], is currently always considered to have the
805 // raw type. 821 // raw type.
806 } else if (!RuntimeTypesSubstitutions.hasTypeArguments(type)) { 822 } else if (!RuntimeTypesSubstitutions.hasTypeArguments(type)) {
807 TypeMask expressionMask = expression.instructionType; 823 TypeMask expressionMask = expression.instructionType;
808 assert(TypeMask.assertIsNormalized(expressionMask, closedWorld)); 824 assert(TypeMask.assertIsNormalized(expressionMask, _closedWorld));
809 TypeMask typeMask = (element == commonElements.nullClass) 825 TypeMask typeMask = (element == commonElements.nullClass)
810 ? new TypeMask.subtype(element, closedWorld) 826 ? new TypeMask.subtype(element, _closedWorld)
811 : new TypeMask.nonNullSubtype(element, closedWorld); 827 : new TypeMask.nonNullSubtype(element, _closedWorld);
812 if (expressionMask.union(typeMask, closedWorld) == typeMask) { 828 if (expressionMask.union(typeMask, _closedWorld) == typeMask) {
813 return graph.addConstantBool(true, closedWorld); 829 return _graph.addConstantBool(true, _closedWorld);
814 } else if (expressionMask.isDisjoint(typeMask, closedWorld)) { 830 } else if (expressionMask.isDisjoint(typeMask, _closedWorld)) {
815 return graph.addConstantBool(false, closedWorld); 831 return _graph.addConstantBool(false, _closedWorld);
816 } 832 }
817 } 833 }
818 return node; 834 return node;
819 } 835 }
820 836
821 HInstruction visitTypeConversion(HTypeConversion node) { 837 HInstruction visitTypeConversion(HTypeConversion node) {
822 ResolutionDartType type = node.typeExpression; 838 ResolutionDartType type = node.typeExpression;
823 if (type != null) { 839 if (type != null) {
824 if (type.isMalformed) { 840 if (type.isMalformed) {
825 // Malformed types are treated as dynamic statically, but should 841 // Malformed types are treated as dynamic statically, but should
(...skipping 23 matching lines...) Expand all
849 } 865 }
850 } 866 }
851 return removeIfCheckAlwaysSucceeds(node, node.checkedType); 867 return removeIfCheckAlwaysSucceeds(node, node.checkedType);
852 } 868 }
853 869
854 HInstruction visitTypeKnown(HTypeKnown node) { 870 HInstruction visitTypeKnown(HTypeKnown node) {
855 return removeIfCheckAlwaysSucceeds(node, node.knownType); 871 return removeIfCheckAlwaysSucceeds(node, node.knownType);
856 } 872 }
857 873
858 HInstruction removeIfCheckAlwaysSucceeds(HCheck node, TypeMask checkedType) { 874 HInstruction removeIfCheckAlwaysSucceeds(HCheck node, TypeMask checkedType) {
859 if (checkedType.containsAll(closedWorld)) return node; 875 if (checkedType.containsAll(_closedWorld)) return node;
860 HInstruction input = node.checkedInput; 876 HInstruction input = node.checkedInput;
861 TypeMask inputType = input.instructionType; 877 TypeMask inputType = input.instructionType;
862 return inputType.isInMask(checkedType, closedWorld) ? input : node; 878 return inputType.isInMask(checkedType, _closedWorld) ? input : node;
863 } 879 }
864 880
865 HInstruction removeCheck(HCheck node) => node.checkedInput; 881 HInstruction removeCheck(HCheck node) => node.checkedInput;
866 882
867 FieldEntity findConcreteFieldForDynamicAccess( 883 FieldEntity findConcreteFieldForDynamicAccess(
868 HInstruction receiver, Selector selector) { 884 HInstruction receiver, Selector selector) {
869 TypeMask receiverType = receiver.instructionType; 885 TypeMask receiverType = receiver.instructionType;
870 return closedWorld.locateSingleField(selector, receiverType); 886 return _closedWorld.locateSingleField(selector, receiverType);
871 } 887 }
872 888
873 HInstruction visitFieldGet(HFieldGet node) { 889 HInstruction visitFieldGet(HFieldGet node) {
874 if (node.isNullCheck) return node; 890 if (node.isNullCheck) return node;
875 var receiver = node.receiver; 891 var receiver = node.receiver;
876 892
877 // HFieldGet of a constructed constant can be replaced with the constant's 893 // HFieldGet of a constructed constant can be replaced with the constant's
878 // field. 894 // field.
879 if (receiver is HConstant) { 895 if (receiver is HConstant) {
880 ConstantValue constant = receiver.constant; 896 ConstantValue constant = receiver.constant;
881 if (constant.isConstructedObject) { 897 if (constant.isConstructedObject) {
882 ConstructedConstantValue constructedConstant = constant; 898 ConstructedConstantValue constructedConstant = constant;
883 Map<FieldEntity, ConstantValue> fields = constructedConstant.fields; 899 Map<FieldEntity, ConstantValue> fields = constructedConstant.fields;
884 ConstantValue value = fields[node.element]; 900 ConstantValue value = fields[node.element];
885 if (value != null) { 901 if (value != null) {
886 return graph.addConstant(value, closedWorld); 902 return _graph.addConstant(value, _closedWorld);
887 } 903 }
888 } 904 }
889 } 905 }
890 906
891 return node; 907 return node;
892 } 908 }
893 909
894 HInstruction visitGetLength(HGetLength node) { 910 HInstruction visitGetLength(HGetLength node) {
895 var receiver = node.receiver; 911 var receiver = node.receiver;
896 if (graph.allocatedFixedLists.contains(receiver)) { 912 if (_graph.allocatedFixedLists.contains(receiver)) {
897 // TODO(ngeoffray): checking if the second input is an integer 913 // TODO(ngeoffray): checking if the second input is an integer
898 // should not be necessary but it currently makes it easier for 914 // should not be necessary but it currently makes it easier for
899 // other optimizations to reason about a fixed length constructor 915 // other optimizations to reason about a fixed length constructor
900 // that we know takes an int. 916 // that we know takes an int.
901 if (receiver.inputs[0].isInteger(closedWorld)) { 917 if (receiver.inputs[0].isInteger(_closedWorld)) {
902 return receiver.inputs[0]; 918 return receiver.inputs[0];
903 } 919 }
904 } else if (receiver.isConstantList() || receiver.isConstantString()) { 920 } else if (receiver.isConstantList() || receiver.isConstantString()) {
905 return graph.addConstantInt(receiver.constant.length, closedWorld); 921 return _graph.addConstantInt(receiver.constant.length, _closedWorld);
906 } else { 922 } else {
907 var type = receiver.instructionType; 923 var type = receiver.instructionType;
908 if (type.isContainer && type.length != null) { 924 if (type.isContainer && type.length != null) {
909 HInstruction constant = graph.addConstantInt(type.length, closedWorld); 925 HInstruction constant =
926 _graph.addConstantInt(type.length, _closedWorld);
910 if (type.isNullable) { 927 if (type.isNullable) {
911 // If the container can be null, we update all uses of the length 928 // If the container can be null, we update all uses of the length
912 // access to use the constant instead, but keep the length access in 929 // access to use the constant instead, but keep the length access in
913 // the graph, to ensure we still have a null check. 930 // the graph, to ensure we still have a null check.
914 node.block.rewrite(node, constant); 931 node.block.rewrite(node, constant);
915 return node; 932 return node;
916 } else { 933 } else {
917 return constant; 934 return constant;
918 } 935 }
919 } 936 }
920 } 937 }
921 938
922 if (node.isAssignable && 939 if (node.isAssignable &&
923 isFixedLength(receiver.instructionType, closedWorld)) { 940 isFixedLength(receiver.instructionType, _closedWorld)) {
924 // The input type has changed to fixed-length so change to an unassignable 941 // The input type has changed to fixed-length so change to an unassignable
925 // HGetLength to allow more GVN optimizations. 942 // HGetLength to allow more GVN optimizations.
926 return new HGetLength(receiver, node.instructionType, 943 return new HGetLength(receiver, node.instructionType,
927 isAssignable: false); 944 isAssignable: false);
928 } 945 }
929 return node; 946 return node;
930 } 947 }
931 948
932 HInstruction visitIndex(HIndex node) { 949 HInstruction visitIndex(HIndex node) {
933 if (node.receiver.isConstantList() && node.index.isConstantInteger()) { 950 if (node.receiver.isConstantList() && node.index.isConstantInteger()) {
934 var instruction = node.receiver; 951 var instruction = node.receiver;
935 List<ConstantValue> entries = instruction.constant.entries; 952 List<ConstantValue> entries = instruction.constant.entries;
936 instruction = node.index; 953 instruction = node.index;
937 int index = instruction.constant.primitiveValue; 954 int index = instruction.constant.primitiveValue;
938 if (index >= 0 && index < entries.length) { 955 if (index >= 0 && index < entries.length) {
939 return graph.addConstant(entries[index], closedWorld); 956 return _graph.addConstant(entries[index], _closedWorld);
940 } 957 }
941 } 958 }
942 return node; 959 return node;
943 } 960 }
944 961
945 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { 962 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
946 propagateConstantValueToUses(node); 963 propagateConstantValueToUses(node);
947 if (node.isInterceptedCall) { 964 if (node.isInterceptedCall) {
948 HInstruction folded = handleInterceptedCall(node); 965 HInstruction folded = handleInterceptedCall(node);
949 if (folded != node) return folded; 966 if (folded != node) return folded;
950 } 967 }
951 HInstruction receiver = node.getDartReceiver(closedWorld); 968 HInstruction receiver = node.getDartReceiver(_closedWorld);
952 FieldEntity field = 969 FieldEntity field =
953 findConcreteFieldForDynamicAccess(receiver, node.selector); 970 findConcreteFieldForDynamicAccess(receiver, node.selector);
954 if (field != null) return directFieldGet(receiver, field); 971 if (field != null) return directFieldGet(receiver, field);
955 972
956 if (node.element == null) { 973 if (node.element == null) {
957 MemberEntity element = closedWorld.locateSingleElement( 974 MemberEntity element = _closedWorld.locateSingleElement(
958 node.selector, receiver.instructionType); 975 node.selector, receiver.instructionType);
959 if (element != null && element.name == node.selector.name) { 976 if (element != null && element.name == node.selector.name) {
960 node.element = element; 977 node.element = element;
961 if (element.isFunction) { 978 if (element.isFunction) {
962 // A property extraction getter, aka a tear-off. 979 // A property extraction getter, aka a tear-off.
963 node.sideEffects.clearAllDependencies(); 980 node.sideEffects.clearAllDependencies();
964 node.sideEffects.clearAllSideEffects(); 981 node.sideEffects.clearAllSideEffects();
965 node.setUseGvn(); // We don't care about identity of tear-offs. 982 node.setUseGvn(); // We don't care about identity of tear-offs.
966 } 983 }
967 } 984 }
968 } 985 }
969 return node; 986 return node;
970 } 987 }
971 988
972 HInstruction directFieldGet(HInstruction receiver, FieldEntity field) { 989 HInstruction directFieldGet(HInstruction receiver, FieldEntity field) {
973 bool isAssignable = !closedWorld.fieldNeverChanges(field); 990 bool isAssignable = !_closedWorld.fieldNeverChanges(field);
974 991
975 TypeMask type; 992 TypeMask type;
976 if (backend.nativeData.isNativeClass(field.enclosingClass)) { 993 if (_nativeData.isNativeClass(field.enclosingClass)) {
977 type = TypeMaskFactory.fromNativeBehavior( 994 type = TypeMaskFactory.fromNativeBehavior(
978 backend.nativeData.getNativeFieldLoadBehavior(field), closedWorld); 995 _nativeData.getNativeFieldLoadBehavior(field), _closedWorld);
979 } else { 996 } else {
980 type = TypeMaskFactory.inferredTypeForElement( 997 type = TypeMaskFactory.inferredTypeForElement(
981 field as Entity, globalInferenceResults); 998 field as Entity, _globalInferenceResults);
982 } 999 }
983 1000
984 return new HFieldGet(field, receiver, type, isAssignable: isAssignable); 1001 return new HFieldGet(field, receiver, type, isAssignable: isAssignable);
985 } 1002 }
986 1003
987 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { 1004 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) {
988 if (node.isInterceptedCall) { 1005 if (node.isInterceptedCall) {
989 HInstruction folded = handleInterceptedCall(node); 1006 HInstruction folded = handleInterceptedCall(node);
990 if (folded != node) return folded; 1007 if (folded != node) return folded;
991 } 1008 }
992 1009
993 HInstruction receiver = node.getDartReceiver(closedWorld); 1010 HInstruction receiver = node.getDartReceiver(_closedWorld);
994 FieldElement field = 1011 FieldElement field =
995 findConcreteFieldForDynamicAccess(receiver, node.selector); 1012 findConcreteFieldForDynamicAccess(receiver, node.selector);
996 if (field == null || !field.isAssignable) return node; 1013 if (field == null || !field.isAssignable) return node;
997 // Use `node.inputs.last` in case the call follows the interceptor calling 1014 // Use `node.inputs.last` in case the call follows the interceptor calling
998 // convention, but is not a call on an interceptor. 1015 // convention, but is not a call on an interceptor.
999 HInstruction value = node.inputs.last; 1016 HInstruction value = node.inputs.last;
1000 if (compiler.options.enableTypeAssertions) { 1017 if (_options.enableTypeAssertions) {
1001 ResolutionDartType type = field.type; 1018 ResolutionDartType type = field.type;
1002 if (!type.treatAsRaw || 1019 if (!type.treatAsRaw ||
1003 type.isTypeVariable || 1020 type.isTypeVariable ||
1004 type.unaliased.isFunctionType) { 1021 type.unaliased.isFunctionType) {
1005 // We cannot generate the correct type representation here, so don't 1022 // We cannot generate the correct type representation here, so don't
1006 // inline this access. 1023 // inline this access.
1007 // TODO(sra): If the input is such that we don't need a type check, we 1024 // TODO(sra): If the input is such that we don't need a type check, we
1008 // can skip the test an generate the HFieldSet. 1025 // can skip the test an generate the HFieldSet.
1009 return node; 1026 return node;
1010 } 1027 }
1011 HInstruction other = value.convertType( 1028 HInstruction other = value.convertType(
1012 closedWorld, type, HTypeConversion.CHECKED_MODE_CHECK); 1029 _closedWorld, type, HTypeConversion.CHECKED_MODE_CHECK);
1013 if (other != value) { 1030 if (other != value) {
1014 node.block.addBefore(node, other); 1031 node.block.addBefore(node, other);
1015 value = other; 1032 value = other;
1016 } 1033 }
1017 } 1034 }
1018 return new HFieldSet(field, receiver, value); 1035 return new HFieldSet(field, receiver, value);
1019 } 1036 }
1020 1037
1021 HInstruction visitInvokeStatic(HInvokeStatic node) { 1038 HInstruction visitInvokeStatic(HInvokeStatic node) {
1022 propagateConstantValueToUses(node); 1039 propagateConstantValueToUses(node);
1023 MemberEntity element = node.element; 1040 MemberEntity element = node.element;
1024 1041
1025 if (element == compiler.commonElements.identicalFunction) { 1042 if (element == commonElements.identicalFunction) {
1026 if (node.inputs.length == 2) { 1043 if (node.inputs.length == 2) {
1027 return new HIdentity(node.inputs[0], node.inputs[1], null, 1044 return new HIdentity(node.inputs[0], node.inputs[1], null,
1028 closedWorld.commonMasks.boolType) 1045 _closedWorld.commonMasks.boolType)
1029 ..sourceInformation = node.sourceInformation; 1046 ..sourceInformation = node.sourceInformation;
1030 } 1047 }
1031 } else if (element == backend.helpers.checkConcurrentModificationError) { 1048 } else if (element == _helpers.checkConcurrentModificationError) {
1032 if (node.inputs.length == 2) { 1049 if (node.inputs.length == 2) {
1033 HInstruction firstArgument = node.inputs[0]; 1050 HInstruction firstArgument = node.inputs[0];
1034 if (firstArgument is HConstant) { 1051 if (firstArgument is HConstant) {
1035 HConstant constant = firstArgument; 1052 HConstant constant = firstArgument;
1036 if (constant.constant.isTrue) return constant; 1053 if (constant.constant.isTrue) return constant;
1037 } 1054 }
1038 } 1055 }
1039 } else if (element == backend.helpers.checkInt) { 1056 } else if (element == _helpers.checkInt) {
1040 if (node.inputs.length == 1) { 1057 if (node.inputs.length == 1) {
1041 HInstruction argument = node.inputs[0]; 1058 HInstruction argument = node.inputs[0];
1042 if (argument.isInteger(closedWorld)) return argument; 1059 if (argument.isInteger(_closedWorld)) return argument;
1043 } 1060 }
1044 } else if (element == backend.helpers.checkNum) { 1061 } else if (element == _helpers.checkNum) {
1045 if (node.inputs.length == 1) { 1062 if (node.inputs.length == 1) {
1046 HInstruction argument = node.inputs[0]; 1063 HInstruction argument = node.inputs[0];
1047 if (argument.isNumber(closedWorld)) return argument; 1064 if (argument.isNumber(_closedWorld)) return argument;
1048 } 1065 }
1049 } else if (element == backend.helpers.checkString) { 1066 } else if (element == _helpers.checkString) {
1050 if (node.inputs.length == 1) { 1067 if (node.inputs.length == 1) {
1051 HInstruction argument = node.inputs[0]; 1068 HInstruction argument = node.inputs[0];
1052 if (argument.isString(closedWorld)) return argument; 1069 if (argument.isString(_closedWorld)) return argument;
1053 } 1070 }
1054 } 1071 }
1055 return node; 1072 return node;
1056 } 1073 }
1057 1074
1058 HInstruction visitStringConcat(HStringConcat node) { 1075 HInstruction visitStringConcat(HStringConcat node) {
1059 // Simplify string concat: 1076 // Simplify string concat:
1060 // 1077 //
1061 // "" + R -> R 1078 // "" + R -> R
1062 // L + "" -> L 1079 // L + "" -> L
(...skipping 24 matching lines...) Expand all
1087 prefix = leftConcat.left; 1104 prefix = leftConcat.left;
1088 leftString = getString(leftConcat.right); 1105 leftString = getString(leftConcat.right);
1089 if (leftString == null) return node; 1106 if (leftString == null) return node;
1090 } 1107 }
1091 1108
1092 if (leftString.primitiveValue.length + rightString.primitiveValue.length > 1109 if (leftString.primitiveValue.length + rightString.primitiveValue.length >
1093 MAX_SHARED_CONSTANT_FOLDED_STRING_LENGTH) { 1110 MAX_SHARED_CONSTANT_FOLDED_STRING_LENGTH) {
1094 if (node.usedBy.length > 1) return node; 1111 if (node.usedBy.length > 1) return node;
1095 } 1112 }
1096 1113
1097 HInstruction folded = graph.addConstant( 1114 HInstruction folded = _graph.addConstant(
1098 constantSystem.createString(new ast.DartString.concat( 1115 constantSystem.createString(new ast.DartString.concat(
1099 leftString.primitiveValue, rightString.primitiveValue)), 1116 leftString.primitiveValue, rightString.primitiveValue)),
1100 closedWorld); 1117 _closedWorld);
1101 if (prefix == null) return folded; 1118 if (prefix == null) return folded;
1102 return new HStringConcat( 1119 return new HStringConcat(
1103 prefix, folded, closedWorld.commonMasks.stringType); 1120 prefix, folded, _closedWorld.commonMasks.stringType);
1104 } 1121 }
1105 1122
1106 HInstruction visitStringify(HStringify node) { 1123 HInstruction visitStringify(HStringify node) {
1107 HInstruction input = node.inputs[0]; 1124 HInstruction input = node.inputs[0];
1108 if (input.isString(closedWorld)) return input; 1125 if (input.isString(_closedWorld)) return input;
1109 1126
1110 HInstruction tryConstant() { 1127 HInstruction tryConstant() {
1111 if (!input.isConstant()) return null; 1128 if (!input.isConstant()) return null;
1112 HConstant constant = input; 1129 HConstant constant = input;
1113 if (!constant.constant.isPrimitive) return null; 1130 if (!constant.constant.isPrimitive) return null;
1114 if (constant.constant.isInt) { 1131 if (constant.constant.isInt) {
1115 // Only constant-fold int.toString() when Dart and JS results the same. 1132 // Only constant-fold int.toString() when Dart and JS results the same.
1116 // TODO(18103): We should be able to remove this work-around when issue 1133 // TODO(18103): We should be able to remove this work-around when issue
1117 // 18103 is resolved by providing the correct string. 1134 // 18103 is resolved by providing the correct string.
1118 IntConstantValue intConstant = constant.constant; 1135 IntConstantValue intConstant = constant.constant;
1119 // Very conservative range. 1136 // Very conservative range.
1120 if (!intConstant.isUInt32()) return null; 1137 if (!intConstant.isUInt32()) return null;
1121 } 1138 }
1122 PrimitiveConstantValue primitive = constant.constant; 1139 PrimitiveConstantValue primitive = constant.constant;
1123 return graph.addConstant( 1140 return _graph.addConstant(
1124 constantSystem.createString(primitive.toDartString()), closedWorld); 1141 constantSystem.createString(primitive.toDartString()), _closedWorld);
1125 } 1142 }
1126 1143
1127 HInstruction tryToString() { 1144 HInstruction tryToString() {
1128 // If the `toString` method is guaranteed to return a string we can call 1145 // If the `toString` method is guaranteed to return a string we can call
1129 // it directly. Keep the stringifier for primitives (since they have fast 1146 // it directly. Keep the stringifier for primitives (since they have fast
1130 // path code in the stringifier) and for classes requiring interceptors 1147 // path code in the stringifier) and for classes requiring interceptors
1131 // (since SsaInstructionSimplifier runs after SsaSimplifyInterceptors). 1148 // (since SsaInstructionSimplifier runs after SsaSimplifyInterceptors).
1132 if (input.canBePrimitive(closedWorld)) return null; 1149 if (input.canBePrimitive(_closedWorld)) return null;
1133 if (input.canBeNull()) return null; 1150 if (input.canBeNull()) return null;
1134 Selector selector = Selectors.toString_; 1151 Selector selector = Selectors.toString_;
1135 TypeMask toStringType = TypeMaskFactory.inferredTypeForSelector( 1152 TypeMask toStringType = TypeMaskFactory.inferredTypeForSelector(
1136 selector, input.instructionType, globalInferenceResults); 1153 selector, input.instructionType, _globalInferenceResults);
1137 if (!toStringType.containsOnlyString(closedWorld)) return null; 1154 if (!toStringType.containsOnlyString(_closedWorld)) return null;
1138 // All intercepted classes extend `Interceptor`, so if the receiver can't 1155 // All intercepted classes extend `Interceptor`, so if the receiver can't
1139 // be a class extending `Interceptor` then it can be called directly. 1156 // be a class extending `Interceptor` then it can be called directly.
1140 if (new TypeMask.nonNullSubclass(helpers.jsInterceptorClass, closedWorld) 1157 if (new TypeMask.nonNullSubclass(
1141 .isDisjoint(input.instructionType, closedWorld)) { 1158 _helpers.jsInterceptorClass, _closedWorld)
1159 .isDisjoint(input.instructionType, _closedWorld)) {
1142 var inputs = <HInstruction>[input, input]; // [interceptor, receiver]. 1160 var inputs = <HInstruction>[input, input]; // [interceptor, receiver].
1143 HInstruction result = new HInvokeDynamicMethod( 1161 HInstruction result = new HInvokeDynamicMethod(
1144 selector, 1162 selector,
1145 input.instructionType, // receiver mask. 1163 input.instructionType, // receiver mask.
1146 inputs, 1164 inputs,
1147 toStringType)..sourceInformation = node.sourceInformation; 1165 toStringType)..sourceInformation = node.sourceInformation;
1148 return result; 1166 return result;
1149 } 1167 }
1150 return null; 1168 return null;
1151 } 1169 }
1152 1170
1153 return tryConstant() ?? tryToString() ?? node; 1171 return tryConstant() ?? tryToString() ?? node;
1154 } 1172 }
1155 1173
1156 HInstruction visitOneShotInterceptor(HOneShotInterceptor node) { 1174 HInstruction visitOneShotInterceptor(HOneShotInterceptor node) {
1157 return handleInterceptedCall(node); 1175 return handleInterceptedCall(node);
1158 } 1176 }
1159 1177
1160 bool needsSubstitutionForTypeVariableAccess(ClassEntity cls) { 1178 bool needsSubstitutionForTypeVariableAccess(ClassEntity cls) {
1161 if (closedWorld.isUsedAsMixin(cls)) return true; 1179 if (_closedWorld.isUsedAsMixin(cls)) return true;
1162 1180
1163 return closedWorld.anyStrictSubclassOf(cls, (ClassEntity subclass) { 1181 return _closedWorld.anyStrictSubclassOf(cls, (ClassEntity subclass) {
1164 return !backend.rtiSubstitutions.isTrivialSubstitution(subclass, cls); 1182 return !_rtiSubstitutions.isTrivialSubstitution(subclass, cls);
1165 }); 1183 });
1166 } 1184 }
1167 1185
1168 HInstruction visitTypeInfoExpression(HTypeInfoExpression node) { 1186 HInstruction visitTypeInfoExpression(HTypeInfoExpression node) {
1169 // Identify the case where the type info expression would be of the form: 1187 // Identify the case where the type info expression would be of the form:
1170 // 1188 //
1171 // [getTypeArgumentByIndex(this, 0), .., getTypeArgumentByIndex(this, k)] 1189 // [getTypeArgumentByIndex(this, 0), .., getTypeArgumentByIndex(this, k)]
1172 // 1190 //
1173 // and k is the number of type arguments of 'this'. We can simply copy the 1191 // and k is the number of type arguments of 'this'. We can simply copy the
1174 // list from 'this'. 1192 // list from 'this'.
(...skipping 28 matching lines...) Expand all
1203 // substitution, even though the general case does, e.g. inlining a 1221 // substitution, even though the general case does, e.g. inlining a
1204 // method on an exact class. 1222 // method on an exact class.
1205 return null; 1223 return null;
1206 } 1224 }
1207 } else { 1225 } else {
1208 return null; 1226 return null;
1209 } 1227 }
1210 } 1228 }
1211 1229
1212 if (source == null) return null; 1230 if (source == null) return null;
1213 return new HTypeInfoReadRaw(source, closedWorld.commonMasks.dynamicType); 1231 return new HTypeInfoReadRaw(source, _closedWorld.commonMasks.dynamicType);
1214 } 1232 }
1215 1233
1216 // TODO(sra): Consider fusing type expression trees with no type variables, 1234 // TODO(sra): Consider fusing type expression trees with no type variables,
1217 // as these could be represented like constants. 1235 // as these could be represented like constants.
1218 1236
1219 return tryCopyInfo() ?? node; 1237 return tryCopyInfo() ?? node;
1220 } 1238 }
1221 1239
1222 HInstruction visitTypeInfoReadVariable(HTypeInfoReadVariable node) { 1240 HInstruction visitTypeInfoReadVariable(HTypeInfoReadVariable node) {
1223 ResolutionTypeVariableType variable = node.variable; 1241 ResolutionTypeVariableType variable = node.variable;
1224 HInstruction object = node.object; 1242 HInstruction object = node.object;
1225 1243
1226 HInstruction finishGroundType(ResolutionInterfaceType groundType) { 1244 HInstruction finishGroundType(ResolutionInterfaceType groundType) {
1227 ResolutionInterfaceType typeAtVariable = 1245 ResolutionInterfaceType typeAtVariable =
1228 groundType.asInstanceOf(variable.element.enclosingClass); 1246 groundType.asInstanceOf(variable.element.enclosingClass);
1229 if (typeAtVariable != null) { 1247 if (typeAtVariable != null) {
1230 int index = variable.element.index; 1248 int index = variable.element.index;
1231 ResolutionDartType typeArgument = typeAtVariable.typeArguments[index]; 1249 ResolutionDartType typeArgument = typeAtVariable.typeArguments[index];
1232 HInstruction replacement = new HTypeInfoExpression( 1250 HInstruction replacement = new HTypeInfoExpression(
1233 TypeInfoExpressionKind.COMPLETE, 1251 TypeInfoExpressionKind.COMPLETE,
1234 typeArgument, 1252 typeArgument,
1235 const <HInstruction>[], 1253 const <HInstruction>[],
1236 closedWorld.commonMasks.dynamicType); 1254 _closedWorld.commonMasks.dynamicType);
1237 return replacement; 1255 return replacement;
1238 } 1256 }
1239 return node; 1257 return node;
1240 } 1258 }
1241 1259
1242 /// Read the type variable from an allocation of type [createdClass], where 1260 /// Read the type variable from an allocation of type [createdClass], where
1243 /// [selectTypeArgumentFromObjectCreation] extracts the type argument from 1261 /// [selectTypeArgumentFromObjectCreation] extracts the type argument from
1244 /// the allocation for factory constructor call. 1262 /// the allocation for factory constructor call.
1245 HInstruction finishSubstituted(ClassElement createdClass, 1263 HInstruction finishSubstituted(ClassElement createdClass,
1246 HInstruction selectTypeArgumentFromObjectCreation(int index)) { 1264 HInstruction selectTypeArgumentFromObjectCreation(int index)) {
1247 HInstruction instructionForTypeVariable(ResolutionTypeVariableType tv) { 1265 HInstruction instructionForTypeVariable(ResolutionTypeVariableType tv) {
1248 return selectTypeArgumentFromObjectCreation( 1266 return selectTypeArgumentFromObjectCreation(
1249 createdClass.thisType.typeArguments.indexOf(tv)); 1267 createdClass.thisType.typeArguments.indexOf(tv));
1250 } 1268 }
1251 1269
1252 ResolutionDartType type = createdClass.thisType 1270 ResolutionDartType type = createdClass.thisType
1253 .asInstanceOf(variable.element.enclosingClass) 1271 .asInstanceOf(variable.element.enclosingClass)
1254 .typeArguments[variable.element.index]; 1272 .typeArguments[variable.element.index];
1255 if (type is ResolutionTypeVariableType) { 1273 if (type is ResolutionTypeVariableType) {
1256 return instructionForTypeVariable(type); 1274 return instructionForTypeVariable(type);
1257 } 1275 }
1258 List<HInstruction> arguments = <HInstruction>[]; 1276 List<HInstruction> arguments = <HInstruction>[];
1259 type.forEachTypeVariable((v) { 1277 type.forEachTypeVariable((v) {
1260 arguments.add(instructionForTypeVariable(v)); 1278 arguments.add(instructionForTypeVariable(v));
1261 }); 1279 });
1262 HInstruction replacement = new HTypeInfoExpression( 1280 HInstruction replacement = new HTypeInfoExpression(
1263 TypeInfoExpressionKind.COMPLETE, 1281 TypeInfoExpressionKind.COMPLETE,
1264 type, 1282 type,
1265 arguments, 1283 arguments,
1266 closedWorld.commonMasks.dynamicType); 1284 _closedWorld.commonMasks.dynamicType);
1267 return replacement; 1285 return replacement;
1268 } 1286 }
1269 1287
1270 // Type variable evaluated in the context of a constant can be replaced with 1288 // Type variable evaluated in the context of a constant can be replaced with
1271 // a ground term type. 1289 // a ground term type.
1272 if (object is HConstant) { 1290 if (object is HConstant) {
1273 ConstantValue value = object.constant; 1291 ConstantValue value = object.constant;
1274 if (value is ConstructedConstantValue) { 1292 if (value is ConstructedConstantValue) {
1275 return finishGroundType(value.type); 1293 return finishGroundType(value.type);
1276 } 1294 }
(...skipping 12 matching lines...) Expand all
1289 // HTypeInfoExpression(t_0, t_1, t_2, ...)]); 1307 // HTypeInfoExpression(t_0, t_1, t_2, ...)]);
1290 // 1308 //
1291 // The `t_i` are the values of the type parameters of ClassElement. 1309 // The `t_i` are the values of the type parameters of ClassElement.
1292 1310
1293 if (object is HCreate) { 1311 if (object is HCreate) {
1294 void registerInstantiations() { 1312 void registerInstantiations() {
1295 // Forwarding the type variable references might cause the HCreate to 1313 // Forwarding the type variable references might cause the HCreate to
1296 // become dead. This breaks the algorithm for generating the per-type 1314 // become dead. This breaks the algorithm for generating the per-type
1297 // runtime type information, so we instantiate them here in case the 1315 // runtime type information, so we instantiate them here in case the
1298 // HCreate becomes dead. 1316 // HCreate becomes dead.
1299 object.instantiatedTypes?.forEach(registry.registerInstantiation); 1317 object.instantiatedTypes?.forEach(_registry.registerInstantiation);
1300 } 1318 }
1301 1319
1302 if (object.hasRtiInput) { 1320 if (object.hasRtiInput) {
1303 HInstruction typeInfo = object.rtiInput; 1321 HInstruction typeInfo = object.rtiInput;
1304 if (typeInfo is HTypeInfoExpression) { 1322 if (typeInfo is HTypeInfoExpression) {
1305 registerInstantiations(); 1323 registerInstantiations();
1306 return finishSubstituted( 1324 return finishSubstituted(
1307 object.element, (int index) => typeInfo.inputs[index]); 1325 object.element, (int index) => typeInfo.inputs[index]);
1308 } 1326 }
1309 } else { 1327 } else {
1310 // Non-generic type (which extends or mixes in a generic type, for 1328 // Non-generic type (which extends or mixes in a generic type, for
1311 // example CodeUnits extends UnmodifiableListBase<int>). Also used for 1329 // example CodeUnits extends UnmodifiableListBase<int>). Also used for
1312 // raw-type when the type parameters are elided. 1330 // raw-type when the type parameters are elided.
1313 registerInstantiations(); 1331 registerInstantiations();
1314 return finishSubstituted( 1332 return finishSubstituted(
1315 object.element, 1333 object.element,
1316 // If there are type arguments, all type arguments are 'dynamic'. 1334 // If there are type arguments, all type arguments are 'dynamic'.
1317 (int i) => graph.addConstantNull(closedWorld)); 1335 (int i) => _graph.addConstantNull(_closedWorld));
1318 } 1336 }
1319 } 1337 }
1320 1338
1321 // TODO(sra): Factory constructors pass type arguments after the value 1339 // TODO(sra): Factory constructors pass type arguments after the value
1322 // arguments. The [selectTypeArgumentFromObjectCreation] argument of 1340 // arguments. The [selectTypeArgumentFromObjectCreation] argument of
1323 // [finishSubstituted] indexes into these type arguments. 1341 // [finishSubstituted] indexes into these type arguments.
1324 1342
1325 return node; 1343 return node;
1326 } 1344 }
1327 } 1345 }
1328 1346
1329 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { 1347 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase {
1330 final Set<HInstruction> boundsChecked; 1348 final Set<HInstruction> boundsChecked;
1331 final bool trustPrimitives; 1349 final bool trustPrimitives;
1332 final JavaScriptBackend backend; 1350 final BackendHelpers _helpers;
1333 final ClosedWorld closedWorld; 1351 final ClosedWorld closedWorld;
1334 final String name = "SsaCheckInserter"; 1352 final String name = "SsaCheckInserter";
1335 HGraph graph; 1353 HGraph graph;
1336 1354
1337 SsaCheckInserter( 1355 SsaCheckInserter(this.trustPrimitives, this._helpers, this.closedWorld,
1338 this.trustPrimitives, this.backend, this.closedWorld, this.boundsChecked); 1356 this.boundsChecked);
1339
1340 BackendHelpers get helpers => backend.helpers;
1341 1357
1342 void visitGraph(HGraph graph) { 1358 void visitGraph(HGraph graph) {
1343 this.graph = graph; 1359 this.graph = graph;
1344 1360
1345 // In --trust-primitives mode we don't add bounds checks. This is better 1361 // In --trust-primitives mode we don't add bounds checks. This is better
1346 // than trying to remove them later as the limit expression would become 1362 // than trying to remove them later as the limit expression would become
1347 // dead and require DCE. 1363 // dead and require DCE.
1348 if (trustPrimitives) return; 1364 if (trustPrimitives) return;
1349 1365
1350 visitDominatorTree(graph); 1366 visitDominatorTree(graph);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1393 1409
1394 void visitIndexAssign(HIndexAssign node) { 1410 void visitIndexAssign(HIndexAssign node) {
1395 if (boundsChecked.contains(node)) return; 1411 if (boundsChecked.contains(node)) return;
1396 HInstruction index = node.index; 1412 HInstruction index = node.index;
1397 index = insertBoundsCheck(node, node.receiver, index); 1413 index = insertBoundsCheck(node, node.receiver, index);
1398 } 1414 }
1399 1415
1400 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { 1416 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
1401 MemberEntity element = node.element; 1417 MemberEntity element = node.element;
1402 if (node.isInterceptedCall) return; 1418 if (node.isInterceptedCall) return;
1403 if (element != helpers.jsArrayRemoveLast) return; 1419 if (element != _helpers.jsArrayRemoveLast) return;
1404 if (boundsChecked.contains(node)) return; 1420 if (boundsChecked.contains(node)) return;
1405 // `0` is the index we want to check, but we want to report `-1`, as if we 1421 // `0` is the index we want to check, but we want to report `-1`, as if we
1406 // executed `a[a.length-1]` 1422 // executed `a[a.length-1]`
1407 HBoundsCheck check = insertBoundsCheck( 1423 HBoundsCheck check = insertBoundsCheck(
1408 node, node.receiver, graph.addConstantInt(0, closedWorld)); 1424 node, node.receiver, graph.addConstantInt(0, closedWorld));
1409 HInstruction minusOne = graph.addConstantInt(-1, closedWorld); 1425 HInstruction minusOne = graph.addConstantInt(-1, closedWorld);
1410 check.inputs.add(minusOne); 1426 check.inputs.add(minusOne);
1411 minusOne.usedBy.add(check); 1427 minusOne.usedBy.add(check);
1412 } 1428 }
1413 } 1429 }
(...skipping 837 matching lines...) Expand 10 before | Expand all | Expand 10 after
2251 } 2267 }
2252 } 2268 }
2253 } 2269 }
2254 2270
2255 /** 2271 /**
2256 * Optimization phase that tries to eliminate memory loads (for 2272 * Optimization phase that tries to eliminate memory loads (for
2257 * example [HFieldGet]), when it knows the value stored in that memory 2273 * example [HFieldGet]), when it knows the value stored in that memory
2258 * location. 2274 * location.
2259 */ 2275 */
2260 class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase { 2276 class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase {
2261 final JavaScriptBackend backend; 2277 final BackendHelpers _helpers;
2262 final Compiler compiler; 2278 final Compiler compiler;
2263 final ClosedWorld closedWorld; 2279 final ClosedWorld closedWorld;
2264 final String name = "SsaLoadElimination"; 2280 final String name = "SsaLoadElimination";
2265 MemorySet memorySet; 2281 MemorySet memorySet;
2266 List<MemorySet> memories; 2282 List<MemorySet> memories;
2267 bool newGvnCandidates = false; 2283 bool newGvnCandidates = false;
2268 2284
2269 SsaLoadElimination(this.backend, this.compiler, this.closedWorld); 2285 SsaLoadElimination(this._helpers, this.compiler, this.closedWorld);
2270 2286
2271 void visitGraph(HGraph graph) { 2287 void visitGraph(HGraph graph) {
2272 memories = new List<MemorySet>(graph.blocks.length); 2288 memories = new List<MemorySet>(graph.blocks.length);
2273 List<HBasicBlock> blocks = graph.blocks; 2289 List<HBasicBlock> blocks = graph.blocks;
2274 for (int i = 0; i < blocks.length; i++) { 2290 for (int i = 0; i < blocks.length; i++) {
2275 HBasicBlock block = blocks[i]; 2291 HBasicBlock block = blocks[i];
2276 visitBasicBlock(block); 2292 visitBasicBlock(block);
2277 if (block.successors.isNotEmpty && block.successors[0].isLoopHeader()) { 2293 if (block.successors.isNotEmpty && block.successors[0].isLoopHeader()) {
2278 // We've reached the ending block of a loop. Iterate over the 2294 // We've reached the ending block of a loop. Iterate over the
2279 // blocks of the loop again to take values that flow from that 2295 // blocks of the loop again to take values that flow from that
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
2328 } 2344 }
2329 2345
2330 void visitFieldGet(HFieldGet instruction) { 2346 void visitFieldGet(HFieldGet instruction) {
2331 if (instruction.isNullCheck) return; 2347 if (instruction.isNullCheck) return;
2332 FieldEntity element = instruction.element; 2348 FieldEntity element = instruction.element;
2333 HInstruction receiver = instruction.getDartReceiver(closedWorld).nonCheck(); 2349 HInstruction receiver = instruction.getDartReceiver(closedWorld).nonCheck();
2334 _visitFieldGet(element, receiver, instruction); 2350 _visitFieldGet(element, receiver, instruction);
2335 } 2351 }
2336 2352
2337 void visitGetLength(HGetLength instruction) { 2353 void visitGetLength(HGetLength instruction) {
2338 _visitFieldGet(backend.helpers.jsIndexableLength, 2354 _visitFieldGet(_helpers.jsIndexableLength, instruction.receiver.nonCheck(),
2339 instruction.receiver.nonCheck(), instruction); 2355 instruction);
2340 } 2356 }
2341 2357
2342 void _visitFieldGet( 2358 void _visitFieldGet(
2343 MemberEntity element, HInstruction receiver, HInstruction instruction) { 2359 MemberEntity element, HInstruction receiver, HInstruction instruction) {
2344 HInstruction existing = memorySet.lookupFieldValue(element, receiver); 2360 HInstruction existing = memorySet.lookupFieldValue(element, receiver);
2345 if (existing != null) { 2361 if (existing != null) {
2346 checkNewGvnCandidates(instruction, existing); 2362 checkNewGvnCandidates(instruction, existing);
2347 instruction.block.rewriteWithBetterUser(instruction, existing); 2363 instruction.block.rewriteWithBetterUser(instruction, existing);
2348 instruction.block.remove(instruction); 2364 instruction.block.remove(instruction);
2349 } else { 2365 } else {
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after
2804 2820
2805 keyedValues.forEach((receiver, values) { 2821 keyedValues.forEach((receiver, values) {
2806 result.keyedValues[receiver] = 2822 result.keyedValues[receiver] =
2807 new Map<HInstruction, HInstruction>.from(values); 2823 new Map<HInstruction, HInstruction>.from(values);
2808 }); 2824 });
2809 2825
2810 result.nonEscapingReceivers.addAll(nonEscapingReceivers); 2826 result.nonEscapingReceivers.addAll(nonEscapingReceivers);
2811 return result; 2827 return result;
2812 } 2828 }
2813 } 2829 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart ('k') | pkg/compiler/lib/src/ssa/types_propagation.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698