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

Side by Side Diff: pkg/compiler/lib/src/cps_ir/gvn.dart

Issue 1444363002: dart2js cps: Global value numbering and loop-invariant code motion. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Rebase Created 5 years 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
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/loop_effects.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
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.
4
5 library dart2js.cps_ir.gvn;
6
7 import 'cps_ir_nodes.dart';
8 import '../universe/side_effects.dart';
9 import '../elements/elements.dart';
10 import 'optimizers.dart' show Pass;
11 import 'loop_hierarchy.dart';
12 import 'loop_effects.dart';
13 import '../world.dart';
14 import '../compiler.dart' show Compiler;
15 import '../js_backend/js_backend.dart' show JavaScriptBackend;
16 import '../constants/values.dart';
17
18 /// Eliminates redundant primitives by reusing the value of another primitive
19 /// that is known to have the same result. Primitives are also hoisted out of
20 /// loops when possible.
21 ///
22 /// Reusing values can introduce new temporaries, which in some cases is more
23 /// expensive than recomputing the value on-demand. For example, pulling an
24 /// expression such as "n+1" out of a loop is generally not worth it.
25 /// Such primitives are said to be "trivial".
26 ///
27 /// Trivial primitives are shared on-demand, i.e. they are only shared if
28 /// this enables a non-trivial primitive to be hoisted out of a loop.
29 //
30 // TODO(asgerf): Enable hoisting across refinement guards when this is safe:
31 // - Determine the type required for a given primitive to be "safe"
32 // - Recompute the type of a primitive after hoisting.
33 // E.g. GetIndex on a String can become a GetIndex on an arbitrary
34 // indexable, which is still safe but the type may change
35 // - Since the new type may be worse, insert a refinement at the old
36 // definition site, so we do not degrade existing type information.
37 //
38 // TODO(asgerf): Put this pass at a better place in the pipeline. We currently
39 // cannot put it anywhere we want, because this pass relies on refinement
40 // nodes being present (for safety), whereas other passes rely on refinement
41 // nodes being absent (for simplicity & precision).
42 //
43 class GVN extends TrampolineRecursiveVisitor implements Pass {
44 String get passName => 'GVN';
45
46 final Compiler compiler;
47 JavaScriptBackend get backend => compiler.backend;
48 World get world => compiler.world;
49
50 final GvnTable gvnTable = new GvnTable();
51 GvnVectorBuilder gvnVectorBuilder;
52 LoopHierarchy loopHierarchy;
53 LoopSideEffects loopEffects;
54
55 /// Effect numbers at the given join point.
56 Map<Continuation, EffectNumbers> effectsAt = <Continuation, EffectNumbers>{};
57
58 /// The effect numbers at the current position (during traversal).
59 EffectNumbers effectNumbers = new EffectNumbers();
60
61 /// The loop currently enclosing the binding of a given primitive.
62 final Map<Primitive, Continuation> loopHeaderFor =
63 <Primitive, Continuation>{};
64
65 /// The loop to which a given trivial primitive can be hoisted.
66 final Map<Primitive, Continuation> potentialLoopHeaderFor =
67 <Primitive, Continuation>{};
68
69 /// The GVNs for primitives that have been hoisted outside the given loop.
70 ///
71 /// These should be removed from the environment when exiting the loop.
72 final Map<Continuation, List<int>> loopHoistedBindings =
73 <Continuation, List<int>>{};
74
75 /// Maps GVNs to a currently-in-scope binding for that value.
76 final Map<int, Primitive> environment = <int, Primitive>{};
77
78 /// Maps GVN'able primitives to their global value number.
79 final Map<Primitive, int> gvnFor = <Primitive, int>{};
80
81 Continuation currentLoopHeader;
82
83 GVN(this.compiler);
84
85 int _usedEffectNumbers = 0;
86 int makeNewEffect() => ++_usedEffectNumbers;
87
88 void rewrite(FunctionDefinition node) {
89 gvnVectorBuilder = new GvnVectorBuilder(gvnFor, backend);
90 loopHierarchy = new LoopHierarchy(node);
91 loopEffects =
92 new LoopSideEffects(node, world, loopHierarchy: loopHierarchy);
93 visit(node);
94 }
95
96 // ------------------ GLOBAL VALUE NUMBERING ---------------------
97
98 @override
99 Expression traverseLetPrim(LetPrim node) {
100 Expression next = node.body;
101 Primitive prim = node.primitive;
102
103 loopHeaderFor[prim] = currentLoopHeader;
104
105 if (prim is Refinement) {
106 // Do not share refinements (they have no runtime or code size cost), and
107 // do not put them in the GVN table because GvnVectorBuilder unfolds
108 // refinements by itself.
109 return next;
110 }
111
112 // Compute the GVN vector for this computation.
113 List vector = gvnVectorBuilder.make(prim, effectNumbers);
114
115 // Update effect numbers due to side effects.
116 // Do this after computing the GVN vector so the primitive's GVN is not
117 // influenced by its own side effects.
118 visit(prim);
119
120 if (vector == null) {
121 // The primitive is not GVN'able. Move on.
122 return next;
123 }
124
125 // Compute the GVN for this primitive.
126 int gvn = gvnTable.insert(vector);
127 gvnFor[prim] = gvn;
128
129 // Try to reuse a previously computed value with the same GVN.
130 Primitive existing = environment[gvn];
131 if (existing != null &&
132 (prim.isSafeForElimination || prim is GetLazyStatic) &&
133 !isTrivialPrimitive(prim)) {
134 if (prim is Interceptor) {
135 Interceptor interceptor = existing;
136 interceptor.interceptedClasses.addAll(prim.interceptedClasses);
137 interceptor.flags |= prim.flags;
138 }
139 prim..replaceUsesWith(existing)..destroy();
140 node.remove();
141 return next;
142 }
143
144 if (tryToHoistOutOfLoop(prim, gvn)) {
145 return next;
146 }
147
148 // The primitive could not be hoisted. Put the primitive in the
149 // environment while processing the body of the LetPrim.
150 environment[gvn] = prim;
151 pushAction(() {
152 assert(environment[gvn] == prim);
153 environment[gvn] = existing;
154 });
155
156 return next;
157 }
158
159 /// Try to hoist the binding of [prim] out of loops. Returns `true` if it was
160 /// hoisted or marked as a trivial hoist-on-demand primitive.
161 bool tryToHoistOutOfLoop(Primitive prim, int gvn) {
162 // Do not hoist primitives with side effects.
163 if (!prim.isSafeForElimination) return false;
164
165 // Bail out fast if the primitive is not inside a loop.
166 if (currentLoopHeader == null) return false;
167
168 LetPrim letPrim = prim.parent;
169
170 // Find the depth of the outermost scope where we can bind the primitive
171 // without bringing a reference out of scope. 0 is the depth of the
172 // top-level scope.
173 int hoistDepth = 0;
174 List<Primitive> inputsHoistedOnDemand = <Primitive>[];
175 InputVisitor.forEach(prim, (Reference ref) {
176 Primitive input = ref.definition;
177 if (canIgnoreRefinementGuards(prim)) {
178 input = input.effectiveDefinition;
179 }
180 Continuation loopHeader;
181 if (potentialLoopHeaderFor.containsKey(input)) {
182 // This is a reference to a value that can be hoisted further out than
183 // it currently is. If we decide to hoist [prim], we must also hoist
184 // such dependent values.
185 loopHeader = potentialLoopHeaderFor[input];
186 inputsHoistedOnDemand.add(input);
187 } else {
188 loopHeader = loopHeaderFor[input];
189 }
190 Continuation referencedLoop =
191 loopHierarchy.lowestCommonAncestor(loopHeader, currentLoopHeader);
192 int depth = loopHierarchy.getDepth(referencedLoop);
193 if (depth > hoistDepth) {
194 hoistDepth = depth;
195 }
196 });
197
198 // Bail out if it can not be hoisted further out than it is now.
199 if (hoistDepth == loopHierarchy.getDepth(currentLoopHeader)) return false;
200
201 // Walk up the loop hierarchy and check at every step that any heap
202 // dependencies can safely be hoisted out of the loop.
203 Continuation enclosingLoop = currentLoopHeader;
204 Continuation hoistTarget = null;
205 while (loopHierarchy.getDepth(enclosingLoop) > hoistDepth &&
206 canHoistHeapDependencyOutOfLoop(prim, enclosingLoop)) {
207 hoistTarget = enclosingLoop;
208 enclosingLoop = loopHierarchy.getEnclosingLoop(enclosingLoop);
209 }
210
211 // Bail out if heap dependencies prohibit any hoisting at all.
212 if (hoistTarget == null) return false;
213
214 if (isTrivialPrimitive(prim)) {
215 // The overhead from introducting a temporary might be greater than
216 // the overhead of evaluating this primitive at every iteration.
217 // Only hoist if this enables hoisting of a non-trivial primitive.
218 potentialLoopHeaderFor[prim] = enclosingLoop;
219 return true;
220 }
221
222 LetCont loopBinding = hoistTarget.parent;
223
224 // The primitive may depend on values that have not yet been
225 // hoisted as far as they can. Hoist those now.
226 for (Primitive input in inputsHoistedOnDemand) {
227 hoistTrivialPrimitive(input, loopBinding, enclosingLoop);
228 }
229
230 // Hoist the primitive.
231 letPrim.remove();
232 letPrim.insertAbove(loopBinding);
233 loopHeaderFor[prim] = enclosingLoop;
234
235 // If a refinement guard was bypassed, use the best refinement
236 // currently in scope.
237 if (canIgnoreRefinementGuards(prim)) {
238 int target = loopHierarchy.getDepth(enclosingLoop);
239 InputVisitor.forEach(prim, (Reference ref) {
240 Primitive input = ref.definition;
241 while (input is Refinement) {
242 Continuation loop = loopHeaderFor[input];
243 loop = loopHierarchy.lowestCommonAncestor(loop, currentLoopHeader);
244 if (loopHierarchy.getDepth(loop) <= target) break;
245 Refinement refinement = input;
246 input = refinement.value.definition;
247 }
248 ref.changeTo(input);
249 });
250 }
251
252 // Put the primitive in the environment while processing the loop.
253 environment[gvn] = prim;
254 loopHoistedBindings
255 .putIfAbsent(hoistTarget, () => <int>[])
256 .add(gvn);
257 return true;
258 }
259
260 /// If the given primitive is a trivial primitive that should be hoisted
261 /// on-demand, hoist it and its dependent values above [loopBinding].
262 void hoistTrivialPrimitive(Primitive prim,
263 LetCont loopBinding,
264 Continuation enclosingLoop) {
265 if (!potentialLoopHeaderFor.containsKey(prim)) return;
266 assert(isTrivialPrimitive(prim));
267
268 // The primitive might already be bound in an outer scope. Do not relocate
269 // the primitive unless we are lifting it. For example;
270 // t1 = a + b
271 // t2 = t1 + c
272 // t3 = t1 * t2
273 // If it was decided that `t3` should be hoisted, `t1` will be seen twice by
274 // this method: by the direct reference and by reference through `t2`.
275 // The second time it is seen, it will already have been moved.
276 Continuation currentLoop = loopHeaderFor[prim];
277 int currentDepth = loopHierarchy.getDepth(currentLoop);
278 int targetDepth = loopHierarchy.getDepth(enclosingLoop);
279 if (currentDepth <= targetDepth) return;
280
281 // Hoist the trivial primitives being depended on so they remain in scope.
282 InputVisitor.forEach(prim, (Reference ref) {
283 hoistTrivialPrimitive(ref.definition, loopBinding, enclosingLoop);
284 });
285
286 // Move the primitive.
287 LetPrim binding = prim.parent;
288 binding.remove();
289 binding.insertAbove(loopBinding);
290 loopHeaderFor[prim] = enclosingLoop;
291
292 if (potentialLoopHeaderFor[prim] == enclosingLoop) {
293 potentialLoopHeaderFor.remove(prim);
294 }
295 }
296
297 bool canIgnoreRefinementGuards(Primitive primitive) {
298 return primitive is Interceptor;
299 }
300
301 /// Returns true if the given primitive is so cheap at runtime that it is
302 /// better to (redundantly) recompute it rather than introduce a temporary.
303 bool isTrivialPrimitive(Primitive primitive) {
304 return primitive is ApplyBuiltinOperator ||
305 primitive is Constant && isTrivialConstant(primitive.value);
306 }
307
308 /// Returns true if the given constant has almost no runtime cost.
309 bool isTrivialConstant(ConstantValue value) {
310 return value.isPrimitive || value.isDummy;
311 }
312
313 /// True if [element] is a final or constant field or a function.
314 bool isImmutable(Element element) {
315 if (element.isField && backend.isNative(element)) return false;
316 return element.isField && (element.isFinal || element.isConst) ||
317 element.isFunction;
318 }
319
320 /// Assuming [prim] has no side effects, returns true if it can safely
321 /// be hoisted out of [loop] without changing its value.
322 bool canHoistHeapDependencyOutOfLoop(Primitive prim, Continuation loop) {
323 assert(prim.isSafeForElimination);
324 if (prim is GetLength) {
325 return !loopEffects.loopChangesLength(loop);
326 } else if (prim is GetField && !isImmutable(prim.field)) {
327 return !loopEffects.getSideEffectsInLoop(loop).changesInstanceProperty();
328 } else if (prim is GetStatic && !isImmutable(prim.element)) {
329 return !loopEffects.getSideEffectsInLoop(loop).changesStaticProperty();
330 } else if (prim is GetIndex) {
331 return !loopEffects.getSideEffectsInLoop(loop).changesIndex();
332 } else {
333 return true;
334 }
335 }
336
337
338 // ------------------ TRAVERSAL AND EFFECT NUMBERING ---------------------
339 //
340 // These methods traverse the IR while updating the current effect numbers.
341 // They are not specific to GVN.
342 //
343 // TODO(asgerf): Avoid duplicated code for side effect analysis.
344 // Should be easier to fix once primitives and call expressions are the same.
345
346 void addSideEffects(SideEffects fx, {bool length: true}) {
347 if (fx.changesInstanceProperty()) {
348 effectNumbers.instanceField = makeNewEffect();
349 }
350 if (fx.changesStaticProperty()) {
351 effectNumbers.staticField = makeNewEffect();
352 }
353 if (fx.changesIndex()) {
354 effectNumbers.indexableContent = makeNewEffect();
355 }
356 if (length && fx.changesIndex()) {
357 effectNumbers.indexableLength = makeNewEffect();
358 }
359 }
360
361 void addAllSideEffects() {
362 effectNumbers.instanceField = makeNewEffect();
363 effectNumbers.staticField = makeNewEffect();
364 effectNumbers.indexableContent = makeNewEffect();
365 effectNumbers.indexableLength = makeNewEffect();
366 }
367
368 Expression traverseLetHandler(LetHandler node) {
369 // Assume any kind of side effects may occur in the try block.
370 effectsAt[node.handler] = new EffectNumbers()
371 ..instanceField = makeNewEffect()
372 ..staticField = makeNewEffect()
373 ..indexableContent = makeNewEffect()
374 ..indexableLength = makeNewEffect();
375 push(node.handler);
376 return node.body;
377 }
378
379 Expression traverseContinuation(Continuation cont) {
380 Continuation oldLoopHeader = currentLoopHeader;
381 currentLoopHeader = loopHierarchy.getLoopHeader(cont);
382 pushAction(() {
383 currentLoopHeader = oldLoopHeader;
384 });
385 for (Parameter param in cont.parameters) {
386 loopHeaderFor[param] = currentLoopHeader;
387 }
388 if (cont.isRecursive) {
389 addSideEffects(loopEffects.getSideEffectsInLoop(cont), length: false);
390 if (loopEffects.loopChangesLength(cont)) {
391 effectNumbers.indexableLength = makeNewEffect();
392 }
393 pushAction(() {
394 List<int> hoistedBindings = loopHoistedBindings[cont];
395 if (hoistedBindings != null) {
396 hoistedBindings.forEach(environment.remove);
397 }
398 });
399 } else {
400 EffectNumbers join = effectsAt[cont];
401 if (join != null) {
402 effectNumbers = join;
403 } else {
404 // This is a call continuation seen immediately after its use.
405 // Reuse the current effect numbers.
406 }
407 }
408
409 return cont.body;
410 }
411
412 void visitInvokeContinuation(InvokeContinuation node) {
413 Continuation cont = node.continuation.definition;
414 if (cont.isRecursive) return;
415 EffectNumbers join = effectsAt[cont];
416 if (join == null) {
417 effectsAt[cont] = effectNumbers.copy();
418 } else {
419 if (effectNumbers.instanceField != join.instanceField) {
420 join.instanceField = makeNewEffect();
421 }
422 if (effectNumbers.staticField != join.staticField) {
423 join.staticField = makeNewEffect();
424 }
425 if (effectNumbers.indexableContent != join.indexableContent) {
426 join.indexableContent = makeNewEffect();
427 }
428 if (effectNumbers.indexableLength != join.indexableLength) {
429 join.indexableLength = makeNewEffect();
430 }
431 }
432 }
433
434 void visitBranch(Branch node) {
435 Continuation trueCont = node.trueContinuation.definition;
436 Continuation falseCont = node.falseContinuation.definition;
437 // Copy the effect number vector once, so the analysis of one branch does
438 // not influence the other.
439 effectsAt[trueCont] = effectNumbers;
440 effectsAt[falseCont] = effectNumbers.copy();
441 }
442
443 void visitInvokeMethod(InvokeMethod node) {
444 addSideEffects(world.getSideEffectsOfSelector(node.selector, node.mask));
445 }
446
447 void visitInvokeStatic(InvokeStatic node) {
448 addSideEffects(world.getSideEffectsOfElement(node.target));
449 }
450
451 void visitInvokeMethodDirectly(InvokeMethodDirectly node) {
452 FunctionElement target = node.target;
453 if (target is ConstructorBodyElement) {
454 ConstructorBodyElement body = target;
455 target = body.constructor;
456 }
457 addSideEffects(world.getSideEffectsOfElement(target));
458 }
459
460 void visitInvokeConstructor(InvokeConstructor node) {
461 addSideEffects(world.getSideEffectsOfElement(node.target));
462 }
463
464 void visitSetStatic(SetStatic node) {
465 effectNumbers.staticField = makeNewEffect();
466 }
467
468 void visitSetField(SetField node) {
469 effectNumbers.instanceField = makeNewEffect();
470 }
471
472 void visitSetIndex(SetIndex node) {
473 effectNumbers.indexableContent = makeNewEffect();
474 }
475
476 void visitForeignCode(ForeignCode node) {
477 addSideEffects(node.nativeBehavior.sideEffects);
478 }
479
480 void visitGetLazyStatic(GetLazyStatic node) {
481 // TODO(asgerf): How do we get the side effects of a lazy field initializer?
482 addAllSideEffects();
483 }
484
485 void visitAwait(Await node) {
486 addAllSideEffects();
487 }
488
489 void visitYield(Yield node) {
490 addAllSideEffects();
491 }
492
493 void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
494 // Push and pop.
495 effectNumbers.indexableContent = makeNewEffect();
496 effectNumbers.indexableLength = makeNewEffect();
497 }
498 }
499
500 /// For each of the four categories of heap locations, the IR is divided into
501 /// regions wherein the given heap locations are known not to be modified.
502 ///
503 /// Each region is identified by its "effect number". Effect numbers from
504 /// different categories have no relationship to each other.
505 class EffectNumbers {
506 int indexableLength = 0;
507 int indexableContent = 0;
508 int staticField = 0;
509 int instanceField = 0;
510
511 EffectNumbers copy() {
512 return new EffectNumbers()
513 ..indexableLength = indexableLength
514 ..indexableContent = indexableContent
515 ..staticField = staticField
516 ..instanceField = instanceField;
517 }
518 }
519
520 /// Maps vectors to numbers, such that two vectors with the same contents
521 /// map to the same number.
522 class GvnTable {
523 Map<GvnEntry, int> _table = <GvnEntry, int>{};
524 int _usedGvns = 0;
525 int _makeNewGvn() => ++_usedGvns;
526
527 int insert(List vector) {
528 return _table.putIfAbsent(new GvnEntry(vector), _makeNewGvn);
529 }
530 }
531
532 /// Wrapper around a [List] that compares for equality based on contents
533 /// instead of object identity.
534 class GvnEntry {
535 final List vector;
536 final int hashCode;
537
538 GvnEntry(List vector) : vector = vector, hashCode = computeHashCode(vector);
539
540 bool operator==(other) {
541 if (other is! GvnEntry) return false;
542 GvnEntry entry = other;
543 List otherVector = entry.vector;
544 if (vector.length != otherVector.length) return false;
545 for (int i = 0; i < vector.length; ++i) {
546 if (vector[i] != otherVector[i]) return false;
547 }
548 return true;
549 }
550
551 /// Combines the hash codes of [vector] using Jenkin's hash function, with
552 /// intermdiate results truncated to SMI range.
553 static int computeHashCode(List vector) {
554 int hash = 0;
555 for (int i = 0; i < vector.length; ++i) {
556 hash = 0x1fffffff & (hash + vector[i].hashCode);
557 hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
558 hash = hash ^ (hash >> 6);
559 }
560 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
561 hash = hash ^ (hash >> 11);
562 return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
563 }
564 }
565
566 /// Converts GVN'able primitives to a vector containing all the values
567 /// to be considered when computing a GVN for it.
568 ///
569 /// This includes the instruction type, inputs, effect numbers for any part
570 /// of the heap being depended on, as well as any instruction-specific payload
571 /// such as any DartTypes, Elements, and operator kinds.
572 ///
573 /// Each `visit` or `process` method for a primitive must initialize [vector]
574 /// if the primitive is GVN'able and fill in any components except the inputs.
575 /// The inputs will be filled in by [processReference].
576 class GvnVectorBuilder extends DeepRecursiveVisitor {
577 List vector;
578 final Map<Primitive, int> gvnFor;
579 final JavaScriptBackend backend;
580 EffectNumbers effectNumbers;
581
582 GvnVectorBuilder(this.gvnFor, this.backend);
583
584 List make(Primitive prim, EffectNumbers effectNumbers) {
585 this.effectNumbers = effectNumbers;
586 vector = null;
587 visit(prim);
588 return vector;
589 }
590
591 /// The `process` methods below do not insert the referenced arguments into
592 /// the vector, but instead rely on them being inserted here.
593 processReference(Reference ref) {
594 if (vector == null) return;
595 Primitive prim = ref.definition.effectiveDefinition;
596 vector.add(gvnFor[prim] ?? prim);
597 }
598
599 visitTypeTest(TypeTest node) {
600 vector = [GvnCode.TYPE_TEST, node.dartType];
601 processReference(node.value);
602 node.typeArguments.forEach(processReference);
603 // Suppress processing of the interceptor argument.
604 }
605
606 processTypeTestViaFlag(TypeTestViaFlag node) {
607 vector = [GvnCode.TYPE_TEST_VIA_FLAG, node.dartType];
608 }
609
610 processApplyBuiltinOperator(ApplyBuiltinOperator node) {
611 vector = [GvnCode.BUILTIN_OPERATOR, node.operator.index];
612 }
613
614 processGetLength(GetLength node) {
615 // TODO(asgerf): Take fixed lengths into account?
616 vector = [GvnCode.GET_LENGTH, effectNumbers.indexableLength];
617 }
618
619 bool isImmutable(Element element) {
620 return element.isFunction ||
621 element.isField && (element.isFinal || element.isConst);
622 }
623
624 bool isNativeField(FieldElement field) {
625 // TODO(asgerf): We should add a GetNativeField instruction.
626 return backend.isNative(field);
627 }
628
629 processGetField(GetField node) {
630 if (isNativeField(node.field)) {
631 vector = null; // Native field access cannot be GVN'ed.
632 } else if (isImmutable(node.field)) {
633 vector = [GvnCode.GET_FIELD, node.field];
634 } else {
635 vector = [GvnCode.GET_FIELD, node.field, effectNumbers.instanceField];
636 }
637 }
638
639 processGetIndex(GetIndex node) {
640 vector = [GvnCode.GET_INDEX, effectNumbers.indexableContent];
641 }
642
643 processGetStatic(GetStatic node) {
644 if (isImmutable(node.element)) {
645 vector = [GvnCode.GET_STATIC, node.element];
646 } else {
647 vector = [GvnCode.GET_STATIC, node.element, effectNumbers.staticField];
648 }
649 }
650
651 processGetLazyStatic(GetLazyStatic node) {
652 if (isImmutable(node.element)) {
653 vector = [GvnCode.GET_STATIC, node.element];
654 } else {
655 vector = [GvnCode.GET_STATIC, node.element, effectNumbers.staticField];
656 }
657 }
658
659 processConstant(Constant node) {
660 vector = [GvnCode.CONSTANT, node.value];
661 }
662
663 processReifyRuntimeType(ReifyRuntimeType node) {
664 vector = [GvnCode.REIFY_RUNTIME_TYPE];
665 }
666
667 processReadTypeVariable(ReadTypeVariable node) {
668 vector = [GvnCode.READ_TYPE_VARIABLE, node.variable];
669 }
670
671 processTypeExpression(TypeExpression node) {
672 vector = [GvnCode.TYPE_EXPRESSION, node.dartType];
673 }
674
675 processInterceptor(Interceptor node) {
676 vector = [GvnCode.INTERCEPTOR];
677 }
678 }
679
680 class GvnCode {
681 static const int TYPE_TEST = 1;
682 static const int TYPE_TEST_VIA_FLAG = 2;
683 static const int BUILTIN_OPERATOR = 3;
684 static const int GET_LENGTH = 4;
685 static const int GET_FIELD = 5;
686 static const int GET_INDEX = 6;
687 static const int GET_STATIC = 7;
688 static const int CONSTANT = 8;
689 static const int REIFY_RUNTIME_TYPE = 9;
690 static const int READ_TYPE_VARIABLE = 10;
691 static const int TYPE_EXPRESSION = 11;
692 static const int INTERCEPTOR = 12;
693 }
694
695 typedef ReferenceCallback(Reference ref);
696 class InputVisitor extends DeepRecursiveVisitor {
697 ReferenceCallback callback;
698
699 InputVisitor(this.callback);
700
701 @override
702 processReference(Reference ref) {
703 callback(ref);
704 }
705
706 static void forEach(Primitive node, ReferenceCallback callback) {
707 new InputVisitor(callback).visit(node);
708 }
709 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/loop_effects.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698