blob: 2ec6382612cf1353c10b0e4fefef5a24c07d9cf9 [file] [log] [blame]
// Copyright (c) 2023, 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.threading;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.keepanno.annotations.KeepConstraint;
import com.android.tools.r8.keepanno.annotations.KeepItemKind;
import com.android.tools.r8.keepanno.annotations.KeepTarget;
import com.android.tools.r8.keepanno.annotations.MemberAccessFlags;
import com.android.tools.r8.keepanno.annotations.UsedByReflection;
import com.android.tools.r8.keepanno.annotations.UsesReflection;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
/**
* Threading module interface to enable non-blocking usage of R8.
*
* <p>The threading module has multiple implementations outside the main R8 jar. The concrete
* implementations are loaded via reflection. Since these implementations are dynamically loaded the
* interface they implement must be kept.
*/
@UsedByReflection(
description = "Implementations of this interface are dynamically loaded at runtime",
kind = KeepItemKind.CLASS_AND_MEMBERS,
memberAccess = {MemberAccessFlags.PUBLIC})
public interface ThreadingModule {
ExecutorService createSingleThreadedExecutorService();
ExecutorService createThreadedExecutorService(int threadCount);
<T> Future<T> submit(Callable<T> task, ExecutorService executorService) throws ExecutionException;
<T> void awaitFutures(List<Future<T>> futures) throws ExecutionException;
class Loader {
@UsedByReflection(
description = "Prevent analysis any inlining and assumptions of the provider class names",
constraints = {KeepConstraint.NEVER_INLINE})
private static List<String> getProviderNames() {
return ImmutableList.of(
"com.android.tools.r8.threading.providers.blocking.ThreadingModuleBlockingProvider",
"com.android.tools.r8.threading.providers.singlethreaded.ThreadingModuleSingleThreadedProvider");
}
@UsesReflection({
@KeepTarget(
kind = KeepItemKind.CLASS_AND_METHODS,
className =
"com.android.tools.r8.threading.providers."
+ "blocking.ThreadingModuleBlockingProvider",
methodName = "<init>",
methodParameters = {}),
@KeepTarget(
kind = KeepItemKind.CLASS_AND_METHODS,
className =
"com.android.tools.r8.threading.providers."
+ "singlethreaded.ThreadingModuleSingleThreadedProvider",
methodName = "<init>",
methodParameters = {})
})
public static ThreadingModuleProvider load() {
for (String name : getProviderNames()) {
try {
Class<?> providerClass = Class.forName(name);
return (ThreadingModuleProvider) providerClass.getDeclaredConstructor().newInstance();
} catch (ClassNotFoundException ignored) {
continue;
} catch (ReflectiveOperationException e) {
throw new CompilationError("Failure creating provider for the threading module", e);
}
}
throw new CompilationError("Failure to find a provider for the threading module");
}
}
}