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

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

Issue 10964016: Change the type inference for fields in dart2js (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebased to r12709 Created 8 years, 3 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 abstract class OptimizationPhase { 5 abstract class OptimizationPhase {
6 String get name; 6 String get name;
7 void visitGraph(HGraph graph); 7 void visitGraph(HGraph graph);
8 } 8 }
9 9
10 class SsaOptimizerTask extends CompilerTask { 10 class SsaOptimizerTask extends CompilerTask {
(...skipping 29 matching lines...) Expand all
40 new SsaCheckInserter(backend, types, context.boundsChecked), 40 new SsaCheckInserter(backend, types, context.boundsChecked),
41 new SsaConstantFolder(constantSystem, backend, work, types), 41 new SsaConstantFolder(constantSystem, backend, work, types),
42 new SsaRedundantPhiEliminator(), 42 new SsaRedundantPhiEliminator(),
43 new SsaDeadPhiEliminator(), 43 new SsaDeadPhiEliminator(),
44 new SsaGlobalValueNumberer(compiler, types), 44 new SsaGlobalValueNumberer(compiler, types),
45 new SsaCodeMotion(), 45 new SsaCodeMotion(),
46 // Previous optimizations may have generated new 46 // Previous optimizations may have generated new
47 // opportunities for constant folding. 47 // opportunities for constant folding.
48 new SsaConstantFolder(constantSystem, backend, work, types), 48 new SsaConstantFolder(constantSystem, backend, work, types),
49 new SsaDeadCodeEliminator(types), 49 new SsaDeadCodeEliminator(types),
50 new SsaRegisterRecompilationCandidates(backend, work, types)]; 50 new SsaConstructionFieldTypes(backend, work, types)];
ngeoffray 2012/09/24 08:15:49 This will also be run by the speculative optimizat
Søren Gjesse 2012/09/24 15:06:50 Done.
51 runPhases(graph, phases); 51 runPhases(graph, phases);
52 }); 52 });
53 } 53 }
54 54
55 bool trySpeculativeOptimizations(WorkItem work, HGraph graph) { 55 bool trySpeculativeOptimizations(WorkItem work, HGraph graph) {
56 if (work.element.isField()) { 56 if (work.element.isField()) {
57 // Lazy initializers may not have bailout methods. 57 // Lazy initializers may not have bailout methods.
58 return false; 58 return false;
59 } 59 }
60 JavaScriptItemCompilationContext context = work.compilationContext; 60 JavaScriptItemCompilationContext context = work.compilationContext;
61 HTypeMap types = context.types; 61 HTypeMap types = context.types;
62 return measure(() { 62 return measure(() {
63 // Run the phases that will generate type guards. 63 // Run the phases that will generate type guards.
64 List<OptimizationPhase> phases = <OptimizationPhase>[ 64 List<OptimizationPhase> phases = <OptimizationPhase>[
65 new SsaRecompilationFieldTypePropagator(backend, work, types),
66 new SsaSpeculativeTypePropagator(compiler, types), 65 new SsaSpeculativeTypePropagator(compiler, types),
67 new SsaTypeGuardInserter(compiler, work, types), 66 new SsaTypeGuardInserter(compiler, work, types),
68 new SsaEnvironmentBuilder(compiler), 67 new SsaEnvironmentBuilder(compiler),
69 // Change the propagated types back to what they were before we 68 // Change the propagated types back to what they were before we
70 // speculatively propagated, so that we can generate the bailout 69 // speculatively propagated, so that we can generate the bailout
71 // version. 70 // version.
72 // Note that we do this even if there were no guards inserted. If a 71 // Note that we do this even if there were no guards inserted. If a
73 // guard is not beneficial enough we don't emit one, but there might 72 // guard is not beneficial enough we don't emit one, but there might
74 // still be speculative types on the instructions. 73 // still be speculative types on the instructions.
75 new SsaTypePropagator(compiler, types), 74 new SsaTypePropagator(compiler, types),
(...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after
605 Modifiers modifiers = field.modifiers; 604 Modifiers modifiers = field.modifiers;
606 bool isFinalOrConst = false; 605 bool isFinalOrConst = false;
607 if (modifiers != null) { 606 if (modifiers != null) {
608 isFinalOrConst = modifiers.isFinal() || modifiers.isConst(); 607 isFinalOrConst = modifiers.isFinal() || modifiers.isConst();
609 } 608 }
610 if (!compiler.resolverWorld.hasInvokedSetter(field, compiler)) { 609 if (!compiler.resolverWorld.hasInvokedSetter(field, compiler)) {
611 // If no setter is ever used for this field it is only initialized in the 610 // If no setter is ever used for this field it is only initialized in the
612 // initializer list. 611 // initializer list.
613 isFinalOrConst = true; 612 isFinalOrConst = true;
614 } 613 }
615 if (!isFinalOrConst && 614 HFieldGet result = new HFieldGet(
616 !compiler.codegenWorld.hasInvokedSetter(field, compiler) && 615 field, node.inputs[0], isAssignable: !isFinalOrConst);
617 !compiler.codegenWorld.hasFieldSetter(field, compiler)) { 616 if (work.element.isMember()) {
ngeoffray 2012/09/24 08:15:49 Why this check?
Søren Gjesse 2012/09/24 15:06:50 Because I did not add support for static or top le
618 switch (compiler.phase) { 617 HType type = backend.optimisticFieldType(field);
619 case Compiler.PHASE_COMPILING: 618 if (type != null) {
620 compiler.enqueuer.codegen.registerRecompilationCandidate( 619 result.guaranteedType = type;
621 work.element); 620 backend.registerFieldTypesOptimization(
622 break; 621 work.element, field, result.guaranteedType);
623 case Compiler.PHASE_RECOMPILING:
624 // If field is not final or const but no setters are used then the
625 // field might be considered final anyway as it will be either
626 // un-initialized or initialized in the constructor initializer list.
627 isFinalOrConst = true;
628 break;
629 } 622 }
630 } 623 }
631 return new HFieldGet(field, node.inputs[0], isAssignable: !isFinalOrConst); 624 return result;
632 } 625 }
633 626
634 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { 627 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) {
635 Element field = 628 Element field =
636 findConcreteFieldForDynamicAccess(node.receiver, node.selector); 629 findConcreteFieldForDynamicAccess(node.receiver, node.selector);
637 if (field === null) return node; 630 if (field === null) return node;
638 HInstruction value = node.inputs[1]; 631 HInstruction value = node.inputs[1];
639 if (compiler.enableTypeAssertions) { 632 if (compiler.enableTypeAssertions) {
640 HInstruction other = value.convertType( 633 HInstruction other = value.convertType(
641 compiler, field, HTypeConversion.CHECKED_MODE_CHECK); 634 compiler, field, HTypeConversion.CHECKED_MODE_CHECK);
(...skipping 571 matching lines...) Expand 10 before | Expand all | Expand 10 after
1213 1206
1214 for (HIf ifUser in notIfUsers) { 1207 for (HIf ifUser in notIfUsers) {
1215 changeUsesDominatedBy(ifUser.elseBlock, input, convertedType); 1208 changeUsesDominatedBy(ifUser.elseBlock, input, convertedType);
1216 // TODO(ngeoffray): Also change uses for the then block on a HType 1209 // TODO(ngeoffray): Also change uses for the then block on a HType
1217 // that knows it is not of a specific Type. 1210 // that knows it is not of a specific Type.
1218 } 1211 }
1219 } 1212 }
1220 } 1213 }
1221 1214
1222 1215
1223 // Base class for the handling of recompilation based on inferred 1216 // Analyze the constructors to see if some fields will always have a specific
1224 // field types. 1217 // type after construction. If this is the case we can ignore the type given
1225 class BaseRecompilationVisitor extends HBaseVisitor { 1218 // by the field initializer. This is especially useful when the field
1219 // initializer is initializing the field to null.
1220 class SsaConstructionFieldTypes
1221 extends HBaseVisitor implements OptimizationPhase {
1226 final JavaScriptBackend backend; 1222 final JavaScriptBackend backend;
1227 final WorkItem work; 1223 final WorkItem work;
1228 final HTypeMap types; 1224 final HTypeMap types;
1229 Compiler get compiler => backend.compiler; 1225 final String name = "SsaConstructionFieldTypes";
1226 final Set<Element> allSetters;
1227 final Map<HBasicBlock, Map<Element, HType>> blockFieldSetters;
1228 bool thisExposed = false;
1229 HGraph currentGraph;
1230 Map<Element, HType> currentFieldSetters;
1230 1231
1231 BaseRecompilationVisitor(this.backend, this.work, this.types); 1232 SsaConstructionFieldTypes(JavaScriptBackend this.backend,
1233 WorkItem this.work,
1234 HTypeMap this.types)
1235 : allSetters = new Set<Element>(),
1236 blockFieldSetters = new Map<HBasicBlock, Map<Element, HType>>();
1232 1237
1233 abstract void handleFieldGet(HFieldGet node, HType type); 1238 void visitGraph(HGraph graph) {
1234 abstract void handleFieldNumberOperation(HFieldGet field, HType type); 1239 currentGraph = graph;
1240 if (!work.element.isGenerativeConstructorBody() &&
1241 !work.element.isGenerativeConstructor()) return;
1242 visitDominatorTree(graph);
1243 }
1235 1244
1236 // Checks if the binary invocation operates on a field and a 1245 visitBasicBlock(HBasicBlock block) {
1237 // constant number. If it does [handleFieldNumberOperation] is 1246 if (block.predecessors.length == 0) {
1238 // called with the field and the type inferred for the field so far. 1247 // Create a new empty map for the first block.
1239 void checkFieldNumberOperation(HInvokeBinary node) { 1248 currentFieldSetters = new Map<Element, HType>();
1240 // Determine if one of the operands is an HFieldGet. 1249 } else {
1241 HFieldGet field; 1250 // Build a map which unions the fields from all predecessors.
ngeoffray 2012/09/24 08:15:49 It's a union of the types but an intersection of t
Søren Gjesse 2012/09/24 15:06:50 Updated comments.
1242 HInstruction other; 1251 currentFieldSetters =
1243 if (node.left is HFieldGet) { 1252 new Map.from(blockFieldSetters[block.predecessors[0]]);
1244 field = node.left; 1253 // Loop headers are the only nodes with back edges.
ngeoffray 2012/09/24 08:15:49 Please also assert that they only have 2 predecess
Søren Gjesse 2012/09/24 15:06:50 Done.
1245 other = node.right; 1254 if (!block.isLoopHeader()) {
1246 } else if (node.right is HFieldGet) { 1255 for (int i = 1; i < block.predecessors.length; i++) {
1247 field = node.right; 1256 Map<Element, HType> predecessorsFieldSetters =
1248 other = node.left; 1257 blockFieldSetters[block.predecessors[i]];
1258 Map<Element, HType> newFieldSetters = new Map<Element, HType>();
1259 predecessorsFieldSetters.forEach((Element element, HType type) {
1260 HType currentType = currentFieldSetters[element];
1261 if (currentType != null) {
1262 newFieldSetters[element] = currentType.union(type);
1263 } else {
1264 newFieldSetters[element] = type;
1265 }
1266 });
1267 currentFieldSetters = newFieldSetters;
1268 }
1269 }
1249 } 1270 }
1250 // Try to optimize the case where a field which is known to always 1271 block.forEachInstruction(
1251 // be an integer is compared with a constant number. 1272 (HInstruction instruction) => instruction.accept(this));
1252 if (other != null && 1273 assert(currentFieldSetters != null);
1253 other.isConstantNumber() && 1274 blockFieldSetters[block] = currentFieldSetters;
1254 field.element != null && 1275 }
1255 field.element.isMember()) { 1276
1256 // Calculate the field type from the information available. If 1277 visitInstruction(HInstruction instruction) {
1257 // we have type information for the field and it contains NUMBER 1278 // Instruction not explicitly handled keeps the current inferred types.
ngeoffray 2012/09/24 08:15:49 Kasper suggested to do the other way around and ha
Søren Gjesse 2012/09/24 15:06:50 Done.
1258 // we use it as a candidate for recompilation. 1279 }
1259 Element fieldElement = field.element; 1280
1260 HType fieldSettersType = backend.fieldSettersTypeSoFar(fieldElement); 1281 visitForeignNew(HForeignNew node) {
1261 HType initializersType = backend.typeFromInitializersSoFar(fieldElement); 1282 // The HForeignNew instruction is used in the generative constructor to
1262 HType fieldType = fieldSettersType.union(initializersType); 1283 // initialize all fields in newly created objects. The fields are
1263 HType type = HType.NUMBER.union(fieldType); 1284 // initialized to the value present in the initializer list or set to null
1264 if (type == HType.NUMBER) { 1285 // if not otherwise initialized.
1265 handleFieldNumberOperation(field, fieldType); 1286 int j = 0;
1266 } 1287 node.element.forEachInstanceField(
1288 includeBackendMembers: true,
1289 includeSuperMembers: true,
1290 f: (ClassElement enclosingClass, Element element) {
1291 backend.registerFieldInitializer(element, types[node.inputs[j]]);
1292 j++;
1293 });
1294 }
1295
1296 visitInvoke(HInvoke node) {
1297 for (int i = 0; i < node.inputs.length && !thisExposed; i++) {
1298 if (node.inputs[i] is HThis) thisExposed = true;
1267 } 1299 }
1268 } 1300 }
1269 1301
1270 void visitFieldGet(HFieldGet node) { 1302 visitFieldSet(HFieldSet node) {
1271 if (!node.element.isInstanceMember()) return;
1272 Element field = node.element; 1303 Element field = node.element;
1273 if (field != null) { 1304 assert(field.isMember());
ngeoffray 2012/09/24 08:15:49 Why this assert?
Søren Gjesse 2012/09/24 15:06:50 Good question - removed.
1274 HType type = backend.optimisticFieldTypeAfterConstruction(field); 1305 HInstruction value = node.value;
1275 if (!type.isUnknown()) { 1306 HType type = types[value];
1276 // Allow handling even if we haven't seen any types for this 1307 allSetters.add(field);
1277 // field yet. There might still be only one setter in an 1308 if (work.element.getEnclosingClass() === field.getEnclosingClass() &&
1278 // initializer list or constructor body and recompilation 1309 value.hasGuaranteedType()) {
1279 // can therefore pay off. 1310 currentFieldSetters[field] = type;
1280 handleFieldGet(node, type);
1281 }
1282 } 1311 }
1283 } 1312 }
1284 1313
1285 HInstruction visitEquals(HEquals node) { 1314 visitExit(HExit node) {
1286 checkFieldNumberOperation(node); 1315 // If this has been exposed then we cannot say anything about types after
1287 } 1316 // construction.
1317 if (thisExposed) return;
1288 1318
1289 HInstruction visitBinaryArithmetic(HBinaryArithmetic node) { 1319 // Register the known field types.
1290 checkFieldNumberOperation(node); 1320 currentFieldSetters.forEach((Element element, HType type) {
1321 backend.registerFieldConstructor(element, type);
1322 allSetters.remove(element);
1323 });
1324 allSetters.forEach((Element element) {
1325 backend.registerFieldConstructor(element, HType.UNKNOWN);
ngeoffray 2012/09/24 08:15:49 Why do you have to say they're unknown?
Søren Gjesse 2012/09/24 15:06:50 Because I just know that these fields have been se
1326 });
1291 } 1327 }
1292 } 1328 }
1293
1294
1295 // Visitor that registers candidates for recompilation.
1296 class SsaRegisterRecompilationCandidates
1297 extends BaseRecompilationVisitor implements OptimizationPhase {
1298 final String name = "SsaRegisterRecompileCandidates";
1299 HGraph graph;
1300
1301 SsaRegisterRecompilationCandidates(JavaScriptBackend backend,
1302 WorkItem work,
1303 HTypeMap types)
1304 : super(backend, work, types);
1305
1306 void visitGraph(HGraph visitee) {
1307 graph = visitee;
1308 if (compiler.phase == Compiler.PHASE_COMPILING) {
1309 visitDominatorTree(visitee);
1310 }
1311 }
1312
1313 void handleFieldGet(HFieldGet node, HType type) {
1314 assert(compiler.phase == Compiler.PHASE_COMPILING);
1315 compiler.enqueuer.codegen.registerRecompilationCandidate(
1316 work.element);
1317 }
1318
1319 void handleFieldNumberOperation(HFieldGet node, HType type) {
1320 assert(compiler.phase == Compiler.PHASE_COMPILING);
1321 compiler.enqueuer.codegen.registerRecompilationCandidate(
1322 work.element);
1323 }
1324 }
1325
1326
1327 // Visitor that sets the known or suspected type of fields during
1328 // recompilation.
1329 class SsaRecompilationFieldTypePropagator
1330 extends BaseRecompilationVisitor implements OptimizationPhase {
1331 final String name = "SsaRecompilationFieldTypePropagator";
1332 HGraph graph;
1333
1334 SsaRecompilationFieldTypePropagator(JavaScriptBackend backend,
1335 WorkItem work,
1336 HTypeMap types)
1337 : super(backend, work, types);
1338
1339 void visitGraph(HGraph visitee) {
1340 graph = visitee;
1341 if (compiler.phase == Compiler.PHASE_RECOMPILING) {
1342 visitDominatorTree(visitee);
1343 }
1344 }
1345
1346 void handleFieldGet(HFieldGet field, HType type) {
1347 assert(compiler.phase == Compiler.PHASE_RECOMPILING);
1348 if (!type.isConflicting()) {
1349 // If there are no invoked setters with this name, the union of
1350 // the types of the initializers and the setters is guaranteed
1351 // otherwise it is only speculative.
1352 Element element = field.element;
1353 assert(!element.isGenerativeConstructorBody());
1354 if (!compiler.codegenWorld.hasInvokedSetter(element, compiler)) {
1355 field.guaranteedType =
1356 type.union(backend.fieldSettersTypeSoFar(element));
1357 } else {
1358 types[field] = type.union(backend.fieldSettersTypeSoFar(element));
1359 }
1360 }
1361 }
1362
1363 void handleFieldNumberOperation(HFieldGet field, HType type) {
1364 assert(compiler.phase == Compiler.PHASE_RECOMPILING);
1365 if (compiler.codegenWorld.hasInvokedSetter(field.element, compiler)) {
1366 // If there are invoked setters we don't know for sure
1367 // that the field will hold a value of the calculated
1368 // type, but the fact that the class itself sticks to
1369 // this type for the field is still a strong signal
1370 // indicating the expected type of the field.
1371 types[field] = type;
1372 } else {
1373 // If there are no invoked setters we know the type of
1374 // this field for sure.
1375 field.guaranteedType = type;
1376 }
1377 }
1378 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698