| 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 '../core_types.dart' show CommonElements, CoreClasses; | 11 import '../core_types.dart' show CommonElements; |
| 12 import '../dart_types.dart'; | 12 import '../dart_types.dart'; |
| 13 import '../elements/elements.dart'; | 13 import '../elements/elements.dart'; |
| 14 import '../js/js.dart' as js; | 14 import '../js/js.dart' as js; |
| 15 import '../js_backend/backend_helpers.dart' show BackendHelpers; | 15 import '../js_backend/backend_helpers.dart' show BackendHelpers; |
| 16 import '../js_backend/js_backend.dart'; | 16 import '../js_backend/js_backend.dart'; |
| 17 import '../native/native.dart' as native; | 17 import '../native/native.dart' as native; |
| 18 import '../tree/dartstring.dart' as ast; | 18 import '../tree/dartstring.dart' as ast; |
| 19 import '../types/types.dart'; | 19 import '../types/types.dart'; |
| 20 import '../universe/selector.dart' show Selector; | 20 import '../universe/selector.dart' show Selector; |
| 21 import '../universe/side_effects.dart' show SideEffects; | 21 import '../universe/side_effects.dart' show SideEffects; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 46 | 46 |
| 47 Compiler get compiler => backend.compiler; | 47 Compiler get compiler => backend.compiler; |
| 48 | 48 |
| 49 void optimize(CodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) { | 49 void optimize(CodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) { |
| 50 void runPhase(OptimizationPhase phase) { | 50 void runPhase(OptimizationPhase phase) { |
| 51 measureSubtask(phase.name, () => phase.visitGraph(graph)); | 51 measureSubtask(phase.name, () => phase.visitGraph(graph)); |
| 52 backend.tracer.traceGraph(phase.name, graph); | 52 backend.tracer.traceGraph(phase.name, graph); |
| 53 assert(graph.isValid()); | 53 assert(graph.isValid()); |
| 54 } | 54 } |
| 55 | 55 |
| 56 ConstantSystem constantSystem = compiler.backend.constantSystem; | |
| 57 bool trustPrimitives = compiler.options.trustPrimitives; | 56 bool trustPrimitives = compiler.options.trustPrimitives; |
| 58 CodegenRegistry registry = work.registry; | 57 CodegenRegistry registry = work.registry; |
| 59 Set<HInstruction> boundsChecked = new Set<HInstruction>(); | 58 Set<HInstruction> boundsChecked = new Set<HInstruction>(); |
| 60 SsaCodeMotion codeMotion; | 59 SsaCodeMotion codeMotion; |
| 61 measure(() { | 60 measure(() { |
| 62 List<OptimizationPhase> phases = <OptimizationPhase>[ | 61 List<OptimizationPhase> phases = <OptimizationPhase>[ |
| 63 // Run trivial instruction simplification first to optimize | 62 // Run trivial instruction simplification first to optimize |
| 64 // some patterns useful for type conversion. | 63 // some patterns useful for type conversion. |
| 65 new SsaInstructionSimplifier( | 64 new SsaInstructionSimplifier(backend, closedWorld, this, registry), |
| 66 constantSystem, backend, closedWorld, this, registry), | |
| 67 new SsaTypeConversionInserter(closedWorld), | 65 new SsaTypeConversionInserter(closedWorld), |
| 68 new SsaRedundantPhiEliminator(), | 66 new SsaRedundantPhiEliminator(), |
| 69 new SsaDeadPhiEliminator(), | 67 new SsaDeadPhiEliminator(), |
| 70 new SsaTypePropagator(compiler, closedWorld), | 68 new SsaTypePropagator(compiler, closedWorld), |
| 71 // After type propagation, more instructions can be | 69 // After type propagation, more instructions can be |
| 72 // simplified. | 70 // simplified. |
| 73 new SsaInstructionSimplifier( | 71 new SsaInstructionSimplifier(backend, closedWorld, this, registry), |
| 74 constantSystem, backend, closedWorld, this, registry), | |
| 75 new SsaCheckInserter( | 72 new SsaCheckInserter( |
| 76 trustPrimitives, backend, closedWorld, boundsChecked), | 73 trustPrimitives, backend, closedWorld, boundsChecked), |
| 77 new SsaInstructionSimplifier( | 74 new SsaInstructionSimplifier(backend, closedWorld, this, registry), |
| 78 constantSystem, backend, closedWorld, this, registry), | |
| 79 new SsaCheckInserter( | 75 new SsaCheckInserter( |
| 80 trustPrimitives, backend, closedWorld, boundsChecked), | 76 trustPrimitives, backend, closedWorld, boundsChecked), |
| 81 new SsaTypePropagator(compiler, closedWorld), | 77 new SsaTypePropagator(compiler, closedWorld), |
| 82 // Run a dead code eliminator before LICM because dead | 78 // Run a dead code eliminator before LICM because dead |
| 83 // interceptors are often in the way of LICM'able instructions. | 79 // interceptors are often in the way of LICM'able instructions. |
| 84 new SsaDeadCodeEliminator(compiler, closedWorld, this), | 80 new SsaDeadCodeEliminator(closedWorld, this), |
| 85 new SsaGlobalValueNumberer(compiler), | 81 new SsaGlobalValueNumberer(), |
| 86 // After GVN, some instructions might need their type to be | 82 // After GVN, some instructions might need their type to be |
| 87 // updated because they now have different inputs. | 83 // updated because they now have different inputs. |
| 88 new SsaTypePropagator(compiler, closedWorld), | 84 new SsaTypePropagator(compiler, closedWorld), |
| 89 codeMotion = new SsaCodeMotion(), | 85 codeMotion = new SsaCodeMotion(), |
| 90 new SsaLoadElimination(compiler, closedWorld), | 86 new SsaLoadElimination(compiler, closedWorld), |
| 91 new SsaRedundantPhiEliminator(), | 87 new SsaRedundantPhiEliminator(), |
| 92 new SsaDeadPhiEliminator(), | 88 new SsaDeadPhiEliminator(), |
| 93 new SsaTypePropagator(compiler, closedWorld), | 89 new SsaTypePropagator(compiler, closedWorld), |
| 94 new SsaValueRangeAnalyzer(compiler, closedWorld, constantSystem, this), | 90 new SsaValueRangeAnalyzer(backend.helpers, closedWorld, this), |
| 95 // Previous optimizations may have generated new | 91 // Previous optimizations may have generated new |
| 96 // opportunities for instruction simplification. | 92 // opportunities for instruction simplification. |
| 97 new SsaInstructionSimplifier( | 93 new SsaInstructionSimplifier(backend, closedWorld, this, registry), |
| 98 constantSystem, backend, closedWorld, this, registry), | |
| 99 new SsaCheckInserter( | 94 new SsaCheckInserter( |
| 100 trustPrimitives, backend, closedWorld, boundsChecked), | 95 trustPrimitives, backend, closedWorld, boundsChecked), |
| 101 ]; | 96 ]; |
| 102 phases.forEach(runPhase); | 97 phases.forEach(runPhase); |
| 103 | 98 |
| 104 // Simplifying interceptors is not strictly just an optimization, it is | 99 // Simplifying interceptors is not strictly just an optimization, it is |
| 105 // required for implementation correctness because the code generator | 100 // required for implementation correctness because the code generator |
| 106 // assumes it is always performed. | 101 // assumes it is always performed. |
| 107 runPhase(new SsaSimplifyInterceptors( | 102 runPhase( |
| 108 compiler, closedWorld, constantSystem, work.element)); | 103 new SsaSimplifyInterceptors(compiler, closedWorld, work.element)); |
| 109 | 104 |
| 110 SsaDeadCodeEliminator dce = | 105 SsaDeadCodeEliminator dce = new SsaDeadCodeEliminator(closedWorld, this); |
| 111 new SsaDeadCodeEliminator(compiler, closedWorld, this); | |
| 112 runPhase(dce); | 106 runPhase(dce); |
| 113 if (codeMotion.movedCode || dce.eliminatedSideEffects) { | 107 if (codeMotion.movedCode || dce.eliminatedSideEffects) { |
| 114 phases = <OptimizationPhase>[ | 108 phases = <OptimizationPhase>[ |
| 115 new SsaTypePropagator(compiler, closedWorld), | 109 new SsaTypePropagator(compiler, closedWorld), |
| 116 new SsaGlobalValueNumberer(compiler), | 110 new SsaGlobalValueNumberer(), |
| 117 new SsaCodeMotion(), | 111 new SsaCodeMotion(), |
| 118 new SsaValueRangeAnalyzer( | 112 new SsaValueRangeAnalyzer(backend.helpers, closedWorld, this), |
| 119 compiler, closedWorld, constantSystem, this), | 113 new SsaInstructionSimplifier(backend, closedWorld, this, registry), |
| 120 new SsaInstructionSimplifier( | |
| 121 constantSystem, backend, closedWorld, this, registry), | |
| 122 new SsaCheckInserter( | 114 new SsaCheckInserter( |
| 123 trustPrimitives, backend, closedWorld, boundsChecked), | 115 trustPrimitives, backend, closedWorld, boundsChecked), |
| 124 new SsaSimplifyInterceptors( | 116 new SsaSimplifyInterceptors(compiler, closedWorld, work.element), |
| 125 compiler, closedWorld, constantSystem, work.element), | 117 new SsaDeadCodeEliminator(closedWorld, this), |
| 126 new SsaDeadCodeEliminator(compiler, closedWorld, this), | |
| 127 ]; | 118 ]; |
| 128 } else { | 119 } else { |
| 129 phases = <OptimizationPhase>[ | 120 phases = <OptimizationPhase>[ |
| 130 new SsaTypePropagator(compiler, closedWorld), | 121 new SsaTypePropagator(compiler, closedWorld), |
| 131 // Run the simplifier to remove unneeded type checks inserted by | 122 // Run the simplifier to remove unneeded type checks inserted by |
| 132 // type propagation. | 123 // type propagation. |
| 133 new SsaInstructionSimplifier( | 124 new SsaInstructionSimplifier(backend, closedWorld, this, registry), |
| 134 constantSystem, backend, closedWorld, this, registry), | |
| 135 ]; | 125 ]; |
| 136 } | 126 } |
| 137 phases.forEach(runPhase); | 127 phases.forEach(runPhase); |
| 138 }); | 128 }); |
| 139 } | 129 } |
| 140 } | 130 } |
| 141 | 131 |
| 142 /// Returns `true` if [mask] represents only types that have a length that | 132 /// Returns `true` if [mask] represents only types that have a length that |
| 143 /// cannot change. The current implementation is conservative for the purpose | 133 /// cannot change. The current implementation is conservative for the purpose |
| 144 /// of identifying gvn-able lengths and mis-identifies some unions of fixed | 134 /// of identifying gvn-able lengths and mis-identifies some unions of fixed |
| (...skipping 20 matching lines...) Expand all Loading... |
| 165 class SsaInstructionSimplifier extends HBaseVisitor | 155 class SsaInstructionSimplifier extends HBaseVisitor |
| 166 implements OptimizationPhase { | 156 implements OptimizationPhase { |
| 167 // We don't produce constant-folded strings longer than this unless they have | 157 // We don't produce constant-folded strings longer than this unless they have |
| 168 // a single use. This protects against exponentially large constant folded | 158 // a single use. This protects against exponentially large constant folded |
| 169 // strings. | 159 // strings. |
| 170 static const MAX_SHARED_CONSTANT_FOLDED_STRING_LENGTH = 512; | 160 static const MAX_SHARED_CONSTANT_FOLDED_STRING_LENGTH = 512; |
| 171 | 161 |
| 172 final String name = "SsaInstructionSimplifier"; | 162 final String name = "SsaInstructionSimplifier"; |
| 173 final JavaScriptBackend backend; | 163 final JavaScriptBackend backend; |
| 174 final ClosedWorld closedWorld; | 164 final ClosedWorld closedWorld; |
| 175 final ConstantSystem constantSystem; | |
| 176 final CodegenRegistry registry; | 165 final CodegenRegistry registry; |
| 177 HGraph graph; | 166 HGraph graph; |
| 178 Compiler get compiler => backend.compiler; | 167 Compiler get compiler => backend.compiler; |
| 179 final SsaOptimizerTask optimizer; | 168 final SsaOptimizerTask optimizer; |
| 180 | 169 |
| 181 SsaInstructionSimplifier(this.constantSystem, this.backend, this.closedWorld, | 170 SsaInstructionSimplifier( |
| 182 this.optimizer, this.registry); | 171 this.backend, this.closedWorld, this.optimizer, this.registry); |
| 183 | 172 |
| 184 CommonElements get commonElements => closedWorld.commonElements; | 173 CommonElements get commonElements => closedWorld.commonElements; |
| 185 | 174 |
| 186 BackendHelpers get helpers => backend.helpers; | 175 BackendHelpers get helpers => backend.helpers; |
| 187 | 176 |
| 177 ConstantSystem get constantSystem => closedWorld.constantSystem; |
| 178 |
| 188 GlobalTypeInferenceResults get globalInferenceResults => | 179 GlobalTypeInferenceResults get globalInferenceResults => |
| 189 compiler.globalInference.results; | 180 compiler.globalInference.results; |
| 190 | 181 |
| 191 void visitGraph(HGraph visitee) { | 182 void visitGraph(HGraph visitee) { |
| 192 graph = visitee; | 183 graph = visitee; |
| 193 visitDominatorTree(visitee); | 184 visitDominatorTree(visitee); |
| 194 } | 185 } |
| 195 | 186 |
| 196 visitBasicBlock(HBasicBlock block) { | 187 visitBasicBlock(HBasicBlock block) { |
| 197 HInstruction instruction = block.first; | 188 HInstruction instruction = block.first; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 } | 242 } |
| 252 // TODO(het): consider supporting other values (short strings?) | 243 // TODO(het): consider supporting other values (short strings?) |
| 253 } | 244 } |
| 254 return null; | 245 return null; |
| 255 } | 246 } |
| 256 | 247 |
| 257 void propagateConstantValueToUses(HInstruction node) { | 248 void propagateConstantValueToUses(HInstruction node) { |
| 258 if (node.usedBy.isEmpty) return; | 249 if (node.usedBy.isEmpty) return; |
| 259 ConstantValue value = getConstantFromType(node); | 250 ConstantValue value = getConstantFromType(node); |
| 260 if (value != null) { | 251 if (value != null) { |
| 261 HConstant constant = graph.addConstant(value, compiler); | 252 HConstant constant = graph.addConstant(value, closedWorld); |
| 262 for (HInstruction user in node.usedBy.toList()) { | 253 for (HInstruction user in node.usedBy.toList()) { |
| 263 user.changeUse(node, constant); | 254 user.changeUse(node, constant); |
| 264 } | 255 } |
| 265 } | 256 } |
| 266 } | 257 } |
| 267 | 258 |
| 268 HInstruction visitParameterValue(HParameterValue node) { | 259 HInstruction visitParameterValue(HParameterValue node) { |
| 269 // [HParameterValue]s are either the value of the parameter (in fully SSA | 260 // [HParameterValue]s are either the value of the parameter (in fully SSA |
| 270 // converted code), or the mutable variable containing the value (in | 261 // converted code), or the mutable variable containing the value (in |
| 271 // incompletely SSA converted code, e.g. methods containing exceptions). | 262 // incompletely SSA converted code, e.g. methods containing exceptions). |
| (...skipping 26 matching lines...) Expand all Loading... |
| 298 | 289 |
| 299 // If the code is unreachable, remove the HBoolify. This can happen when | 290 // If the code is unreachable, remove the HBoolify. This can happen when |
| 300 // there is a throw expression in a short-circuit conditional. Removing the | 291 // there is a throw expression in a short-circuit conditional. Removing the |
| 301 // unreachable HBoolify makes it easier to reconstruct the short-circuit | 292 // unreachable HBoolify makes it easier to reconstruct the short-circuit |
| 302 // operation. | 293 // operation. |
| 303 if (input.instructionType.isEmpty) return input; | 294 if (input.instructionType.isEmpty) return input; |
| 304 | 295 |
| 305 // All values that cannot be 'true' are boolified to false. | 296 // All values that cannot be 'true' are boolified to false. |
| 306 TypeMask mask = input.instructionType; | 297 TypeMask mask = input.instructionType; |
| 307 if (!mask.contains(helpers.jsBoolClass, closedWorld)) { | 298 if (!mask.contains(helpers.jsBoolClass, closedWorld)) { |
| 308 return graph.addConstantBool(false, compiler); | 299 return graph.addConstantBool(false, closedWorld); |
| 309 } | 300 } |
| 310 return node; | 301 return node; |
| 311 } | 302 } |
| 312 | 303 |
| 313 HInstruction visitNot(HNot node) { | 304 HInstruction visitNot(HNot node) { |
| 314 List<HInstruction> inputs = node.inputs; | 305 List<HInstruction> inputs = node.inputs; |
| 315 assert(inputs.length == 1); | 306 assert(inputs.length == 1); |
| 316 HInstruction input = inputs[0]; | 307 HInstruction input = inputs[0]; |
| 317 if (input is HConstant) { | 308 if (input is HConstant) { |
| 318 HConstant constant = input; | 309 HConstant constant = input; |
| 319 bool isTrue = constant.constant.isTrue; | 310 bool isTrue = constant.constant.isTrue; |
| 320 return graph.addConstantBool(!isTrue, compiler); | 311 return graph.addConstantBool(!isTrue, closedWorld); |
| 321 } else if (input is HNot) { | 312 } else if (input is HNot) { |
| 322 return input.inputs[0]; | 313 return input.inputs[0]; |
| 323 } | 314 } |
| 324 return node; | 315 return node; |
| 325 } | 316 } |
| 326 | 317 |
| 327 HInstruction visitInvokeUnary(HInvokeUnary node) { | 318 HInstruction visitInvokeUnary(HInvokeUnary node) { |
| 328 HInstruction folded = | 319 HInstruction folded = |
| 329 foldUnary(node.operation(constantSystem), node.operand); | 320 foldUnary(node.operation(constantSystem), node.operand); |
| 330 return folded != null ? folded : node; | 321 return folded != null ? folded : node; |
| 331 } | 322 } |
| 332 | 323 |
| 333 HInstruction foldUnary(UnaryOperation operation, HInstruction operand) { | 324 HInstruction foldUnary(UnaryOperation operation, HInstruction operand) { |
| 334 if (operand is HConstant) { | 325 if (operand is HConstant) { |
| 335 HConstant receiver = operand; | 326 HConstant receiver = operand; |
| 336 ConstantValue folded = operation.fold(receiver.constant); | 327 ConstantValue folded = operation.fold(receiver.constant); |
| 337 if (folded != null) return graph.addConstant(folded, compiler); | 328 if (folded != null) return graph.addConstant(folded, closedWorld); |
| 338 } | 329 } |
| 339 return null; | 330 return null; |
| 340 } | 331 } |
| 341 | 332 |
| 342 HInstruction tryOptimizeLengthInterceptedGetter(HInvokeDynamic node) { | 333 HInstruction tryOptimizeLengthInterceptedGetter(HInvokeDynamic node) { |
| 343 HInstruction actualReceiver = node.inputs[1]; | 334 HInstruction actualReceiver = node.inputs[1]; |
| 344 if (actualReceiver.isIndexablePrimitive(closedWorld)) { | 335 if (actualReceiver.isIndexablePrimitive(closedWorld)) { |
| 345 if (actualReceiver.isConstantString()) { | 336 if (actualReceiver.isConstantString()) { |
| 346 HConstant constantInput = actualReceiver; | 337 HConstant constantInput = actualReceiver; |
| 347 StringConstantValue constant = constantInput.constant; | 338 StringConstantValue constant = constantInput.constant; |
| 348 return graph.addConstantInt(constant.length, compiler); | 339 return graph.addConstantInt(constant.length, closedWorld); |
| 349 } else if (actualReceiver.isConstantList()) { | 340 } else if (actualReceiver.isConstantList()) { |
| 350 HConstant constantInput = actualReceiver; | 341 HConstant constantInput = actualReceiver; |
| 351 ListConstantValue constant = constantInput.constant; | 342 ListConstantValue constant = constantInput.constant; |
| 352 return graph.addConstantInt(constant.length, compiler); | 343 return graph.addConstantInt(constant.length, closedWorld); |
| 353 } | 344 } |
| 354 MemberElement element = helpers.jsIndexableLength; | 345 MemberElement element = helpers.jsIndexableLength; |
| 355 bool isFixed = isFixedLength(actualReceiver.instructionType, closedWorld); | 346 bool isFixed = isFixedLength(actualReceiver.instructionType, closedWorld); |
| 356 TypeMask actualType = node.instructionType; | 347 TypeMask actualType = node.instructionType; |
| 357 TypeMask resultType = closedWorld.commonMasks.positiveIntType; | 348 TypeMask resultType = closedWorld.commonMasks.positiveIntType; |
| 358 // If we already have computed a more specific type, keep that type. | 349 // If we already have computed a more specific type, keep that type. |
| 359 if (HInstruction.isInstanceOf( | 350 if (HInstruction.isInstanceOf( |
| 360 actualType, helpers.jsUInt31Class, closedWorld)) { | 351 actualType, helpers.jsUInt31Class, closedWorld)) { |
| 361 resultType = closedWorld.commonMasks.uint31Type; | 352 resultType = closedWorld.commonMasks.uint31Type; |
| 362 } else if (HInstruction.isInstanceOf( | 353 } else if (HInstruction.isInstanceOf( |
| 363 actualType, helpers.jsUInt32Class, closedWorld)) { | 354 actualType, helpers.jsUInt32Class, closedWorld)) { |
| 364 resultType = closedWorld.commonMasks.uint32Type; | 355 resultType = closedWorld.commonMasks.uint32Type; |
| 365 } | 356 } |
| 366 HFieldGet result = new HFieldGet(element, actualReceiver, resultType, | 357 HFieldGet result = new HFieldGet(element, actualReceiver, resultType, |
| 367 isAssignable: !isFixed); | 358 isAssignable: !isFixed); |
| 368 return result; | 359 return result; |
| 369 } else if (actualReceiver.isConstantMap()) { | 360 } else if (actualReceiver.isConstantMap()) { |
| 370 HConstant constantInput = actualReceiver; | 361 HConstant constantInput = actualReceiver; |
| 371 MapConstantValue constant = constantInput.constant; | 362 MapConstantValue constant = constantInput.constant; |
| 372 return graph.addConstantInt(constant.length, compiler); | 363 return graph.addConstantInt(constant.length, closedWorld); |
| 373 } | 364 } |
| 374 return null; | 365 return null; |
| 375 } | 366 } |
| 376 | 367 |
| 377 HInstruction handleInterceptedCall(HInvokeDynamic node) { | 368 HInstruction handleInterceptedCall(HInvokeDynamic node) { |
| 378 // Try constant folding the instruction. | 369 // Try constant folding the instruction. |
| 379 Operation operation = node.specializer.operation(constantSystem); | 370 Operation operation = node.specializer.operation(constantSystem); |
| 380 if (operation != null) { | 371 if (operation != null) { |
| 381 HInstruction instruction = node.inputs.length == 2 | 372 HInstruction instruction = node.inputs.length == 2 |
| 382 ? foldUnary(operation, node.inputs[1]) | 373 ? foldUnary(operation, node.inputs[1]) |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 587 } | 578 } |
| 588 return node; | 579 return node; |
| 589 } | 580 } |
| 590 | 581 |
| 591 HInstruction foldBinary( | 582 HInstruction foldBinary( |
| 592 BinaryOperation operation, HInstruction left, HInstruction right) { | 583 BinaryOperation operation, HInstruction left, HInstruction right) { |
| 593 if (left is HConstant && right is HConstant) { | 584 if (left is HConstant && right is HConstant) { |
| 594 HConstant op1 = left; | 585 HConstant op1 = left; |
| 595 HConstant op2 = right; | 586 HConstant op2 = right; |
| 596 ConstantValue folded = operation.fold(op1.constant, op2.constant); | 587 ConstantValue folded = operation.fold(op1.constant, op2.constant); |
| 597 if (folded != null) return graph.addConstant(folded, compiler); | 588 if (folded != null) return graph.addConstant(folded, closedWorld); |
| 598 } | 589 } |
| 599 return null; | 590 return null; |
| 600 } | 591 } |
| 601 | 592 |
| 602 HInstruction visitAdd(HAdd node) { | 593 HInstruction visitAdd(HAdd node) { |
| 603 HInstruction left = node.left; | 594 HInstruction left = node.left; |
| 604 HInstruction right = node.right; | 595 HInstruction right = node.right; |
| 605 // We can only perform this rewriting on Integer, as it is not | 596 // We can only perform this rewriting on Integer, as it is not |
| 606 // valid for -0.0. | 597 // valid for -0.0. |
| 607 if (left.isInteger(closedWorld) && right.isInteger(closedWorld)) { | 598 if (left.isInteger(closedWorld) && right.isInteger(closedWorld)) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 648 // in the remaining optimizations. | 639 // in the remaining optimizations. |
| 649 return super.visitRelational(node); | 640 return super.visitRelational(node); |
| 650 } | 641 } |
| 651 | 642 |
| 652 HInstruction handleIdentityCheck(HRelational node) { | 643 HInstruction handleIdentityCheck(HRelational node) { |
| 653 HInstruction left = node.left; | 644 HInstruction left = node.left; |
| 654 HInstruction right = node.right; | 645 HInstruction right = node.right; |
| 655 TypeMask leftType = left.instructionType; | 646 TypeMask leftType = left.instructionType; |
| 656 TypeMask rightType = right.instructionType; | 647 TypeMask rightType = right.instructionType; |
| 657 | 648 |
| 658 HInstruction makeTrue() => graph.addConstantBool(true, compiler); | 649 HInstruction makeTrue() => graph.addConstantBool(true, closedWorld); |
| 659 HInstruction makeFalse() => graph.addConstantBool(false, compiler); | 650 HInstruction makeFalse() => graph.addConstantBool(false, closedWorld); |
| 660 | 651 |
| 661 // Intersection of int and double return conflicting, so | 652 // Intersection of int and double return conflicting, so |
| 662 // we don't optimize on numbers to preserve the runtime semantics. | 653 // we don't optimize on numbers to preserve the runtime semantics. |
| 663 if (!(left.isNumberOrNull(closedWorld) && | 654 if (!(left.isNumberOrNull(closedWorld) && |
| 664 right.isNumberOrNull(closedWorld))) { | 655 right.isNumberOrNull(closedWorld))) { |
| 665 if (leftType.isDisjoint(rightType, closedWorld)) { | 656 if (leftType.isDisjoint(rightType, closedWorld)) { |
| 666 return makeFalse(); | 657 return makeFalse(); |
| 667 } | 658 } |
| 668 } | 659 } |
| 669 | 660 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 700 } | 691 } |
| 701 | 692 |
| 702 HInstruction visitIdentity(HIdentity node) { | 693 HInstruction visitIdentity(HIdentity node) { |
| 703 HInstruction newInstruction = handleIdentityCheck(node); | 694 HInstruction newInstruction = handleIdentityCheck(node); |
| 704 return newInstruction == null ? super.visitIdentity(node) : newInstruction; | 695 return newInstruction == null ? super.visitIdentity(node) : newInstruction; |
| 705 } | 696 } |
| 706 | 697 |
| 707 void simplifyCondition( | 698 void simplifyCondition( |
| 708 HBasicBlock block, HInstruction condition, bool value) { | 699 HBasicBlock block, HInstruction condition, bool value) { |
| 709 condition.dominatedUsers(block.first).forEach((user) { | 700 condition.dominatedUsers(block.first).forEach((user) { |
| 710 HInstruction newCondition = graph.addConstantBool(value, compiler); | 701 HInstruction newCondition = graph.addConstantBool(value, closedWorld); |
| 711 user.changeUse(condition, newCondition); | 702 user.changeUse(condition, newCondition); |
| 712 }); | 703 }); |
| 713 } | 704 } |
| 714 | 705 |
| 715 HInstruction visitIf(HIf node) { | 706 HInstruction visitIf(HIf node) { |
| 716 HInstruction condition = node.condition; | 707 HInstruction condition = node.condition; |
| 717 if (condition.isConstant()) return node; | 708 if (condition.isConstant()) return node; |
| 718 bool isNegated = condition is HNot; | 709 bool isNegated = condition is HNot; |
| 719 | 710 |
| 720 if (isNegated) { | 711 if (isNegated) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 743 | 734 |
| 744 if (!node.isRawCheck) { | 735 if (!node.isRawCheck) { |
| 745 return node; | 736 return node; |
| 746 } else if (type.isTypedef) { | 737 } else if (type.isTypedef) { |
| 747 return node; | 738 return node; |
| 748 } else if (element == commonElements.functionClass) { | 739 } else if (element == commonElements.functionClass) { |
| 749 return node; | 740 return node; |
| 750 } | 741 } |
| 751 | 742 |
| 752 if (type.isObject || type.treatAsDynamic) { | 743 if (type.isObject || type.treatAsDynamic) { |
| 753 return graph.addConstantBool(true, compiler); | 744 return graph.addConstantBool(true, closedWorld); |
| 754 } | 745 } |
| 755 | 746 |
| 756 HInstruction expression = node.expression; | 747 HInstruction expression = node.expression; |
| 757 if (expression.isInteger(closedWorld)) { | 748 if (expression.isInteger(closedWorld)) { |
| 758 if (element == commonElements.intClass || | 749 if (element == commonElements.intClass || |
| 759 element == commonElements.numClass || | 750 element == commonElements.numClass || |
| 760 Elements.isNumberOrStringSupertype(element, commonElements)) { | 751 Elements.isNumberOrStringSupertype(element, commonElements)) { |
| 761 return graph.addConstantBool(true, compiler); | 752 return graph.addConstantBool(true, closedWorld); |
| 762 } else if (element == commonElements.doubleClass) { | 753 } else if (element == commonElements.doubleClass) { |
| 763 // We let the JS semantics decide for that check. Currently | 754 // We let the JS semantics decide for that check. Currently |
| 764 // the code we emit will always return true. | 755 // the code we emit will always return true. |
| 765 return node; | 756 return node; |
| 766 } else { | 757 } else { |
| 767 return graph.addConstantBool(false, compiler); | 758 return graph.addConstantBool(false, closedWorld); |
| 768 } | 759 } |
| 769 } else if (expression.isDouble(closedWorld)) { | 760 } else if (expression.isDouble(closedWorld)) { |
| 770 if (element == commonElements.doubleClass || | 761 if (element == commonElements.doubleClass || |
| 771 element == commonElements.numClass || | 762 element == commonElements.numClass || |
| 772 Elements.isNumberOrStringSupertype(element, commonElements)) { | 763 Elements.isNumberOrStringSupertype(element, commonElements)) { |
| 773 return graph.addConstantBool(true, compiler); | 764 return graph.addConstantBool(true, closedWorld); |
| 774 } else if (element == commonElements.intClass) { | 765 } else if (element == commonElements.intClass) { |
| 775 // We let the JS semantics decide for that check. Currently | 766 // We let the JS semantics decide for that check. Currently |
| 776 // the code we emit will return true for a double that can be | 767 // the code we emit will return true for a double that can be |
| 777 // represented as a 31-bit integer and for -0.0. | 768 // represented as a 31-bit integer and for -0.0. |
| 778 return node; | 769 return node; |
| 779 } else { | 770 } else { |
| 780 return graph.addConstantBool(false, compiler); | 771 return graph.addConstantBool(false, closedWorld); |
| 781 } | 772 } |
| 782 } else if (expression.isNumber(closedWorld)) { | 773 } else if (expression.isNumber(closedWorld)) { |
| 783 if (element == commonElements.numClass) { | 774 if (element == commonElements.numClass) { |
| 784 return graph.addConstantBool(true, compiler); | 775 return graph.addConstantBool(true, closedWorld); |
| 785 } else { | 776 } else { |
| 786 // We cannot just return false, because the expression may be of | 777 // We cannot just return false, because the expression may be of |
| 787 // type int or double. | 778 // type int or double. |
| 788 } | 779 } |
| 789 } else if (expression.canBePrimitiveNumber(closedWorld) && | 780 } else if (expression.canBePrimitiveNumber(closedWorld) && |
| 790 element == commonElements.intClass) { | 781 element == commonElements.intClass) { |
| 791 // We let the JS semantics decide for that check. | 782 // We let the JS semantics decide for that check. |
| 792 return node; | 783 return node; |
| 793 // We need the [:hasTypeArguments:] check because we don't have | 784 // We need the [:hasTypeArguments:] check because we don't have |
| 794 // the notion of generics in the backend. For example, [:this:] in | 785 // the notion of generics in the backend. For example, [:this:] in |
| 795 // a class [:A<T>:], is currently always considered to have the | 786 // a class [:A<T>:], is currently always considered to have the |
| 796 // raw type. | 787 // raw type. |
| 797 } else if (!RuntimeTypes.hasTypeArguments(type)) { | 788 } else if (!RuntimeTypes.hasTypeArguments(type)) { |
| 798 TypeMask expressionMask = expression.instructionType; | 789 TypeMask expressionMask = expression.instructionType; |
| 799 assert(TypeMask.assertIsNormalized(expressionMask, closedWorld)); | 790 assert(TypeMask.assertIsNormalized(expressionMask, closedWorld)); |
| 800 TypeMask typeMask = (element == commonElements.nullClass) | 791 TypeMask typeMask = (element == commonElements.nullClass) |
| 801 ? new TypeMask.subtype(element, closedWorld) | 792 ? new TypeMask.subtype(element, closedWorld) |
| 802 : new TypeMask.nonNullSubtype(element, closedWorld); | 793 : new TypeMask.nonNullSubtype(element, closedWorld); |
| 803 if (expressionMask.union(typeMask, closedWorld) == typeMask) { | 794 if (expressionMask.union(typeMask, closedWorld) == typeMask) { |
| 804 return graph.addConstantBool(true, compiler); | 795 return graph.addConstantBool(true, closedWorld); |
| 805 } else if (expressionMask.isDisjoint(typeMask, closedWorld)) { | 796 } else if (expressionMask.isDisjoint(typeMask, closedWorld)) { |
| 806 return graph.addConstantBool(false, compiler); | 797 return graph.addConstantBool(false, closedWorld); |
| 807 } | 798 } |
| 808 } | 799 } |
| 809 return node; | 800 return node; |
| 810 } | 801 } |
| 811 | 802 |
| 812 HInstruction visitTypeConversion(HTypeConversion node) { | 803 HInstruction visitTypeConversion(HTypeConversion node) { |
| 813 DartType type = node.typeExpression; | 804 DartType type = node.typeExpression; |
| 814 if (type != null) { | 805 if (type != null) { |
| 815 if (type.isMalformed) { | 806 if (type.isMalformed) { |
| 816 // Malformed types are treated as dynamic statically, but should | 807 // Malformed types are treated as dynamic statically, but should |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 867 if (node.element == helpers.jsIndexableLength) { | 858 if (node.element == helpers.jsIndexableLength) { |
| 868 if (graph.allocatedFixedLists.contains(receiver)) { | 859 if (graph.allocatedFixedLists.contains(receiver)) { |
| 869 // TODO(ngeoffray): checking if the second input is an integer | 860 // TODO(ngeoffray): checking if the second input is an integer |
| 870 // should not be necessary but it currently makes it easier for | 861 // should not be necessary but it currently makes it easier for |
| 871 // other optimizations to reason about a fixed length constructor | 862 // other optimizations to reason about a fixed length constructor |
| 872 // that we know takes an int. | 863 // that we know takes an int. |
| 873 if (receiver.inputs[0].isInteger(closedWorld)) { | 864 if (receiver.inputs[0].isInteger(closedWorld)) { |
| 874 return receiver.inputs[0]; | 865 return receiver.inputs[0]; |
| 875 } | 866 } |
| 876 } else if (receiver.isConstantList() || receiver.isConstantString()) { | 867 } else if (receiver.isConstantList() || receiver.isConstantString()) { |
| 877 return graph.addConstantInt(receiver.constant.length, compiler); | 868 return graph.addConstantInt(receiver.constant.length, closedWorld); |
| 878 } else { | 869 } else { |
| 879 var type = receiver.instructionType; | 870 var type = receiver.instructionType; |
| 880 if (type.isContainer && type.length != null) { | 871 if (type.isContainer && type.length != null) { |
| 881 HInstruction constant = graph.addConstantInt(type.length, compiler); | 872 HInstruction constant = |
| 873 graph.addConstantInt(type.length, closedWorld); |
| 882 if (type.isNullable) { | 874 if (type.isNullable) { |
| 883 // If the container can be null, we update all uses of the | 875 // If the container can be null, we update all uses of the |
| 884 // length access to use the constant instead, but keep the | 876 // length access to use the constant instead, but keep the |
| 885 // length access in the graph, to ensure we still have a | 877 // length access in the graph, to ensure we still have a |
| 886 // null check. | 878 // null check. |
| 887 node.block.rewrite(node, constant); | 879 node.block.rewrite(node, constant); |
| 888 return node; | 880 return node; |
| 889 } else { | 881 } else { |
| 890 return constant; | 882 return constant; |
| 891 } | 883 } |
| 892 } | 884 } |
| 893 } | 885 } |
| 894 } | 886 } |
| 895 | 887 |
| 896 // HFieldGet of a constructed constant can be replaced with the constant's | 888 // HFieldGet of a constructed constant can be replaced with the constant's |
| 897 // field. | 889 // field. |
| 898 if (receiver is HConstant) { | 890 if (receiver is HConstant) { |
| 899 ConstantValue constant = receiver.constant; | 891 ConstantValue constant = receiver.constant; |
| 900 if (constant.isConstructedObject) { | 892 if (constant.isConstructedObject) { |
| 901 ConstructedConstantValue constructedConstant = constant; | 893 ConstructedConstantValue constructedConstant = constant; |
| 902 Map<Element, ConstantValue> fields = constructedConstant.fields; | 894 Map<Element, ConstantValue> fields = constructedConstant.fields; |
| 903 ConstantValue value = fields[node.element]; | 895 ConstantValue value = fields[node.element]; |
| 904 if (value != null) { | 896 if (value != null) { |
| 905 return graph.addConstant(value, compiler); | 897 return graph.addConstant(value, closedWorld); |
| 906 } | 898 } |
| 907 } | 899 } |
| 908 } | 900 } |
| 909 | 901 |
| 910 return node; | 902 return node; |
| 911 } | 903 } |
| 912 | 904 |
| 913 HInstruction visitIndex(HIndex node) { | 905 HInstruction visitIndex(HIndex node) { |
| 914 if (node.receiver.isConstantList() && node.index.isConstantInteger()) { | 906 if (node.receiver.isConstantList() && node.index.isConstantInteger()) { |
| 915 var instruction = node.receiver; | 907 var instruction = node.receiver; |
| 916 List<ConstantValue> entries = instruction.constant.entries; | 908 List<ConstantValue> entries = instruction.constant.entries; |
| 917 instruction = node.index; | 909 instruction = node.index; |
| 918 int index = instruction.constant.primitiveValue; | 910 int index = instruction.constant.primitiveValue; |
| 919 if (index >= 0 && index < entries.length) { | 911 if (index >= 0 && index < entries.length) { |
| 920 return graph.addConstant(entries[index], compiler); | 912 return graph.addConstant(entries[index], closedWorld); |
| 921 } | 913 } |
| 922 } | 914 } |
| 923 return node; | 915 return node; |
| 924 } | 916 } |
| 925 | 917 |
| 926 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { | 918 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { |
| 927 propagateConstantValueToUses(node); | 919 propagateConstantValueToUses(node); |
| 928 if (node.isInterceptedCall) { | 920 if (node.isInterceptedCall) { |
| 929 HInstruction folded = handleInterceptedCall(node); | 921 HInstruction folded = handleInterceptedCall(node); |
| 930 if (folded != node) return folded; | 922 if (folded != node) return folded; |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1065 } | 1057 } |
| 1066 | 1058 |
| 1067 if (leftString.primitiveValue.length + rightString.primitiveValue.length > | 1059 if (leftString.primitiveValue.length + rightString.primitiveValue.length > |
| 1068 MAX_SHARED_CONSTANT_FOLDED_STRING_LENGTH) { | 1060 MAX_SHARED_CONSTANT_FOLDED_STRING_LENGTH) { |
| 1069 if (node.usedBy.length > 1) return node; | 1061 if (node.usedBy.length > 1) return node; |
| 1070 } | 1062 } |
| 1071 | 1063 |
| 1072 HInstruction folded = graph.addConstant( | 1064 HInstruction folded = graph.addConstant( |
| 1073 constantSystem.createString(new ast.DartString.concat( | 1065 constantSystem.createString(new ast.DartString.concat( |
| 1074 leftString.primitiveValue, rightString.primitiveValue)), | 1066 leftString.primitiveValue, rightString.primitiveValue)), |
| 1075 compiler); | 1067 closedWorld); |
| 1076 if (prefix == null) return folded; | 1068 if (prefix == null) return folded; |
| 1077 return new HStringConcat( | 1069 return new HStringConcat( |
| 1078 prefix, folded, closedWorld.commonMasks.stringType); | 1070 prefix, folded, closedWorld.commonMasks.stringType); |
| 1079 } | 1071 } |
| 1080 | 1072 |
| 1081 HInstruction visitStringify(HStringify node) { | 1073 HInstruction visitStringify(HStringify node) { |
| 1082 HInstruction input = node.inputs[0]; | 1074 HInstruction input = node.inputs[0]; |
| 1083 if (input.isString(closedWorld)) return input; | 1075 if (input.isString(closedWorld)) return input; |
| 1084 | 1076 |
| 1085 HInstruction tryConstant() { | 1077 HInstruction tryConstant() { |
| 1086 if (!input.isConstant()) return null; | 1078 if (!input.isConstant()) return null; |
| 1087 HConstant constant = input; | 1079 HConstant constant = input; |
| 1088 if (!constant.constant.isPrimitive) return null; | 1080 if (!constant.constant.isPrimitive) return null; |
| 1089 if (constant.constant.isInt) { | 1081 if (constant.constant.isInt) { |
| 1090 // Only constant-fold int.toString() when Dart and JS results the same. | 1082 // Only constant-fold int.toString() when Dart and JS results the same. |
| 1091 // TODO(18103): We should be able to remove this work-around when issue | 1083 // TODO(18103): We should be able to remove this work-around when issue |
| 1092 // 18103 is resolved by providing the correct string. | 1084 // 18103 is resolved by providing the correct string. |
| 1093 IntConstantValue intConstant = constant.constant; | 1085 IntConstantValue intConstant = constant.constant; |
| 1094 // Very conservative range. | 1086 // Very conservative range. |
| 1095 if (!intConstant.isUInt32()) return null; | 1087 if (!intConstant.isUInt32()) return null; |
| 1096 } | 1088 } |
| 1097 PrimitiveConstantValue primitive = constant.constant; | 1089 PrimitiveConstantValue primitive = constant.constant; |
| 1098 return graph.addConstant( | 1090 return graph.addConstant( |
| 1099 constantSystem.createString(primitive.toDartString()), compiler); | 1091 constantSystem.createString(primitive.toDartString()), closedWorld); |
| 1100 } | 1092 } |
| 1101 | 1093 |
| 1102 HInstruction tryToString() { | 1094 HInstruction tryToString() { |
| 1103 // If the `toString` method is guaranteed to return a string we can call | 1095 // If the `toString` method is guaranteed to return a string we can call |
| 1104 // it directly. Keep the stringifier for primitives (since they have fast | 1096 // it directly. Keep the stringifier for primitives (since they have fast |
| 1105 // path code in the stringifier) and for classes requiring interceptors | 1097 // path code in the stringifier) and for classes requiring interceptors |
| 1106 // (since SsaInstructionSimplifier runs after SsaSimplifyInterceptors). | 1098 // (since SsaInstructionSimplifier runs after SsaSimplifyInterceptors). |
| 1107 if (input.canBePrimitive(closedWorld)) return null; | 1099 if (input.canBePrimitive(closedWorld)) return null; |
| 1108 if (input.canBeNull()) return null; | 1100 if (input.canBeNull()) return null; |
| 1109 Selector selector = Selectors.toString_; | 1101 Selector selector = Selectors.toString_; |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1282 object.element, (int index) => typeInfo.inputs[index]); | 1274 object.element, (int index) => typeInfo.inputs[index]); |
| 1283 } | 1275 } |
| 1284 } else { | 1276 } else { |
| 1285 // Non-generic type (which extends or mixes in a generic type, for | 1277 // Non-generic type (which extends or mixes in a generic type, for |
| 1286 // example CodeUnits extends UnmodifiableListBase<int>). Also used for | 1278 // example CodeUnits extends UnmodifiableListBase<int>). Also used for |
| 1287 // raw-type when the type parameters are elided. | 1279 // raw-type when the type parameters are elided. |
| 1288 registerInstantiations(); | 1280 registerInstantiations(); |
| 1289 return finishSubstituted( | 1281 return finishSubstituted( |
| 1290 object.element, | 1282 object.element, |
| 1291 // If there are type arguments, all type arguments are 'dynamic'. | 1283 // If there are type arguments, all type arguments are 'dynamic'. |
| 1292 (int i) => graph.addConstantNull(compiler)); | 1284 (int i) => graph.addConstantNull(closedWorld)); |
| 1293 } | 1285 } |
| 1294 } | 1286 } |
| 1295 | 1287 |
| 1296 // TODO(sra): Factory constructors pass type arguments after the value | 1288 // TODO(sra): Factory constructors pass type arguments after the value |
| 1297 // arguments. The [selectTypeArgumentFromObjectCreation] argument of | 1289 // arguments. The [selectTypeArgumentFromObjectCreation] argument of |
| 1298 // [finishSubstituted] indexes into these type arguments. | 1290 // [finishSubstituted] indexes into these type arguments. |
| 1299 | 1291 |
| 1300 return node; | 1292 return node; |
| 1301 } | 1293 } |
| 1302 } | 1294 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1329 HInstruction instruction = block.first; | 1321 HInstruction instruction = block.first; |
| 1330 while (instruction != null) { | 1322 while (instruction != null) { |
| 1331 HInstruction next = instruction.next; | 1323 HInstruction next = instruction.next; |
| 1332 instruction = instruction.accept(this); | 1324 instruction = instruction.accept(this); |
| 1333 instruction = next; | 1325 instruction = next; |
| 1334 } | 1326 } |
| 1335 } | 1327 } |
| 1336 | 1328 |
| 1337 HBoundsCheck insertBoundsCheck( | 1329 HBoundsCheck insertBoundsCheck( |
| 1338 HInstruction indexNode, HInstruction array, HInstruction indexArgument) { | 1330 HInstruction indexNode, HInstruction array, HInstruction indexArgument) { |
| 1339 Compiler compiler = backend.compiler; | |
| 1340 HFieldGet length = new HFieldGet(helpers.jsIndexableLength, array, | 1331 HFieldGet length = new HFieldGet(helpers.jsIndexableLength, array, |
| 1341 closedWorld.commonMasks.positiveIntType, | 1332 closedWorld.commonMasks.positiveIntType, |
| 1342 isAssignable: !isFixedLength(array.instructionType, closedWorld)); | 1333 isAssignable: !isFixedLength(array.instructionType, closedWorld)); |
| 1343 indexNode.block.addBefore(indexNode, length); | 1334 indexNode.block.addBefore(indexNode, length); |
| 1344 | 1335 |
| 1345 TypeMask type = indexArgument.isPositiveInteger(closedWorld) | 1336 TypeMask type = indexArgument.isPositiveInteger(closedWorld) |
| 1346 ? indexArgument.instructionType | 1337 ? indexArgument.instructionType |
| 1347 : closedWorld.commonMasks.positiveIntType; | 1338 : closedWorld.commonMasks.positiveIntType; |
| 1348 HBoundsCheck check = new HBoundsCheck(indexArgument, length, array, type); | 1339 HBoundsCheck check = new HBoundsCheck(indexArgument, length, array, type); |
| 1349 indexNode.block.addBefore(indexNode, check); | 1340 indexNode.block.addBefore(indexNode, check); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1374 } | 1365 } |
| 1375 | 1366 |
| 1376 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 1367 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
| 1377 MemberElement element = node.element; | 1368 MemberElement element = node.element; |
| 1378 if (node.isInterceptedCall) return; | 1369 if (node.isInterceptedCall) return; |
| 1379 if (element != helpers.jsArrayRemoveLast) return; | 1370 if (element != helpers.jsArrayRemoveLast) return; |
| 1380 if (boundsChecked.contains(node)) return; | 1371 if (boundsChecked.contains(node)) return; |
| 1381 // `0` is the index we want to check, but we want to report `-1`, as if we | 1372 // `0` is the index we want to check, but we want to report `-1`, as if we |
| 1382 // executed `a[a.length-1]` | 1373 // executed `a[a.length-1]` |
| 1383 HBoundsCheck check = insertBoundsCheck( | 1374 HBoundsCheck check = insertBoundsCheck( |
| 1384 node, node.receiver, graph.addConstantInt(0, backend.compiler)); | 1375 node, node.receiver, graph.addConstantInt(0, closedWorld)); |
| 1385 HInstruction minusOne = graph.addConstantInt(-1, backend.compiler); | 1376 HInstruction minusOne = graph.addConstantInt(-1, closedWorld); |
| 1386 check.inputs.add(minusOne); | 1377 check.inputs.add(minusOne); |
| 1387 minusOne.usedBy.add(check); | 1378 minusOne.usedBy.add(check); |
| 1388 } | 1379 } |
| 1389 } | 1380 } |
| 1390 | 1381 |
| 1391 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { | 1382 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { |
| 1392 final String name = "SsaDeadCodeEliminator"; | 1383 final String name = "SsaDeadCodeEliminator"; |
| 1393 | 1384 |
| 1394 final Compiler compiler; | |
| 1395 final ClosedWorld closedWorld; | 1385 final ClosedWorld closedWorld; |
| 1396 final SsaOptimizerTask optimizer; | 1386 final SsaOptimizerTask optimizer; |
| 1397 SsaLiveBlockAnalyzer analyzer; | 1387 SsaLiveBlockAnalyzer analyzer; |
| 1398 Map<HInstruction, bool> trivialDeadStoreReceivers = | 1388 Map<HInstruction, bool> trivialDeadStoreReceivers = |
| 1399 new Maplet<HInstruction, bool>(); | 1389 new Maplet<HInstruction, bool>(); |
| 1400 bool eliminatedSideEffects = false; | 1390 bool eliminatedSideEffects = false; |
| 1401 | 1391 |
| 1402 SsaDeadCodeEliminator(this.compiler, this.closedWorld, this.optimizer); | 1392 SsaDeadCodeEliminator(this.closedWorld, this.optimizer); |
| 1403 | 1393 |
| 1404 HInstruction zapInstructionCache; | 1394 HInstruction zapInstructionCache; |
| 1405 HInstruction get zapInstruction { | 1395 HInstruction get zapInstruction { |
| 1406 if (zapInstructionCache == null) { | 1396 if (zapInstructionCache == null) { |
| 1407 // A constant with no type does not pollute types at phi nodes. | 1397 // A constant with no type does not pollute types at phi nodes. |
| 1408 ConstantValue constant = new SyntheticConstantValue( | 1398 ConstantValue constant = new SyntheticConstantValue( |
| 1409 SyntheticConstantKind.EMPTY_VALUE, const TypeMask.nonNullEmpty()); | 1399 SyntheticConstantKind.EMPTY_VALUE, const TypeMask.nonNullEmpty()); |
| 1410 zapInstructionCache = analyzer.graph.addConstant(constant, compiler); | 1400 zapInstructionCache = analyzer.graph.addConstant(constant, closedWorld); |
| 1411 } | 1401 } |
| 1412 return zapInstructionCache; | 1402 return zapInstructionCache; |
| 1413 } | 1403 } |
| 1414 | 1404 |
| 1415 /// Returns true of [foreign] will throw an noSuchMethod error if | 1405 /// Returns true of [foreign] will throw an noSuchMethod error if |
| 1416 /// receiver is `null` before having any other side-effects. | 1406 /// receiver is `null` before having any other side-effects. |
| 1417 bool templateThrowsNSMonNull(HForeignCode foreign, HInstruction receiver) { | 1407 bool templateThrowsNSMonNull(HForeignCode foreign, HInstruction receiver) { |
| 1418 if (foreign.inputs.length < 1) return false; | 1408 if (foreign.inputs.length < 1) return false; |
| 1419 if (foreign.inputs.first != receiver) return false; | 1409 if (foreign.inputs.first != receiver) return false; |
| 1420 if (foreign.throwBehavior.isNullNSMGuard) return true; | 1410 if (foreign.throwBehavior.isNullNSMGuard) return true; |
| (...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1795 } | 1785 } |
| 1796 | 1786 |
| 1797 class GvnWorkItem { | 1787 class GvnWorkItem { |
| 1798 final HBasicBlock block; | 1788 final HBasicBlock block; |
| 1799 final ValueSet valueSet; | 1789 final ValueSet valueSet; |
| 1800 GvnWorkItem(this.block, this.valueSet); | 1790 GvnWorkItem(this.block, this.valueSet); |
| 1801 } | 1791 } |
| 1802 | 1792 |
| 1803 class SsaGlobalValueNumberer implements OptimizationPhase { | 1793 class SsaGlobalValueNumberer implements OptimizationPhase { |
| 1804 final String name = "SsaGlobalValueNumberer"; | 1794 final String name = "SsaGlobalValueNumberer"; |
| 1805 final Compiler compiler; | |
| 1806 final Set<int> visited; | 1795 final Set<int> visited; |
| 1807 | 1796 |
| 1808 List<int> blockChangesFlags; | 1797 List<int> blockChangesFlags; |
| 1809 List<int> loopChangesFlags; | 1798 List<int> loopChangesFlags; |
| 1810 | 1799 |
| 1811 SsaGlobalValueNumberer(this.compiler) : visited = new Set<int>(); | 1800 SsaGlobalValueNumberer() : visited = new Set<int>(); |
| 1812 | 1801 |
| 1813 void visitGraph(HGraph graph) { | 1802 void visitGraph(HGraph graph) { |
| 1814 computeChangesFlags(graph); | 1803 computeChangesFlags(graph); |
| 1815 moveLoopInvariantCode(graph); | 1804 moveLoopInvariantCode(graph); |
| 1816 List<GvnWorkItem> workQueue = <GvnWorkItem>[ | 1805 List<GvnWorkItem> workQueue = <GvnWorkItem>[ |
| 1817 new GvnWorkItem(graph.entry, new ValueSet()) | 1806 new GvnWorkItem(graph.entry, new ValueSet()) |
| 1818 ]; | 1807 ]; |
| 1819 do { | 1808 do { |
| 1820 GvnWorkItem item = workQueue.removeLast(); | 1809 GvnWorkItem item = workQueue.removeLast(); |
| 1821 visitBasicBlock(item.block, item.valueSet, workQueue); | 1810 visitBasicBlock(item.block, item.valueSet, workQueue); |
| (...skipping 931 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2753 | 2742 |
| 2754 keyedValues.forEach((receiver, values) { | 2743 keyedValues.forEach((receiver, values) { |
| 2755 result.keyedValues[receiver] = | 2744 result.keyedValues[receiver] = |
| 2756 new Map<HInstruction, HInstruction>.from(values); | 2745 new Map<HInstruction, HInstruction>.from(values); |
| 2757 }); | 2746 }); |
| 2758 | 2747 |
| 2759 result.nonEscapingReceivers.addAll(nonEscapingReceivers); | 2748 result.nonEscapingReceivers.addAll(nonEscapingReceivers); |
| 2760 return result; | 2749 return result; |
| 2761 } | 2750 } |
| 2762 } | 2751 } |
| OLD | NEW |