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

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

Powered by Google App Engine
This is Rietveld 408576698