私は、私のカスタム プログラミング言語の REPL に取り組んでいます。Class<?>
これは、入力のバイトコードを生成し、メソッドを使用してインスタンスに変換するために使用するコンパイラの上に実装されますsun.misc.Unsafe.defineClass(String, byte[], int, int, ClassLoader, ProtectionDomain)
。関連するコードは次のようになります (例外処理などの無関係な部分は省略されています)。
void compileAndLoad(List<ICompilable> compilables)
{
List<Class<?>> classes = ...;
for (ICompilable c : compilables)
{
classes.add(compile(compilable));
}
for (Class<?> c : classes)
{
UNSAFE.ensureClassInitialized(c);
}
}
// CLASS_LOADER = Enclosing.class.getClassLoader()
// PROTECTION_DOMAIN = Enclosing.class.getClassLoader()
Class<?> compile(ICompilable compilable)
{
byte[] bytecode = genBytecode(compilable);
String name = compilable.getFullName() // e.g. 'foo.bar.Baz'
return UNSAFE.defineClass(name, bytes, 0, bytes.length, CLASS_LOADER, PROTECTION_DOMAIN);
}
入力で複数のクラスをコンパイルしてロードする必要があるとします。
> class A { interface B { }; func b() = new B { /* anonymous class */ } }
compilables
リストにはコンテンツがあります
[ repl.Result_0, repl.Result_0$A, repl.Result_0$A$0, repl.Result_0$A$B ]
クラスは(匿名) クラスとrepl.Result_0$A
クラスに依存し、バイトコードでそれらの名前を参照します。を使用して定義すると、次のエラーが発生します。repl.Result_0$A$0
repl.Result_0$B
Unsafe
java.lang.NoClassDefFoundError: repl/Result_0$A$B
at sun.misc.Unsafe.defineClass(Native Method)
at MyClass.compile(MyClass.java:42)
// ... snip
Caused by: java.lang.ClassNotFoundException: repl.Result_0$A$B
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 9 more
リストを並べ替えて最初に定義することでこれを解決できることはわかってrepl.Result_0$A$B
いますが、参照もある可能性があるため、それは一般的な解決策ではありませんB -> A
。
Unsafe.defineClass
未解決のクラスの検証エラーを引き起こすことなく、複数のクラスを定義してロードする方法はありますか?