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

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

Issue 10827180: Move types out of the HInstructions. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Simplifications. 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 interface OptimizationPhase { 5 interface 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 {
11 final JavaScriptBackend backend; 11 final JavaScriptBackend backend;
12 SsaOptimizerTask(JavaScriptBackend backend) 12 SsaOptimizerTask(JavaScriptBackend backend)
13 : this.backend = backend, 13 : this.backend = backend,
14 super(backend.compiler); 14 super(backend.compiler);
15 String get name() => 'SSA optimizer'; 15 String get name() => 'SSA optimizer';
16 Compiler get compiler() => backend.compiler; 16 Compiler get compiler() => backend.compiler;
17 17
18 void runPhases(HGraph graph, List<OptimizationPhase> phases) { 18 void runPhases(HGraph graph, List<OptimizationPhase> phases) {
19 for (OptimizationPhase phase in phases) { 19 for (OptimizationPhase phase in phases) {
20 phase.visitGraph(graph); 20 runPhase(graph, phase);
21 compiler.tracer.traceGraph(phase.name, graph);
22 } 21 }
23 } 22 }
24 23
24 void runPhase(HGraph graph, OptimizationPhase phase) {
25 phase.visitGraph(graph);
26 compiler.tracer.traceGraph(phase.name, graph);
27 }
28
25 void optimize(WorkItem work, HGraph graph) { 29 void optimize(WorkItem work, HGraph graph) {
Lasse Reichstein Nielsen 2012/08/16 10:41:34 You know this work item is a JavaScriptWorkItem?
floitsch 2012/08/16 14:10:04 There is no JavaScriptWorkItem anymore.
30 JavaScriptItemCompilationContext context = work.compilationContext;
31 HTypeMap types = context.types;
26 measure(() { 32 measure(() {
27 List<OptimizationPhase> phases = <OptimizationPhase>[ 33 List<OptimizationPhase> phases = <OptimizationPhase>[
28 // Run trivial constant folding first to optimize 34 // Run trivial constant folding first to optimize
29 // some patterns useful for type conversion. 35 // some patterns useful for type conversion.
30 new SsaConstantFolder(backend, work), 36 new SsaConstantFolder(backend, work, types),
31 new SsaTypeConversionInserter(compiler), 37 new SsaTypeConversionInserter(compiler),
32 new SsaTypePropagator(compiler), 38 new SsaTypePropagator(compiler, types),
33 new SsaCheckInserter(backend), 39 new SsaCheckInserter(backend, types),
34 new SsaConstantFolder(backend, work), 40 new SsaConstantFolder(backend, work, types),
35 new SsaRedundantPhiEliminator(), 41 new SsaRedundantPhiEliminator(),
36 new SsaDeadPhiEliminator(), 42 new SsaDeadPhiEliminator(),
37 new SsaGlobalValueNumberer(compiler), 43 new SsaGlobalValueNumberer(compiler, types),
38 new SsaCodeMotion(), 44 new SsaCodeMotion(),
39 new SsaDeadCodeEliminator(), 45 new SsaDeadCodeEliminator(types),
40 new SsaRegisterRecompilationCandidates(backend, work)]; 46 new SsaRegisterRecompilationCandidates(backend, work, types)];
41 runPhases(graph, phases); 47 runPhases(graph, phases);
42 }); 48 });
43 } 49 }
44 50
45 bool trySpeculativeOptimizations(WorkItem work, HGraph graph) { 51 bool trySpeculativeOptimizations(WorkItem work, HGraph graph) {
52 JavaScriptItemCompilationContext context = work.compilationContext;
53 HTypeMap types = context.types;
46 return measure(() { 54 return measure(() {
47 // Run the phases that will generate type guards. 55 // Run the phases that will generate type guards.
48 List<OptimizationPhase> phases = <OptimizationPhase>[ 56 List<OptimizationPhase> phases = <OptimizationPhase>[
49 new SsaRecompilationFieldTypePropagator(backend, work), 57 new SsaRecompilationFieldTypePropagator(backend, work, types),
50 new SsaSpeculativeTypePropagator(compiler), 58 new SsaSpeculativeTypePropagator(compiler, types),
51 new SsaTypeGuardInserter(compiler, work), 59 new SsaTypeGuardInserter(compiler, work, types),
52 new SsaEnvironmentBuilder(compiler), 60 new SsaEnvironmentBuilder(compiler),
53 // Change the propagated types back to what they were before we 61 // Change the propagated types back to what they were before we
54 // speculatively propagated, so that we can generate the bailout 62 // speculatively propagated, so that we can generate the bailout
55 // version. 63 // version.
56 // Note that we do this even if there were no guards inserted. If a 64 // Note that we do this even if there were no guards inserted. If a
57 // guard is not beneficial enough we don't emit one, but there might 65 // guard is not beneficial enough we don't emit one, but there might
58 // still be speculative types on the instructions. 66 // still be speculative types on the instructions.
59 new SsaTypePropagator(compiler), 67 new SsaTypePropagator(compiler, types),
60 // Then run the [SsaCheckInserter] because the type propagator also 68 // Then run the [SsaCheckInserter] because the type propagator also
61 // propagated types non-speculatively. For example, it might have 69 // propagated types non-speculatively. For example, it might have
62 // propagated the type array for a call to the List constructor. 70 // propagated the type array for a call to the List constructor.
63 new SsaCheckInserter(backend)]; 71 new SsaCheckInserter(backend, types)];
64 runPhases(graph, phases); 72 runPhases(graph, phases);
65 return !work.guards.isEmpty(); 73 return !work.guards.isEmpty();
66 }); 74 });
67 } 75 }
68 76
69 void prepareForSpeculativeOptimizations(WorkItem work, HGraph graph) { 77 void prepareForSpeculativeOptimizations(WorkItem work, HGraph graph) {
78 JavaScriptItemCompilationContext context = work.compilationContext;
79 HTypeMap types = context.types;
70 measure(() { 80 measure(() {
71 // In order to generate correct code for the bailout version, we did not 81 // In order to generate correct code for the bailout version, we did not
72 // propagate types from the instruction to the type guard. We do it 82 // propagate types from the instruction to the type guard. We do it
73 // now to be able to optimize further. 83 // now to be able to optimize further.
74 work.guards.forEach((HTypeGuard guard) { guard.isEnabled = true; }); 84 work.guards.forEach((HTypeGuard guard) { guard.isEnabled = true; });
75 // We also need to insert range and integer checks for the type 85 // We also need to insert range and integer checks for the type
76 // guards. Now that they claim to have a certain type, some 86 // guards. Now that they claim to have a certain type, some
77 // depending instructions might become builtin (like native array 87 // depending instructions might become builtin (like native array
78 // accesses) and need to be checked. 88 // accesses) and need to be checked.
79 // Also run the type propagator, to please the codegen in case 89 // Also run the type propagator, to please the codegen in case
80 // no other optimization is run. 90 // no other optimization is run.
81 runPhases(graph, 91 runPhases(graph,
82 <OptimizationPhase>[new SsaCheckInserter(backend), 92 <OptimizationPhase>[new SsaCheckInserter(backend, types),
83 new SsaTypePropagator(compiler)]); 93 new SsaTypePropagator(compiler, types)]);
84 }); 94 });
85 } 95 }
86 } 96 }
87 97
88 /** 98 /**
89 * If both inputs to known operations are available execute the operation at 99 * If both inputs to known operations are available execute the operation at
90 * compile-time. 100 * compile-time.
91 */ 101 */
92 class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { 102 class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase {
93 final String name = "SsaConstantFolder"; 103 final String name = "SsaConstantFolder";
94 final JavaScriptBackend backend; 104 final JavaScriptBackend backend;
95 final WorkItem work; 105 final WorkItem work;
106 final HTypeMap types;
96 HGraph graph; 107 HGraph graph;
97 Compiler get compiler() => backend.compiler; 108 Compiler get compiler() => backend.compiler;
98 109
99 SsaConstantFolder(this.backend, this.work); 110 SsaConstantFolder(this.backend, this.work, this.types);
100 111
101 void visitGraph(HGraph visitee) { 112 void visitGraph(HGraph visitee) {
102 graph = visitee; 113 graph = visitee;
103 visitDominatorTree(visitee); 114 visitDominatorTree(visitee);
104 } 115 }
105 116
106 visitBasicBlock(HBasicBlock block) { 117 visitBasicBlock(HBasicBlock block) {
107 HInstruction instruction = block.first; 118 HInstruction instruction = block.first;
108 while (instruction !== null) { 119 while (instruction !== null) {
109 HInstruction next = instruction.next; 120 HInstruction next = instruction.next;
110 HInstruction replacement = instruction.accept(this); 121 HInstruction replacement = instruction.accept(this);
111 if (replacement !== instruction) { 122 if (replacement !== instruction) {
112 if (!replacement.isInBasicBlock()) { 123 if (!replacement.isInBasicBlock()) {
113 // The constant folding can return an instruction that is already 124 // The constant folding can return an instruction that is already
114 // part of the graph (like an input), so we only add the replacement 125 // part of the graph (like an input), so we only add the replacement
115 // if necessary. 126 // if necessary.
116 block.addAfter(instruction, replacement); 127 block.addAfter(instruction, replacement);
117 } 128 }
118 block.rewrite(instruction, replacement); 129 block.rewrite(instruction, replacement);
119 block.remove(instruction); 130 block.remove(instruction);
120 // If the replacement instruction does not know its type or 131 // If the replacement instruction does not know its type or
121 // source element yet, use the type and source element of the 132 // source element yet, use the type and source element of the
122 // instruction. 133 // instruction.
123 if (!replacement.propagatedType.isUseful()) { 134 if (!types[replacement].isUseful()) {
124 replacement.propagatedType = instruction.propagatedType; 135 types[replacement] = types[instruction];
125 } 136 }
126 if (replacement.sourceElement === null) { 137 if (replacement.sourceElement === null) {
127 replacement.sourceElement = instruction.sourceElement; 138 replacement.sourceElement = instruction.sourceElement;
128 } 139 }
129 } 140 }
130 instruction = next; 141 instruction = next;
131 } 142 }
132 } 143 }
133 144
134 HInstruction visitInstruction(HInstruction node) { 145 HInstruction visitInstruction(HInstruction node) {
135 return node; 146 return node;
136 } 147 }
137 148
138 HInstruction visitBoolify(HBoolify node) { 149 HInstruction visitBoolify(HBoolify node) {
139 List<HInstruction> inputs = node.inputs; 150 List<HInstruction> inputs = node.inputs;
140 assert(inputs.length == 1); 151 assert(inputs.length == 1);
141 HInstruction input = inputs[0]; 152 HInstruction input = inputs[0];
142 if (input.isBoolean()) return input; 153 if (input.isBoolean(types)) return input;
143 // All values !== true are boolified to false. 154 // All values !== true are boolified to false.
144 Type type = input.propagatedType.computeType(compiler); 155 Type type = types[input].computeType(compiler);
145 if (type !== null && type.element !== compiler.boolClass) { 156 if (type !== null && type.element !== compiler.boolClass) {
146 return graph.addConstantBool(false); 157 return graph.addConstantBool(false);
147 } 158 }
148 return node; 159 return node;
149 } 160 }
150 161
151 HInstruction visitNot(HNot node) { 162 HInstruction visitNot(HNot node) {
152 List<HInstruction> inputs = node.inputs; 163 List<HInstruction> inputs = node.inputs;
153 assert(inputs.length == 1); 164 assert(inputs.length == 1);
154 HInstruction input = inputs[0]; 165 HInstruction input = inputs[0];
(...skipping 29 matching lines...) Expand all
184 HConstant constantInput = input; 195 HConstant constantInput = input;
185 ListConstant constant = constantInput.constant; 196 ListConstant constant = constantInput.constant;
186 return graph.addConstantInt(constant.length); 197 return graph.addConstantInt(constant.length);
187 } else if (input.isConstantMap()) { 198 } else if (input.isConstantMap()) {
188 HConstant constantInput = input; 199 HConstant constantInput = input;
189 MapConstant constant = constantInput.constant; 200 MapConstant constant = constantInput.constant;
190 return graph.addConstantInt(constant.length); 201 return graph.addConstantInt(constant.length);
191 } 202 }
192 } 203 }
193 204
194 if (input.isString() 205 if (input.isString(types)
195 && node.name == const SourceString('toString')) { 206 && node.name == const SourceString('toString')) {
196 return node.inputs[1]; 207 return node.inputs[1];
197 } 208 }
198 209
199 if (!input.canBePrimitive() && !node.getter && !node.setter) { 210 if (!input.canBePrimitive(types) && !node.getter && !node.setter) {
200 bool transformToDynamicInvocation = true; 211 bool transformToDynamicInvocation = true;
201 if (input.canBeNull()) { 212 if (input.canBeNull(types)) {
202 // Check if the method exists on Null. If yes we must not transform 213 // Check if the method exists on Null. If yes we must not transform
203 // the static interceptor call to a dynamic invocation. 214 // the static interceptor call to a dynamic invocation.
204 // TODO(floitsch): get a list of methods that exist on 'null' and only 215 // TODO(floitsch): get a list of methods that exist on 'null' and only
205 // bail out on them. 216 // bail out on them.
206 transformToDynamicInvocation = false; 217 transformToDynamicInvocation = false;
207 } 218 }
208 if (transformToDynamicInvocation) { 219 if (transformToDynamicInvocation) {
209 return fromInterceptorToDynamicInvocation(node, node.name); 220 return fromInterceptorToDynamicInvocation(node, node.name);
210 } 221 }
211 } 222 }
212 223
213 return node; 224 return node;
214 } 225 }
215 226
216 HInstruction visitInvokeDynamic(HInvokeDynamic node) { 227 HInstruction visitInvokeDynamic(HInvokeDynamic node) {
217 HType receiverType = node.receiver.propagatedType; 228 HType receiverType = types[node.receiver];
218 if (receiverType.isExact()) { 229 if (receiverType.isExact()) {
219 HBoundedType type = receiverType; 230 HBoundedType type = receiverType;
220 Element element = type.lookupMember(node.name); 231 Element element = type.lookupMember(node.name);
221 // TODO(ngeoffray): Also fold if it's a getter or variable. 232 // TODO(ngeoffray): Also fold if it's a getter or variable.
222 if (element != null && element.isFunction()) { 233 if (element != null && element.isFunction()) {
223 if (node.selector.applies(element, compiler)) { 234 if (node.selector.applies(element, compiler)) {
224 FunctionElement method = element; 235 FunctionElement method = element;
225 FunctionSignature parameters = method.computeSignature(compiler); 236 FunctionSignature parameters = method.computeSignature(compiler);
226 if (parameters.optionalParameterCount == 0) { 237 if (parameters.optionalParameterCount == 0) {
227 node.element = element; 238 node.element = element;
228 } 239 }
229 // TODO(ngeoffray): If the method has optional parameters, 240 // TODO(ngeoffray): If the method has optional parameters,
230 // we should pass the default values here. 241 // we should pass the default values here.
231 } 242 }
232 } 243 }
233 } 244 }
234 return node; 245 return node;
235 } 246 }
236 247
237 HInstruction fromInterceptorToDynamicInvocation( 248 HInstruction fromInterceptorToDynamicInvocation(
238 HInvokeStatic node, SourceString methodName) { 249 HInvokeStatic node, SourceString methodName) {
239 HBoundedType type = node.inputs[1].propagatedType; 250 HBoundedType type = types[node.inputs[1]];
240 HInvokeDynamicMethod result = new HInvokeDynamicMethod( 251 HInvokeDynamicMethod result = new HInvokeDynamicMethod(
241 node.selector, 252 node.selector,
242 methodName, 253 methodName,
243 node.inputs.getRange(1, node.inputs.length - 1)); 254 node.inputs.getRange(1, node.inputs.length - 1));
244 if (type.isExact()) { 255 if (type.isExact()) {
245 HBoundedType concrete = type; 256 HBoundedType concrete = type;
246 result.element = concrete.lookupMember(methodName); 257 result.element = concrete.lookupMember(methodName);
247 } 258 }
248 return result; 259 return result;
249 } 260 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
281 } 292 }
282 return node; 293 return node;
283 } 294 }
284 node.staticChecks = HBoundsCheck.ALWAYS_ABOVE_ZERO; 295 node.staticChecks = HBoundsCheck.ALWAYS_ABOVE_ZERO;
285 } 296 }
286 return node; 297 return node;
287 } 298 }
288 299
289 HInstruction visitIntegerCheck(HIntegerCheck node) { 300 HInstruction visitIntegerCheck(HIntegerCheck node) {
290 HInstruction value = node.value; 301 HInstruction value = node.value;
291 if (value.isInteger()) return value; 302 if (value.isInteger(types)) return value;
292 if (value.isConstant()) { 303 if (value.isConstant()) {
293 assert((){ 304 assert((){
294 HConstant constantInstruction = value; 305 HConstant constantInstruction = value;
295 return !constantInstruction.constant.isInt(); 306 return !constantInstruction.constant.isInt();
296 }); 307 });
297 node.alwaysFalse = true; 308 node.alwaysFalse = true;
298 } 309 }
299 return node; 310 return node;
300 } 311 }
301 312
302 313
303 HInstruction visitIndex(HIndex node) { 314 HInstruction visitIndex(HIndex node) {
304 if (!node.receiver.canBePrimitive()) { 315 if (!node.receiver.canBePrimitive(types)) {
305 SourceString methodName = Elements.constructOperatorName( 316 SourceString methodName = Elements.constructOperatorName(
306 const SourceString('operator'), const SourceString('[]')); 317 const SourceString('operator'), const SourceString('[]'));
307 return fromInterceptorToDynamicInvocation(node, methodName); 318 return fromInterceptorToDynamicInvocation(node, methodName);
308 } 319 }
309 return node; 320 return node;
310 } 321 }
311 322
312 HInstruction visitIndexAssign(HIndexAssign node) { 323 HInstruction visitIndexAssign(HIndexAssign node) {
313 if (!node.receiver.canBePrimitive()) { 324 if (!node.receiver.canBePrimitive(types)) {
314 SourceString methodName = Elements.constructOperatorName( 325 SourceString methodName = Elements.constructOperatorName(
315 const SourceString('operator'), const SourceString('[]=')); 326 const SourceString('operator'), const SourceString('[]='));
316 return fromInterceptorToDynamicInvocation(node, methodName); 327 return fromInterceptorToDynamicInvocation(node, methodName);
317 } 328 }
318 return node; 329 return node;
319 } 330 }
320 331
321 HInstruction visitInvokeBinary(HInvokeBinary node) { 332 HInstruction visitInvokeBinary(HInvokeBinary node) {
322 HInstruction left = node.left; 333 HInstruction left = node.left;
323 HInstruction right = node.right; 334 HInstruction right = node.right;
324 if (left is HConstant && right is HConstant) { 335 if (left is HConstant && right is HConstant) {
325 BinaryOperation operation = node.operation; 336 BinaryOperation operation = node.operation;
326 HConstant op1 = left; 337 HConstant op1 = left;
327 HConstant op2 = right; 338 HConstant op2 = right;
328 Constant folded = operation.fold(op1.constant, op2.constant); 339 Constant folded = operation.fold(op1.constant, op2.constant);
329 if (folded !== null) return graph.addConstant(folded); 340 if (folded !== null) return graph.addConstant(folded);
330 } 341 }
331 342
332 if (!left.canBePrimitive() 343 if (!left.canBePrimitive(types)
333 && node.operation.isUserDefinable() 344 && node.operation.isUserDefinable()
334 // The equals operation is being optimized in visitEquals. 345 // The equals operation is being optimized in visitEquals.
335 && node.operation !== const EqualsOperation()) { 346 && node.operation !== const EqualsOperation()) {
336 SourceString methodName = Elements.constructOperatorName( 347 SourceString methodName = Elements.constructOperatorName(
337 const SourceString('operator'), node.operation.name); 348 const SourceString('operator'), node.operation.name);
338 return fromInterceptorToDynamicInvocation(node, methodName); 349 return fromInterceptorToDynamicInvocation(node, methodName);
339 } 350 }
340 return node; 351 return node;
341 } 352 }
342 353
(...skipping 18 matching lines...) Expand all
361 // instructions. If it is unused it will be treated as dead code and 372 // instructions. If it is unused it will be treated as dead code and
362 // discarded. 373 // discarded.
363 oldTarget.block.addAfter(oldTarget, boolifiedTarget); 374 oldTarget.block.addAfter(oldTarget, boolifiedTarget);
364 // Remove us as user from the [oldTarget]. 375 // Remove us as user from the [oldTarget].
365 oldTarget.removeUser(node); 376 oldTarget.removeUser(node);
366 // Replace old target with boolified target. 377 // Replace old target with boolified target.
367 assert(node.target == node.inputs[0]); 378 assert(node.target == node.inputs[0]);
368 node.inputs[0] = boolifiedTarget; 379 node.inputs[0] = boolifiedTarget;
369 boolifiedTarget.usedBy.add(node); 380 boolifiedTarget.usedBy.add(node);
370 node.usesBoolifiedInterceptor = true; 381 node.usesBoolifiedInterceptor = true;
371 node.propagatedType = HType.BOOLEAN; 382 types[node] = HType.BOOLEAN;
372 } 383 }
373 // This node stays the same, but the Boolify node will go away. 384 // This node stays the same, but the Boolify node will go away.
374 } 385 }
375 // Note that we still have to call [super] to make sure that we end up 386 // Note that we still have to call [super] to make sure that we end up
376 // in the remaining optimizations. 387 // in the remaining optimizations.
377 return super.visitRelational(node); 388 return super.visitRelational(node);
378 } 389 }
379 390
380 HInstruction handleIdentityCheck(HInvokeBinary node) { 391 HInstruction handleIdentityCheck(HInvokeBinary node) {
381 HInstruction left = node.left; 392 HInstruction left = node.left;
382 HInstruction right = node.right; 393 HInstruction right = node.right;
383 HType leftType = left.propagatedType; 394 HType leftType = types[left];
384 HType rightType = right.propagatedType; 395 HType rightType = types[right];
385 assert(!leftType.isConflicting() && !rightType.isConflicting()); 396 assert(!leftType.isConflicting() && !rightType.isConflicting());
386 397
387 // We don't optimize on numbers to preserve the runtime semantics. 398 // We don't optimize on numbers to preserve the runtime semantics.
388 if (!(left.isNumber() && right.isNumber()) && 399 if (!(left.isNumber(types) && right.isNumber(types)) &&
389 leftType.intersection(rightType).isConflicting()) { 400 leftType.intersection(rightType).isConflicting()) {
390 return graph.addConstantBool(false); 401 return graph.addConstantBool(false);
391 } 402 }
392 403
393 if (left.isConstantBoolean() && right.isBoolean()) { 404 if (left.isConstantBoolean() && right.isBoolean(types)) {
394 HConstant constant = left; 405 HConstant constant = left;
395 if (constant.constant.isTrue()) { 406 if (constant.constant.isTrue()) {
396 return right; 407 return right;
397 } else { 408 } else {
398 return new HNot(right); 409 return new HNot(right);
399 } 410 }
400 } 411 }
401 412
402 if (right.isConstantBoolean() && left.isBoolean()) { 413 if (right.isConstantBoolean() && left.isBoolean(types)) {
403 HConstant constant = right; 414 HConstant constant = right;
404 if (constant.constant.isTrue()) { 415 if (constant.constant.isTrue()) {
405 return left; 416 return left;
406 } else { 417 } else {
407 return new HNot(left); 418 return new HNot(left);
408 } 419 }
409 } 420 }
410 421
411 return null; 422 return null;
412 } 423 }
(...skipping 13 matching lines...) Expand all
426 return new HIdentity(target, node.left, node.right); 437 return new HIdentity(target, node.left, node.right);
427 } else { 438 } else {
428 return newInstruction; 439 return newInstruction;
429 } 440 }
430 } 441 }
431 442
432 HInstruction visitEquals(HEquals node) { 443 HInstruction visitEquals(HEquals node) {
433 HInstruction left = node.left; 444 HInstruction left = node.left;
434 HInstruction right = node.right; 445 HInstruction right = node.right;
435 446
436 if (node.builtin) { 447 if (node.isBuiltin(types)) {
437 return foldBuiltinEqualsCheck(node); 448 return foldBuiltinEqualsCheck(node);
438 } 449 }
439 450
440 if (left.isConstant() && right.isConstant()) { 451 if (left.isConstant() && right.isConstant()) {
441 return super.visitEquals(node); 452 return super.visitEquals(node);
442 } 453 }
443 454
444 if (left.propagatedType.isExact()) { 455 HType leftType = types[left];
445 HBoundedType type = left.propagatedType; 456 if (leftType.isExact()) {
457 HBoundedType type = leftType;
446 Element element = type.lookupMember(Elements.OPERATOR_EQUALS); 458 Element element = type.lookupMember(Elements.OPERATOR_EQUALS);
447 if (element !== null) { 459 if (element !== null) {
448 // If the left-hand side is guaranteed to be a non-primitive 460 // If the left-hand side is guaranteed to be a non-primitive
449 // type and and it defines operator==, we emit a call to that 461 // type and and it defines operator==, we emit a call to that
450 // operator. 462 // operator.
451 return super.visitEquals(node); 463 return super.visitEquals(node);
452 } else if (right.isConstantNull()) { 464 } else if (right.isConstantNull()) {
453 return graph.addConstantBool(false); 465 return graph.addConstantBool(false);
454 } else { 466 } else {
455 // We can just emit an identity check because the type does 467 // We can just emit an identity check because the type does
456 // not implement operator=. 468 // not implement operator=.
457 return foldBuiltinEqualsCheck(node); 469 return foldBuiltinEqualsCheck(node);
458 } 470 }
459 } 471 }
460 472
461 if (right.isConstantNull()) { 473 if (right.isConstantNull()) {
462 if (left.propagatedType.isPrimitive()) { 474 if (leftType.isPrimitive()) {
463 return graph.addConstantBool(false); 475 return graph.addConstantBool(false);
464 } 476 }
465 } 477 }
466 478
467 // All other cases are dealt with by the [visitRelational] and 479 // All other cases are dealt with by the [visitRelational] and
468 // [visitInvokeBinary], which are visited by invoking the [super]'s 480 // [visitInvokeBinary], which are visited by invoking the [super]'s
469 // visit method. 481 // visit method.
470 return super.visitEquals(node); 482 return super.visitEquals(node);
471 } 483 }
472 484
473 HInstruction visitTypeGuard(HTypeGuard node) { 485 HInstruction visitTypeGuard(HTypeGuard node) {
474 HInstruction value = node.guarded; 486 HInstruction value = node.guarded;
475 // If the intersection of the types is still the incoming type then 487 // If the intersection of the types is still the incoming type then
476 // the incoming type was a subtype of the guarded type, and no check 488 // the incoming type was a subtype of the guarded type, and no check
477 // is required. 489 // is required.
478 HType combinedType = value.propagatedType.intersection(node.guardedType); 490 HType combinedType = types[value].intersection(node.guardedType);
479 return (combinedType == value.propagatedType) ? value : node; 491 return (combinedType == types[value]) ? value : node;
480 } 492 }
481 493
482 HInstruction visitIs(HIs node) { 494 HInstruction visitIs(HIs node) {
483 Type type = node.typeExpression; 495 Type type = node.typeExpression;
484 Element element = type.element; 496 Element element = type.element;
485 if (element.kind === ElementKind.TYPE_VARIABLE) { 497 if (element.kind === ElementKind.TYPE_VARIABLE) {
486 compiler.unimplemented("visitIs for type variables"); 498 compiler.unimplemented("visitIs for type variables");
487 } 499 }
488 500
489 HType expressionType = node.expression.propagatedType; 501 HType expressionType = types[node.expression];
490 if (element === compiler.objectClass 502 if (element === compiler.objectClass
491 || element === compiler.dynamicClass) { 503 || element === compiler.dynamicClass) {
492 return graph.addConstantBool(true); 504 return graph.addConstantBool(true);
493 } else if (expressionType.isInteger()) { 505 } else if (expressionType.isInteger()) {
494 if (element === compiler.intClass || element === compiler.numClass) { 506 if (element === compiler.intClass || element === compiler.numClass) {
495 return graph.addConstantBool(true); 507 return graph.addConstantBool(true);
496 } else if (element === compiler.doubleClass) { 508 } else if (element === compiler.doubleClass) {
497 // We let the JS semantics decide for that check. Currently 509 // We let the JS semantics decide for that check. Currently
498 // the code we emit will always return true. 510 // the code we emit will always return true.
499 return node; 511 return node;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
542 } else if (expressionType.isExact()) { 554 } else if (expressionType.isExact()) {
543 return graph.addConstantBool(false); 555 return graph.addConstantBool(false);
544 } 556 }
545 } 557 }
546 } 558 }
547 return node; 559 return node;
548 } 560 }
549 561
550 HInstruction visitTypeConversion(HTypeConversion node) { 562 HInstruction visitTypeConversion(HTypeConversion node) {
551 HInstruction value = node.inputs[0]; 563 HInstruction value = node.inputs[0];
552 Type type = node.propagatedType.computeType(compiler); 564 Type type = types[node].computeType(compiler);
553 if (type.element === compiler.dynamicClass 565 if (type.element === compiler.dynamicClass
554 || type.element === compiler.objectClass) { 566 || type.element === compiler.objectClass) {
555 return value; 567 return value;
556 } 568 }
557 HType combinedType = value.propagatedType.intersection(node.propagatedType); 569 HType combinedType = types[value].intersection(types[node]);
558 return (combinedType == value.propagatedType) ? value : node; 570 return (combinedType == types[value]) ? value : node;
559 } 571 }
560 572
561 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { 573 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
562 HInstruction receiver = node.inputs[0]; 574 HInstruction receiver = node.inputs[0];
563 if (!receiver.propagatedType.isUseful()) return node; 575 HType receiverType = types[receiver];
564 if (receiver.propagatedType.canBeNull()) return node; 576 if (!receiverType.isUseful()) return node;
565 Type type = receiver.propagatedType.computeType(compiler); 577 if (receiverType.canBeNull()) return node;
578 Type type = receiverType.computeType(compiler);
566 if (type === null) return node; 579 if (type === null) return node;
567 Element field = compiler.world.locateSingleField(type, node.name); 580 Element field = compiler.world.locateSingleField(type, node.name);
568 if (field === null) return node; 581 if (field === null) return node;
569 Modifiers modifiers = field.modifiers; 582 Modifiers modifiers = field.modifiers;
570 bool isFinalOrConst = false; 583 bool isFinalOrConst = false;
571 if (modifiers != null) { 584 if (modifiers != null) {
572 isFinalOrConst = modifiers.isFinal() || modifiers.isConst(); 585 isFinalOrConst = modifiers.isFinal() || modifiers.isConst();
573 } 586 }
574 if (!compiler.resolverWorld.hasInvokedSetter(field, compiler)) { 587 if (!compiler.resolverWorld.hasInvokedSetter(field, compiler)) {
575 // If no setter is ever used for this field it is only initialized in the 588 // If no setter is ever used for this field it is only initialized in the
(...skipping 15 matching lines...) Expand all
591 isFinalOrConst = true; 604 isFinalOrConst = true;
592 break; 605 break;
593 } 606 }
594 } 607 }
595 return new HFieldGet.withElement( 608 return new HFieldGet.withElement(
596 field, node.inputs[0], isFinalOrConst: isFinalOrConst); 609 field, node.inputs[0], isFinalOrConst: isFinalOrConst);
597 } 610 }
598 611
599 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { 612 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) {
600 HInstruction receiver = node.inputs[0]; 613 HInstruction receiver = node.inputs[0];
601 if (!receiver.propagatedType.isUseful()) return node; 614 HType receiverType = types[receiver];
602 if (receiver.propagatedType.canBeNull()) return node; 615 if (!receiverType.isUseful()) return node;
603 Type type = receiver.propagatedType.computeType(compiler); 616 if (receiverType.canBeNull()) return node;
617 Type type = receiverType.computeType(compiler);
604 if (type === null) return node; 618 if (type === null) return node;
605 Element field = compiler.world.locateSingleField(type, node.name); 619 Element field = compiler.world.locateSingleField(type, node.name);
606 if (field === null) return node; 620 if (field === null) return node;
607 return new HFieldSet.withElement(field, node.inputs[0], node.inputs[1]); 621 return new HFieldSet.withElement(field, node.inputs[0], node.inputs[1]);
608 } 622 }
609 623
610 HInstruction visitStringConcat(HStringConcat node) { 624 HInstruction visitStringConcat(HStringConcat node) {
611 DartString folded = const LiteralDartString(""); 625 DartString folded = const LiteralDartString("");
612 for (int i = 0; i < node.inputs.length; i++) { 626 for (int i = 0; i < node.inputs.length; i++) {
613 HInstruction part = node.inputs[i]; 627 HInstruction part = node.inputs[i];
614 if (!part.isConstant()) return node; 628 if (!part.isConstant()) return node;
615 HConstant constant = part; 629 HConstant constant = part;
616 if (!constant.constant.isPrimitive()) return node; 630 if (!constant.constant.isPrimitive()) return node;
617 PrimitiveConstant primitive = constant.constant; 631 PrimitiveConstant primitive = constant.constant;
618 folded = new DartString.concat(folded, primitive.toDartString()); 632 folded = new DartString.concat(folded, primitive.toDartString());
619 } 633 }
620 return graph.addConstantString(folded, node.node); 634 return graph.addConstantString(folded, node.node);
621 } 635 }
622 } 636 }
623 637
624 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { 638 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase {
639 final HTypeMap types;
625 final String name = "SsaCheckInserter"; 640 final String name = "SsaCheckInserter";
626 Element lengthInterceptor; 641 Element lengthInterceptor;
627 642
628 SsaCheckInserter(JavaScriptBackend backend) { 643 SsaCheckInserter(JavaScriptBackend backend, this.types) {
629 SourceString lengthString = const SourceString('length'); 644 SourceString lengthString = const SourceString('length');
630 lengthInterceptor = 645 lengthInterceptor =
631 backend.builder.interceptors.getStaticGetInterceptor(lengthString); 646 backend.builder.interceptors.getStaticGetInterceptor(lengthString);
632 } 647 }
633 648
634 void visitGraph(HGraph graph) { 649 void visitGraph(HGraph graph) {
635 visitDominatorTree(graph); 650 visitDominatorTree(graph);
636 } 651 }
637 652
638 void visitBasicBlock(HBasicBlock block) { 653 void visitBasicBlock(HBasicBlock block) {
639 HInstruction instruction = block.first; 654 HInstruction instruction = block.first;
640 while (instruction !== null) { 655 while (instruction !== null) {
641 HInstruction next = instruction.next; 656 HInstruction next = instruction.next;
642 instruction = instruction.accept(this); 657 instruction = instruction.accept(this);
643 instruction = next; 658 instruction = next;
644 } 659 }
645 } 660 }
646 661
647 HBoundsCheck insertBoundsCheck(HInstruction node, 662 HBoundsCheck insertBoundsCheck(HInstruction node,
648 HInstruction receiver, 663 HInstruction receiver,
649 HInstruction index) { 664 HInstruction index) {
650 HStatic interceptor = new HStatic(lengthInterceptor); 665 HStatic interceptor = new HStatic(lengthInterceptor);
651 node.block.addBefore(node, interceptor); 666 node.block.addBefore(node, interceptor);
652 HInvokeInterceptor length = new HInvokeInterceptor( 667 HInvokeInterceptor length = new HInvokeInterceptor(
653 Selector.INVOCATION_0, 668 Selector.INVOCATION_0,
654 const SourceString("length"), 669 const SourceString("length"),
655 <HInstruction>[interceptor, receiver], 670 <HInstruction>[interceptor, receiver],
656 getter: true); 671 getter: true);
657 length.propagatedType = HType.INTEGER; 672 types[length] = HType.INTEGER;
658 node.block.addBefore(node, length); 673 node.block.addBefore(node, length);
659 674
660 HBoundsCheck check = new HBoundsCheck(index, length); 675 HBoundsCheck check = new HBoundsCheck(index, length);
661 node.block.addBefore(node, check); 676 node.block.addBefore(node, check);
662 return check; 677 return check;
663 } 678 }
664 679
665 HIntegerCheck insertIntegerCheck(HInstruction node, HInstruction value) { 680 HIntegerCheck insertIntegerCheck(HInstruction node, HInstruction value) {
666 HIntegerCheck check = new HIntegerCheck(value); 681 HIntegerCheck check = new HIntegerCheck(value);
667 node.block.addBefore(node, check); 682 node.block.addBefore(node, check);
668 Set<HInstruction> dominatedUsers = value.dominatedUsers(check); 683 Set<HInstruction> dominatedUsers = value.dominatedUsers(check);
669 for (HInstruction user in dominatedUsers) { 684 for (HInstruction user in dominatedUsers) {
670 user.changeUse(value, check); 685 user.changeUse(value, check);
671 } 686 }
672 return check; 687 return check;
673 } 688 }
674 689
675 void visitIndex(HIndex node) { 690 void visitIndex(HIndex node) {
676 if (!node.receiver.isIndexablePrimitive()) return; 691 if (!node.receiver.isIndexablePrimitive(types)) return;
677 HInstruction index = node.index; 692 HInstruction index = node.index;
678 if (index is HBoundsCheck) return; 693 if (index is HBoundsCheck) return;
679 if (!node.index.isInteger()) { 694 if (!node.index.isInteger(types)) {
680 index = insertIntegerCheck(node, index); 695 index = insertIntegerCheck(node, index);
681 } 696 }
682 index = insertBoundsCheck(node, node.receiver, index); 697 index = insertBoundsCheck(node, node.receiver, index);
683 node.changeUse(node.index, index); 698 node.changeUse(node.index, index);
684 } 699 }
685 700
686 void visitIndexAssign(HIndexAssign node) { 701 void visitIndexAssign(HIndexAssign node) {
687 if (!node.receiver.isMutableArray()) return; 702 if (!node.receiver.isMutableArray(types)) return;
688 HInstruction index = node.index; 703 HInstruction index = node.index;
689 if (index is HBoundsCheck) return; 704 if (index is HBoundsCheck) return;
690 if (!node.index.isInteger()) { 705 if (!node.index.isInteger(types)) {
691 index = insertIntegerCheck(node, index); 706 index = insertIntegerCheck(node, index);
692 } 707 }
693 index = insertBoundsCheck(node, node.receiver, index); 708 index = insertBoundsCheck(node, node.receiver, index);
694 node.changeUse(node.index, index); 709 node.changeUse(node.index, index);
695 } 710 }
696 } 711 }
697 712
698 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { 713 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase {
714 final HTypeMap types;
699 final String name = "SsaDeadCodeEliminator"; 715 final String name = "SsaDeadCodeEliminator";
700 716
701 static bool isDeadCode(HInstruction instruction) { 717 SsaDeadCodeEliminator(this.types);
702 return !instruction.hasSideEffects() 718
719 bool isDeadCode(HInstruction instruction) {
720 return !instruction.hasSideEffects(types)
703 && instruction.usedBy.isEmpty() 721 && instruction.usedBy.isEmpty()
704 && instruction is !HCheck 722 && instruction is !HCheck
705 && instruction is !HTypeGuard 723 && instruction is !HTypeGuard
706 && !instruction.isControlFlow(); 724 && !instruction.isControlFlow();
707 } 725 }
708 726
709 void visitGraph(HGraph graph) { 727 void visitGraph(HGraph graph) {
710 visitPostDominatorTree(graph); 728 visitPostDominatorTree(graph);
711 } 729 }
712 730
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
819 } 837 }
820 phi.block.rewrite(phi, candidate); 838 phi.block.rewrite(phi, candidate);
821 phi.block.removePhi(phi); 839 phi.block.removePhi(phi);
822 } 840 }
823 } 841 }
824 } 842 }
825 843
826 class SsaGlobalValueNumberer implements OptimizationPhase { 844 class SsaGlobalValueNumberer implements OptimizationPhase {
827 final String name = "SsaGlobalValueNumberer"; 845 final String name = "SsaGlobalValueNumberer";
828 final Compiler compiler; 846 final Compiler compiler;
847 final HTypeMap types;
829 final Set<int> visited; 848 final Set<int> visited;
830 849
831 List<int> blockChangesFlags; 850 List<int> blockChangesFlags;
832 List<int> loopChangesFlags; 851 List<int> loopChangesFlags;
833 852
834 SsaGlobalValueNumberer(this.compiler) : visited = new Set<int>(); 853 SsaGlobalValueNumberer(this.compiler, this.types) : visited = new Set<int>();
835 854
836 void visitGraph(HGraph graph) { 855 void visitGraph(HGraph graph) {
837 computeChangesFlags(graph); 856 computeChangesFlags(graph);
838 moveLoopInvariantCode(graph); 857 moveLoopInvariantCode(graph);
839 visitBasicBlock(graph.entry, new ValueSet()); 858 visitBasicBlock(graph.entry, new ValueSet());
840 } 859 }
841 860
842 void moveLoopInvariantCode(HGraph graph) { 861 void moveLoopInvariantCode(HGraph graph) {
843 for (int i = graph.blocks.length - 1; i >= 0; i--) { 862 for (int i = graph.blocks.length - 1; i >= 0; i--) {
844 HBasicBlock block = graph.blocks[i]; 863 HBasicBlock block = graph.blocks[i];
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
950 // Run through all the basic blocks in the graph and fill in the 969 // Run through all the basic blocks in the graph and fill in the
951 // changes flags lists. 970 // changes flags lists.
952 for (int i = length - 1; i >= 0; i--) { 971 for (int i = length - 1; i >= 0; i--) {
953 final HBasicBlock block = graph.blocks[i]; 972 final HBasicBlock block = graph.blocks[i];
954 final int id = block.id; 973 final int id = block.id;
955 974
956 // Compute block changes flags for the block. 975 // Compute block changes flags for the block.
957 int changesFlags = 0; 976 int changesFlags = 0;
958 HInstruction instruction = block.first; 977 HInstruction instruction = block.first;
959 while (instruction !== null) { 978 while (instruction !== null) {
960 instruction.prepareGvn(); 979 instruction.prepareGvn(types);
961 changesFlags |= instruction.getChangesFlags(); 980 changesFlags |= instruction.getChangesFlags();
962 instruction = instruction.next; 981 instruction = instruction.next;
963 } 982 }
964 assert(blockChangesFlags[id] === null); 983 assert(blockChangesFlags[id] === null);
965 blockChangesFlags[id] = changesFlags; 984 blockChangesFlags[id] = changesFlags;
966 985
967 // Loop headers are part of their loop, so update the loop 986 // Loop headers are part of their loop, so update the loop
968 // changes flags accordingly. 987 // changes flags accordingly.
969 if (block.isLoopHeader()) { 988 if (block.isLoopHeader()) {
970 loopChangesFlags[id] |= changesFlags; 989 loopChangesFlags[id] |= changesFlags;
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
1158 } 1177 }
1159 } 1178 }
1160 } 1179 }
1161 1180
1162 1181
1163 // Base class for the handling of recompilation based on inferred 1182 // Base class for the handling of recompilation based on inferred
1164 // field types. 1183 // field types.
1165 class BaseRecompilationVisitor extends HBaseVisitor { 1184 class BaseRecompilationVisitor extends HBaseVisitor {
1166 final JavaScriptBackend backend; 1185 final JavaScriptBackend backend;
1167 final WorkItem work; 1186 final WorkItem work;
1187 final HTypeMap types;
1168 Compiler get compiler() => backend.compiler; 1188 Compiler get compiler() => backend.compiler;
1169 1189
1170 BaseRecompilationVisitor(this.backend, this.work); 1190 BaseRecompilationVisitor(this.backend, this.work, this.types);
1171 1191
1172 abstract void handleFieldGet(HFieldGet node, HType type); 1192 abstract void handleFieldGet(HFieldGet node, HType type);
1173 abstract void handleFieldNumberOperation(HFieldGet field, HType type); 1193 abstract void handleFieldNumberOperation(HFieldGet field, HType type);
1174 1194
1175 // Checks if the binary invocation operates on a field and a 1195 // Checks if the binary invocation operates on a field and a
1176 // constant number. If it does [handleFieldNumberOperation] is 1196 // constant number. If it does [handleFieldNumberOperation] is
1177 // called with the field and the type inferred for the field so far. 1197 // called with the field and the type inferred for the field so far.
1178 void checkFieldNumberOperation(HInvokeBinary node) { 1198 void checkFieldNumberOperation(HInvokeBinary node) {
1179 // Determine if one of the operands is an HFieldGet. 1199 // Determine if one of the operands is an HFieldGet.
1180 HFieldGet field; 1200 HFieldGet field;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1228 } 1248 }
1229 } 1249 }
1230 1250
1231 1251
1232 // Visitor that registers candidates for recompilation. 1252 // Visitor that registers candidates for recompilation.
1233 class SsaRegisterRecompilationCandidates 1253 class SsaRegisterRecompilationCandidates
1234 extends BaseRecompilationVisitor implements OptimizationPhase { 1254 extends BaseRecompilationVisitor implements OptimizationPhase {
1235 final String name = "SsaRegisterRecompileCandidates"; 1255 final String name = "SsaRegisterRecompileCandidates";
1236 HGraph graph; 1256 HGraph graph;
1237 1257
1238 SsaRegisterRecompilationCandidates( 1258 SsaRegisterRecompilationCandidates(JavaScriptBackend backend,
1239 JavaScriptBackend backend, WorkItem work) : super(backend, work); 1259 WorkItem work,
1260 HTypeMap types)
1261 : super(backend, work, types);
1240 1262
1241 void visitGraph(HGraph visitee) { 1263 void visitGraph(HGraph visitee) {
1242 graph = visitee; 1264 graph = visitee;
1243 if (compiler.phase == Compiler.PHASE_COMPILING) { 1265 if (compiler.phase == Compiler.PHASE_COMPILING) {
1244 visitDominatorTree(visitee); 1266 visitDominatorTree(visitee);
1245 } 1267 }
1246 } 1268 }
1247 1269
1248 void handleFieldGet(HFieldGet node, HType type) { 1270 void handleFieldGet(HFieldGet node, HType type) {
1249 assert(compiler.phase == Compiler.PHASE_COMPILING); 1271 assert(compiler.phase == Compiler.PHASE_COMPILING);
1250 compiler.enqueuer.codegen.registerRecompilationCandidate( 1272 compiler.enqueuer.codegen.registerRecompilationCandidate(
1251 work.element); 1273 work.element);
1252 } 1274 }
1253 1275
1254 void handleFieldNumberOperation(HFieldGet node, HType type) { 1276 void handleFieldNumberOperation(HFieldGet node, HType type) {
1255 assert(compiler.phase == Compiler.PHASE_COMPILING); 1277 assert(compiler.phase == Compiler.PHASE_COMPILING);
1256 compiler.enqueuer.codegen.registerRecompilationCandidate( 1278 compiler.enqueuer.codegen.registerRecompilationCandidate(
1257 work.element); 1279 work.element);
1258 } 1280 }
1259 } 1281 }
1260 1282
1261 1283
1262 // Visitor that sets the known or suspected type of fields during 1284 // Visitor that sets the known or suspected type of fields during
1263 // recompilation. 1285 // recompilation.
1264 class SsaRecompilationFieldTypePropagator 1286 class SsaRecompilationFieldTypePropagator
1265 extends BaseRecompilationVisitor implements OptimizationPhase { 1287 extends BaseRecompilationVisitor implements OptimizationPhase {
1266 final String name = "SsaRecompilationFieldTypePropagator"; 1288 final String name = "SsaRecompilationFieldTypePropagator";
1267 HGraph graph; 1289 HGraph graph;
1268 1290
1269 SsaRecompilationFieldTypePropagator( 1291 SsaRecompilationFieldTypePropagator(JavaScriptBackend backend,
1270 JavaScriptBackend backend, WorkItem work) : super(backend, work); 1292 WorkItem work,
1293 HTypeMap types)
1294 : super(backend, work, types);
1271 1295
1272 void visitGraph(HGraph visitee) { 1296 void visitGraph(HGraph visitee) {
1273 graph = visitee; 1297 graph = visitee;
1274 if (compiler.phase == Compiler.PHASE_RECOMPILING) { 1298 if (compiler.phase == Compiler.PHASE_RECOMPILING) {
1275 visitDominatorTree(visitee); 1299 visitDominatorTree(visitee);
1276 } 1300 }
1277 } 1301 }
1278 1302
1279 void handleFieldGet(HFieldGet field, HType type) { 1303 void handleFieldGet(HFieldGet field, HType type) {
1280 assert(compiler.phase == Compiler.PHASE_RECOMPILING); 1304 assert(compiler.phase == Compiler.PHASE_RECOMPILING);
1281 if (!type.isConflicting()) { 1305 if (!type.isConflicting()) {
1282 // If there are no invoked setters with this name, the union of 1306 // If there are no invoked setters with this name, the union of
1283 // the types of the initializers and the setters is guaranteed 1307 // the types of the initializers and the setters is guaranteed
1284 // otherwise it is only speculative. 1308 // otherwise it is only speculative.
1285 Element element = field.element; 1309 Element element = field.element;
1286 assert(!element.isGenerativeConstructorBody()); 1310 assert(!element.isGenerativeConstructorBody());
1287 if (!compiler.codegenWorld.hasInvokedSetter(element, compiler)) { 1311 if (!compiler.codegenWorld.hasInvokedSetter(element, compiler)) {
1288 field.guaranteedType = 1312 field.guaranteedType =
1289 type.union(backend.fieldSettersTypeSoFar(element)); 1313 type.union(backend.fieldSettersTypeSoFar(element));
1290 } else { 1314 } else {
1291 field.propagatedType = 1315 types[field] = type.union(backend.fieldSettersTypeSoFar(element));
1292 type.union(backend.fieldSettersTypeSoFar(element));
1293 } 1316 }
1294 } 1317 }
1295 } 1318 }
1296 1319
1297 void handleFieldNumberOperation(HFieldGet field, HType type) { 1320 void handleFieldNumberOperation(HFieldGet field, HType type) {
1298 assert(compiler.phase == Compiler.PHASE_RECOMPILING); 1321 assert(compiler.phase == Compiler.PHASE_RECOMPILING);
1299 if (compiler.codegenWorld.hasInvokedSetter(field.element, compiler)) { 1322 if (compiler.codegenWorld.hasInvokedSetter(field.element, compiler)) {
1300 // If there are invoked setters we don't know for sure 1323 // If there are invoked setters we don't know for sure
1301 // that the field will hold a value of the calculated 1324 // that the field will hold a value of the calculated
1302 // type, but the fact that the class itself sticks to 1325 // type, but the fact that the class itself sticks to
1303 // this type for the field is still a strong signal 1326 // this type for the field is still a strong signal
1304 // indicating the expected type of the field. 1327 // indicating the expected type of the field.
1305 field.propagatedType = type; 1328 types[field] = type;
1306 } else { 1329 } else {
1307 // If there are no invoked setters we know the type of 1330 // If there are no invoked setters we know the type of
1308 // this field for sure. 1331 // this field for sure.
1309 field.guaranteedType = type; 1332 field.guaranteedType = type;
1310 } 1333 }
1311 } 1334 }
1312 } 1335 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698