aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackDelayed.java
blob: a8c81ef75b3a9c1928626a658e15350f66a93672 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

package com.android.tools.r8.ir.conversion;

import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.ir.optimize.Inliner.Constraint;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.Reference2LongMap;
import it.unimi.dsi.fastutil.objects.Reference2LongOpenHashMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class OptimizationFeedbackDelayed implements OptimizationFeedback {

  private Reference2IntMap<DexEncodedMethod> returnsArgument = new Reference2IntOpenHashMap<>();
  private Reference2LongMap<DexEncodedMethod> returnsConstant = new Reference2LongOpenHashMap<>();
  private Set<DexEncodedMethod> neverReturnsNull = Sets.newIdentityHashSet();
  private Map<DexEncodedMethod, Constraint> inliningConstraints = Maps.newIdentityHashMap();

  @Override
  synchronized public void methodReturnsArgument(DexEncodedMethod method, int argument) {
    if (method.getOptimizationInfo().returnsArgument()) {
      assert method.getOptimizationInfo().getReturnedArgument() == argument;
      return;
    }
    assert !returnsArgument.containsKey(method);
    returnsArgument.put(method, argument);
  }

  @Override
  synchronized public void methodReturnsConstant(DexEncodedMethod method, long value) {
    if (method.getOptimizationInfo().returnsConstant()) {
      assert method.getOptimizationInfo().getReturnedConstant() == value;
      return;
    }
    assert !returnsConstant.containsKey(method);
    returnsConstant.put(method, value);
  }

  @Override
  synchronized public void methodNeverReturnsNull(DexEncodedMethod method) {
    if (method.getOptimizationInfo().neverReturnsNull()) {
      return;
    }
    assert !neverReturnsNull.contains(method);
    neverReturnsNull.add(method);
  }

  @Override
  public void markProcessed(DexEncodedMethod method, Constraint state) {
    if (state == Constraint.NEVER) {
      assert method.cannotInline();
      method.markProcessed(state);
    } else {
      inliningConstraints.put(method, state);
    }
  }

  private <T> boolean setsOverlap(Set<T> set1, Set<T> set2) {
    for (T element : set1) {
      if (set2.contains(element)) {
        return true;
      }
    }
    return false;
  }

  /**
   * Apply the optimization feedback.
   *
   * Returns the methods from the passed in list that could be affected by applying the
   * optimization feedback.
   */
  public List<DexEncodedMethod> applyAndClear(
      List<DexEncodedMethod> processed, CallGraph.Leaves leaves) {
    returnsArgument.forEach(DexEncodedMethod::markReturnsArgument);
    returnsConstant.forEach(DexEncodedMethod::markReturnsConstant);
    neverReturnsNull.forEach(DexEncodedMethod::markNeverReturnsNull);

    // Collect all methods affected by the optimization feedback applied.
    Set<DexEncodedMethod> all = Sets.newIdentityHashSet();
    all.addAll(returnsArgument.keySet());
    all.addAll(returnsConstant.keySet());
    all.addAll(neverReturnsNull);
    inliningConstraints.forEach((method, constraint) -> {
      boolean changed = method.markProcessed(constraint);
      if (changed) {
        all.add(method);
      }
    });

    // Collect the processed methods which could be affected by the applied optimization feedback.
    List<DexEncodedMethod> result = new ArrayList<>();
    for (DexEncodedMethod method : processed) {
      Set<DexEncodedMethod> calls = leaves.getCycleBreakingCalls().get(method);
      if (setsOverlap(calls, all)) {
        result.add(method);
      }
    }

    // Clear the collected optimization feedback.
    returnsArgument.clear();
    returnsConstant.clear();
    neverReturnsNull.clear();
    inliningConstraints.clear();

    return result;
  }
}