Skip to content

Commit d0afa11

Browse files
committed
Merge pull request #14 in G/truffle from ~VOJIN.JOVANOVIC_ORACLE.COM/truffle:issue/AS-745 to master
* commit '37dce9619a7c447a87ee620bdd7b575444556819': Re-factoring the LanguageCache so that languages can be re-initialized with reflection.
2 parents 6d70bc8 + 37dce96 commit d0afa11

File tree

2 files changed

+87
-25
lines changed

2 files changed

+87
-25
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package com.oracle.truffle.api.vm;
24+
25+
import java.lang.reflect.Field;
26+
import java.lang.reflect.InvocationTargetException;
27+
import java.lang.reflect.Method;
28+
import java.util.Map;
29+
30+
import org.junit.Test;
31+
32+
public class LanguageCacheReflectiveReinitializationTest {
33+
34+
@Test
35+
@SuppressWarnings("unchecked")
36+
public void canReinitializeLanguages() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
37+
System.setProperty("com.oracle.truffle.aot", "true");
38+
39+
Class<?> languageCacheClass = Class.forName("com.oracle.truffle.api.vm.LanguageCache");
40+
Field languageCacheField = languageCacheClass.getDeclaredField("CACHE");
41+
languageCacheField.setAccessible(true);
42+
assert languageCacheField.get(null) == null;
43+
44+
Method initMethod = languageCacheClass.getDeclaredMethod("initializeLanguages", ClassLoader.class);
45+
initMethod.setAccessible(true);
46+
Map<String, Object> languages = (Map<String, Object>) initMethod.invoke(null, Thread.currentThread().getContextClassLoader());
47+
48+
assert languages.containsKey("application/x-test") : "Re-initialized languages must contain application/x-test language after reflective initialization.";
49+
}
50+
}

truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/LanguageCache.java

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
* cache with languages found in application classloader.
4747
*/
4848
final class LanguageCache {
49-
static final boolean PRELOAD;
49+
private static final boolean PRELOAD;
5050
private static final Map<String, LanguageCache> CACHE;
5151
private TruffleLanguage<?> language;
5252
private final String className;
@@ -55,18 +55,29 @@ final class LanguageCache {
5555
private final String version;
5656

5757
static {
58-
Map<String, LanguageCache> map = null;
59-
if (TruffleOptions.AOT) {
60-
map = languages();
61-
for (LanguageCache info : map.values()) {
62-
info.getImpl(true);
63-
}
64-
}
65-
CACHE = map;
58+
CACHE = TruffleOptions.AOT ? initializeLanguages(loader()) : null;
6659
PRELOAD = CACHE != null;
6760
}
6861

69-
LanguageCache(String prefix, Properties info, TruffleLanguage<?> language) {
62+
/**
63+
* This method initializes all languages under the provided classloader.
64+
*
65+
* NOTE: Method's signature should not be changed as it is reflectively invoked from AOT
66+
* compilation.
67+
*
68+
* @param loader The classloader to be used for finding languages.
69+
* @return A map of initialized languages.
70+
*/
71+
private static Map<String, LanguageCache> initializeLanguages(ClassLoader loader) {
72+
Map<String, LanguageCache> map;
73+
map = createLanguages(loader);
74+
for (LanguageCache info : map.values()) {
75+
info.createLanguage(loader);
76+
}
77+
return map;
78+
}
79+
80+
private LanguageCache(String prefix, Properties info, TruffleLanguage<?> language) {
7081
this.className = info.getProperty(prefix + "className");
7182
this.name = info.getProperty(prefix + "name");
7283
this.version = info.getProperty(prefix + "version");
@@ -90,20 +101,14 @@ private static ClassLoader loader() {
90101
return l;
91102
}
92103

93-
private static TruffleLanguage<?> find(String name, ClassLoader loader) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
94-
if (PRELOAD) {
95-
return CACHE.get(name).language;
96-
} else {
97-
Class<?> langClazz = Class.forName(name, true, loader);
98-
return (TruffleLanguage<?>) langClazz.getField("INSTANCE").get(null);
99-
}
100-
}
101-
102104
static Map<String, LanguageCache> languages() {
103105
if (PRELOAD) {
104106
return CACHE;
105107
}
106-
ClassLoader loader = loader();
108+
return createLanguages(loader());
109+
}
110+
111+
private static Map<String, LanguageCache> createLanguages(ClassLoader loader) {
107112
Map<String, LanguageCache> map = new LinkedHashMap<>();
108113
Enumeration<URL> en;
109114
try {
@@ -154,13 +159,20 @@ TruffleLanguage<?> getImpl(boolean create) {
154159
return language;
155160
}
156161
if (create) {
157-
try {
158-
language = LanguageCache.find(className, loader());
159-
} catch (Exception ex) {
160-
throw new IllegalStateException("Cannot initialize " + getName() + " language with implementation " + className, ex);
161-
}
162+
createLanguage(loader());
162163
}
163164
return language;
164165
}
165166

167+
private void createLanguage(ClassLoader loader) {
168+
try {
169+
TruffleLanguage<?> result;
170+
Class<?> langClazz = Class.forName(className, true, loader);
171+
result = (TruffleLanguage<?>) langClazz.getField("INSTANCE").get(null);
172+
language = result;
173+
} catch (Exception ex) {
174+
throw new IllegalStateException("Cannot initialize " + getName() + " language with implementation " + className, ex);
175+
}
176+
}
177+
166178
}

0 commit comments

Comments
 (0)