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

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

Issue 2673513003: dart2js: Introduce HGetLength to replace strange use of HFieldGet (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; 5 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
6 import '../common/names.dart' show Selectors; 6 import '../common/names.dart' show Selectors;
7 import '../common/tasks.dart' show CompilerTask; 7 import '../common/tasks.dart' show CompilerTask;
8 import '../compiler.dart' show Compiler; 8 import '../compiler.dart' show Compiler;
9 import '../constants/constant_system.dart'; 9 import '../constants/constant_system.dart';
10 import '../constants/values.dart'; 10 import '../constants/values.dart';
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
78 trustPrimitives, backend, closedWorld, boundsChecked), 78 trustPrimitives, backend, closedWorld, boundsChecked),
79 new SsaTypePropagator(compiler, closedWorld), 79 new SsaTypePropagator(compiler, closedWorld),
80 // Run a dead code eliminator before LICM because dead 80 // Run a dead code eliminator before LICM because dead
81 // interceptors are often in the way of LICM'able instructions. 81 // interceptors are often in the way of LICM'able instructions.
82 new SsaDeadCodeEliminator(closedWorld, this), 82 new SsaDeadCodeEliminator(closedWorld, this),
83 new SsaGlobalValueNumberer(), 83 new SsaGlobalValueNumberer(),
84 // After GVN, some instructions might need their type to be 84 // After GVN, some instructions might need their type to be
85 // updated because they now have different inputs. 85 // updated because they now have different inputs.
86 new SsaTypePropagator(compiler, closedWorld), 86 new SsaTypePropagator(compiler, closedWorld),
87 codeMotion = new SsaCodeMotion(), 87 codeMotion = new SsaCodeMotion(),
88 new SsaLoadElimination(compiler, closedWorld), 88 new SsaLoadElimination(backend, compiler, closedWorld),
89 new SsaRedundantPhiEliminator(), 89 new SsaRedundantPhiEliminator(),
90 new SsaDeadPhiEliminator(), 90 new SsaDeadPhiEliminator(),
91 // After GVN and load elimination the same value may be used in code 91 // After GVN and load elimination the same value may be used in code
92 // controlled by a test on the value, so redo 'conversion insertion' to 92 // controlled by a test on the value, so redo 'conversion insertion' to
93 // learn from the refined type. 93 // learn from the refined type.
94 new SsaTypeConversionInserter(closedWorld), 94 new SsaTypeConversionInserter(closedWorld),
95 new SsaTypePropagator(compiler, closedWorld), 95 new SsaTypePropagator(compiler, closedWorld),
96 new SsaValueRangeAnalyzer(backend.helpers, closedWorld, this), 96 new SsaValueRangeAnalyzer(backend.helpers, closedWorld, this),
97 // Previous optimizations may have generated new 97 // Previous optimizations may have generated new
98 // opportunities for instruction simplification. 98 // opportunities for instruction simplification.
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 if (actualReceiver.isIndexablePrimitive(closedWorld)) { 342 if (actualReceiver.isIndexablePrimitive(closedWorld)) {
343 if (actualReceiver.isConstantString()) { 343 if (actualReceiver.isConstantString()) {
344 HConstant constantInput = actualReceiver; 344 HConstant constantInput = actualReceiver;
345 StringConstantValue constant = constantInput.constant; 345 StringConstantValue constant = constantInput.constant;
346 return graph.addConstantInt(constant.length, closedWorld); 346 return graph.addConstantInt(constant.length, closedWorld);
347 } else if (actualReceiver.isConstantList()) { 347 } else if (actualReceiver.isConstantList()) {
348 HConstant constantInput = actualReceiver; 348 HConstant constantInput = actualReceiver;
349 ListConstantValue constant = constantInput.constant; 349 ListConstantValue constant = constantInput.constant;
350 return graph.addConstantInt(constant.length, closedWorld); 350 return graph.addConstantInt(constant.length, closedWorld);
351 } 351 }
352 MemberEntity element = helpers.jsIndexableLength;
353 bool isFixed = isFixedLength(actualReceiver.instructionType, closedWorld); 352 bool isFixed = isFixedLength(actualReceiver.instructionType, closedWorld);
354 TypeMask actualType = node.instructionType; 353 TypeMask actualType = node.instructionType;
355 TypeMask resultType = closedWorld.commonMasks.positiveIntType; 354 TypeMask resultType = closedWorld.commonMasks.positiveIntType;
356 // If we already have computed a more specific type, keep that type. 355 // If we already have computed a more specific type, keep that type.
357 if (HInstruction.isInstanceOf( 356 if (HInstruction.isInstanceOf(
358 actualType, helpers.jsUInt31Class, closedWorld)) { 357 actualType, helpers.jsUInt31Class, closedWorld)) {
359 resultType = closedWorld.commonMasks.uint31Type; 358 resultType = closedWorld.commonMasks.uint31Type;
360 } else if (HInstruction.isInstanceOf( 359 } else if (HInstruction.isInstanceOf(
361 actualType, helpers.jsUInt32Class, closedWorld)) { 360 actualType, helpers.jsUInt32Class, closedWorld)) {
362 resultType = closedWorld.commonMasks.uint32Type; 361 resultType = closedWorld.commonMasks.uint32Type;
363 } 362 }
364 HFieldGet result = new HFieldGet(element, actualReceiver, resultType, 363 HGetLength result =
365 isAssignable: !isFixed); 364 new HGetLength(actualReceiver, resultType, isAssignable: !isFixed);
366 return result; 365 return result;
367 } else if (actualReceiver.isConstantMap()) { 366 } else if (actualReceiver.isConstantMap()) {
368 HConstant constantInput = actualReceiver; 367 HConstant constantInput = actualReceiver;
369 MapConstantValue constant = constantInput.constant; 368 MapConstantValue constant = constantInput.constant;
370 return graph.addConstantInt(constant.length, closedWorld); 369 return graph.addConstantInt(constant.length, closedWorld);
371 } 370 }
372 return null; 371 return null;
373 } 372 }
374 373
375 HInstruction handleInterceptedCall(HInvokeDynamic node) { 374 HInstruction handleInterceptedCall(HInvokeDynamic node) {
(...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after
862 861
863 FieldEntity findConcreteFieldForDynamicAccess( 862 FieldEntity findConcreteFieldForDynamicAccess(
864 HInstruction receiver, Selector selector) { 863 HInstruction receiver, Selector selector) {
865 TypeMask receiverType = receiver.instructionType; 864 TypeMask receiverType = receiver.instructionType;
866 return closedWorld.locateSingleField(selector, receiverType); 865 return closedWorld.locateSingleField(selector, receiverType);
867 } 866 }
868 867
869 HInstruction visitFieldGet(HFieldGet node) { 868 HInstruction visitFieldGet(HFieldGet node) {
870 if (node.isNullCheck) return node; 869 if (node.isNullCheck) return node;
871 var receiver = node.receiver; 870 var receiver = node.receiver;
872 if (node.element == helpers.jsIndexableLength) {
873 if (graph.allocatedFixedLists.contains(receiver)) {
874 // TODO(ngeoffray): checking if the second input is an integer
875 // should not be necessary but it currently makes it easier for
876 // other optimizations to reason about a fixed length constructor
877 // that we know takes an int.
878 if (receiver.inputs[0].isInteger(closedWorld)) {
879 return receiver.inputs[0];
880 }
881 } else if (receiver.isConstantList() || receiver.isConstantString()) {
882 return graph.addConstantInt(receiver.constant.length, closedWorld);
883 } else {
884 var type = receiver.instructionType;
885 if (type.isContainer && type.length != null) {
886 HInstruction constant =
887 graph.addConstantInt(type.length, closedWorld);
888 if (type.isNullable) {
889 // If the container can be null, we update all uses of the
890 // length access to use the constant instead, but keep the
891 // length access in the graph, to ensure we still have a
892 // null check.
893 node.block.rewrite(node, constant);
894 return node;
895 } else {
896 return constant;
897 }
898 }
899 }
900 }
901 871
902 // HFieldGet of a constructed constant can be replaced with the constant's 872 // HFieldGet of a constructed constant can be replaced with the constant's
903 // field. 873 // field.
904 if (receiver is HConstant) { 874 if (receiver is HConstant) {
905 ConstantValue constant = receiver.constant; 875 ConstantValue constant = receiver.constant;
906 if (constant.isConstructedObject) { 876 if (constant.isConstructedObject) {
907 ConstructedConstantValue constructedConstant = constant; 877 ConstructedConstantValue constructedConstant = constant;
908 Map<FieldEntity, ConstantValue> fields = constructedConstant.fields; 878 Map<FieldEntity, ConstantValue> fields = constructedConstant.fields;
909 ConstantValue value = fields[node.element]; 879 ConstantValue value = fields[node.element];
910 if (value != null) { 880 if (value != null) {
911 return graph.addConstant(value, closedWorld); 881 return graph.addConstant(value, closedWorld);
912 } 882 }
913 } 883 }
914 } 884 }
915 885
916 return node; 886 return node;
917 } 887 }
918 888
889 HInstruction visitGetLength(HGetLength node) {
890 var receiver = node.receiver;
891 if (graph.allocatedFixedLists.contains(receiver)) {
892 // TODO(ngeoffray): checking if the second input is an integer
893 // should not be necessary but it currently makes it easier for
894 // other optimizations to reason about a fixed length constructor
895 // that we know takes an int.
896 if (receiver.inputs[0].isInteger(closedWorld)) {
897 return receiver.inputs[0];
898 }
899 } else if (receiver.isConstantList() || receiver.isConstantString()) {
900 return graph.addConstantInt(receiver.constant.length, closedWorld);
901 } else {
902 var type = receiver.instructionType;
903 if (type.isContainer && type.length != null) {
904 HInstruction constant = graph.addConstantInt(type.length, closedWorld);
905 if (type.isNullable) {
906 // If the container can be null, we update all uses of the
907 // length access to use the constant instead, but keep the
908 // length access in the graph, to ensure we still have a
909 // null check.
910 node.block.rewrite(node, constant);
911 return node;
912 } else {
913 return constant;
914 }
915 }
916 }
917 return node;
918 }
919
919 HInstruction visitIndex(HIndex node) { 920 HInstruction visitIndex(HIndex node) {
920 if (node.receiver.isConstantList() && node.index.isConstantInteger()) { 921 if (node.receiver.isConstantList() && node.index.isConstantInteger()) {
921 var instruction = node.receiver; 922 var instruction = node.receiver;
922 List<ConstantValue> entries = instruction.constant.entries; 923 List<ConstantValue> entries = instruction.constant.entries;
923 instruction = node.index; 924 instruction = node.index;
924 int index = instruction.constant.primitiveValue; 925 int index = instruction.constant.primitiveValue;
925 if (index >= 0 && index < entries.length) { 926 if (index >= 0 && index < entries.length) {
926 return graph.addConstant(entries[index], closedWorld); 927 return graph.addConstant(entries[index], closedWorld);
927 } 928 }
928 } 929 }
(...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after
1341 HInstruction instruction = block.first; 1342 HInstruction instruction = block.first;
1342 while (instruction != null) { 1343 while (instruction != null) {
1343 HInstruction next = instruction.next; 1344 HInstruction next = instruction.next;
1344 instruction = instruction.accept(this); 1345 instruction = instruction.accept(this);
1345 instruction = next; 1346 instruction = next;
1346 } 1347 }
1347 } 1348 }
1348 1349
1349 HBoundsCheck insertBoundsCheck( 1350 HBoundsCheck insertBoundsCheck(
1350 HInstruction indexNode, HInstruction array, HInstruction indexArgument) { 1351 HInstruction indexNode, HInstruction array, HInstruction indexArgument) {
1351 HFieldGet length = new HFieldGet(helpers.jsIndexableLength, array, 1352 HGetLength length = new HGetLength(
1352 closedWorld.commonMasks.positiveIntType, 1353 array, closedWorld.commonMasks.positiveIntType,
1353 isAssignable: !isFixedLength(array.instructionType, closedWorld)); 1354 isAssignable: !isFixedLength(array.instructionType, closedWorld));
1354 indexNode.block.addBefore(indexNode, length); 1355 indexNode.block.addBefore(indexNode, length);
1355 1356
1356 TypeMask type = indexArgument.isPositiveInteger(closedWorld) 1357 TypeMask type = indexArgument.isPositiveInteger(closedWorld)
1357 ? indexArgument.instructionType 1358 ? indexArgument.instructionType
1358 : closedWorld.commonMasks.positiveIntType; 1359 : closedWorld.commonMasks.positiveIntType;
1359 HBoundsCheck check = new HBoundsCheck(indexArgument, length, array, type); 1360 HBoundsCheck check = new HBoundsCheck(indexArgument, length, array, type);
1360 indexNode.block.addBefore(indexNode, check); 1361 indexNode.block.addBefore(indexNode, check);
1361 // If the index input to the bounds check was not known to be an integer 1362 // If the index input to the bounds check was not known to be an integer
1362 // then we replace its uses with the bounds check, which is known to be an 1363 // then we replace its uses with the bounds check, which is known to be an
(...skipping 875 matching lines...) Expand 10 before | Expand all | Expand 10 after
2238 } 2239 }
2239 } 2240 }
2240 } 2241 }
2241 2242
2242 /** 2243 /**
2243 * Optimization phase that tries to eliminate memory loads (for 2244 * Optimization phase that tries to eliminate memory loads (for
2244 * example [HFieldGet]), when it knows the value stored in that memory 2245 * example [HFieldGet]), when it knows the value stored in that memory
2245 * location. 2246 * location.
2246 */ 2247 */
2247 class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase { 2248 class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase {
2249 final JavaScriptBackend backend;
2248 final Compiler compiler; 2250 final Compiler compiler;
2249 final ClosedWorld closedWorld; 2251 final ClosedWorld closedWorld;
2250 final String name = "SsaLoadElimination"; 2252 final String name = "SsaLoadElimination";
2251 MemorySet memorySet; 2253 MemorySet memorySet;
2252 List<MemorySet> memories; 2254 List<MemorySet> memories;
2253 2255
2254 SsaLoadElimination(this.compiler, this.closedWorld); 2256 SsaLoadElimination(this.backend, this.compiler, this.closedWorld);
2255 2257
2256 void visitGraph(HGraph graph) { 2258 void visitGraph(HGraph graph) {
2257 memories = new List<MemorySet>(graph.blocks.length); 2259 memories = new List<MemorySet>(graph.blocks.length);
2258 List<HBasicBlock> blocks = graph.blocks; 2260 List<HBasicBlock> blocks = graph.blocks;
2259 for (int i = 0; i < blocks.length; i++) { 2261 for (int i = 0; i < blocks.length; i++) {
2260 HBasicBlock block = blocks[i]; 2262 HBasicBlock block = blocks[i];
2261 visitBasicBlock(block); 2263 visitBasicBlock(block);
2262 if (block.successors.isNotEmpty && block.successors[0].isLoopHeader()) { 2264 if (block.successors.isNotEmpty && block.successors[0].isLoopHeader()) {
2263 // We've reached the ending block of a loop. Iterate over the 2265 // We've reached the ending block of a loop. Iterate over the
2264 // blocks of the loop again to take values that flow from that 2266 // blocks of the loop again to take values that flow from that
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2299 HInstruction instruction = block.first; 2301 HInstruction instruction = block.first;
2300 while (instruction != null) { 2302 while (instruction != null) {
2301 HInstruction next = instruction.next; 2303 HInstruction next = instruction.next;
2302 instruction.accept(this); 2304 instruction.accept(this);
2303 instruction = next; 2305 instruction = next;
2304 } 2306 }
2305 } 2307 }
2306 2308
2307 void visitFieldGet(HFieldGet instruction) { 2309 void visitFieldGet(HFieldGet instruction) {
2308 if (instruction.isNullCheck) return; 2310 if (instruction.isNullCheck) return;
2309 MemberEntity element = instruction.element; 2311 FieldEntity element = instruction.element;
2310 HInstruction receiver = instruction.getDartReceiver(closedWorld).nonCheck(); 2312 HInstruction receiver = instruction.getDartReceiver(closedWorld).nonCheck();
2313 _visitFieldGet(element, receiver, instruction);
2314 }
2315
2316 void visitGetLength(HGetLength instruction) {
2317 _visitFieldGet(backend.helpers.jsIndexableLength,
2318 instruction.receiver.nonCheck(), instruction);
2319 }
2320
2321 void _visitFieldGet(
2322 MemberEntity element, HInstruction receiver, HInstruction instruction) {
2311 HInstruction existing = memorySet.lookupFieldValue(element, receiver); 2323 HInstruction existing = memorySet.lookupFieldValue(element, receiver);
2312 if (existing != null) { 2324 if (existing != null) {
2313 instruction.block.rewriteWithBetterUser(instruction, existing); 2325 instruction.block.rewriteWithBetterUser(instruction, existing);
2314 instruction.block.remove(instruction); 2326 instruction.block.remove(instruction);
2315 } else { 2327 } else {
2316 memorySet.registerFieldValue(element, receiver, instruction); 2328 memorySet.registerFieldValue(element, receiver, instruction);
2317 } 2329 }
2318 } 2330 }
2319 2331
2320 void visitFieldSet(HFieldSet instruction) { 2332 void visitFieldSet(HFieldSet instruction) {
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
2457 * other checks removed to ensure that checks and type refinements do not 2469 * other checks removed to ensure that checks and type refinements do not
2458 * confuse aliasing. Values stored into a memory place keep the type 2470 * confuse aliasing. Values stored into a memory place keep the type
2459 * refinements to help further optimizations. 2471 * refinements to help further optimizations.
2460 */ 2472 */
2461 class MemorySet { 2473 class MemorySet {
2462 final ClosedWorld closedWorld; 2474 final ClosedWorld closedWorld;
2463 2475
2464 /** 2476 /**
2465 * Maps a field to a map of receiver to value. 2477 * Maps a field to a map of receiver to value.
2466 */ 2478 */
2479 // The key is [MemberEntity] rather than [FieldEntity] so that HGetLength can
2480 // be modeled as the JSIndexable.length abstract getter.
2481 // TODO(25544): Split length effects from other effects and model lengths
2482 // separately.
2467 final Map<MemberEntity, Map<HInstruction, HInstruction>> fieldValues = 2483 final Map<MemberEntity, Map<HInstruction, HInstruction>> fieldValues =
2468 <MemberEntity, Map<HInstruction, HInstruction>>{}; 2484 <MemberEntity, Map<HInstruction, HInstruction>>{};
2469 2485
2470 /** 2486 /**
2471 * Maps a receiver to a map of keys to value. 2487 * Maps a receiver to a map of keys to value.
2472 */ 2488 */
2473 final Map<HInstruction, Map<HInstruction, HInstruction>> keyedValues = 2489 final Map<HInstruction, Map<HInstruction, HInstruction>> keyedValues =
2474 <HInstruction, Map<HInstruction, HInstruction>>{}; 2490 <HInstruction, Map<HInstruction, HInstruction>>{};
2475 2491
2476 /** 2492 /**
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after
2764 2780
2765 keyedValues.forEach((receiver, values) { 2781 keyedValues.forEach((receiver, values) {
2766 result.keyedValues[receiver] = 2782 result.keyedValues[receiver] =
2767 new Map<HInstruction, HInstruction>.from(values); 2783 new Map<HInstruction, HInstruction>.from(values);
2768 }); 2784 });
2769 2785
2770 result.nonEscapingReceivers.addAll(nonEscapingReceivers); 2786 result.nonEscapingReceivers.addAll(nonEscapingReceivers);
2771 return result; 2787 return result;
2772 } 2788 }
2773 } 2789 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698