Skip to content

Commit a431239

Browse files
committed
[GR-50682] Quarkus fails even if class loader disabled.
PullRequest: graal/16311
2 parents f62e631 + 9867608 commit a431239

File tree

5 files changed

+48
-48
lines changed

5 files changed

+48
-48
lines changed

sdk/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ This changelog summarizes major changes between GraalVM SDK versions. The main f
88
* (GR-49386) Added the ability to use `Value#as(ByteSequence.class)` to map guest language byte buffers (`Value#hasBufferElements()`) to the read-only `ByteSequence` interface in order to access the bytes without copying the guest language buffer.
99
* (GR-49386) Custom implementations of `ByteSequence`, like the values returned by `ByteSequence.create(byte[])`, are now interpreted by guest languages as buffers.
1010
* (GR-38404) Added the ability to use `Value#as(Collection.class)` to map guest language arrays (`Value#hasArrayElements()`) to the `Collection` interface in order to access the array elements without copying the guest language array.
11+
* (GR-50682) The Truffle languages and instrument implementations are now loaded exclusively using the context class loader if it is set and Truffle is found there. If the context class loader is not set or Truffle is not found, then the system class loader is used instead. Previously, the context and system class loader were used to load Truffle languages and instruments which causes issues if the context class loader does not delegate to the system class loader and classes are loaded from both. Context class loaders that do not delegate to the system class loader are commonly used to implement hot-reload functionality.
12+
1113

1214
## Version 23.1.0
1315
* (GR-43819) The GraalVM SDK was split into several more fine-grained modules. The use of the graalvm-sdk module is now deprecated. Please update your Maven and module dependencies accordingly. Note that all APIs remain compatible. The following new modules are available:

truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
import java.util.logging.Level;
7575
import java.util.logging.LogRecord;
7676

77+
import com.oracle.truffle.api.Truffle;
7778
import org.graalvm.collections.Pair;
7879
import org.graalvm.nativeimage.ImageInfo;
7980
import org.graalvm.options.OptionKey;
@@ -157,24 +158,57 @@ private static List<AbstractClassLoaderSupplier> locatorLoaders() {
157158
return null;
158159
}
159160
List<AbstractClassLoaderSupplier> suppliers = new ArrayList<>(2 + loaders.size());
160-
suppliers.add(new ModulePathLoaderSupplier(ClassLoader.getSystemClassLoader()));
161-
suppliers.add(new WeakModulePathLoaderSupplier(Thread.currentThread().getContextClassLoader()));
161+
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
162+
if (isValidLoader(systemClassLoader)) {
163+
suppliers.add(new ModulePathLoaderSupplier(systemClassLoader));
164+
}
165+
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
166+
if (isValidLoader(contextClassLoader)) {
167+
suppliers.add(new WeakModulePathLoaderSupplier(contextClassLoader));
168+
}
162169
for (ClassLoader loader : loaders) {
163-
suppliers.add(new StrongClassLoaderSupplier(loader));
170+
if (isValidLoader(loader)) {
171+
suppliers.add(new StrongClassLoaderSupplier(loader));
172+
}
164173
}
165174
return suppliers;
166175
}
167176

168-
private static List<AbstractClassLoaderSupplier> defaultLoaders() {
169-
return List.of(new StrongClassLoaderSupplier(EngineAccessor.class.getClassLoader()),
170-
new StrongClassLoaderSupplier(ClassLoader.getSystemClassLoader()),
171-
new WeakClassLoaderSupplier(Thread.currentThread().getContextClassLoader()));
177+
private static AbstractClassLoaderSupplier defaultLoader() {
178+
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
179+
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
180+
if (contextClassLoader != null && isValidLoader(contextClassLoader)) {
181+
return new WeakClassLoaderSupplier(contextClassLoader);
182+
} else if (isValidLoader(systemClassLoader)) {
183+
return new StrongClassLoaderSupplier(ClassLoader.getSystemClassLoader());
184+
} else {
185+
/*
186+
* This class loader is necessary for classpath isolation, enabled by the
187+
* `-Dpolyglotimpl.DisableClassPathIsolation=false` option. It's needed because the
188+
* system classloader does not load Truffle from a new module layer but from an unnamed
189+
* module.
190+
*/
191+
return new StrongClassLoaderSupplier(EngineAccessor.class.getClassLoader());
192+
}
193+
}
194+
195+
/**
196+
* Check that Truffle classes loaded by {@code loader} are the same as active Truffle runtime
197+
* classes.
198+
*/
199+
private static boolean isValidLoader(ClassLoader loader) {
200+
try {
201+
Class<?> truffleClassAsSeenByLoader = Class.forName(Truffle.class.getName(), true, loader);
202+
return truffleClassAsSeenByLoader == Truffle.class;
203+
} catch (ClassNotFoundException ex) {
204+
return false;
205+
}
172206
}
173207

174208
static List<AbstractClassLoaderSupplier> locatorOrDefaultLoaders() {
175209
List<AbstractClassLoaderSupplier> loaders = locatorLoaders();
176210
if (loaders == null) {
177-
loaders = defaultLoaders();
211+
loaders = List.of(defaultLoader());
178212
}
179213
return loaders;
180214
}
@@ -302,7 +336,7 @@ public <T> Iterable<T> loadServices(Class<T> type) {
302336
}
303337
for (AbstractClassLoaderSupplier loaderSupplier : EngineAccessor.locatorOrDefaultLoaders()) {
304338
ClassLoader loader = loaderSupplier.get();
305-
if (seesTheSameClass(loader, type)) {
339+
if (loader != null) {
306340
// 2) Lookup implementations of a module aware interface
307341
for (T service : ServiceLoader.load(type, loader)) {
308342
if (loaderSupplier.accepts(service.getClass())) {
@@ -325,14 +359,6 @@ public <T> Iterable<T> loadServices(Class<T> type) {
325359
return found.values();
326360
}
327361

328-
private static boolean seesTheSameClass(ClassLoader loader, Class<?> type) {
329-
try {
330-
return loader != null && loader.loadClass(type.getName()) == type;
331-
} catch (ClassNotFoundException ex) {
332-
return false;
333-
}
334-
}
335-
336362
@Override
337363
public <T> T lookup(InstrumentInfo info, Class<T> serviceClass) {
338364
PolyglotInstrument instrument = (PolyglotInstrument) LANGUAGE.getPolyglotInstrument(info);

truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ static List<InstrumentCache> doLoad(List<AbstractClassLoaderSupplier> suppliers)
170170
Map<String, Map<String, Supplier<InternalResourceCache>>> optionalResources = InternalResourceCache.loadOptionalInternalResources(suppliers);
171171
for (AbstractClassLoaderSupplier supplier : suppliers) {
172172
ClassLoader loader = supplier.get();
173-
if (loader == null || !isValidLoader(loader)) {
173+
if (loader == null) {
174174
continue;
175175
}
176176
usesTruffleClassLoader |= truffleClassLoader == loader;
@@ -249,15 +249,6 @@ private static void loadInstrumentImpl(ProviderAdapter providerAdapter, List<? s
249249
}
250250
}
251251

252-
private static boolean isValidLoader(ClassLoader loader) {
253-
try {
254-
Class<?> truffleInstrumentClassAsSeenByLoader = Class.forName(TruffleInstrument.class.getName(), true, loader);
255-
return truffleInstrumentClassAsSeenByLoader == TruffleInstrument.class;
256-
} catch (ClassNotFoundException ex) {
257-
return false;
258-
}
259-
}
260-
261252
String getId() {
262253
return id;
263254
}

truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceCache.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242

4343
import com.oracle.truffle.api.CompilerDirectives;
4444
import com.oracle.truffle.api.InternalResource;
45-
import com.oracle.truffle.api.TruffleLanguage;
4645
import com.oracle.truffle.api.TruffleOptions;
4746
import com.oracle.truffle.api.provider.InternalResourceProvider;
4847
import com.oracle.truffle.polyglot.EngineAccessor.AbstractClassLoaderSupplier;
@@ -384,7 +383,7 @@ private static Map<String, Map<String, Supplier<InternalResourceCache>>> collect
384383
Map<String, Map<String, Supplier<InternalResourceCache>>> cache = new HashMap<>();
385384
for (EngineAccessor.AbstractClassLoaderSupplier supplier : suppliers) {
386385
ClassLoader loader = supplier.get();
387-
if (loader == null || !isValidLoader(loader)) {
386+
if (loader == null) {
388387
continue;
389388
}
390389
StreamSupport.stream(ServiceLoader.load(InternalResourceProvider.class, loader).spliterator(), false).filter((p) -> supplier.accepts(p.getClass())).forEach((p) -> {
@@ -406,15 +405,6 @@ private static boolean hasSameCodeSource(OptionalResourceSupplier first, Optiona
406405
return first.optionalResourceProvider.getClass() == second.optionalResourceProvider.getClass();
407406
}
408407

409-
private static boolean isValidLoader(ClassLoader loader) {
410-
try {
411-
Class<?> truffleLanguageClassAsSeenByLoader = Class.forName(TruffleLanguage.class.getName(), true, loader);
412-
return truffleLanguageClassAsSeenByLoader == TruffleLanguage.class;
413-
} catch (ClassNotFoundException ex) {
414-
return false;
415-
}
416-
}
417-
418408
static RuntimeException throwDuplicateOptionalResourceException(InternalResourceCache existing, InternalResourceCache duplicate) {
419409
String message = String.format("Duplicate optional resource id %s for component %s. First optional resource [%s]. Second optional resource [%s].",
420410
existing.resourceId,

truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ private static synchronized Map<String, LanguageCache> createLanguages(List<Abst
270270
Map<String, Map<String, Supplier<InternalResourceCache>>> optionalResources = InternalResourceCache.loadOptionalInternalResources(suppliers);
271271
for (AbstractClassLoaderSupplier supplier : suppliers) {
272272
ClassLoader loader = supplier.get();
273-
if (loader == null || !isValidLoader(loader)) {
273+
if (loader == null) {
274274
continue;
275275
}
276276
loadProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadLanguageImpl(p, caches, optionalResources));
@@ -316,15 +316,6 @@ private static boolean hasSameCodeSource(LanguageCache first, LanguageCache seco
316316
return first.providerAdapter.getProviderClass() == second.providerAdapter.getProviderClass();
317317
}
318318

319-
private static boolean isValidLoader(ClassLoader loader) {
320-
try {
321-
Class<?> truffleLanguageClassAsSeenByLoader = Class.forName(TruffleLanguage.class.getName(), true, loader);
322-
return truffleLanguageClassAsSeenByLoader == TruffleLanguage.class;
323-
} catch (ClassNotFoundException ex) {
324-
return false;
325-
}
326-
}
327-
328319
private static void loadLanguageImpl(ProviderAdapter providerAdapter, List<LanguageCache> into, Map<String, Map<String, Supplier<InternalResourceCache>>> optionalResources) {
329320
Class<?> providerClass = providerAdapter.getProviderClass();
330321
Module providerModule = providerClass.getModule();

0 commit comments

Comments
 (0)