blob: bee8182bb6cc47ccd03211d20398c463c163351c [file] [log] [blame]
// 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.ir.conversion;
import com.android.tools.r8.contexts.CompilationContext.ProcessorContext;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
import com.android.tools.r8.utils.ThreadUtils;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
public class D8MethodProcessor extends MethodProcessor {
private final IRConverter converter;
private final ExecutorService executorService;
private final List<Future<?>> futures = Collections.synchronizedList(new ArrayList<>());
private final Set<DexType> scheduled = Sets.newIdentityHashSet();
private ProcessorContext processorContext;
public D8MethodProcessor(IRConverter converter, ExecutorService executorService) {
this.converter = converter;
this.executorService = executorService;
this.processorContext = converter.appView.createProcessorContext();
}
public void addScheduled(DexProgramClass clazz) {
boolean added = scheduled.add(clazz.getType());
assert added;
}
public void newWave() {
this.processorContext = converter.appView.createProcessorContext();
}
@Override
public boolean isProcessedConcurrently(ProgramMethod method) {
// In D8 all methods are considered independently compiled.
return true;
}
@Override
public boolean shouldApplyCodeRewritings(ProgramMethod method) {
return true;
}
@Override
public void scheduleDesugaredMethodForProcessing(ProgramMethod method) {
// TODO(b/179755192): By building up waves of methods in the class converter, we can avoid the
// following check and always process the method asynchronously.
if (!scheduled.contains(method.getHolderType())
&& !converter.appView.getSyntheticItems().isNonLegacySynthetic(method.getHolder())) {
// The non-synthetic holder is not scheduled. It will be processed once holder is scheduled.
return;
}
futures.add(
ThreadUtils.processAsynchronously(
() ->
converter.rewriteDesugaredCode(
method,
OptimizationFeedbackIgnore.getInstance(),
this,
processorContext.createMethodProcessingContext(method)),
executorService));
}
public D8MethodProcessor scheduleDesugaredMethodsForProcessing(Iterable<ProgramMethod> methods) {
methods.forEach(this::scheduleDesugaredMethodForProcessing);
return this;
}
@Override
public CallSiteInformation getCallSiteInformation() {
throw new Unreachable("Invalid attempt to obtain call-site information in D8");
}
public void awaitMethodProcessing() throws ExecutionException {
ThreadUtils.awaitFutures(futures);
futures.clear();
}
public void processMethod(
ProgramMethod method, CfInstructionDesugaringEventConsumer desugaringEventConsumer) {
converter.convertMethod(
method,
desugaringEventConsumer,
this,
processorContext.createMethodProcessingContext(method));
}
public void processDesugaredMethod(ProgramMethod method) {
processMethod(method, CfInstructionDesugaringEventConsumer.createForDesugaredCode());
}
public boolean verifyNoPendingMethodProcessing() {
assert futures.isEmpty();
return true;
}
}