| 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 class SsaCodeGeneratorTask extends CompilerTask { | 5 class SsaCodeGeneratorTask extends CompilerTask { |
| 6 final JavaScriptBackend backend; | 6 final JavaScriptBackend backend; |
| 7 SsaCodeGeneratorTask(JavaScriptBackend backend) | 7 SsaCodeGeneratorTask(JavaScriptBackend backend) |
| 8 : this.backend = backend, | 8 : this.backend = backend, |
| 9 super(backend.compiler); | 9 super(backend.compiler); |
| 10 String get name() => 'SSA code generator'; | 10 String get name() => 'SSA code generator'; |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 124 static final int TYPE_DECLARATION = 2; | 124 static final int TYPE_DECLARATION = 2; |
| 125 | 125 |
| 126 /** | 126 /** |
| 127 * Whether we are currently generating expressions instead of statements. | 127 * Whether we are currently generating expressions instead of statements. |
| 128 * This includes declarations, which are generated as expressions. | 128 * This includes declarations, which are generated as expressions. |
| 129 */ | 129 */ |
| 130 bool isGeneratingExpression = false; | 130 bool isGeneratingExpression = false; |
| 131 | 131 |
| 132 final JavaScriptBackend backend; | 132 final JavaScriptBackend backend; |
| 133 final WorkItem work; | 133 final WorkItem work; |
| 134 final HTypeMap types; |
| 134 | 135 |
| 135 final Set<HInstruction> generateAtUseSite; | 136 final Set<HInstruction> generateAtUseSite; |
| 136 final Set<HInstruction> controlFlowOperators; | 137 final Set<HInstruction> controlFlowOperators; |
| 137 final Map<Element, ElementAction> breakAction; | 138 final Map<Element, ElementAction> breakAction; |
| 138 final Map<Element, ElementAction> continueAction; | 139 final Map<Element, ElementAction> continueAction; |
| 139 final Map<Element, String> parameterNames; | 140 final Map<Element, String> parameterNames; |
| 140 | 141 |
| 141 js.Block currentContainer; | 142 js.Block currentContainer; |
| 142 js.Block get body() => currentContainer; | 143 js.Block get body() => currentContainer; |
| 143 List<js.Expression> expressionStack; | 144 List<js.Expression> expressionStack; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 166 HGraph currentGraph; | 167 HGraph currentGraph; |
| 167 HBasicBlock currentBlock; | 168 HBasicBlock currentBlock; |
| 168 | 169 |
| 169 // Records a block-information that is being handled specially. | 170 // Records a block-information that is being handled specially. |
| 170 // Used to break bad recursion. | 171 // Used to break bad recursion. |
| 171 HBlockInformation currentBlockInformation; | 172 HBlockInformation currentBlockInformation; |
| 172 // The subgraph is used to delimit traversal for some constructions, e.g., | 173 // The subgraph is used to delimit traversal for some constructions, e.g., |
| 173 // if branches. | 174 // if branches. |
| 174 SubGraph subGraph; | 175 SubGraph subGraph; |
| 175 | 176 |
| 177 SsaCodeGenerator(this.backend, |
| 178 WorkItem work, |
| 179 this.parameterNames) |
| 180 : this.work = work, |
| 181 this.types = |
| 182 (work.compilationContext as JavaScriptItemCompilationContext).types, |
| 183 declaredVariables = new Set<String>(), |
| 184 delayedVariableDeclarations = new Set<String>(), |
| 185 currentContainer = new js.Block.empty(), |
| 186 expressionStack = <js.Expression>[], |
| 187 oldContainerStack = <js.Block>[], |
| 188 generateAtUseSite = new Set<HInstruction>(), |
| 189 controlFlowOperators = new Set<HInstruction>(), |
| 190 breakAction = new Map<Element, ElementAction>(), |
| 191 continueAction = new Map<Element, ElementAction>(); |
| 192 |
| 176 LibraryElement get currentLibrary() => work.element.getLibrary(); | 193 LibraryElement get currentLibrary() => work.element.getLibrary(); |
| 177 Compiler get compiler() => backend.compiler; | 194 Compiler get compiler() => backend.compiler; |
| 178 NativeEmitter get nativeEmitter() => backend.emitter.nativeEmitter; | 195 NativeEmitter get nativeEmitter() => backend.emitter.nativeEmitter; |
| 179 Enqueuer get world() => backend.compiler.enqueuer.codegen; | 196 Enqueuer get world() => backend.compiler.enqueuer.codegen; |
| 180 | 197 |
| 181 bool isGenerateAtUseSite(HInstruction instruction) { | 198 bool isGenerateAtUseSite(HInstruction instruction) { |
| 182 return generateAtUseSite.contains(instruction); | 199 return generateAtUseSite.contains(instruction); |
| 183 } | 200 } |
| 184 | 201 |
| 185 bool isNonNegativeInt32Constant(HInstruction instruction) { | 202 bool isNonNegativeInt32Constant(HInstruction instruction) { |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 } | 287 } |
| 271 return jsNode; | 288 return jsNode; |
| 272 } | 289 } |
| 273 | 290 |
| 274 js.Node attachLocationRange(js.Node jsNode, Node node) { | 291 js.Node attachLocationRange(js.Node jsNode, Node node) { |
| 275 jsNode.sourcePosition = node.getBeginToken(); | 292 jsNode.sourcePosition = node.getBeginToken(); |
| 276 jsNode.endSourcePosition = node.getEndToken(); | 293 jsNode.endSourcePosition = node.getEndToken(); |
| 277 return jsNode; | 294 return jsNode; |
| 278 } | 295 } |
| 279 | 296 |
| 280 SsaCodeGenerator(this.backend, | |
| 281 this.work, | |
| 282 this.parameterNames) | |
| 283 : declaredVariables = new Set<String>(), | |
| 284 delayedVariableDeclarations = new Set<String>(), | |
| 285 currentContainer = new js.Block.empty(), | |
| 286 expressionStack = <js.Expression>[], | |
| 287 oldContainerStack = <js.Block>[], | |
| 288 generateAtUseSite = new Set<HInstruction>(), | |
| 289 controlFlowOperators = new Set<HInstruction>(), | |
| 290 breakAction = new Map<Element, ElementAction>(), | |
| 291 continueAction = new Map<Element, ElementAction>(); | |
| 292 | |
| 293 abstract visitTypeGuard(HTypeGuard node); | 297 abstract visitTypeGuard(HTypeGuard node); |
| 294 abstract visitBailoutTarget(HBailoutTarget node); | 298 abstract visitBailoutTarget(HBailoutTarget node); |
| 295 | 299 |
| 296 abstract beginGraph(HGraph graph); | 300 abstract beginGraph(HGraph graph); |
| 297 abstract endGraph(HGraph graph); | 301 abstract endGraph(HGraph graph); |
| 298 | 302 |
| 299 abstract beginLoop(HBasicBlock block); | 303 abstract beginLoop(HBasicBlock block); |
| 300 abstract endLoop(HBasicBlock block); | 304 abstract endLoop(HBasicBlock block); |
| 301 abstract handleLoopCondition(HLoopBranch node); | 305 abstract handleLoopCondition(HLoopBranch node); |
| 302 | 306 |
| 303 abstract preLabeledBlock(HLabeledBlockInformation labeledBlockInfo); | 307 abstract preLabeledBlock(HLabeledBlockInformation labeledBlockInfo); |
| 304 abstract startLabeledBlock(HLabeledBlockInformation labeledBlockInfo); | 308 abstract startLabeledBlock(HLabeledBlockInformation labeledBlockInfo); |
| 305 abstract endLabeledBlock(HLabeledBlockInformation labeledBlockInfo); | 309 abstract endLabeledBlock(HLabeledBlockInformation labeledBlockInfo); |
| 306 | 310 |
| 307 void preGenerateMethod(HGraph graph) { | 311 void preGenerateMethod(HGraph graph) { |
| 308 new SsaInstructionMerger(generateAtUseSite).visitGraph(graph); | 312 new SsaInstructionMerger(types, generateAtUseSite).visitGraph(graph); |
| 309 new SsaConditionMerger(generateAtUseSite, | 313 new SsaConditionMerger( |
| 310 controlFlowOperators).visitGraph(graph); | 314 types, generateAtUseSite, controlFlowOperators).visitGraph(graph); |
| 311 SsaLiveIntervalBuilder intervalBuilder = | 315 SsaLiveIntervalBuilder intervalBuilder = |
| 312 new SsaLiveIntervalBuilder(compiler, generateAtUseSite); | 316 new SsaLiveIntervalBuilder(compiler, generateAtUseSite); |
| 313 intervalBuilder.visitGraph(graph); | 317 intervalBuilder.visitGraph(graph); |
| 314 SsaVariableAllocator allocator = new SsaVariableAllocator( | 318 SsaVariableAllocator allocator = new SsaVariableAllocator( |
| 315 compiler, | 319 compiler, |
| 316 intervalBuilder.liveInstructions, | 320 intervalBuilder.liveInstructions, |
| 317 intervalBuilder.liveIntervals, | 321 intervalBuilder.liveIntervals, |
| 318 generateAtUseSite, | 322 generateAtUseSite, |
| 319 parameterNames); | 323 parameterNames); |
| 320 allocator.visitGraph(graph); | 324 allocator.visitGraph(graph); |
| (...skipping 806 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1127 } else if (!isGenerateAtUseSite(instruction)) { | 1131 } else if (!isGenerateAtUseSite(instruction)) { |
| 1128 define(instruction); | 1132 define(instruction); |
| 1129 } | 1133 } |
| 1130 instruction = instruction.next; | 1134 instruction = instruction.next; |
| 1131 } | 1135 } |
| 1132 assignPhisOfSuccessors(node); | 1136 assignPhisOfSuccessors(node); |
| 1133 visit(instruction); | 1137 visit(instruction); |
| 1134 } | 1138 } |
| 1135 | 1139 |
| 1136 visitInvokeBinary(HInvokeBinary node, String op) { | 1140 visitInvokeBinary(HInvokeBinary node, String op) { |
| 1137 if (node.builtin) { | 1141 if (node.isBuiltin(types)) { |
| 1138 use(node.left); | 1142 use(node.left); |
| 1139 js.Expression jsLeft = pop(); | 1143 js.Expression jsLeft = pop(); |
| 1140 use(node.right); | 1144 use(node.right); |
| 1141 push(new js.Binary(op, jsLeft, pop()), node); | 1145 push(new js.Binary(op, jsLeft, pop()), node); |
| 1142 } else { | 1146 } else { |
| 1143 visitInvokeStatic(node); | 1147 visitInvokeStatic(node); |
| 1144 } | 1148 } |
| 1145 } | 1149 } |
| 1146 | 1150 |
| 1147 // We want the outcome of bit-operations to be positive. We use the unsigned | 1151 // We want the outcome of bit-operations to be positive. We use the unsigned |
| 1148 // shift operator to achieve this. | 1152 // shift operator to achieve this. |
| 1149 visitBitInvokeBinary(HBinaryBitOp node, String op) { | 1153 visitBitInvokeBinary(HBinaryBitOp node, String op) { |
| 1150 visitInvokeBinary(node, op); | 1154 visitInvokeBinary(node, op); |
| 1151 if (node.builtin && requiresUintConversion(node)) { | 1155 if (node.isBuiltin(types) && requiresUintConversion(node)) { |
| 1152 push(new js.Binary(">>>", pop(), new js.LiteralNumber("0")), node); | 1156 push(new js.Binary(">>>", pop(), new js.LiteralNumber("0")), node); |
| 1153 } | 1157 } |
| 1154 } | 1158 } |
| 1155 | 1159 |
| 1156 visitInvokeUnary(HInvokeUnary node, String op) { | 1160 visitInvokeUnary(HInvokeUnary node, String op) { |
| 1157 if (node.builtin) { | 1161 if (node.isBuiltin(types)) { |
| 1158 use(node.operand); | 1162 use(node.operand); |
| 1159 push(new js.Prefix(op, pop()), node); | 1163 push(new js.Prefix(op, pop()), node); |
| 1160 } else { | 1164 } else { |
| 1161 visitInvokeStatic(node); | 1165 visitInvokeStatic(node); |
| 1162 } | 1166 } |
| 1163 } | 1167 } |
| 1164 | 1168 |
| 1165 // We want the outcome of bit-operations to be positive. We use the unsigned | 1169 // We want the outcome of bit-operations to be positive. We use the unsigned |
| 1166 // shift operator to achieve this. | 1170 // shift operator to achieve this. |
| 1167 visitBitInvokeUnary(HInvokeUnary node, String op) { | 1171 visitBitInvokeUnary(HInvokeUnary node, String op) { |
| 1168 visitInvokeUnary(node, op); | 1172 visitInvokeUnary(node, op); |
| 1169 if (node.builtin && requiresUintConversion(node)) { | 1173 if (node.isBuiltin(types) && requiresUintConversion(node)) { |
| 1170 push(new js.Binary(">>>", pop(), new js.LiteralNumber("0")), node); | 1174 push(new js.Binary(">>>", pop(), new js.LiteralNumber("0")), node); |
| 1171 } | 1175 } |
| 1172 } | 1176 } |
| 1173 | 1177 |
| 1174 void emitIdentityComparison(HInstruction left, HInstruction right) { | 1178 void emitIdentityComparison(HInstruction left, HInstruction right) { |
| 1175 String op = singleIdentityComparison(left, right); | 1179 String op = singleIdentityComparison(left, right, types); |
| 1176 if (op != null) { | 1180 if (op != null) { |
| 1177 use(left); | 1181 use(left); |
| 1178 js.Expression jsLeft = pop(); | 1182 js.Expression jsLeft = pop(); |
| 1179 use(right); | 1183 use(right); |
| 1180 push(new js.Binary(op, jsLeft, pop())); | 1184 push(new js.Binary(op, jsLeft, pop())); |
| 1181 } else { | 1185 } else { |
| 1182 assert(NullConstant.JsNull == 'null'); | 1186 assert(NullConstant.JsNull == 'null'); |
| 1183 use(left); | 1187 use(left); |
| 1184 js.Binary leftEqualsNull = | 1188 js.Binary leftEqualsNull = |
| 1185 new js.Binary("==", pop(), new js.LiteralNull()); | 1189 new js.Binary("==", pop(), new js.LiteralNull()); |
| 1186 use(right); | 1190 use(right); |
| 1187 js.Binary rightEqualsNull = | 1191 js.Binary rightEqualsNull = |
| 1188 new js.Binary("==", pop(), new js.LiteralNull()); | 1192 new js.Binary("==", pop(), new js.LiteralNull()); |
| 1189 use(right); | 1193 use(right); |
| 1190 use(left); | 1194 use(left); |
| 1191 js.Binary tripleEq = new js.Binary("===", pop(), pop()); | 1195 js.Binary tripleEq = new js.Binary("===", pop(), pop()); |
| 1192 | 1196 |
| 1193 push(new js.Conditional(leftEqualsNull, rightEqualsNull, tripleEq)); | 1197 push(new js.Conditional(leftEqualsNull, rightEqualsNull, tripleEq)); |
| 1194 } | 1198 } |
| 1195 } | 1199 } |
| 1196 | 1200 |
| 1197 visitEquals(HEquals node) { | 1201 visitEquals(HEquals node) { |
| 1198 if (node.builtin) { | 1202 if (node.isBuiltin(types)) { |
| 1199 emitIdentityComparison(node.left, node.right); | 1203 emitIdentityComparison(node.left, node.right); |
| 1200 } else { | 1204 } else { |
| 1201 visitInvokeStatic(node); | 1205 visitInvokeStatic(node); |
| 1202 } | 1206 } |
| 1203 } | 1207 } |
| 1204 | 1208 |
| 1205 visitIdentity(HIdentity node) { | 1209 visitIdentity(HIdentity node) { |
| 1206 assert(node.builtin); | 1210 assert(node.isBuiltin(types)); |
| 1207 emitIdentityComparison(node.left, node.right); | 1211 emitIdentityComparison(node.left, node.right); |
| 1208 } | 1212 } |
| 1209 | 1213 |
| 1210 visitAdd(HAdd node) => visitInvokeBinary(node, '+'); | 1214 visitAdd(HAdd node) => visitInvokeBinary(node, '+'); |
| 1211 visitDivide(HDivide node) => visitInvokeBinary(node, '/'); | 1215 visitDivide(HDivide node) => visitInvokeBinary(node, '/'); |
| 1212 visitMultiply(HMultiply node) => visitInvokeBinary(node, '*'); | 1216 visitMultiply(HMultiply node) => visitInvokeBinary(node, '*'); |
| 1213 visitSubtract(HSubtract node) => visitInvokeBinary(node, '-'); | 1217 visitSubtract(HSubtract node) => visitInvokeBinary(node, '-'); |
| 1214 // Truncating divide does not have a JS equivalent. | 1218 // Truncating divide does not have a JS equivalent. |
| 1215 visitTruncatingDivide(HTruncatingDivide node) => visitInvokeStatic(node); | 1219 visitTruncatingDivide(HTruncatingDivide node) => visitInvokeStatic(node); |
| 1216 // Modulo cannot be mapped to the native operator (different semantics). | 1220 // Modulo cannot be mapped to the native operator (different semantics). |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1401 methodName = node.name.slowToString(); | 1405 methodName = node.name.slowToString(); |
| 1402 arguments = visitArguments(node.inputs); | 1406 arguments = visitArguments(node.inputs); |
| 1403 } else { | 1407 } else { |
| 1404 methodName = compiler.namer.instanceMethodInvocationName( | 1408 methodName = compiler.namer.instanceMethodInvocationName( |
| 1405 currentLibrary, node.name, node.selector); | 1409 currentLibrary, node.name, node.selector); |
| 1406 arguments = visitArguments(node.inputs); | 1410 arguments = visitArguments(node.inputs); |
| 1407 bool inLoop = node.block.enclosingLoopHeader !== null; | 1411 bool inLoop = node.block.enclosingLoopHeader !== null; |
| 1408 | 1412 |
| 1409 // Register this invocation to collect the types used at all call sites. | 1413 // Register this invocation to collect the types used at all call sites. |
| 1410 Selector selector = getOptimizedSelectorFor(node, node.selector); | 1414 Selector selector = getOptimizedSelectorFor(node, node.selector); |
| 1411 backend.registerDynamicInvocation(node, selector); | 1415 backend.registerDynamicInvocation(node, selector, types); |
| 1412 | 1416 |
| 1413 // If we don't know what we're calling or if we are calling a getter, | 1417 // If we don't know what we're calling or if we are calling a getter, |
| 1414 // we need to register that fact that we may be calling a closure | 1418 // we need to register that fact that we may be calling a closure |
| 1415 // with the same arguments. | 1419 // with the same arguments. |
| 1416 Element target = node.element; | 1420 Element target = node.element; |
| 1417 if (target === null || target.isGetter()) { | 1421 if (target === null || target.isGetter()) { |
| 1418 // TODO(kasperl): If we have a typed selector for the call, we | 1422 // TODO(kasperl): If we have a typed selector for the call, we |
| 1419 // may know something about the types of closures that need | 1423 // may know something about the types of closures that need |
| 1420 // the specific closure call method. | 1424 // the specific closure call method. |
| 1421 Selector call = new Selector.callClosureFrom(selector); | 1425 Selector call = new Selector.callClosureFrom(selector); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1432 world.registerDynamicInvocation(node.name, selector); | 1436 world.registerDynamicInvocation(node.name, selector); |
| 1433 } | 1437 } |
| 1434 } | 1438 } |
| 1435 push(jsPropertyCall(object, methodName, arguments), node); | 1439 push(jsPropertyCall(object, methodName, arguments), node); |
| 1436 } | 1440 } |
| 1437 | 1441 |
| 1438 Selector getOptimizedSelectorFor(HInvokeDynamic node, | 1442 Selector getOptimizedSelectorFor(HInvokeDynamic node, |
| 1439 Selector defaultSelector) { | 1443 Selector defaultSelector) { |
| 1440 // TODO(4434): For private members we need to use the untyped selector. | 1444 // TODO(4434): For private members we need to use the untyped selector. |
| 1441 if (node.name.isPrivate()) return defaultSelector; | 1445 if (node.name.isPrivate()) return defaultSelector; |
| 1442 Type receiverType = node.inputs[0].propagatedType.computeType(compiler); | 1446 HType receiverHType = types[node.inputs[0]]; |
| 1447 Type receiverType = receiverHType.computeType(compiler); |
| 1443 if (receiverType !== null) { | 1448 if (receiverType !== null) { |
| 1444 return new TypedSelector(receiverType, defaultSelector); | 1449 return new TypedSelector(receiverType, defaultSelector); |
| 1445 } else { | 1450 } else { |
| 1446 return defaultSelector; | 1451 return defaultSelector; |
| 1447 } | 1452 } |
| 1448 } | 1453 } |
| 1449 | 1454 |
| 1450 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { | 1455 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
| 1451 use(node.receiver); | 1456 use(node.receiver); |
| 1452 push(jsPropertyCall(pop(), | 1457 push(jsPropertyCall(pop(), |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1476 visitArguments(node.inputs)), | 1481 visitArguments(node.inputs)), |
| 1477 node); | 1482 node); |
| 1478 Selector call = new Selector.callClosureFrom(node.selector); | 1483 Selector call = new Selector.callClosureFrom(node.selector); |
| 1479 world.registerDynamicInvocation(call.name, call); | 1484 world.registerDynamicInvocation(call.name, call); |
| 1480 } | 1485 } |
| 1481 | 1486 |
| 1482 visitInvokeStatic(HInvokeStatic node) { | 1487 visitInvokeStatic(HInvokeStatic node) { |
| 1483 if (Elements.isStaticOrTopLevelFunction(node.element) && | 1488 if (Elements.isStaticOrTopLevelFunction(node.element) && |
| 1484 node.typeCode() == HInvokeStatic.INVOKE_STATIC_TYPECODE) { | 1489 node.typeCode() == HInvokeStatic.INVOKE_STATIC_TYPECODE) { |
| 1485 // Register this invocation to collect the types used at all call sites. | 1490 // Register this invocation to collect the types used at all call sites. |
| 1486 backend.registerStaticInvocation(node); | 1491 backend.registerStaticInvocation(node, types); |
| 1487 } | 1492 } |
| 1488 use(node.target); | 1493 use(node.target); |
| 1489 push(new js.Call(pop(), visitArguments(node.inputs)), node); | 1494 push(new js.Call(pop(), visitArguments(node.inputs)), node); |
| 1490 } | 1495 } |
| 1491 | 1496 |
| 1492 visitInvokeSuper(HInvokeSuper node) { | 1497 visitInvokeSuper(HInvokeSuper node) { |
| 1493 Element superMethod = node.element; | 1498 Element superMethod = node.element; |
| 1494 Element superClass = superMethod.getEnclosingClass(); | 1499 Element superClass = superMethod.getEnclosingClass(); |
| 1495 // Remove the element and 'this'. | 1500 // Remove the element and 'this'. |
| 1496 int argumentCount = node.inputs.length - 2; | 1501 int argumentCount = node.inputs.length - 2; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1542 compiler.namer.instanceFieldName(node.library, node.fieldName); | 1547 compiler.namer.instanceFieldName(node.library, node.fieldName); |
| 1543 use(node.receiver); | 1548 use(node.receiver); |
| 1544 push(new js.PropertyAccess.field(pop(), name), node); | 1549 push(new js.PropertyAccess.field(pop(), name), node); |
| 1545 if (node.element == null) { | 1550 if (node.element == null) { |
| 1546 // If we don't have an element we register a dynamic field getter. | 1551 // If we don't have an element we register a dynamic field getter. |
| 1547 // This might lead to unnecessary getters, but these cases should be | 1552 // This might lead to unnecessary getters, but these cases should be |
| 1548 // rare. | 1553 // rare. |
| 1549 Selector getter = new Selector.getter(node.fieldName, node.library); | 1554 Selector getter = new Selector.getter(node.fieldName, node.library); |
| 1550 world.registerDynamicGetter(node.fieldName, getter); | 1555 world.registerDynamicGetter(node.fieldName, getter); |
| 1551 } else { | 1556 } else { |
| 1552 Type type = node.receiver.propagatedType.computeType(compiler); | 1557 HType receiverHType = types[node.receiver]; |
| 1558 Type type = receiverHType.computeType(compiler); |
| 1553 if (type != null) { | 1559 if (type != null) { |
| 1554 world.registerFieldGetter(node.element.name, node.library, type); | 1560 world.registerFieldGetter(node.element.name, node.library, type); |
| 1555 } | 1561 } |
| 1556 } | 1562 } |
| 1557 } | 1563 } |
| 1558 | 1564 |
| 1559 // Determine if an instruction is a simple number computation | 1565 // Determine if an instruction is a simple number computation |
| 1560 // involving only things with guaranteed number types and a given | 1566 // involving only things with guaranteed number types and a given |
| 1561 // field. | 1567 // field. |
| 1562 bool isSimpleFieldNumberComputation(HInstruction value, HFieldSet node) { | 1568 bool isSimpleFieldNumberComputation(HInstruction value, HFieldSet node) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1580 } | 1586 } |
| 1581 String name = | 1587 String name = |
| 1582 compiler.namer.instanceFieldName(node.library, node.fieldName); | 1588 compiler.namer.instanceFieldName(node.library, node.fieldName); |
| 1583 if (node.element == null) { | 1589 if (node.element == null) { |
| 1584 // If we don't have an element we register a dynamic field setter. | 1590 // If we don't have an element we register a dynamic field setter. |
| 1585 // This might lead to unnecessary setters, but these cases should be | 1591 // This might lead to unnecessary setters, but these cases should be |
| 1586 // rare. | 1592 // rare. |
| 1587 Selector setter = new Selector.setter(node.fieldName, node.library); | 1593 Selector setter = new Selector.setter(node.fieldName, node.library); |
| 1588 world.registerDynamicSetter(node.fieldName, setter); | 1594 world.registerDynamicSetter(node.fieldName, setter); |
| 1589 } else { | 1595 } else { |
| 1590 Type type = node.receiver.propagatedType.computeType(compiler); | 1596 Type type = types[node.receiver].computeType(compiler); |
| 1591 if (type != null) { | 1597 if (type != null) { |
| 1592 if (!work.element.isGenerativeConstructorBody()) { | 1598 if (!work.element.isGenerativeConstructorBody()) { |
| 1593 world.registerFieldSetter(node.element.name, node.library, type); | 1599 world.registerFieldSetter(node.element.name, node.library, type); |
| 1594 } | 1600 } |
| 1595 // Determine the types seen so far for the field. If only number | 1601 // Determine the types seen so far for the field. If only number |
| 1596 // types have been seen and the value of the field set is a | 1602 // types have been seen and the value of the field set is a |
| 1597 // simple number computation only depending on that field, we | 1603 // simple number computation only depending on that field, we |
| 1598 // can safely keep the number type for the field. | 1604 // can safely keep the number type for the field. |
| 1599 HType fieldSettersType = backend.fieldSettersTypeSoFar(node.element); | 1605 HType fieldSettersType = backend.fieldSettersTypeSoFar(node.element); |
| 1600 HType initializersType = | 1606 HType initializersType = |
| 1601 backend.typeFromInitializersSoFar(node.element); | 1607 backend.typeFromInitializersSoFar(node.element); |
| 1602 HType fieldType = fieldSettersType.union(initializersType); | 1608 HType fieldType = fieldSettersType.union(initializersType); |
| 1603 if (HType.NUMBER.union(fieldType) == HType.NUMBER && | 1609 if (HType.NUMBER.union(fieldType) == HType.NUMBER && |
| 1604 isSimpleFieldNumberComputation(node.value, node)) { | 1610 isSimpleFieldNumberComputation(node.value, node)) { |
| 1605 backend.updateFieldSetters(node.element, HType.NUMBER); | 1611 backend.updateFieldSetters(node.element, HType.NUMBER); |
| 1606 } else { | 1612 } else { |
| 1607 backend.updateFieldSetters(node.element, | 1613 backend.updateFieldSetters(node.element, types[node.value]); |
| 1608 node.value.propagatedType); | |
| 1609 } | 1614 } |
| 1610 } | 1615 } |
| 1611 } | 1616 } |
| 1612 use(node.receiver); | 1617 use(node.receiver); |
| 1613 js.Expression receiver = pop(); | 1618 js.Expression receiver = pop(); |
| 1614 use(node.value); | 1619 use(node.value); |
| 1615 push(new js.Assignment(new js.PropertyAccess.field(receiver, name), pop()), | 1620 push(new js.Assignment(new js.PropertyAccess.field(receiver, name), pop()), |
| 1616 node); | 1621 node); |
| 1617 } | 1622 } |
| 1618 | 1623 |
| 1619 visitLocalGet(HLocalGet node) { | 1624 visitLocalGet(HLocalGet node) { |
| 1620 use(node.receiver); | 1625 use(node.receiver); |
| 1621 } | 1626 } |
| 1622 | 1627 |
| 1623 visitLocalSet(HLocalSet node) { | 1628 visitLocalSet(HLocalSet node) { |
| 1624 use(node.value); | 1629 use(node.value); |
| 1625 assignVariable(variableNames.getName(node.receiver), pop()); | 1630 assignVariable(variableNames.getName(node.receiver), pop()); |
| 1626 } | 1631 } |
| 1627 | 1632 |
| 1628 visitForeign(HForeign node) { | 1633 visitForeign(HForeign node) { |
| 1629 String code = node.code.slowToString(); | 1634 String code = node.code.slowToString(); |
| 1630 List<HInstruction> inputs = node.inputs; | 1635 List<HInstruction> inputs = node.inputs; |
| 1631 if (node.isStatement) { | 1636 if (node.isStatement(types)) { |
| 1632 if (!inputs.isEmpty()) { | 1637 if (!inputs.isEmpty()) { |
| 1633 compiler.internalError("foreign statement with inputs: $code", | 1638 compiler.internalError("foreign statement with inputs: $code", |
| 1634 instruction: node); | 1639 instruction: node); |
| 1635 } | 1640 } |
| 1636 pushStatement(new js.LiteralStatement(code), node); | 1641 pushStatement(new js.LiteralStatement(code), node); |
| 1637 } else { | 1642 } else { |
| 1638 List<js.Expression> data = <js.Expression>[]; | 1643 List<js.Expression> data = <js.Expression>[]; |
| 1639 for (int i = 0; i < inputs.length; i++) { | 1644 for (int i = 0; i < inputs.length; i++) { |
| 1640 use(inputs[i]); | 1645 use(inputs[i]); |
| 1641 data.add(pop()); | 1646 data.add(pop()); |
| 1642 } | 1647 } |
| 1643 push(new js.LiteralExpression.withData(code, data), node); | 1648 push(new js.LiteralExpression.withData(code, data), node); |
| 1644 } | 1649 } |
| 1645 } | 1650 } |
| 1646 | 1651 |
| 1647 visitForeignNew(HForeignNew node) { | 1652 visitForeignNew(HForeignNew node) { |
| 1648 int j = 0; | 1653 int j = 0; |
| 1649 node.element.forEachInstanceField( | 1654 node.element.forEachInstanceField( |
| 1650 includeBackendMembers: true, | 1655 includeBackendMembers: true, |
| 1651 includeSuperMembers: true, | 1656 includeSuperMembers: true, |
| 1652 f: (ClassElement enclosingClass, Element member) { | 1657 f: (ClassElement enclosingClass, Element member) { |
| 1653 backend.updateFieldInitializers(member, | 1658 backend.updateFieldInitializers(member, types[node.inputs[j]]); |
| 1654 node.inputs[j].propagatedType); | |
| 1655 j++; | 1659 j++; |
| 1656 }); | 1660 }); |
| 1657 String jsClassReference = compiler.namer.isolateAccess(node.element); | 1661 String jsClassReference = compiler.namer.isolateAccess(node.element); |
| 1658 List<HInstruction> inputs = node.inputs; | 1662 List<HInstruction> inputs = node.inputs; |
| 1659 // We can't use 'visitArguments', since our arguments start at input[0]. | 1663 // We can't use 'visitArguments', since our arguments start at input[0]. |
| 1660 List<js.Expression> arguments = <js.Expression>[]; | 1664 List<js.Expression> arguments = <js.Expression>[]; |
| 1661 for (int i = 0; i < inputs.length; i++) { | 1665 for (int i = 0; i < inputs.length; i++) { |
| 1662 use(inputs[i]); | 1666 use(inputs[i]); |
| 1663 arguments.add(pop()); | 1667 arguments.add(pop()); |
| 1664 } | 1668 } |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1742 assert(node.inputs.length == 1); | 1746 assert(node.inputs.length == 1); |
| 1743 generateNot(node.inputs[0]); | 1747 generateNot(node.inputs[0]); |
| 1744 attachLocationToLast(node); | 1748 attachLocationToLast(node); |
| 1745 } | 1749 } |
| 1746 | 1750 |
| 1747 | 1751 |
| 1748 void generateNot(HInstruction input) { | 1752 void generateNot(HInstruction input) { |
| 1749 bool isBuiltinRelational(HInstruction instruction) { | 1753 bool isBuiltinRelational(HInstruction instruction) { |
| 1750 if (instruction is !HRelational) return false; | 1754 if (instruction is !HRelational) return false; |
| 1751 HRelational relational = instruction; | 1755 HRelational relational = instruction; |
| 1752 return relational.builtin; | 1756 return relational.isBuiltin(types); |
| 1753 } | 1757 } |
| 1754 | 1758 |
| 1755 if (input is HBoolify && isGenerateAtUseSite(input)) { | 1759 if (input is HBoolify && isGenerateAtUseSite(input)) { |
| 1756 use(input.inputs[0]); | 1760 use(input.inputs[0]); |
| 1757 push(new js.Binary("!==", pop(), new js.LiteralBool(true)), input); | 1761 push(new js.Binary("!==", pop(), new js.LiteralBool(true)), input); |
| 1758 } else if (isBuiltinRelational(input) && | 1762 } else if (isBuiltinRelational(input) && |
| 1759 isGenerateAtUseSite(input) && | 1763 isGenerateAtUseSite(input) && |
| 1760 input.inputs[0].propagatedType.isUseful() && | 1764 types[input.inputs[0]].isUseful() && |
| 1761 !input.inputs[0].isDouble() && | 1765 !input.inputs[0].isDouble(types) && |
| 1762 input.inputs[1].propagatedType.isUseful() && | 1766 types[input.inputs[1]].isUseful() && |
| 1763 !input.inputs[1].isDouble()) { | 1767 !input.inputs[1].isDouble(types)) { |
| 1764 // This optimization doesn't work for NaN, so we only do it if the | 1768 // This optimization doesn't work for NaN, so we only do it if the |
| 1765 // type is known to be non-Double. | 1769 // type is known to be non-Double. |
| 1766 Map<String, String> inverseOperator = const <String>{ | 1770 Map<String, String> inverseOperator = const <String>{ |
| 1767 "==" : "!=", | 1771 "==" : "!=", |
| 1768 "!=" : "==", | 1772 "!=" : "==", |
| 1769 "===": "!==", | 1773 "===": "!==", |
| 1770 "!==": "===", | 1774 "!==": "===", |
| 1771 "<" : ">=", | 1775 "<" : ">=", |
| 1772 "<=" : ">", | 1776 "<=" : ">", |
| 1773 ">" : "<=", | 1777 ">" : "<=", |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1955 } | 1959 } |
| 1956 | 1960 |
| 1957 bool isEmptyString(HInstruction node) { | 1961 bool isEmptyString(HInstruction node) { |
| 1958 if (!node.isConstantString()) return false; | 1962 if (!node.isConstantString()) return false; |
| 1959 HConstant constant = node; | 1963 HConstant constant = node; |
| 1960 StringConstant string = constant.constant; | 1964 StringConstant string = constant.constant; |
| 1961 return string.value.length == 0; | 1965 return string.value.length == 0; |
| 1962 } | 1966 } |
| 1963 | 1967 |
| 1964 void useStringified(HInstruction node) { | 1968 void useStringified(HInstruction node) { |
| 1965 if (node.isString()) { | 1969 if (node.isString(types)) { |
| 1966 use(node); | 1970 use(node); |
| 1967 } else { | 1971 } else { |
| 1968 Element convertToString = compiler.findHelper(const SourceString("S")); | 1972 Element convertToString = compiler.findHelper(const SourceString("S")); |
| 1969 world.registerStaticUse(convertToString); | 1973 world.registerStaticUse(convertToString); |
| 1970 js.VariableUse variableUse = | 1974 js.VariableUse variableUse = |
| 1971 new js.VariableUse(compiler.namer.isolateAccess(convertToString)); | 1975 new js.VariableUse(compiler.namer.isolateAccess(convertToString)); |
| 1972 use(node); | 1976 use(node); |
| 1973 push(new js.Call(variableUse, <js.Expression>[pop()]), node); | 1977 push(new js.Call(variableUse, <js.Expression>[pop()]), node); |
| 1974 } | 1978 } |
| 1975 } | 1979 } |
| 1976 | 1980 |
| 1977 void visitLiteralList(HLiteralList node) { | 1981 void visitLiteralList(HLiteralList node) { |
| 1978 generateArrayLiteral(node); | 1982 generateArrayLiteral(node); |
| 1979 } | 1983 } |
| 1980 | 1984 |
| 1981 void generateArrayLiteral(HLiteralList node) { | 1985 void generateArrayLiteral(HLiteralList node) { |
| 1982 int len = node.inputs.length; | 1986 int len = node.inputs.length; |
| 1983 List<js.ArrayElement> elements = <js.ArrayElement>[]; | 1987 List<js.ArrayElement> elements = <js.ArrayElement>[]; |
| 1984 for (int i = 0; i < len; i++) { | 1988 for (int i = 0; i < len; i++) { |
| 1985 use(node.inputs[i]); | 1989 use(node.inputs[i]); |
| 1986 elements.add(new js.ArrayElement(i, pop())); | 1990 elements.add(new js.ArrayElement(i, pop())); |
| 1987 } | 1991 } |
| 1988 push(new js.ArrayInitializer(len, elements), node); | 1992 push(new js.ArrayInitializer(len, elements), node); |
| 1989 } | 1993 } |
| 1990 | 1994 |
| 1991 void visitIndex(HIndex node) { | 1995 void visitIndex(HIndex node) { |
| 1992 if (node.builtin) { | 1996 if (node.isBuiltin(types)) { |
| 1993 use(node.inputs[1]); | 1997 use(node.inputs[1]); |
| 1994 js.Expression receiver = pop(); | 1998 js.Expression receiver = pop(); |
| 1995 use(node.inputs[2]); | 1999 use(node.inputs[2]); |
| 1996 push(new js.PropertyAccess(receiver, pop()), node); | 2000 push(new js.PropertyAccess(receiver, pop()), node); |
| 1997 } else { | 2001 } else { |
| 1998 visitInvokeStatic(node); | 2002 visitInvokeStatic(node); |
| 1999 } | 2003 } |
| 2000 } | 2004 } |
| 2001 | 2005 |
| 2002 void visitIndexAssign(HIndexAssign node) { | 2006 void visitIndexAssign(HIndexAssign node) { |
| 2003 if (node.builtin) { | 2007 if (node.isBuiltin(types)) { |
| 2004 use(node.inputs[1]); | 2008 use(node.inputs[1]); |
| 2005 js.Expression receiver = pop(); | 2009 js.Expression receiver = pop(); |
| 2006 use(node.inputs[2]); | 2010 use(node.inputs[2]); |
| 2007 js.Expression index = pop(); | 2011 js.Expression index = pop(); |
| 2008 use(node.inputs[3]); | 2012 use(node.inputs[3]); |
| 2009 push(new js.Assignment(new js.PropertyAccess(receiver, index), pop()), | 2013 push(new js.Assignment(new js.PropertyAccess(receiver, index), pop()), |
| 2010 node); | 2014 node); |
| 2011 } else { | 2015 } else { |
| 2012 visitInvokeStatic(node); | 2016 visitInvokeStatic(node); |
| 2013 } | 2017 } |
| 2014 } | 2018 } |
| 2015 | 2019 |
| 2016 String builtinJsName(HInvokeInterceptor interceptor) { | 2020 String builtinJsName(HInvokeInterceptor interceptor) { |
| 2017 // Don't count the target method or the receiver in the arity. | 2021 // Don't count the target method or the receiver in the arity. |
| 2018 int arity = interceptor.inputs.length - 2; | 2022 int arity = interceptor.inputs.length - 2; |
| 2019 HInstruction receiver = interceptor.inputs[1]; | 2023 HInstruction receiver = interceptor.inputs[1]; |
| 2020 bool getter = interceptor.getter; | 2024 bool getter = interceptor.getter; |
| 2021 SourceString name = interceptor.name; | 2025 SourceString name = interceptor.name; |
| 2022 | 2026 |
| 2023 if (interceptor.isLengthGetterOnStringOrArray()) { | 2027 if (interceptor.isLengthGetterOnStringOrArray(types)) { |
| 2024 return 'length'; | 2028 return 'length'; |
| 2025 } else if (receiver.isExtendableArray() && !getter) { | 2029 } else if (receiver.isExtendableArray(types) && !getter) { |
| 2026 if (name == const SourceString('add') && arity == 1) { | 2030 if (name == const SourceString('add') && arity == 1) { |
| 2027 return 'push'; | 2031 return 'push'; |
| 2028 } | 2032 } |
| 2029 if (name == const SourceString('removeLast') && arity == 0) { | 2033 if (name == const SourceString('removeLast') && arity == 0) { |
| 2030 return 'pop'; | 2034 return 'pop'; |
| 2031 } | 2035 } |
| 2032 } else if (receiver.isString() && !getter) { | 2036 } else if (receiver.isString(types) && !getter) { |
| 2033 if (name == const SourceString('concat') && | 2037 if (name == const SourceString('concat') && |
| 2034 arity == 1 && | 2038 arity == 1 && |
| 2035 interceptor.inputs[2].isString()) { | 2039 interceptor.inputs[2].isString(types)) { |
| 2036 return '+'; | 2040 return '+'; |
| 2037 } | 2041 } |
| 2038 } | 2042 } |
| 2039 | 2043 |
| 2040 return null; | 2044 return null; |
| 2041 } | 2045 } |
| 2042 | 2046 |
| 2043 void visitInvokeInterceptor(HInvokeInterceptor node) { | 2047 void visitInvokeInterceptor(HInvokeInterceptor node) { |
| 2044 String builtin = builtinJsName(node); | 2048 String builtin = builtinJsName(node); |
| 2045 if (builtin !== null) { | 2049 if (builtin !== null) { |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2234 js.Expression numTest = pop(); | 2238 js.Expression numTest = pop(); |
| 2235 checkInt(input, '==='); | 2239 checkInt(input, '==='); |
| 2236 push(new js.Binary('&&', numTest, pop()), node); | 2240 push(new js.Binary('&&', numTest, pop()), node); |
| 2237 } else if (Elements.isStringSupertype(element, compiler)) { | 2241 } else if (Elements.isStringSupertype(element, compiler)) { |
| 2238 handleStringSupertypeCheck(input, element); | 2242 handleStringSupertypeCheck(input, element); |
| 2239 attachLocationToLast(node); | 2243 attachLocationToLast(node); |
| 2240 } else if (element === compiler.listClass | 2244 } else if (element === compiler.listClass |
| 2241 || Elements.isListSupertype(element, compiler)) { | 2245 || Elements.isListSupertype(element, compiler)) { |
| 2242 handleListOrSupertypeCheck(input, element); | 2246 handleListOrSupertypeCheck(input, element); |
| 2243 attachLocationToLast(node); | 2247 attachLocationToLast(node); |
| 2244 } else if (input.propagatedType.canBePrimitive() | 2248 } else if (types[input].canBePrimitive() || types[input].canBeNull()) { |
| 2245 || input.propagatedType.canBeNull()) { | |
| 2246 checkObject(input, '==='); | 2249 checkObject(input, '==='); |
| 2247 js.Expression objectTest = pop(); | 2250 js.Expression objectTest = pop(); |
| 2248 checkType(input, element); | 2251 checkType(input, element); |
| 2249 push(new js.Binary('&&', objectTest, pop()), node); | 2252 push(new js.Binary('&&', objectTest, pop()), node); |
| 2250 } else { | 2253 } else { |
| 2251 checkType(input, element); | 2254 checkType(input, element); |
| 2252 attachLocationToLast(node); | 2255 attachLocationToLast(node); |
| 2253 } | 2256 } |
| 2254 if (compiler.codegenWorld.rti.hasTypeArguments(type)) { | 2257 if (compiler.codegenWorld.rti.hasTypeArguments(type)) { |
| 2255 InterfaceType interfaceType = type; | 2258 InterfaceType interfaceType = type; |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2446 bailoutTarget = new js.VariableUse(namer.isolateBailoutAccess(element)); | 2449 bailoutTarget = new js.VariableUse(namer.isolateBailoutAccess(element)); |
| 2447 } | 2450 } |
| 2448 js.Call call = new js.Call(bailoutTarget, arguments); | 2451 js.Call call = new js.Call(bailoutTarget, arguments); |
| 2449 attachLocation(call, guard); | 2452 attachLocation(call, guard); |
| 2450 return new js.Return(call); | 2453 return new js.Return(call); |
| 2451 } | 2454 } |
| 2452 | 2455 |
| 2453 void visitTypeGuard(HTypeGuard node) { | 2456 void visitTypeGuard(HTypeGuard node) { |
| 2454 HInstruction input = node.guarded; | 2457 HInstruction input = node.guarded; |
| 2455 Element indexingBehavior = compiler.jsIndexingBehaviorInterface; | 2458 Element indexingBehavior = compiler.jsIndexingBehaviorInterface; |
| 2456 if (node.isInteger()) { | 2459 if (node.isInteger(types)) { |
| 2457 // if (input is !int) bailout | 2460 // if (input is !int) bailout |
| 2458 checkInt(input, '!=='); | 2461 checkInt(input, '!=='); |
| 2459 pushStatement(new js.If.then(pop(), bailout(node, 'Not an integer')), | 2462 pushStatement(new js.If.then(pop(), bailout(node, 'Not an integer')), |
| 2460 node); | 2463 node); |
| 2461 } else if (node.isNumber()) { | 2464 } else if (node.isNumber(types)) { |
| 2462 // if (input is !num) bailout | 2465 // if (input is !num) bailout |
| 2463 checkNum(input, '!=='); | 2466 checkNum(input, '!=='); |
| 2464 pushStatement(new js.If.then(pop(), bailout(node, 'Not a number')), node); | 2467 pushStatement(new js.If.then(pop(), bailout(node, 'Not a number')), node); |
| 2465 } else if (node.isBoolean()) { | 2468 } else if (node.isBoolean(types)) { |
| 2466 // if (input is !bool) bailout | 2469 // if (input is !bool) bailout |
| 2467 checkBool(input, '!=='); | 2470 checkBool(input, '!=='); |
| 2468 pushStatement(new js.If.then(pop(), bailout(node, 'Not a boolean')), | 2471 pushStatement(new js.If.then(pop(), bailout(node, 'Not a boolean')), |
| 2469 node); | 2472 node); |
| 2470 } else if (node.isString()) { | 2473 } else if (node.isString(types)) { |
| 2471 // if (input is !string) bailout | 2474 // if (input is !string) bailout |
| 2472 checkString(input, '!=='); | 2475 checkString(input, '!=='); |
| 2473 pushStatement(new js.If.then(pop(), bailout(node, 'Not a string')), node); | 2476 pushStatement(new js.If.then(pop(), bailout(node, 'Not a string')), node); |
| 2474 } else if (node.isExtendableArray()) { | 2477 } else if (node.isExtendableArray(types)) { |
| 2475 // if (input is !Object || input is !Array || input.isFixed) bailout | 2478 // if (input is !Object || input is !Array || input.isFixed) bailout |
| 2476 checkObject(input, '!=='); | 2479 checkObject(input, '!=='); |
| 2477 js.Expression objectTest = pop(); | 2480 js.Expression objectTest = pop(); |
| 2478 checkArray(input, '!=='); | 2481 checkArray(input, '!=='); |
| 2479 js.Expression arrayTest = pop(); | 2482 js.Expression arrayTest = pop(); |
| 2480 checkFixedArray(input); | 2483 checkFixedArray(input); |
| 2481 js.Expression test = new js.Binary('||', objectTest, arrayTest); | 2484 js.Expression test = new js.Binary('||', objectTest, arrayTest); |
| 2482 test = new js.Binary('||', test, pop()); | 2485 test = new js.Binary('||', test, pop()); |
| 2483 pushStatement(new js.If.then(test, | 2486 pushStatement(new js.If.then(test, |
| 2484 bailout(node, 'Not an extendable array')), | 2487 bailout(node, 'Not an extendable array')), |
| 2485 node); | 2488 node); |
| 2486 } else if (node.isMutableArray()) { | 2489 } else if (node.isMutableArray(types)) { |
| 2487 // if (input is !Object | 2490 // if (input is !Object |
| 2488 // || ((input is !Array || input.isImmutable) | 2491 // || ((input is !Array || input.isImmutable) |
| 2489 // && input is !JsIndexingBehavior)) bailout | 2492 // && input is !JsIndexingBehavior)) bailout |
| 2490 checkObject(input, '!=='); | 2493 checkObject(input, '!=='); |
| 2491 js.Expression objectTest = pop(); | 2494 js.Expression objectTest = pop(); |
| 2492 checkArray(input, '!=='); | 2495 checkArray(input, '!=='); |
| 2493 js.Expression arrayTest = pop(); | 2496 js.Expression arrayTest = pop(); |
| 2494 checkImmutableArray(input); | 2497 checkImmutableArray(input); |
| 2495 js.Binary notArrayOrImmutable = new js.Binary('||', arrayTest, pop()); | 2498 js.Binary notArrayOrImmutable = new js.Binary('||', arrayTest, pop()); |
| 2496 checkType(input, indexingBehavior, negative: true); | 2499 checkType(input, indexingBehavior, negative: true); |
| 2497 js.Binary notIndexing = new js.Binary('&&', notArrayOrImmutable, pop()); | 2500 js.Binary notIndexing = new js.Binary('&&', notArrayOrImmutable, pop()); |
| 2498 pushStatement(new js.If.then(new js.Binary('||', objectTest, notIndexing), | 2501 pushStatement(new js.If.then(new js.Binary('||', objectTest, notIndexing), |
| 2499 bailout(node, 'Not a mutable array')), | 2502 bailout(node, 'Not a mutable array')), |
| 2500 node); | 2503 node); |
| 2501 } else if (node.isReadableArray()) { | 2504 } else if (node.isReadableArray(types)) { |
| 2502 // if (input is !Object | 2505 // if (input is !Object |
| 2503 // || (input is !Array && input is !JsIndexingBehavior)) bailout | 2506 // || (input is !Array && input is !JsIndexingBehavior)) bailout |
| 2504 checkObject(input, '!=='); | 2507 checkObject(input, '!=='); |
| 2505 js.Expression objectTest = pop(); | 2508 js.Expression objectTest = pop(); |
| 2506 checkArray(input, '!=='); | 2509 checkArray(input, '!=='); |
| 2507 js.Expression arrayTest = pop(); | 2510 js.Expression arrayTest = pop(); |
| 2508 checkType(input, indexingBehavior, negative: true); | 2511 checkType(input, indexingBehavior, negative: true); |
| 2509 js.Expression notIndexing = new js.Binary('&&', arrayTest, pop()); | 2512 js.Expression notIndexing = new js.Binary('&&', arrayTest, pop()); |
| 2510 pushStatement(new js.If.then(new js.Binary('||', objectTest, notIndexing), | 2513 pushStatement(new js.If.then(new js.Binary('||', objectTest, notIndexing), |
| 2511 bailout(node, 'Not an array')), | 2514 bailout(node, 'Not an array')), |
| 2512 node); | 2515 node); |
| 2513 } else if (node.isIndexablePrimitive()) { | 2516 } else if (node.isIndexablePrimitive(types)) { |
| 2514 // if (input is !String | 2517 // if (input is !String |
| 2515 // && (input is !Object | 2518 // && (input is !Object |
| 2516 // || (input is !Array && input is !JsIndexingBehavior))) bailout | 2519 // || (input is !Array && input is !JsIndexingBehavior))) bailout |
| 2517 checkString(input, '!=='); | 2520 checkString(input, '!=='); |
| 2518 js.Expression stringTest = pop(); | 2521 js.Expression stringTest = pop(); |
| 2519 checkObject(input, '!=='); | 2522 checkObject(input, '!=='); |
| 2520 js.Expression objectTest = pop(); | 2523 js.Expression objectTest = pop(); |
| 2521 checkArray(input, '!=='); | 2524 checkArray(input, '!=='); |
| 2522 js.Expression arrayTest = pop(); | 2525 js.Expression arrayTest = pop(); |
| 2523 checkType(input, indexingBehavior, negative: true); | 2526 checkType(input, indexingBehavior, negative: true); |
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2881 } | 2884 } |
| 2882 } | 2885 } |
| 2883 | 2886 |
| 2884 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2887 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2885 if (labeledBlockInfo.body.start.hasBailoutTargets()) { | 2888 if (labeledBlockInfo.body.start.hasBailoutTargets()) { |
| 2886 endBailoutSwitch(); | 2889 endBailoutSwitch(); |
| 2887 } | 2890 } |
| 2888 } | 2891 } |
| 2889 } | 2892 } |
| 2890 | 2893 |
| 2891 String singleIdentityComparison(HInstruction left, HInstruction right) { | 2894 String singleIdentityComparison(HInstruction left, |
| 2895 HInstruction right, |
| 2896 HTypeMap propagatedTypes) { |
| 2892 // Returns the single identity comparison (== or ===) or null if a more | 2897 // Returns the single identity comparison (== or ===) or null if a more |
| 2893 // complex expression is required. | 2898 // complex expression is required. |
| 2894 HType leftType = left.propagatedType; | 2899 HType leftType = propagatedTypes[left]; |
| 2895 HType rightType = right.propagatedType; | 2900 HType rightType = propagatedTypes[right]; |
| 2896 if (leftType.canBeNull() && rightType.canBeNull()) { | 2901 if (leftType.canBeNull() && rightType.canBeNull()) { |
| 2897 if (left.isConstantNull() || right.isConstantNull() || | 2902 if (left.isConstantNull() || right.isConstantNull() || |
| 2898 (leftType.isPrimitive() && leftType == rightType)) { | 2903 (leftType.isPrimitive() && leftType == rightType)) { |
| 2899 return '=='; | 2904 return '=='; |
| 2900 } | 2905 } |
| 2901 return null; | 2906 return null; |
| 2902 } else { | 2907 } else { |
| 2903 return '==='; | 2908 return '==='; |
| 2904 } | 2909 } |
| 2905 } | 2910 } |
| OLD | NEW |