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

Side by Side Diff: lib/compiler/implementation/ssa/codegen.dart

Issue 10827180: Move types out of the HInstructions. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « lib/compiler/implementation/ssa/builder.dart ('k') | lib/compiler/implementation/ssa/codegen_helpers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698