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

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

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

Powered by Google App Engine
This is Rietveld 408576698