| // Copyright (c) 2019, 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.shaking; |
| |
| import static com.android.tools.r8.ir.desugar.records.RecordRewriterHelper.isInvokeDynamicOnRecord; |
| |
| import com.android.tools.r8.androidapi.AndroidApiLevelCompute; |
| import com.android.tools.r8.androidapi.ComputedApiLevel; |
| import com.android.tools.r8.dex.code.CfOrDexInstruction; |
| import com.android.tools.r8.graph.AppInfoWithClassHierarchy; |
| import com.android.tools.r8.graph.AppView; |
| import com.android.tools.r8.graph.DexCallSite; |
| import com.android.tools.r8.graph.DexEncodedField; |
| import com.android.tools.r8.graph.DexEncodedMethod; |
| import com.android.tools.r8.graph.DexField; |
| import com.android.tools.r8.graph.DexMethod; |
| import com.android.tools.r8.graph.DexMethodHandle; |
| import com.android.tools.r8.graph.DexProgramClass; |
| import com.android.tools.r8.graph.DexReference; |
| import com.android.tools.r8.graph.DexType; |
| import com.android.tools.r8.graph.ProgramMethod; |
| import com.android.tools.r8.graph.UseRegistry; |
| import java.util.ListIterator; |
| |
| public class DefaultEnqueuerUseRegistry extends UseRegistry<ProgramMethod> { |
| |
| protected final AppView<? extends AppInfoWithClassHierarchy> appView; |
| protected final Enqueuer enqueuer; |
| private final AndroidApiLevelCompute apiLevelCompute; |
| private ComputedApiLevel maxApiReferenceLevel; |
| |
| public DefaultEnqueuerUseRegistry( |
| AppView<? extends AppInfoWithClassHierarchy> appView, |
| ProgramMethod context, |
| Enqueuer enqueuer, |
| AndroidApiLevelCompute apiLevelCompute) { |
| super(appView, context); |
| this.appView = appView; |
| this.enqueuer = enqueuer; |
| this.apiLevelCompute = apiLevelCompute; |
| maxApiReferenceLevel = appView.computedMinApiLevel(); |
| } |
| |
| public DexProgramClass getContextHolder() { |
| return getContext().getHolder(); |
| } |
| |
| public DexEncodedMethod getContextMethod() { |
| return getContext().getDefinition(); |
| } |
| |
| @Override |
| public void registerInitClass(DexType clazz) { |
| enqueuer.traceInitClass(clazz, getContext()); |
| } |
| |
| @Override |
| public void registerRecordFieldValues(DexField[] fields) { |
| super.registerRecordFieldValues(fields); |
| enqueuer.traceRecordFieldValues(fields, getContext()); |
| } |
| |
| @Override |
| public void registerInvokeVirtual(DexMethod invokedMethod) { |
| setMaxApiReferenceLevel(invokedMethod); |
| enqueuer.traceInvokeVirtual(invokedMethod, getContext()); |
| } |
| |
| @Override |
| public void registerInvokeDirect(DexMethod invokedMethod) { |
| setMaxApiReferenceLevel(invokedMethod); |
| enqueuer.traceInvokeDirect(invokedMethod, getContext()); |
| } |
| |
| @Override |
| public void registerInvokeStatic(DexMethod invokedMethod) { |
| setMaxApiReferenceLevel(invokedMethod); |
| enqueuer.traceInvokeStatic(invokedMethod, getContext()); |
| } |
| |
| @Override |
| public void registerInvokeInterface(DexMethod invokedMethod) { |
| setMaxApiReferenceLevel(invokedMethod); |
| enqueuer.traceInvokeInterface(invokedMethod, getContext()); |
| } |
| |
| @Override |
| public void registerInvokeSuper(DexMethod invokedMethod) { |
| setMaxApiReferenceLevel(invokedMethod); |
| enqueuer.traceInvokeSuper(invokedMethod, getContext()); |
| } |
| |
| @Override |
| public void registerInstanceFieldRead(DexField field) { |
| setMaxApiReferenceLevel(field); |
| enqueuer.traceInstanceFieldRead(field, getContext()); |
| } |
| |
| @Override |
| public void registerInstanceFieldReadFromMethodHandle(DexField field) { |
| setMaxApiReferenceLevel(field); |
| enqueuer.traceInstanceFieldReadFromMethodHandle(field, getContext()); |
| } |
| |
| private void registerInstanceFieldReadFromRecordMethodHandle(DexField field) { |
| setMaxApiReferenceLevel(field); |
| enqueuer.traceInstanceFieldReadFromRecordMethodHandle(field, getContext()); |
| } |
| |
| @Override |
| public void registerInstanceFieldWrite(DexField field) { |
| setMaxApiReferenceLevel(field); |
| enqueuer.traceInstanceFieldWrite(field, getContext()); |
| } |
| |
| @Override |
| public void registerInstanceFieldWriteFromMethodHandle(DexField field) { |
| setMaxApiReferenceLevel(field); |
| enqueuer.traceInstanceFieldWriteFromMethodHandle(field, getContext()); |
| } |
| |
| @Override |
| public void registerNewInstance(DexType type) { |
| setMaxApiReferenceLevel(type); |
| enqueuer.traceNewInstance(type, getContext()); |
| } |
| |
| @Override |
| public void registerStaticFieldRead(DexField field) { |
| setMaxApiReferenceLevel(field); |
| enqueuer.traceStaticFieldRead(field, getContext()); |
| } |
| |
| @Override |
| public void registerStaticFieldReadFromMethodHandle(DexField field) { |
| setMaxApiReferenceLevel(field); |
| enqueuer.traceStaticFieldReadFromMethodHandle(field, getContext()); |
| } |
| |
| @Override |
| public void registerStaticFieldWrite(DexField field) { |
| setMaxApiReferenceLevel(field); |
| enqueuer.traceStaticFieldWrite(field, getContext()); |
| } |
| |
| @Override |
| public void registerStaticFieldWriteFromMethodHandle(DexField field) { |
| setMaxApiReferenceLevel(field); |
| enqueuer.traceStaticFieldWriteFromMethodHandle(field, getContext()); |
| } |
| |
| @Override |
| public void registerConstClass( |
| DexType type, |
| ListIterator<? extends CfOrDexInstruction> iterator, |
| boolean ignoreCompatRules) { |
| enqueuer.traceConstClass(type, getContext(), iterator, ignoreCompatRules); |
| } |
| |
| @Override |
| public void registerCheckCast(DexType type, boolean ignoreCompatRules) { |
| enqueuer.traceCheckCast(type, getContext(), ignoreCompatRules); |
| } |
| |
| @Override |
| public void registerSafeCheckCast(DexType type) { |
| enqueuer.traceSafeCheckCast(type, getContext()); |
| } |
| |
| @Override |
| public void registerTypeReference(DexType type) { |
| enqueuer.traceTypeReference(type, getContext()); |
| } |
| |
| @Override |
| public void registerInstanceOf(DexType type) { |
| enqueuer.traceInstanceOf(type, getContext()); |
| } |
| |
| @Override |
| public void registerExceptionGuard(DexType guard) { |
| setMaxApiReferenceLevel(guard); |
| enqueuer.traceExceptionGuard(guard, getContext()); |
| } |
| |
| @Override |
| public void registerMethodHandle(DexMethodHandle methodHandle, MethodHandleUse use) { |
| super.registerMethodHandle(methodHandle, use); |
| enqueuer.traceMethodHandle(methodHandle, use, getContext()); |
| } |
| |
| @Override |
| public void registerCallSite(DexCallSite callSite) { |
| super.registerCallSiteExceptBootstrapArgs(callSite); |
| if (isInvokeDynamicOnRecord(callSite, appView, getContext()) |
| && appView.options().testing.enableRecordModeling) { |
| registerRecordCallSiteBootstrapArgs(callSite); |
| } else { |
| super.registerCallSiteBootstrapArgs(callSite, 0, callSite.bootstrapArgs.size()); |
| } |
| enqueuer.traceCallSite(callSite, getContext()); |
| } |
| |
| private void registerRecordCallSiteBootstrapArgs(DexCallSite callSite) { |
| // The Instance Get method handle in invokeDynamicOnRecord are considered: |
| // - a record use if not a constant value, |
| // - unused if a constant value. |
| registerCallSiteBootstrapArgs(callSite, 0, 2); |
| for (int i = 2; i < callSite.getBootstrapArgs().size(); i++) { |
| DexField field = callSite.getBootstrapArgs().get(i).asDexValueMethodHandle().value.asField(); |
| DexEncodedField encodedField = |
| appView.appInfo().resolveField(field, getContext()).getResolvedField(); |
| // Member value propagation does not rewrite method handles, special handling for this |
| // method handle access is done after the final tree shaking. |
| if (!encodedField.getOptimizationInfo().isDead()) { |
| registerInstanceFieldReadFromRecordMethodHandle(field); |
| } |
| } |
| } |
| |
| private void setMaxApiReferenceLevel(DexReference reference) { |
| maxApiReferenceLevel = |
| maxApiReferenceLevel.max( |
| apiLevelCompute.computeApiLevelForLibraryReference( |
| reference, apiLevelCompute.getPlatformApiLevelOrUnknown(appView))); |
| } |
| |
| public ComputedApiLevel getMaxApiReferenceLevel() { |
| return maxApiReferenceLevel; |
| } |
| } |