Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Simplify runtime class transformation" #10398

Merged
merged 1 commit into from
Jul 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,12 @@ public Map<Path, Set<String>> getTransformedFilesByJar() {

public static class TransformedClass {

private final String className;
private final byte[] data;
private final String fileName;
private final boolean eager;

public TransformedClass(String className, byte[] data, String fileName, boolean eager) {
this.className = className;
public TransformedClass(byte[] data, String fileName) {
this.data = data;
this.fileName = fileName;
this.eager = eager;
}

public byte[] getData() {
Expand All @@ -56,14 +52,6 @@ public String getFileName() {
return fileName;
}

public String getClassName() {
return className;
}

public boolean isEager() {
return eager;
}

@Override
public boolean equals(Object o) {
if (this == o)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ TransformedClassesBuildItem handleClassTransformation(List<BytecodeTransformerBu
bytecodeTransformerBuildItems.size());
Set<String> noConstScanning = new HashSet<>();
Map<String, Set<String>> constScanning = new HashMap<>();
Set<String> eager = new HashSet<>();
for (BytecodeTransformerBuildItem i : bytecodeTransformerBuildItems) {
bytecodeTransformers.computeIfAbsent(i.getClassToTransform(), (h) -> new ArrayList<>())
.add(i.getVisitorFunction());
Expand All @@ -55,9 +54,6 @@ TransformedClassesBuildItem handleClassTransformation(List<BytecodeTransformerBu
constScanning.computeIfAbsent(i.getClassToTransform(), (s) -> new HashSet<>())
.addAll(i.getRequireConstPoolEntry());
}
if (i.isEager()) {
eager.add(i.getClassToTransform());
}
}
QuarkusClassLoader cl = (QuarkusClassLoader) Thread.currentThread().getContextClassLoader();
Map<String, Path> transformedToArchive = new ConcurrentHashMap<>();
Expand Down Expand Up @@ -104,8 +100,8 @@ public TransformedClassesBuildItem.TransformedClass call() throws Exception {
visitor = i.apply(className, visitor);
}
cr.accept(visitor, 0);
return new TransformedClassesBuildItem.TransformedClass(className, writer.toByteArray(),
classFileName, eager.contains(className));
return new TransformedClassesBuildItem.TransformedClass(writer.toByteArray(),
classFileName);
} finally {
Thread.currentThread().setContextClassLoader(old);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import io.quarkus.deployment.ExtensionLoader;
import io.quarkus.deployment.QuarkusAugmentor;
import io.quarkus.deployment.builditem.ApplicationClassNameBuildItem;
import io.quarkus.deployment.builditem.BytecodeTransformerBuildItem;
import io.quarkus.deployment.builditem.ConfigDescriptionBuildItem;
import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
import io.quarkus.deployment.builditem.GeneratedResourceBuildItem;
Expand All @@ -40,7 +41,6 @@
import io.quarkus.deployment.builditem.MainClassBuildItem;
import io.quarkus.deployment.builditem.RawCommandLineArgumentsBuildItem;
import io.quarkus.deployment.builditem.ShutdownContextBuildItem;
import io.quarkus.deployment.builditem.TransformedClassesBuildItem;
import io.quarkus.deployment.pkg.builditem.ArtifactResultBuildItem;
import io.quarkus.deployment.pkg.builditem.JarBuildItem;
import io.quarkus.deployment.pkg.builditem.NativeImageBuildItem;
Expand Down Expand Up @@ -125,7 +125,7 @@ public StartupActionImpl createInitialRuntimeApplication() {
}
ClassLoader classLoader = curatedApplication.createDeploymentClassLoader();
BuildResult result = runAugment(true, Collections.emptySet(), classLoader, GeneratedClassBuildItem.class,
GeneratedResourceBuildItem.class, TransformedClassesBuildItem.class, ApplicationClassNameBuildItem.class,
GeneratedResourceBuildItem.class, BytecodeTransformerBuildItem.class, ApplicationClassNameBuildItem.class,
MainClassBuildItem.class);
return new StartupActionImpl(curatedApplication, result, classLoader);
}
Expand All @@ -137,7 +137,7 @@ public StartupActionImpl reloadExistingApplication(boolean hasStartedSuccessfull
}
ClassLoader classLoader = curatedApplication.createDeploymentClassLoader();
BuildResult result = runAugment(!hasStartedSuccessfully, changedResources, classLoader, GeneratedClassBuildItem.class,
GeneratedResourceBuildItem.class, TransformedClassesBuildItem.class, ApplicationClassNameBuildItem.class,
GeneratedResourceBuildItem.class, BytecodeTransformerBuildItem.class, ApplicationClassNameBuildItem.class,
MainClassBuildItem.class);
return new StartupActionImpl(curatedApplication, result, classLoader);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,20 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Predicate;

import org.jboss.logging.Logger;
import org.objectweb.asm.ClassVisitor;

import io.quarkus.bootstrap.BootstrapDebug;
import io.quarkus.bootstrap.app.CuratedApplication;
Expand All @@ -27,11 +32,12 @@
import io.quarkus.bootstrap.classloading.QuarkusClassLoader;
import io.quarkus.builder.BuildResult;
import io.quarkus.deployment.builditem.ApplicationClassNameBuildItem;
import io.quarkus.deployment.builditem.BytecodeTransformerBuildItem;
import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
import io.quarkus.deployment.builditem.GeneratedResourceBuildItem;
import io.quarkus.deployment.builditem.MainClassBuildItem;
import io.quarkus.deployment.builditem.TransformedClassesBuildItem;
import io.quarkus.deployment.configuration.RunTimeConfigurationGenerator;
import io.quarkus.deployment.index.ConstPoolScanner;
import io.quarkus.dev.appstate.ApplicationStateNotification;
import io.quarkus.runtime.Quarkus;

Expand All @@ -48,27 +54,30 @@ public StartupActionImpl(CuratedApplication curatedApplication, BuildResult buil
this.curatedApplication = curatedApplication;
this.buildResult = buildResult;
Set<String> eagerClasses = new HashSet<>();
Map<String, byte[]> bytecodeTransformers = extractTransformers(eagerClasses);
Map<String, Predicate<byte[]>> transformerPredicates = new HashMap<>();
Map<String, List<BiFunction<String, ClassVisitor, ClassVisitor>>> bytecodeTransformers = extractTransformers(
eagerClasses, transformerPredicates);
QuarkusClassLoader baseClassLoader = curatedApplication.getBaseRuntimeClassLoader();
QuarkusClassLoader runtimeClassLoader;

//so we have some differences between dev and test mode here.
//test mode only has a single class loader, while dev uses a disposable runtime class loader
//that is discarded between restarts
Map<String, byte[]> resources = new HashMap<>();
resources.putAll(extractGeneratedResources(true));
resources.putAll(bytecodeTransformers);
if (curatedApplication.getQuarkusBootstrap().getMode() == QuarkusBootstrap.Mode.DEV) {
baseClassLoader.reset(extractGeneratedResources(false),
baseClassLoader.reset(extractGeneratedResources(false), bytecodeTransformers, transformerPredicates,
deploymentClassLoader);
runtimeClassLoader = curatedApplication.createRuntimeClassLoader(baseClassLoader,
deploymentClassLoader, resources);
bytecodeTransformers, transformerPredicates,
deploymentClassLoader, extractGeneratedResources(true));
} else {
Map<String, byte[]> resources = new HashMap<>();
resources.putAll(extractGeneratedResources(false));
baseClassLoader.reset(resources, deploymentClassLoader);
resources.putAll(extractGeneratedResources(true));
baseClassLoader.reset(resources, bytecodeTransformers, transformerPredicates, deploymentClassLoader);
runtimeClassLoader = baseClassLoader;
}
this.runtimeClassLoader = runtimeClassLoader;
handleEagerClasses(runtimeClassLoader, eagerClasses);
}

private void handleEagerClasses(QuarkusClassLoader runtimeClassLoader, Set<String> eagerClasses) {
Expand Down Expand Up @@ -253,18 +262,40 @@ public ClassLoader getClassLoader() {
return runtimeClassLoader;
}

private Map<String, byte[]> extractTransformers(Set<String> eagerClasses) {
Map<String, byte[]> ret = new HashMap<>();
TransformedClassesBuildItem transformers = buildResult.consume(TransformedClassesBuildItem.class);
for (Set<TransformedClassesBuildItem.TransformedClass> i : transformers.getTransformedClassesByJar().values()) {
for (TransformedClassesBuildItem.TransformedClass clazz : i) {
ret.put(clazz.getFileName(), clazz.getData());
if (clazz.isEager()) {
eagerClasses.add(clazz.getClassName());
}
private Map<String, List<BiFunction<String, ClassVisitor, ClassVisitor>>> extractTransformers(Set<String> eagerClasses,
Map<String, Predicate<byte[]>> transformerPredicates) {
Map<String, List<BiFunction<String, ClassVisitor, ClassVisitor>>> bytecodeTransformers = new HashMap<>();
Set<String> noConstScanning = new HashSet<>();
Map<String, Set<String>> constScanning = new HashMap<>();
List<BytecodeTransformerBuildItem> transformers = buildResult.consumeMulti(BytecodeTransformerBuildItem.class);
for (BytecodeTransformerBuildItem i : transformers) {
List<BiFunction<String, ClassVisitor, ClassVisitor>> list = bytecodeTransformers.get(i.getClassToTransform());
if (list == null) {
bytecodeTransformers.put(i.getClassToTransform(), list = new ArrayList<>());
}
list.add(i.getVisitorFunction());
if (i.isEager()) {
eagerClasses.add(i.getClassToTransform());
}
if (i.getRequireConstPoolEntry() == null || i.getRequireConstPoolEntry().isEmpty()) {
noConstScanning.add(i.getClassToTransform());
} else {
constScanning.computeIfAbsent(i.getClassToTransform(), (s) -> new HashSet<>())
.addAll(i.getRequireConstPoolEntry());
}
}
for (String i : noConstScanning) {
constScanning.remove(i);
}
for (Map.Entry<String, Set<String>> entry : constScanning.entrySet()) {
transformerPredicates.put(entry.getKey(), new Predicate<byte[]>() {
@Override
public boolean test(byte[] bytes) {
return ConstPoolScanner.constPoolEntryPresent(bytes, entry.getValue());
}
});
}
return ret;
return bytecodeTransformers;
}

private Map<String, byte[]> extractGeneratedResources(boolean applicationClasses) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class VerticleWithClassNameDeploymentTest {
public void testDeploymentOfVerticleUsingClassName() {
String resp1 = RestAssured.get("http://localhost:8080").asString();
String resp2 = RestAssured.get("http://localhost:8080").asString();
Assertions.assertTrue(resp1.startsWith("OK"), resp1);
Assertions.assertTrue(resp1.startsWith("OK"));
Assertions.assertTrue(resp2.startsWith("OK"));
Assertions.assertNotEquals(resp1, resp2);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import org.objectweb.asm.ClassVisitor;

/**
* The result of the curate step that is done by QuarkusBootstrap.
Expand Down Expand Up @@ -265,16 +268,19 @@ public QuarkusClassLoader createDeploymentClassLoader() {
}

public QuarkusClassLoader createRuntimeClassLoader(QuarkusClassLoader loader,
Map<String, List<BiFunction<String, ClassVisitor, ClassVisitor>>> bytecodeTransformers,
Map<String, Predicate<byte[]>> transformerPredicates,
ClassLoader deploymentClassLoader, Map<String, byte[]> resources) {
QuarkusClassLoader.Builder builder = QuarkusClassLoader.builder("Quarkus Runtime ClassLoader",
loader, false)
.setAggregateParentResources(true);
builder.setTransformerPredicates(transformerPredicates);
builder.setTransformerClassLoader(deploymentClassLoader);

builder.addElement(new MemoryClassPathElement(resources));
for (Path root : quarkusBootstrap.getApplicationRoot()) {
builder.addElement(ClassPathElement.fromPath(root));
}
builder.addElement(new MemoryClassPathElement(resources));

for (AdditionalDependency i : getQuarkusBootstrap().getAdditionalApplicationArchives()) {
if (i.isHotReloadable()) {
Expand All @@ -283,6 +289,7 @@ public QuarkusClassLoader createRuntimeClassLoader(QuarkusClassLoader loader,
}
}
}
builder.setBytecodeTransformers(bytecodeTransformers);
return builder.build();
}

Expand Down
Loading