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

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

Issue 1750583002: Revert "dart2js cps: Refactor tracking of side effects." (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 9 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
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/effects.dart ('k') | 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
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 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 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 library dart2js.cps_ir.gvn; 5 library dart2js.cps_ir.gvn;
6 6
7 import 'cps_ir_nodes.dart'; 7 import 'cps_ir_nodes.dart';
8 import '../universe/side_effects.dart'; 8 import '../universe/side_effects.dart';
9 import '../elements/elements.dart'; 9 import '../elements/elements.dart';
10 import 'optimizers.dart' show Pass; 10 import 'optimizers.dart' show Pass;
11 import 'loop_hierarchy.dart'; 11 import 'loop_hierarchy.dart';
12 import 'loop_effects.dart'; 12 import 'loop_effects.dart';
13 import '../world.dart'; 13 import '../world.dart';
14 import '../compiler.dart' show Compiler; 14 import '../compiler.dart' show Compiler;
15 import '../js_backend/js_backend.dart' show JavaScriptBackend; 15 import '../js_backend/js_backend.dart' show JavaScriptBackend;
16 import '../constants/values.dart'; 16 import '../constants/values.dart';
17 import 'type_mask_system.dart'; 17 import 'type_mask_system.dart';
18 import 'effects.dart';
19 18
20 /// Eliminates redundant primitives by reusing the value of another primitive 19 /// Eliminates redundant primitives by reusing the value of another primitive
21 /// that is known to have the same result. Primitives are also hoisted out of 20 /// that is known to have the same result. Primitives are also hoisted out of
22 /// loops when possible. 21 /// loops when possible.
23 /// 22 ///
24 /// Reusing values can introduce new temporaries, which in some cases is more 23 /// Reusing values can introduce new temporaries, which in some cases is more
25 /// expensive than recomputing the value on-demand. For example, pulling an 24 /// expensive than recomputing the value on-demand. For example, pulling an
26 /// expression such as "n+1" out of a loop is generally not worth it. 25 /// expression such as "n+1" out of a loop is generally not worth it.
27 /// Such primitives are said to be "trivial". 26 /// Such primitives are said to be "trivial".
28 /// 27 ///
29 /// Trivial primitives are shared on-demand, i.e. they are only shared if 28 /// Trivial primitives are shared on-demand, i.e. they are only shared if
30 /// this enables a non-trivial primitive to be hoisted out of a loop. 29 /// this enables a non-trivial primitive to be hoisted out of a loop.
31 // 30 //
32 // TODO(asgerf): Enable hoisting across refinement guards when this is safe: 31 // TODO(asgerf): Enable hoisting across refinement guards when this is safe:
33 // - Determine the type required for a given primitive to be "safe" 32 // - Determine the type required for a given primitive to be "safe"
34 // - Recompute the type of a primitive after hoisting. 33 // - Recompute the type of a primitive after hoisting.
35 // E.g. GetIndex on a String can become a GetIndex on an arbitrary 34 // E.g. GetIndex on a String can become a GetIndex on an arbitrary
36 // indexable, which is still safe but the type may change 35 // indexable, which is still safe but the type may change
37 // - Since the new type may be worse, insert a refinement at the old 36 // - Since the new type may be worse, insert a refinement at the old
38 // definition site, so we do not degrade existing type information. 37 // definition site, so we do not degrade existing type information.
39 // 38 //
39 // TODO(asgerf): Put this pass at a better place in the pipeline. We currently
40 // cannot put it anywhere we want, because this pass relies on refinement
41 // nodes being present (for safety), whereas other passes rely on refinement
42 // nodes being absent (for simplicity & precision).
43 //
40 class GVN extends TrampolineRecursiveVisitor implements Pass { 44 class GVN extends TrampolineRecursiveVisitor implements Pass {
41 String get passName => 'GVN'; 45 String get passName => 'GVN';
42 46
43 final Compiler compiler; 47 final Compiler compiler;
44 final TypeMaskSystem types; 48 final TypeMaskSystem types;
45 JavaScriptBackend get backend => compiler.backend; 49 JavaScriptBackend get backend => compiler.backend;
46 World get world => compiler.world; 50 World get world => compiler.world;
47 51
48 final GvnTable gvnTable = new GvnTable(); 52 final GvnTable gvnTable = new GvnTable();
49 GvnVectorBuilder gvnVectorBuilder; 53 GvnVectorBuilder gvnVectorBuilder;
50 LoopHierarchy loopHierarchy; 54 LoopHierarchy loopHierarchy;
51 LoopSideEffects loopEffects; 55 LoopSideEffects loopEffects;
52 56
53 final EffectNumberer effectNumberer = new EffectNumberer();
54
55 /// Effect numbers at the given join point. 57 /// Effect numbers at the given join point.
56 Map<Continuation, EffectNumbers> effectsAt = <Continuation, EffectNumbers>{}; 58 Map<Continuation, EffectNumbers> effectsAt = <Continuation, EffectNumbers>{};
57 59
58 /// The effect numbers at the current position (during traversal). 60 /// The effect numbers at the current position (during traversal).
59 EffectNumbers effectNumbers; 61 EffectNumbers effectNumbers = new EffectNumbers();
60 62
61 /// The loop currently enclosing the binding of a given primitive. 63 /// The loop currently enclosing the binding of a given primitive.
62 final Map<Primitive, Continuation> loopHeaderFor = 64 final Map<Primitive, Continuation> loopHeaderFor =
63 <Primitive, Continuation>{}; 65 <Primitive, Continuation>{};
64 66
65 /// The GVNs for primitives that have been hoisted outside the given loop. 67 /// The GVNs for primitives that have been hoisted outside the given loop.
66 /// 68 ///
67 /// These should be removed from the environment when exiting the loop. 69 /// These should be removed from the environment when exiting the loop.
68 final Map<Continuation, List<int>> loopHoistedBindings = 70 final Map<Continuation, List<int>> loopHoistedBindings =
69 <Continuation, List<int>>{}; 71 <Continuation, List<int>>{};
70 72
71 /// Maps GVNs to a currently-in-scope binding for that value. 73 /// Maps GVNs to a currently-in-scope binding for that value.
72 final Map<int, Primitive> environment = <int, Primitive>{}; 74 final Map<int, Primitive> environment = <int, Primitive>{};
73 75
74 /// Maps GVN'able primitives to their global value number. 76 /// Maps GVN'able primitives to their global value number.
75 final Map<Primitive, int> gvnFor = <Primitive, int>{}; 77 final Map<Primitive, int> gvnFor = <Primitive, int>{};
76 78
77 Continuation currentLoopHeader; 79 Continuation currentLoopHeader;
78 80
79 GVN(this.compiler, this.types); 81 GVN(this.compiler, this.types);
80 82
83 int _usedEffectNumbers = 0;
84 int makeNewEffect() => ++_usedEffectNumbers;
85
81 void rewrite(FunctionDefinition node) { 86 void rewrite(FunctionDefinition node) {
82 effectNumbers = new EffectNumbers.fresh(effectNumberer);
83 gvnVectorBuilder = new GvnVectorBuilder(gvnFor, compiler, types); 87 gvnVectorBuilder = new GvnVectorBuilder(gvnFor, compiler, types);
84 loopHierarchy = new LoopHierarchy(node); 88 loopHierarchy = new LoopHierarchy(node);
85 loopEffects = 89 loopEffects =
86 new LoopSideEffects(node, world, loopHierarchy: loopHierarchy); 90 new LoopSideEffects(node, world, loopHierarchy: loopHierarchy);
87 visit(node); 91 visit(node);
88 } 92 }
89 93
90 // ------------------ GLOBAL VALUE NUMBERING --------------------- 94 // ------------------ GLOBAL VALUE NUMBERING ---------------------
91 95
92 /// True if [prim] can be eliminated if its value is already in scope. 96 /// True if [prim] can be eliminated if its value is already in scope.
(...skipping 21 matching lines...) Expand all
114 // Do not share refinements (they have no runtime or code size cost), and 118 // Do not share refinements (they have no runtime or code size cost), and
115 // do not put them in the GVN table because GvnVectorBuilder unfolds 119 // do not put them in the GVN table because GvnVectorBuilder unfolds
116 // refinements by itself. 120 // refinements by itself.
117 return next; 121 return next;
118 } 122 }
119 123
120 // Update effect numbers due to side effects from a static initializer. 124 // Update effect numbers due to side effects from a static initializer.
121 // GetLazyStatic is GVN'ed like a GetStatic, but the effects of the static 125 // GetLazyStatic is GVN'ed like a GetStatic, but the effects of the static
122 // initializer occur before reading the field. 126 // initializer occur before reading the field.
123 if (prim is GetLazyStatic) { 127 if (prim is GetLazyStatic) {
124 addSideEffectsOfPrimitive(prim); 128 visit(prim);
125 } 129 }
126 130
127 // Compute the GVN vector for this computation. 131 // Compute the GVN vector for this computation.
128 List vector = gvnVectorBuilder.make(prim, effectNumbers); 132 List vector = gvnVectorBuilder.make(prim, effectNumbers);
129 133
130 // Update effect numbers due to side effects. 134 // Update effect numbers due to side effects.
131 // Do this after computing the GVN vector so the primitive's GVN is not 135 // Do this after computing the GVN vector so the primitive's GVN is not
132 // influenced by its own side effects, except in the case of GetLazyStatic. 136 // influenced by its own side effects, except in the case of GetLazyStatic.
133 if (prim is! GetLazyStatic) { 137 if (prim is! GetLazyStatic) {
134 addSideEffectsOfPrimitive(prim); 138 visit(prim);
135 } 139 }
136 140
137 if (vector == null) { 141 if (vector == null) {
138 // The primitive is not GVN'able. Move on. 142 // The primitive is not GVN'able. Move on.
139 return next; 143 return next;
140 } 144 }
141 145
142 // Compute the GVN for this primitive. 146 // Compute the GVN for this primitive.
143 int gvn = gvnTable.insert(vector); 147 int gvn = gvnTable.insert(vector);
144 gvnFor[prim] = gvn; 148 gvnFor[prim] = gvn;
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
336 340
337 bool canIgnoreRefinementGuards(Primitive primitive) { 341 bool canIgnoreRefinementGuards(Primitive primitive) {
338 return primitive is Interceptor; 342 return primitive is Interceptor;
339 } 343 }
340 344
341 /// Returns true if [prim] is a constant that has no significant runtime cost. 345 /// Returns true if [prim] is a constant that has no significant runtime cost.
342 bool isFastConstant(Primitive prim) { 346 bool isFastConstant(Primitive prim) {
343 return prim is Constant && (prim.value.isPrimitive || prim.value.isDummy); 347 return prim is Constant && (prim.value.isPrimitive || prim.value.isDummy);
344 } 348 }
345 349
350 /// True if [element] is a final or constant field or a function.
351 bool isImmutable(Element element) {
352 if (element.isField && backend.isNative(element)) return false;
353 return element.isField && world.fieldNeverChanges(element) ||
354 element.isFunction;
355 }
356
357 bool isImmutableLength(GetLength length) {
358 return types.isDefinitelyFixedLengthIndexable(length.object.definition.type,
359 allowNull: true);
360 }
361
346 /// Assuming [prim] has no side effects, returns true if it can safely 362 /// Assuming [prim] has no side effects, returns true if it can safely
347 /// be hoisted out of [loop] without changing its value or changing the timing 363 /// be hoisted out of [loop] without changing its value or changing the timing
348 /// of a thrown exception. 364 /// of a thrown exception.
349 bool canHoistHeapDependencyOutOfLoop(Primitive prim, Continuation loop) { 365 bool canHoistHeapDependencyOutOfLoop(Primitive prim, Continuation loop) {
350 // If the primitive might throw, we have to check that it is the first 366 // If the primitive might throw, we have to check that it is the first
351 // impure expression in the loop. This has already been checked if 367 // impure expression in the loop. This has already been checked if
352 // [loop] is the current loop header, but for other loops we just give up. 368 // [loop] is the current loop header, but for other loops we just give up.
353 if (!prim.isSafeForElimination && loop != currentLoopHeader) { 369 if (!prim.isSafeForElimination && loop != currentLoopHeader) {
354 return false; 370 return false;
355 } 371 }
356 int effects = loopEffects.getSideEffectsInLoop(loop); 372 if (prim is GetLength && !isImmutableLength(prim)) {
357 return Effects.changesToDepends(effects) & prim.effects == 0; 373 return !loopEffects.loopChangesLength(loop);
374 } else if (prim is GetField && !isImmutable(prim.field)) {
375 return !loopEffects.getSideEffectsInLoop(loop).changesInstanceProperty();
376 } else if (prim is GetStatic && !isImmutable(prim.element)) {
377 return !loopEffects.getSideEffectsInLoop(loop).changesStaticProperty();
378 } else if (prim is GetIndex) {
379 return !loopEffects.getSideEffectsInLoop(loop).changesIndex();
380 } else {
381 return true;
382 }
358 } 383 }
359 384
360 // ------------------ TRAVERSAL AND EFFECT NUMBERING --------------------- 385 // ------------------ TRAVERSAL AND EFFECT NUMBERING ---------------------
361 // 386 //
362 // These methods traverse the IR while updating the current effect numbers. 387 // These methods traverse the IR while updating the current effect numbers.
363 // They are not specific to GVN. 388 // They are not specific to GVN.
389 //
390 // TODO(asgerf): Avoid duplicated code for side effect analysis.
391 // Should be easier to fix once primitives and call expressions are the same.
364 392
365 void addSideEffectsOfPrimitive(Primitive prim) { 393 void addSideEffects(SideEffects fx, {bool length: true}) {
366 addSideEffects(prim.effects); 394 if (fx.changesInstanceProperty()) {
395 effectNumbers.instanceField = makeNewEffect();
396 }
397 if (fx.changesStaticProperty()) {
398 effectNumbers.staticField = makeNewEffect();
399 }
400 if (fx.changesIndex()) {
401 effectNumbers.indexableContent = makeNewEffect();
402 }
403 if (length && fx.changesIndex()) {
404 effectNumbers.indexableLength = makeNewEffect();
405 }
367 } 406 }
368 407
369 void addSideEffects(int effectFlags) { 408 void addAllSideEffects() {
370 effectNumbers.change(effectNumberer, effectFlags); 409 effectNumbers.instanceField = makeNewEffect();
410 effectNumbers.staticField = makeNewEffect();
411 effectNumbers.indexableContent = makeNewEffect();
412 effectNumbers.indexableLength = makeNewEffect();
371 } 413 }
372 414
373 Expression traverseLetHandler(LetHandler node) { 415 Expression traverseLetHandler(LetHandler node) {
374 // Assume any kind of side effects may occur in the try block. 416 // Assume any kind of side effects may occur in the try block.
375 effectsAt[node.handler] = new EffectNumbers.fresh(effectNumberer); 417 effectsAt[node.handler] = new EffectNumbers()
418 ..instanceField = makeNewEffect()
419 ..staticField = makeNewEffect()
420 ..indexableContent = makeNewEffect()
421 ..indexableLength = makeNewEffect();
376 push(node.handler); 422 push(node.handler);
377 return node.body; 423 return node.body;
378 } 424 }
379 425
380 Expression traverseContinuation(Continuation cont) { 426 Expression traverseContinuation(Continuation cont) {
381 Continuation oldLoopHeader = currentLoopHeader; 427 Continuation oldLoopHeader = currentLoopHeader;
382 currentLoopHeader = loopHierarchy.getLoopHeader(cont); 428 currentLoopHeader = loopHierarchy.getLoopHeader(cont);
383 pushAction(() { 429 pushAction(() {
384 currentLoopHeader = oldLoopHeader; 430 currentLoopHeader = oldLoopHeader;
385 }); 431 });
386 for (Parameter param in cont.parameters) { 432 for (Parameter param in cont.parameters) {
387 loopHeaderFor[param] = currentLoopHeader; 433 loopHeaderFor[param] = currentLoopHeader;
388 } 434 }
389 if (cont.isRecursive) { 435 if (cont.isRecursive) {
390 addSideEffects(loopEffects.getSideEffectsInLoop(cont)); 436 addSideEffects(loopEffects.getSideEffectsInLoop(cont), length: false);
437 if (loopEffects.loopChangesLength(cont)) {
438 effectNumbers.indexableLength = makeNewEffect();
439 }
391 pushAction(() { 440 pushAction(() {
392 List<int> hoistedBindings = loopHoistedBindings[cont]; 441 List<int> hoistedBindings = loopHoistedBindings[cont];
393 if (hoistedBindings != null) { 442 if (hoistedBindings != null) {
394 hoistedBindings.forEach(environment.remove); 443 hoistedBindings.forEach(environment.remove);
395 } 444 }
396 }); 445 });
397 } else { 446 } else {
398 effectNumbers = effectsAt[cont]; 447 EffectNumbers join = effectsAt[cont];
399 assert(effectNumbers != null); 448 if (join != null) {
449 effectNumbers = join;
450 } else {
451 // This is a call continuation seen immediately after its use.
452 // Reuse the current effect numbers.
453 }
400 } 454 }
401 455
402 return cont.body; 456 return cont.body;
403 } 457 }
404 458
405 void visitInvokeContinuation(InvokeContinuation node) { 459 void visitInvokeContinuation(InvokeContinuation node) {
406 Continuation cont = node.continuation.definition; 460 Continuation cont = node.continuation.definition;
407 if (cont.isRecursive) return; 461 if (cont.isRecursive) return;
408 EffectNumbers join = effectsAt[cont]; 462 EffectNumbers join = effectsAt[cont];
409 if (join == null) { 463 if (join == null) {
410 effectsAt[cont] = effectNumbers.copy(); 464 effectsAt[cont] = effectNumbers.copy();
411 } else { 465 } else {
412 join.join(effectNumberer, effectNumbers); 466 if (effectNumbers.instanceField != join.instanceField) {
467 join.instanceField = makeNewEffect();
468 }
469 if (effectNumbers.staticField != join.staticField) {
470 join.staticField = makeNewEffect();
471 }
472 if (effectNumbers.indexableContent != join.indexableContent) {
473 join.indexableContent = makeNewEffect();
474 }
475 if (effectNumbers.indexableLength != join.indexableLength) {
476 join.indexableLength = makeNewEffect();
477 }
413 } 478 }
414 } 479 }
415 480
416 void visitBranch(Branch node) { 481 void visitBranch(Branch node) {
417 Continuation trueCont = node.trueContinuation.definition; 482 Continuation trueCont = node.trueContinuation.definition;
418 Continuation falseCont = node.falseContinuation.definition; 483 Continuation falseCont = node.falseContinuation.definition;
419 // Copy the effect number vector once, so the analysis of one branch does 484 // Copy the effect number vector once, so the analysis of one branch does
420 // not influence the other. 485 // not influence the other.
421 effectsAt[trueCont] = effectNumbers; 486 effectsAt[trueCont] = effectNumbers;
422 effectsAt[falseCont] = effectNumbers.copy(); 487 effectsAt[falseCont] = effectNumbers.copy();
423 } 488 }
489
490 void visitInvokeMethod(InvokeMethod node) {
491 addSideEffects(world.getSideEffectsOfSelector(node.selector, node.mask));
492 }
493
494 void visitInvokeStatic(InvokeStatic node) {
495 addSideEffects(world.getSideEffectsOfElement(node.target));
496 }
497
498 void visitInvokeMethodDirectly(InvokeMethodDirectly node) {
499 FunctionElement target = node.target;
500 if (target is ConstructorBodyElement) {
501 ConstructorBodyElement body = target;
502 target = body.constructor;
503 }
504 addSideEffects(world.getSideEffectsOfElement(target));
505 }
506
507 void visitInvokeConstructor(InvokeConstructor node) {
508 addSideEffects(world.getSideEffectsOfElement(node.target));
509 }
510
511 void visitSetStatic(SetStatic node) {
512 effectNumbers.staticField = makeNewEffect();
513 }
514
515 void visitSetField(SetField node) {
516 effectNumbers.instanceField = makeNewEffect();
517 }
518
519 void visitSetIndex(SetIndex node) {
520 effectNumbers.indexableContent = makeNewEffect();
521 }
522
523 void visitForeignCode(ForeignCode node) {
524 addSideEffects(node.nativeBehavior.sideEffects);
525 }
526
527 void visitGetLazyStatic(GetLazyStatic node) {
528 // TODO(asgerf): How do we get the side effects of a lazy field initializer?
529 addAllSideEffects();
530 }
531
532 void visitAwait(Await node) {
533 addAllSideEffects();
534 }
535
536 void visitYield(Yield node) {
537 addAllSideEffects();
538 }
539
540 void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
541 // Push and pop.
542 effectNumbers.indexableContent = makeNewEffect();
543 effectNumbers.indexableLength = makeNewEffect();
544 }
545 }
546
547 /// For each of the four categories of heap locations, the IR is divided into
548 /// regions wherein the given heap locations are known not to be modified.
549 ///
550 /// Each region is identified by its "effect number". Effect numbers from
551 /// different categories have no relationship to each other.
552 class EffectNumbers {
553 int indexableLength = 0;
554 int indexableContent = 0;
555 int staticField = 0;
556 int instanceField = 0;
557
558 EffectNumbers copy() {
559 return new EffectNumbers()
560 ..indexableLength = indexableLength
561 ..indexableContent = indexableContent
562 ..staticField = staticField
563 ..instanceField = instanceField;
564 }
424 } 565 }
425 566
426 /// Maps vectors to numbers, such that two vectors with the same contents 567 /// Maps vectors to numbers, such that two vectors with the same contents
427 /// map to the same number. 568 /// map to the same number.
428 class GvnTable { 569 class GvnTable {
429 Map<GvnEntry, int> _table = <GvnEntry, int>{}; 570 Map<GvnEntry, int> _table = <GvnEntry, int>{};
430 int _usedGvns = 0; 571 int _usedGvns = 0;
431 int _makeNewGvn() => ++_usedGvns; 572 int _makeNewGvn() => ++_usedGvns;
432 573
433 int insert(List vector) { 574 int insert(List vector) {
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
511 652
512 processTypeTestViaFlag(TypeTestViaFlag node) { 653 processTypeTestViaFlag(TypeTestViaFlag node) {
513 vector = [GvnCode.TYPE_TEST_VIA_FLAG, node.dartType]; 654 vector = [GvnCode.TYPE_TEST_VIA_FLAG, node.dartType];
514 } 655 }
515 656
516 processApplyBuiltinOperator(ApplyBuiltinOperator node) { 657 processApplyBuiltinOperator(ApplyBuiltinOperator node) {
517 vector = [GvnCode.BUILTIN_OPERATOR, node.operator.index]; 658 vector = [GvnCode.BUILTIN_OPERATOR, node.operator.index];
518 } 659 }
519 660
520 processGetLength(GetLength node) { 661 processGetLength(GetLength node) {
521 if (node.isFinal) { 662 if (isImmutableLength(node)) {
522 // Omit the effect number for fixed-length lists. Note that if a the list 663 // Omit the effect number for fixed-length lists. Note that if a the list
523 // gets refined to a fixed-length type, we still won't be able to GVN a 664 // gets refined to a fixed-length type, we still won't be able to GVN a
524 // GetLength across the refinement, because the first GetLength uses an 665 // GetLength across the refinement, because the first GetLength uses an
525 // effect number in its vector while the second one does not. 666 // effect number in its vector while the second one does not.
526 vector = [GvnCode.GET_LENGTH]; 667 vector = [GvnCode.GET_LENGTH];
527 } else { 668 } else {
528 vector = [GvnCode.GET_LENGTH, effectNumbers.indexableLength]; 669 vector = [GvnCode.GET_LENGTH, effectNumbers.indexableLength];
529 } 670 }
530 } 671 }
531 672
673 bool isImmutable(Element element) {
674 return element.isFunction ||
675 element.isField && world.fieldNeverChanges(element);
676 }
677
678 bool isImmutableLength(GetLength length) {
679 return types.isDefinitelyFixedLengthIndexable(length.object.definition.type,
680 allowNull: true);
681 }
682
532 bool isNativeField(FieldElement field) { 683 bool isNativeField(FieldElement field) {
533 // TODO(asgerf): We should add a GetNativeField instruction. 684 // TODO(asgerf): We should add a GetNativeField instruction.
534 return backend.isNative(field); 685 return backend.isNative(field);
535 } 686 }
536 687
537 processGetField(GetField node) { 688 processGetField(GetField node) {
538 if (isNativeField(node.field)) { 689 if (isNativeField(node.field)) {
539 vector = null; // Native field access cannot be GVN'ed. 690 vector = null; // Native field access cannot be GVN'ed.
540 } else if (node.isFinal) { 691 } else if (isImmutable(node.field)) {
541 vector = [GvnCode.GET_FIELD, node.field]; 692 vector = [GvnCode.GET_FIELD, node.field];
542 } else { 693 } else {
543 vector = [GvnCode.GET_FIELD, node.field, effectNumbers.instanceField]; 694 vector = [GvnCode.GET_FIELD, node.field, effectNumbers.instanceField];
544 } 695 }
545 } 696 }
546 697
547 processGetIndex(GetIndex node) { 698 processGetIndex(GetIndex node) {
548 vector = [GvnCode.GET_INDEX, effectNumbers.indexableContent]; 699 vector = [GvnCode.GET_INDEX, effectNumbers.indexableContent];
549 } 700 }
550 701
551 visitGetStatic(GetStatic node) { 702 visitGetStatic(GetStatic node) {
552 if (node.isFinal) { 703 if (isImmutable(node.element)) {
553 vector = [GvnCode.GET_STATIC, node.element]; 704 vector = [GvnCode.GET_STATIC, node.element];
554 } else { 705 } else {
555 vector = [GvnCode.GET_STATIC, node.element, effectNumbers.staticField]; 706 vector = [GvnCode.GET_STATIC, node.element, effectNumbers.staticField];
556 } 707 }
557 // Suppress visit to witness argument. 708 // Suppress visit to witness argument.
558 } 709 }
559 710
560 processGetLazyStatic(GetLazyStatic node) { 711 processGetLazyStatic(GetLazyStatic node) {
561 if (node.isFinal) { 712 if (isImmutable(node.element)) {
562 vector = [GvnCode.GET_STATIC, node.element]; 713 vector = [GvnCode.GET_STATIC, node.element];
563 } else { 714 } else {
564 vector = [GvnCode.GET_STATIC, node.element, effectNumbers.staticField]; 715 vector = [GvnCode.GET_STATIC, node.element, effectNumbers.staticField];
565 } 716 }
566 } 717 }
567 718
568 processConstant(Constant node) { 719 processConstant(Constant node) {
569 vector = [GvnCode.CONSTANT, node.value]; 720 vector = [GvnCode.CONSTANT, node.value];
570 } 721 }
571 722
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
609 760
610 @override 761 @override
611 processReference(Reference ref) { 762 processReference(Reference ref) {
612 callback(ref); 763 callback(ref);
613 } 764 }
614 765
615 static void forEach(Primitive node, ReferenceCallback callback) { 766 static void forEach(Primitive node, ReferenceCallback callback) {
616 new InputVisitor(callback).visit(node); 767 new InputVisitor(callback).visit(node);
617 } 768 }
618 } 769 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/effects.dart ('k') | pkg/compiler/lib/src/cps_ir/loop_effects.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698