Skip to content

Commit

Permalink
Merge pull request #10398 from gsmet/revert-simplify-transformation
Browse files Browse the repository at this point in the history
Revert "Simplify runtime class transformation"
  • Loading branch information
gsmet authored Jul 1, 2020
2 parents 38f4361 + f5e2a57 commit a2918c8
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 42 deletions.
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

0 comments on commit a2918c8

Please sign in to comment.