OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 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; | |
18 import '../js_backend/js_backend.dart'; | 17 import '../js_backend/js_backend.dart'; |
19 import '../js_backend/interceptor_data.dart' show InterceptorData; | 18 import '../js_backend/interceptor_data.dart' show InterceptorData; |
20 import '../js_backend/native_data.dart' show NativeData; | 19 import '../js_backend/native_data.dart' show NativeData; |
21 import '../native/native.dart' as native; | 20 import '../native/native.dart' as native; |
22 import '../options.dart'; | 21 import '../options.dart'; |
23 import '../tree/dartstring.dart' as ast; | 22 import '../tree/dartstring.dart' as ast; |
24 import '../types/types.dart'; | 23 import '../types/types.dart'; |
25 import '../universe/selector.dart' show Selector; | 24 import '../universe/selector.dart' show Selector; |
26 import '../universe/side_effects.dart' show SideEffects; | 25 import '../universe/side_effects.dart' show SideEffects; |
27 import '../util/util.dart'; | 26 import '../util/util.dart'; |
(...skipping 16 matching lines...) Expand all Loading... |
44 Map<HInstruction, Range> ranges = <HInstruction, Range>{}; | 43 Map<HInstruction, Range> ranges = <HInstruction, Range>{}; |
45 | 44 |
46 SsaOptimizerTask(this._backend) : super(_backend.compiler.measurer); | 45 SsaOptimizerTask(this._backend) : super(_backend.compiler.measurer); |
47 | 46 |
48 String get name => 'SSA optimizer'; | 47 String get name => 'SSA optimizer'; |
49 | 48 |
50 Compiler get _compiler => _backend.compiler; | 49 Compiler get _compiler => _backend.compiler; |
51 | 50 |
52 GlobalTypeInferenceResults get _results => _compiler.globalInference.results; | 51 GlobalTypeInferenceResults get _results => _compiler.globalInference.results; |
53 | 52 |
54 BackendHelpers get _helpers => _backend.helpers; | |
55 | |
56 CompilerOptions get _options => _compiler.options; | 53 CompilerOptions get _options => _compiler.options; |
57 | 54 |
58 RuntimeTypesSubstitutions get _rtiSubstitutions => _backend.rtiSubstitutions; | 55 RuntimeTypesSubstitutions get _rtiSubstitutions => _backend.rtiSubstitutions; |
59 | 56 |
60 InterceptorData get _interceptorData => _backend.interceptorData; | 57 InterceptorData get _interceptorData => _backend.interceptorData; |
61 | 58 |
62 void optimize(CodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) { | 59 void optimize(CodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) { |
63 void runPhase(OptimizationPhase phase) { | 60 void runPhase(OptimizationPhase phase) { |
64 measureSubtask(phase.name, () => phase.visitGraph(graph)); | 61 measureSubtask(phase.name, () => phase.visitGraph(graph)); |
65 _backend.tracer.traceGraph(phase.name, graph); | 62 _backend.tracer.traceGraph(phase.name, graph); |
66 assert(graph.isValid(), 'Graph not valid after ${phase.name}'); | 63 assert(graph.isValid(), 'Graph not valid after ${phase.name}'); |
67 } | 64 } |
68 | 65 |
69 bool trustPrimitives = _options.trustPrimitives; | 66 bool trustPrimitives = _options.trustPrimitives; |
70 CodegenRegistry registry = work.registry; | 67 CodegenRegistry registry = work.registry; |
71 Set<HInstruction> boundsChecked = new Set<HInstruction>(); | 68 Set<HInstruction> boundsChecked = new Set<HInstruction>(); |
72 SsaCodeMotion codeMotion; | 69 SsaCodeMotion codeMotion; |
73 SsaLoadElimination loadElimination; | 70 SsaLoadElimination loadElimination; |
74 measure(() { | 71 measure(() { |
75 List<OptimizationPhase> phases = <OptimizationPhase>[ | 72 List<OptimizationPhase> phases = <OptimizationPhase>[ |
76 // Run trivial instruction simplification first to optimize | 73 // Run trivial instruction simplification first to optimize |
77 // some patterns useful for type conversion. | 74 // some patterns useful for type conversion. |
78 new SsaInstructionSimplifier(_results, _options, _helpers, | 75 new SsaInstructionSimplifier( |
79 _rtiSubstitutions, closedWorld, registry), | 76 _results, _options, _rtiSubstitutions, closedWorld, registry), |
80 new SsaTypeConversionInserter(closedWorld), | 77 new SsaTypeConversionInserter(closedWorld), |
81 new SsaRedundantPhiEliminator(), | 78 new SsaRedundantPhiEliminator(), |
82 new SsaDeadPhiEliminator(), | 79 new SsaDeadPhiEliminator(), |
83 new SsaTypePropagator(_results, _options, _helpers, closedWorld), | 80 new SsaTypePropagator( |
| 81 _results, _options, closedWorld.commonElements, closedWorld), |
84 // After type propagation, more instructions can be | 82 // After type propagation, more instructions can be |
85 // simplified. | 83 // simplified. |
86 new SsaInstructionSimplifier(_results, _options, _helpers, | 84 new SsaInstructionSimplifier( |
87 _rtiSubstitutions, closedWorld, registry), | 85 _results, _options, _rtiSubstitutions, closedWorld, registry), |
88 new SsaCheckInserter( | 86 new SsaCheckInserter(trustPrimitives, closedWorld, boundsChecked), |
89 trustPrimitives, _helpers, closedWorld, boundsChecked), | 87 new SsaInstructionSimplifier( |
90 new SsaInstructionSimplifier(_results, _options, _helpers, | 88 _results, _options, _rtiSubstitutions, closedWorld, registry), |
91 _rtiSubstitutions, closedWorld, registry), | 89 new SsaCheckInserter(trustPrimitives, closedWorld, boundsChecked), |
92 new SsaCheckInserter( | 90 new SsaTypePropagator( |
93 trustPrimitives, _helpers, closedWorld, boundsChecked), | 91 _results, _options, closedWorld.commonElements, closedWorld), |
94 new SsaTypePropagator(_results, _options, _helpers, closedWorld), | |
95 // Run a dead code eliminator before LICM because dead | 92 // Run a dead code eliminator before LICM because dead |
96 // interceptors are often in the way of LICM'able instructions. | 93 // interceptors are often in the way of LICM'able instructions. |
97 new SsaDeadCodeEliminator(closedWorld, this), | 94 new SsaDeadCodeEliminator(closedWorld, this), |
98 new SsaGlobalValueNumberer(), | 95 new SsaGlobalValueNumberer(), |
99 // After GVN, some instructions might need their type to be | 96 // After GVN, some instructions might need their type to be |
100 // updated because they now have different inputs. | 97 // updated because they now have different inputs. |
101 new SsaTypePropagator(_results, _options, _helpers, closedWorld), | 98 new SsaTypePropagator( |
| 99 _results, _options, closedWorld.commonElements, closedWorld), |
102 codeMotion = new SsaCodeMotion(), | 100 codeMotion = new SsaCodeMotion(), |
103 loadElimination = | 101 loadElimination = new SsaLoadElimination(_compiler, closedWorld), |
104 new SsaLoadElimination(_helpers, _compiler, closedWorld), | |
105 new SsaRedundantPhiEliminator(), | 102 new SsaRedundantPhiEliminator(), |
106 new SsaDeadPhiEliminator(), | 103 new SsaDeadPhiEliminator(), |
107 // After GVN and load elimination the same value may be used in code | 104 // After GVN and load elimination the same value may be used in code |
108 // controlled by a test on the value, so redo 'conversion insertion' to | 105 // controlled by a test on the value, so redo 'conversion insertion' to |
109 // learn from the refined type. | 106 // learn from the refined type. |
110 new SsaTypeConversionInserter(closedWorld), | 107 new SsaTypeConversionInserter(closedWorld), |
111 new SsaTypePropagator(_results, _options, _helpers, closedWorld), | 108 new SsaTypePropagator( |
112 new SsaValueRangeAnalyzer(_helpers, closedWorld, this), | 109 _results, _options, closedWorld.commonElements, closedWorld), |
| 110 new SsaValueRangeAnalyzer(closedWorld, this), |
113 // Previous optimizations may have generated new | 111 // Previous optimizations may have generated new |
114 // opportunities for instruction simplification. | 112 // opportunities for instruction simplification. |
115 new SsaInstructionSimplifier(_results, _options, _helpers, | 113 new SsaInstructionSimplifier( |
116 _rtiSubstitutions, closedWorld, registry), | 114 _results, _options, _rtiSubstitutions, closedWorld, registry), |
117 new SsaCheckInserter( | 115 new SsaCheckInserter(trustPrimitives, closedWorld, boundsChecked), |
118 trustPrimitives, _helpers, closedWorld, boundsChecked), | |
119 ]; | 116 ]; |
120 phases.forEach(runPhase); | 117 phases.forEach(runPhase); |
121 | 118 |
122 // Simplifying interceptors is not strictly just an optimization, it is | 119 // Simplifying interceptors is not strictly just an optimization, it is |
123 // required for implementation correctness because the code generator | 120 // required for implementation correctness because the code generator |
124 // assumes it is always performed. | 121 // assumes it is always performed. |
125 runPhase(new SsaSimplifyInterceptors(closedWorld, _helpers, | 122 runPhase(new SsaSimplifyInterceptors( |
126 _interceptorData, work.element.enclosingClass)); | 123 closedWorld, |
| 124 closedWorld.commonElements, |
| 125 _interceptorData, |
| 126 work.element.enclosingClass)); |
127 | 127 |
128 SsaDeadCodeEliminator dce = new SsaDeadCodeEliminator(closedWorld, this); | 128 SsaDeadCodeEliminator dce = new SsaDeadCodeEliminator(closedWorld, this); |
129 runPhase(dce); | 129 runPhase(dce); |
130 if (codeMotion.movedCode || | 130 if (codeMotion.movedCode || |
131 dce.eliminatedSideEffects || | 131 dce.eliminatedSideEffects || |
132 loadElimination.newGvnCandidates) { | 132 loadElimination.newGvnCandidates) { |
133 phases = <OptimizationPhase>[ | 133 phases = <OptimizationPhase>[ |
134 new SsaTypePropagator(_results, _options, _helpers, closedWorld), | 134 new SsaTypePropagator( |
| 135 _results, _options, closedWorld.commonElements, closedWorld), |
135 new SsaGlobalValueNumberer(), | 136 new SsaGlobalValueNumberer(), |
136 new SsaCodeMotion(), | 137 new SsaCodeMotion(), |
137 new SsaValueRangeAnalyzer(_helpers, closedWorld, this), | 138 new SsaValueRangeAnalyzer(closedWorld, this), |
138 new SsaInstructionSimplifier(_results, _options, _helpers, | 139 new SsaInstructionSimplifier( |
139 _rtiSubstitutions, closedWorld, registry), | 140 _results, _options, _rtiSubstitutions, closedWorld, registry), |
140 new SsaCheckInserter( | 141 new SsaCheckInserter(trustPrimitives, closedWorld, boundsChecked), |
141 trustPrimitives, _helpers, closedWorld, boundsChecked), | 142 new SsaSimplifyInterceptors(closedWorld, closedWorld.commonElements, |
142 new SsaSimplifyInterceptors(closedWorld, _helpers, _interceptorData, | 143 _interceptorData, work.element.enclosingClass), |
143 work.element.enclosingClass), | |
144 new SsaDeadCodeEliminator(closedWorld, this), | 144 new SsaDeadCodeEliminator(closedWorld, this), |
145 ]; | 145 ]; |
146 } else { | 146 } else { |
147 phases = <OptimizationPhase>[ | 147 phases = <OptimizationPhase>[ |
148 new SsaTypePropagator(_results, _options, _helpers, closedWorld), | 148 new SsaTypePropagator( |
| 149 _results, _options, closedWorld.commonElements, closedWorld), |
149 // Run the simplifier to remove unneeded type checks inserted by | 150 // Run the simplifier to remove unneeded type checks inserted by |
150 // type propagation. | 151 // type propagation. |
151 new SsaInstructionSimplifier(_results, _options, _helpers, | 152 new SsaInstructionSimplifier( |
152 _rtiSubstitutions, closedWorld, registry), | 153 _results, _options, _rtiSubstitutions, closedWorld, registry), |
153 ]; | 154 ]; |
154 } | 155 } |
155 phases.forEach(runPhase); | 156 phases.forEach(runPhase); |
156 }); | 157 }); |
157 } | 158 } |
158 } | 159 } |
159 | 160 |
160 /// Returns `true` if [mask] represents only types that have a length that | 161 /// Returns `true` if [mask] represents only types that have a length that |
161 /// cannot change. The current implementation is conservative for the purpose | 162 /// cannot change. The current implementation is conservative for the purpose |
162 /// of identifying gvn-able lengths and mis-identifies some unions of fixed | 163 /// of identifying gvn-able lengths and mis-identifies some unions of fixed |
(...skipping 20 matching lines...) Expand all Loading... |
183 class SsaInstructionSimplifier extends HBaseVisitor | 184 class SsaInstructionSimplifier extends HBaseVisitor |
184 implements OptimizationPhase { | 185 implements OptimizationPhase { |
185 // We don't produce constant-folded strings longer than this unless they have | 186 // We don't produce constant-folded strings longer than this unless they have |
186 // a single use. This protects against exponentially large constant folded | 187 // a single use. This protects against exponentially large constant folded |
187 // strings. | 188 // strings. |
188 static const MAX_SHARED_CONSTANT_FOLDED_STRING_LENGTH = 512; | 189 static const MAX_SHARED_CONSTANT_FOLDED_STRING_LENGTH = 512; |
189 | 190 |
190 final String name = "SsaInstructionSimplifier"; | 191 final String name = "SsaInstructionSimplifier"; |
191 final GlobalTypeInferenceResults _globalInferenceResults; | 192 final GlobalTypeInferenceResults _globalInferenceResults; |
192 final CompilerOptions _options; | 193 final CompilerOptions _options; |
193 final BackendHelpers _helpers; | |
194 final RuntimeTypesSubstitutions _rtiSubstitutions; | 194 final RuntimeTypesSubstitutions _rtiSubstitutions; |
195 final ClosedWorld _closedWorld; | 195 final ClosedWorld _closedWorld; |
196 final CodegenRegistry _registry; | 196 final CodegenRegistry _registry; |
197 HGraph _graph; | 197 HGraph _graph; |
198 | 198 |
199 SsaInstructionSimplifier(this._globalInferenceResults, this._options, | 199 SsaInstructionSimplifier(this._globalInferenceResults, this._options, |
200 this._helpers, this._rtiSubstitutions, this._closedWorld, this._registry); | 200 this._rtiSubstitutions, this._closedWorld, this._registry); |
201 | 201 |
202 CommonElements get commonElements => _closedWorld.commonElements; | 202 CommonElements get commonElements => _closedWorld.commonElements; |
203 | 203 |
204 ConstantSystem get constantSystem => _closedWorld.constantSystem; | 204 ConstantSystem get constantSystem => _closedWorld.constantSystem; |
205 | 205 |
206 NativeData get _nativeData => _closedWorld.nativeData; | 206 NativeData get _nativeData => _closedWorld.nativeData; |
207 | 207 |
208 void visitGraph(HGraph visitee) { | 208 void visitGraph(HGraph visitee) { |
209 _graph = visitee; | 209 _graph = visitee; |
210 visitDominatorTree(visitee); | 210 visitDominatorTree(visitee); |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
314 if (input.isBoolean(_closedWorld)) return input; | 314 if (input.isBoolean(_closedWorld)) return input; |
315 | 315 |
316 // 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 |
317 // 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 |
318 // unreachable HBoolify makes it easier to reconstruct the short-circuit | 318 // unreachable HBoolify makes it easier to reconstruct the short-circuit |
319 // operation. | 319 // operation. |
320 if (input.instructionType.isEmpty) return input; | 320 if (input.instructionType.isEmpty) return input; |
321 | 321 |
322 // All values that cannot be 'true' are boolified to false. | 322 // All values that cannot be 'true' are boolified to false. |
323 TypeMask mask = input.instructionType; | 323 TypeMask mask = input.instructionType; |
324 if (!mask.contains(_helpers.jsBoolClass, _closedWorld)) { | 324 if (!mask.contains(commonElements.jsBoolClass, _closedWorld)) { |
325 return _graph.addConstantBool(false, _closedWorld); | 325 return _graph.addConstantBool(false, _closedWorld); |
326 } | 326 } |
327 return node; | 327 return node; |
328 } | 328 } |
329 | 329 |
330 HInstruction visitNot(HNot node) { | 330 HInstruction visitNot(HNot node) { |
331 List<HInstruction> inputs = node.inputs; | 331 List<HInstruction> inputs = node.inputs; |
332 assert(inputs.length == 1); | 332 assert(inputs.length == 1); |
333 HInstruction input = inputs[0]; | 333 HInstruction input = inputs[0]; |
334 if (input is HConstant) { | 334 if (input is HConstant) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 HConstant constantInput = actualReceiver; | 367 HConstant constantInput = actualReceiver; |
368 ListConstantValue constant = constantInput.constant; | 368 ListConstantValue constant = constantInput.constant; |
369 return _graph.addConstantInt(constant.length, _closedWorld); | 369 return _graph.addConstantInt(constant.length, _closedWorld); |
370 } | 370 } |
371 bool isFixed = | 371 bool isFixed = |
372 isFixedLength(actualReceiver.instructionType, _closedWorld); | 372 isFixedLength(actualReceiver.instructionType, _closedWorld); |
373 TypeMask actualType = node.instructionType; | 373 TypeMask actualType = node.instructionType; |
374 TypeMask resultType = _closedWorld.commonMasks.positiveIntType; | 374 TypeMask resultType = _closedWorld.commonMasks.positiveIntType; |
375 // 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. |
376 if (HInstruction.isInstanceOf( | 376 if (HInstruction.isInstanceOf( |
377 actualType, _helpers.jsUInt31Class, _closedWorld)) { | 377 actualType, commonElements.jsUInt31Class, _closedWorld)) { |
378 resultType = _closedWorld.commonMasks.uint31Type; | 378 resultType = _closedWorld.commonMasks.uint31Type; |
379 } else if (HInstruction.isInstanceOf( | 379 } else if (HInstruction.isInstanceOf( |
380 actualType, _helpers.jsUInt32Class, _closedWorld)) { | 380 actualType, commonElements.jsUInt32Class, _closedWorld)) { |
381 resultType = _closedWorld.commonMasks.uint32Type; | 381 resultType = _closedWorld.commonMasks.uint32Type; |
382 } | 382 } |
383 HGetLength result = | 383 HGetLength result = |
384 new HGetLength(actualReceiver, resultType, isAssignable: !isFixed); | 384 new HGetLength(actualReceiver, resultType, isAssignable: !isFixed); |
385 return result; | 385 return result; |
386 } else if (actualReceiver.isConstantMap()) { | 386 } else if (actualReceiver.isConstantMap()) { |
387 HConstant constantInput = actualReceiver; | 387 HConstant constantInput = actualReceiver; |
388 MapConstantValue constant = constantInput.constant; | 388 MapConstantValue constant = constantInput.constant; |
389 return _graph.addConstantInt(constant.length, _closedWorld); | 389 return _graph.addConstantInt(constant.length, _closedWorld); |
390 } | 390 } |
391 return null; | 391 return null; |
392 } | 392 } |
393 | 393 |
394 HInstruction handleInterceptedCall(HInvokeDynamic node) { | 394 HInstruction handleInterceptedCall(HInvokeDynamic node) { |
395 // Try constant folding the instruction. | 395 // Try constant folding the instruction. |
396 Operation operation = node.specializer.operation(constantSystem); | 396 Operation operation = node.specializer.operation(constantSystem); |
397 if (operation != null) { | 397 if (operation != null) { |
398 HInstruction instruction = node.inputs.length == 2 | 398 HInstruction instruction = node.inputs.length == 2 |
399 ? foldUnary(operation, node.inputs[1]) | 399 ? foldUnary(operation, node.inputs[1]) |
400 : foldBinary(operation, node.inputs[1], node.inputs[2]); | 400 : foldBinary(operation, node.inputs[1], node.inputs[2]); |
401 if (instruction != null) return instruction; | 401 if (instruction != null) return instruction; |
402 } | 402 } |
403 | 403 |
404 // Try converting the instruction to a builtin instruction. | 404 // Try converting the instruction to a builtin instruction. |
405 HInstruction instruction = node.specializer.tryConvertToBuiltin(node, | 405 HInstruction instruction = node.specializer.tryConvertToBuiltin( |
406 _graph, _globalInferenceResults, _options, _helpers, _closedWorld); | 406 node, |
| 407 _graph, |
| 408 _globalInferenceResults, |
| 409 _options, |
| 410 commonElements, |
| 411 _closedWorld); |
407 if (instruction != null) return instruction; | 412 if (instruction != null) return instruction; |
408 | 413 |
409 Selector selector = node.selector; | 414 Selector selector = node.selector; |
410 TypeMask mask = node.mask; | 415 TypeMask mask = node.mask; |
411 HInstruction input = node.inputs[1]; | 416 HInstruction input = node.inputs[1]; |
412 | 417 |
413 bool applies(MemberEntity element) { | 418 bool applies(MemberEntity element) { |
414 return selector.applies(element) && | 419 return selector.applies(element) && |
415 (mask == null || mask.canHit(element, selector, _closedWorld)); | 420 (mask == null || mask.canHit(element, selector, _closedWorld)); |
416 } | 421 } |
417 | 422 |
418 if (selector.isCall || selector.isOperator) { | 423 if (selector.isCall || selector.isOperator) { |
419 FunctionEntity target; | 424 FunctionEntity target; |
420 if (input.isExtendableArray(_closedWorld)) { | 425 if (input.isExtendableArray(_closedWorld)) { |
421 if (applies(_helpers.jsArrayRemoveLast)) { | 426 if (applies(commonElements.jsArrayRemoveLast)) { |
422 target = _helpers.jsArrayRemoveLast; | 427 target = commonElements.jsArrayRemoveLast; |
423 } else if (applies(_helpers.jsArrayAdd)) { | 428 } else if (applies(commonElements.jsArrayAdd)) { |
424 // The codegen special cases array calls, but does not | 429 // The codegen special cases array calls, but does not |
425 // inline argument type checks. | 430 // inline argument type checks. |
426 if (!_options.enableTypeAssertions) { | 431 if (!_options.enableTypeAssertions) { |
427 target = _helpers.jsArrayAdd; | 432 target = commonElements.jsArrayAdd; |
428 } | 433 } |
429 } | 434 } |
430 } else if (input.isStringOrNull(_closedWorld)) { | 435 } else if (input.isStringOrNull(_closedWorld)) { |
431 if (applies(_helpers.jsStringSplit)) { | 436 if (applies(commonElements.jsStringSplit)) { |
432 HInstruction argument = node.inputs[2]; | 437 HInstruction argument = node.inputs[2]; |
433 if (argument.isString(_closedWorld)) { | 438 if (argument.isString(_closedWorld)) { |
434 target = _helpers.jsStringSplit; | 439 target = commonElements.jsStringSplit; |
435 } | 440 } |
436 } else if (applies(_helpers.jsStringOperatorAdd)) { | 441 } else if (applies(commonElements.jsStringOperatorAdd)) { |
437 // `operator+` is turned into a JavaScript '+' so we need to | 442 // `operator+` is turned into a JavaScript '+' so we need to |
438 // make sure the receiver and the argument are not null. | 443 // make sure the receiver and the argument are not null. |
439 // TODO(sra): Do this via [node.specializer]. | 444 // TODO(sra): Do this via [node.specializer]. |
440 HInstruction argument = node.inputs[2]; | 445 HInstruction argument = node.inputs[2]; |
441 if (argument.isString(_closedWorld) && !input.canBeNull()) { | 446 if (argument.isString(_closedWorld) && !input.canBeNull()) { |
442 return new HStringConcat(input, argument, node.instructionType); | 447 return new HStringConcat(input, argument, node.instructionType); |
443 } | 448 } |
444 } else if (applies(_helpers.jsStringToString) && !input.canBeNull()) { | 449 } else if (applies(commonElements.jsStringToString) && |
| 450 !input.canBeNull()) { |
445 return input; | 451 return input; |
446 } | 452 } |
447 } | 453 } |
448 if (target != null) { | 454 if (target != null) { |
449 // TODO(ngeoffray): There is a strong dependency between codegen | 455 // TODO(ngeoffray): There is a strong dependency between codegen |
450 // and this optimization that the dynamic invoke does not need an | 456 // and this optimization that the dynamic invoke does not need an |
451 // interceptor. We currently need to keep a | 457 // interceptor. We currently need to keep a |
452 // HInvokeDynamicMethod and not create a HForeign because | 458 // HInvokeDynamicMethod and not create a HForeign because |
453 // HForeign is too opaque for the SsaCheckInserter (that adds a | 459 // HForeign is too opaque for the SsaCheckInserter (that adds a |
454 // bounds check on removeLast). Once we start inlining, the | 460 // bounds check on removeLast). Once we start inlining, the |
455 // bounds check will become explicit, so we won't need this | 461 // bounds check will become explicit, so we won't need this |
456 // optimization. | 462 // optimization. |
457 HInvokeDynamicMethod result = new HInvokeDynamicMethod(node.selector, | 463 HInvokeDynamicMethod result = new HInvokeDynamicMethod(node.selector, |
458 node.mask, node.inputs.sublist(1), node.instructionType); | 464 node.mask, node.inputs.sublist(1), node.instructionType); |
459 result.element = target; | 465 result.element = target; |
460 return result; | 466 return result; |
461 } | 467 } |
462 } else if (selector.isGetter) { | 468 } else if (selector.isGetter) { |
463 if (selector.applies(_helpers.jsIndexableLength)) { | 469 if (selector.applies(commonElements.jsIndexableLength)) { |
464 HInstruction optimized = tryOptimizeLengthInterceptedGetter(node); | 470 HInstruction optimized = tryOptimizeLengthInterceptedGetter(node); |
465 if (optimized != null) return optimized; | 471 if (optimized != null) return optimized; |
466 } | 472 } |
467 } | 473 } |
468 | 474 |
469 return node; | 475 return node; |
470 } | 476 } |
471 | 477 |
472 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 478 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
473 propagateConstantValueToUses(node); | 479 propagateConstantValueToUses(node); |
(...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1061 HInstruction visitInvokeStatic(HInvokeStatic node) { | 1067 HInstruction visitInvokeStatic(HInvokeStatic node) { |
1062 propagateConstantValueToUses(node); | 1068 propagateConstantValueToUses(node); |
1063 MemberEntity element = node.element; | 1069 MemberEntity element = node.element; |
1064 | 1070 |
1065 if (element == commonElements.identicalFunction) { | 1071 if (element == commonElements.identicalFunction) { |
1066 if (node.inputs.length == 2) { | 1072 if (node.inputs.length == 2) { |
1067 return new HIdentity(node.inputs[0], node.inputs[1], null, | 1073 return new HIdentity(node.inputs[0], node.inputs[1], null, |
1068 _closedWorld.commonMasks.boolType) | 1074 _closedWorld.commonMasks.boolType) |
1069 ..sourceInformation = node.sourceInformation; | 1075 ..sourceInformation = node.sourceInformation; |
1070 } | 1076 } |
1071 } else if (element == _helpers.checkConcurrentModificationError) { | 1077 } else if (element == commonElements.checkConcurrentModificationError) { |
1072 if (node.inputs.length == 2) { | 1078 if (node.inputs.length == 2) { |
1073 HInstruction firstArgument = node.inputs[0]; | 1079 HInstruction firstArgument = node.inputs[0]; |
1074 if (firstArgument is HConstant) { | 1080 if (firstArgument is HConstant) { |
1075 HConstant constant = firstArgument; | 1081 HConstant constant = firstArgument; |
1076 if (constant.constant.isTrue) return constant; | 1082 if (constant.constant.isTrue) return constant; |
1077 } | 1083 } |
1078 } | 1084 } |
1079 } else if (element == _helpers.checkInt) { | 1085 } else if (element == commonElements.checkInt) { |
1080 if (node.inputs.length == 1) { | 1086 if (node.inputs.length == 1) { |
1081 HInstruction argument = node.inputs[0]; | 1087 HInstruction argument = node.inputs[0]; |
1082 if (argument.isInteger(_closedWorld)) return argument; | 1088 if (argument.isInteger(_closedWorld)) return argument; |
1083 } | 1089 } |
1084 } else if (element == _helpers.checkNum) { | 1090 } else if (element == commonElements.checkNum) { |
1085 if (node.inputs.length == 1) { | 1091 if (node.inputs.length == 1) { |
1086 HInstruction argument = node.inputs[0]; | 1092 HInstruction argument = node.inputs[0]; |
1087 if (argument.isNumber(_closedWorld)) return argument; | 1093 if (argument.isNumber(_closedWorld)) return argument; |
1088 } | 1094 } |
1089 } else if (element == _helpers.checkString) { | 1095 } else if (element == commonElements.checkString) { |
1090 if (node.inputs.length == 1) { | 1096 if (node.inputs.length == 1) { |
1091 HInstruction argument = node.inputs[0]; | 1097 HInstruction argument = node.inputs[0]; |
1092 if (argument.isString(_closedWorld)) return argument; | 1098 if (argument.isString(_closedWorld)) return argument; |
1093 } | 1099 } |
1094 } | 1100 } |
1095 return node; | 1101 return node; |
1096 } | 1102 } |
1097 | 1103 |
1098 HInstruction visitStringConcat(HStringConcat node) { | 1104 HInstruction visitStringConcat(HStringConcat node) { |
1099 // Simplify string concat: | 1105 // Simplify string concat: |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1171 // (since SsaInstructionSimplifier runs after SsaSimplifyInterceptors). | 1177 // (since SsaInstructionSimplifier runs after SsaSimplifyInterceptors). |
1172 if (input.canBePrimitive(_closedWorld)) return null; | 1178 if (input.canBePrimitive(_closedWorld)) return null; |
1173 if (input.canBeNull()) return null; | 1179 if (input.canBeNull()) return null; |
1174 Selector selector = Selectors.toString_; | 1180 Selector selector = Selectors.toString_; |
1175 TypeMask toStringType = TypeMaskFactory.inferredTypeForSelector( | 1181 TypeMask toStringType = TypeMaskFactory.inferredTypeForSelector( |
1176 selector, input.instructionType, _globalInferenceResults); | 1182 selector, input.instructionType, _globalInferenceResults); |
1177 if (!toStringType.containsOnlyString(_closedWorld)) return null; | 1183 if (!toStringType.containsOnlyString(_closedWorld)) return null; |
1178 // All intercepted classes extend `Interceptor`, so if the receiver can't | 1184 // All intercepted classes extend `Interceptor`, so if the receiver can't |
1179 // be a class extending `Interceptor` then it can be called directly. | 1185 // be a class extending `Interceptor` then it can be called directly. |
1180 if (new TypeMask.nonNullSubclass( | 1186 if (new TypeMask.nonNullSubclass( |
1181 _helpers.jsInterceptorClass, _closedWorld) | 1187 commonElements.jsInterceptorClass, _closedWorld) |
1182 .isDisjoint(input.instructionType, _closedWorld)) { | 1188 .isDisjoint(input.instructionType, _closedWorld)) { |
1183 var inputs = <HInstruction>[input, input]; // [interceptor, receiver]. | 1189 var inputs = <HInstruction>[input, input]; // [interceptor, receiver]. |
1184 HInstruction result = new HInvokeDynamicMethod( | 1190 HInstruction result = new HInvokeDynamicMethod( |
1185 selector, | 1191 selector, |
1186 input.instructionType, // receiver mask. | 1192 input.instructionType, // receiver mask. |
1187 inputs, | 1193 inputs, |
1188 toStringType) | 1194 toStringType) |
1189 ..sourceInformation = node.sourceInformation; | 1195 ..sourceInformation = node.sourceInformation; |
1190 return result; | 1196 return result; |
1191 } | 1197 } |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1364 // arguments. The [selectTypeArgumentFromObjectCreation] argument of | 1370 // arguments. The [selectTypeArgumentFromObjectCreation] argument of |
1365 // [finishSubstituted] indexes into these type arguments. | 1371 // [finishSubstituted] indexes into these type arguments. |
1366 | 1372 |
1367 return node; | 1373 return node; |
1368 } | 1374 } |
1369 } | 1375 } |
1370 | 1376 |
1371 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { | 1377 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { |
1372 final Set<HInstruction> boundsChecked; | 1378 final Set<HInstruction> boundsChecked; |
1373 final bool trustPrimitives; | 1379 final bool trustPrimitives; |
1374 final BackendHelpers _helpers; | |
1375 final ClosedWorld closedWorld; | 1380 final ClosedWorld closedWorld; |
1376 final String name = "SsaCheckInserter"; | 1381 final String name = "SsaCheckInserter"; |
1377 HGraph graph; | 1382 HGraph graph; |
1378 | 1383 |
1379 SsaCheckInserter(this.trustPrimitives, this._helpers, this.closedWorld, | 1384 SsaCheckInserter(this.trustPrimitives, this.closedWorld, this.boundsChecked); |
1380 this.boundsChecked); | |
1381 | 1385 |
1382 void visitGraph(HGraph graph) { | 1386 void visitGraph(HGraph graph) { |
1383 this.graph = graph; | 1387 this.graph = graph; |
1384 | 1388 |
1385 // In --trust-primitives mode we don't add bounds checks. This is better | 1389 // In --trust-primitives mode we don't add bounds checks. This is better |
1386 // than trying to remove them later as the limit expression would become | 1390 // than trying to remove them later as the limit expression would become |
1387 // dead and require DCE. | 1391 // dead and require DCE. |
1388 if (trustPrimitives) return; | 1392 if (trustPrimitives) return; |
1389 | 1393 |
1390 visitDominatorTree(graph); | 1394 visitDominatorTree(graph); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1433 | 1437 |
1434 void visitIndexAssign(HIndexAssign node) { | 1438 void visitIndexAssign(HIndexAssign node) { |
1435 if (boundsChecked.contains(node)) return; | 1439 if (boundsChecked.contains(node)) return; |
1436 HInstruction index = node.index; | 1440 HInstruction index = node.index; |
1437 index = insertBoundsCheck(node, node.receiver, index); | 1441 index = insertBoundsCheck(node, node.receiver, index); |
1438 } | 1442 } |
1439 | 1443 |
1440 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 1444 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
1441 MemberEntity element = node.element; | 1445 MemberEntity element = node.element; |
1442 if (node.isInterceptedCall) return; | 1446 if (node.isInterceptedCall) return; |
1443 if (element != _helpers.jsArrayRemoveLast) return; | 1447 if (element != closedWorld.commonElements.jsArrayRemoveLast) return; |
1444 if (boundsChecked.contains(node)) return; | 1448 if (boundsChecked.contains(node)) return; |
1445 // `0` is the index we want to check, but we want to report `-1`, as if we | 1449 // `0` is the index we want to check, but we want to report `-1`, as if we |
1446 // executed `a[a.length-1]` | 1450 // executed `a[a.length-1]` |
1447 HBoundsCheck check = insertBoundsCheck( | 1451 HBoundsCheck check = insertBoundsCheck( |
1448 node, node.receiver, graph.addConstantInt(0, closedWorld)); | 1452 node, node.receiver, graph.addConstantInt(0, closedWorld)); |
1449 HInstruction minusOne = graph.addConstantInt(-1, closedWorld); | 1453 HInstruction minusOne = graph.addConstantInt(-1, closedWorld); |
1450 check.inputs.add(minusOne); | 1454 check.inputs.add(minusOne); |
1451 minusOne.usedBy.add(check); | 1455 minusOne.usedBy.add(check); |
1452 } | 1456 } |
1453 } | 1457 } |
(...skipping 839 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2293 } | 2297 } |
2294 } | 2298 } |
2295 } | 2299 } |
2296 | 2300 |
2297 /** | 2301 /** |
2298 * Optimization phase that tries to eliminate memory loads (for | 2302 * Optimization phase that tries to eliminate memory loads (for |
2299 * example [HFieldGet]), when it knows the value stored in that memory | 2303 * example [HFieldGet]), when it knows the value stored in that memory |
2300 * location. | 2304 * location. |
2301 */ | 2305 */ |
2302 class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase { | 2306 class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase { |
2303 final BackendHelpers _helpers; | |
2304 final Compiler compiler; | 2307 final Compiler compiler; |
2305 final ClosedWorld closedWorld; | 2308 final ClosedWorld closedWorld; |
2306 final String name = "SsaLoadElimination"; | 2309 final String name = "SsaLoadElimination"; |
2307 MemorySet memorySet; | 2310 MemorySet memorySet; |
2308 List<MemorySet> memories; | 2311 List<MemorySet> memories; |
2309 bool newGvnCandidates = false; | 2312 bool newGvnCandidates = false; |
2310 | 2313 |
2311 SsaLoadElimination(this._helpers, this.compiler, this.closedWorld); | 2314 SsaLoadElimination(this.compiler, this.closedWorld); |
2312 | 2315 |
2313 void visitGraph(HGraph graph) { | 2316 void visitGraph(HGraph graph) { |
2314 memories = new List<MemorySet>(graph.blocks.length); | 2317 memories = new List<MemorySet>(graph.blocks.length); |
2315 List<HBasicBlock> blocks = graph.blocks; | 2318 List<HBasicBlock> blocks = graph.blocks; |
2316 for (int i = 0; i < blocks.length; i++) { | 2319 for (int i = 0; i < blocks.length; i++) { |
2317 HBasicBlock block = blocks[i]; | 2320 HBasicBlock block = blocks[i]; |
2318 visitBasicBlock(block); | 2321 visitBasicBlock(block); |
2319 if (block.successors.isNotEmpty && block.successors[0].isLoopHeader()) { | 2322 if (block.successors.isNotEmpty && block.successors[0].isLoopHeader()) { |
2320 // We've reached the ending block of a loop. Iterate over the | 2323 // We've reached the ending block of a loop. Iterate over the |
2321 // blocks of the loop again to take values that flow from that | 2324 // blocks of the loop again to take values that flow from that |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2370 } | 2373 } |
2371 | 2374 |
2372 void visitFieldGet(HFieldGet instruction) { | 2375 void visitFieldGet(HFieldGet instruction) { |
2373 if (instruction.isNullCheck) return; | 2376 if (instruction.isNullCheck) return; |
2374 FieldEntity element = instruction.element; | 2377 FieldEntity element = instruction.element; |
2375 HInstruction receiver = instruction.getDartReceiver(closedWorld).nonCheck(); | 2378 HInstruction receiver = instruction.getDartReceiver(closedWorld).nonCheck(); |
2376 _visitFieldGet(element, receiver, instruction); | 2379 _visitFieldGet(element, receiver, instruction); |
2377 } | 2380 } |
2378 | 2381 |
2379 void visitGetLength(HGetLength instruction) { | 2382 void visitGetLength(HGetLength instruction) { |
2380 _visitFieldGet(_helpers.jsIndexableLength, instruction.receiver.nonCheck(), | 2383 _visitFieldGet(closedWorld.commonElements.jsIndexableLength, |
2381 instruction); | 2384 instruction.receiver.nonCheck(), instruction); |
2382 } | 2385 } |
2383 | 2386 |
2384 void _visitFieldGet( | 2387 void _visitFieldGet( |
2385 MemberEntity element, HInstruction receiver, HInstruction instruction) { | 2388 MemberEntity element, HInstruction receiver, HInstruction instruction) { |
2386 HInstruction existing = memorySet.lookupFieldValue(element, receiver); | 2389 HInstruction existing = memorySet.lookupFieldValue(element, receiver); |
2387 if (existing != null) { | 2390 if (existing != null) { |
2388 checkNewGvnCandidates(instruction, existing); | 2391 checkNewGvnCandidates(instruction, existing); |
2389 instruction.block.rewriteWithBetterUser(instruction, existing); | 2392 instruction.block.rewriteWithBetterUser(instruction, existing); |
2390 instruction.block.remove(instruction); | 2393 instruction.block.remove(instruction); |
2391 } else { | 2394 } else { |
(...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2858 | 2861 |
2859 keyedValues.forEach((receiver, values) { | 2862 keyedValues.forEach((receiver, values) { |
2860 result.keyedValues[receiver] = | 2863 result.keyedValues[receiver] = |
2861 new Map<HInstruction, HInstruction>.from(values); | 2864 new Map<HInstruction, HInstruction>.from(values); |
2862 }); | 2865 }); |
2863 | 2866 |
2864 result.nonEscapingReceivers.addAll(nonEscapingReceivers); | 2867 result.nonEscapingReceivers.addAll(nonEscapingReceivers); |
2865 return result; | 2868 return result; |
2866 } | 2869 } |
2867 } | 2870 } |
OLD | NEW |