From 4ccfc7ec63a8986140fbd9c9d21852e2ad509e57 Mon Sep 17 00:00:00 2001 From: Philippe Suter Date: Sun, 2 Dec 2012 23:32:42 +0100 Subject: [PATCH] First steps with dynamic loading. We can now (sort of) load cafebabe-generated classes in memory. The API is not final. --- src/main/scala/Test.scala | 59 ------------------- src/main/scala/cafebabe/ClassFile.scala | 3 - src/main/scala/cafebabe/Defaults.scala | 2 +- .../scala/cafebabe/test/DynamicLoading.scala | 25 ++++++++ 4 files changed, 26 insertions(+), 63 deletions(-) delete mode 100644 src/main/scala/Test.scala create mode 100644 src/test/scala/cafebabe/test/DynamicLoading.scala diff --git a/src/main/scala/Test.scala b/src/main/scala/Test.scala deleted file mode 100644 index 71de26d..0000000 --- a/src/main/scala/Test.scala +++ /dev/null @@ -1,59 +0,0 @@ -object Test { - def main(args : Array[String]) : Unit = { - import cafebabe.AbstractByteCodes._ - import cafebabe.ByteCodes._ - - val cf = new cafebabe.ClassFile("Test", None) - - cf.addField("Ljava/lang/String;", "name") - - cf.addDefaultConstructor - - { - val ch = cf.addMethod("I", "sayHello", "I", "Z", "Ljava/lang/String;").codeHandler - ch << Ldc(41) - ch << DefaultNew("Oh") << Ldc(3.14) << InvokeVirtual("Oh", "getInt", "(D)I") << IADD - ch << IRETURN - ch.freeze - } - - { - val ch = cf.addMethod("I", "jumpOver").codeHandler - ch << Ldc(42) - val fresh: Int = ch.getFreshVar - ch << Goto("after") - ch << POP << Ldc(41) - ch << Label("after") - ch << IRETURN - ch.freeze - } - - { - val ch = cf.addMethod("I", "fact", "I").codeHandler - val label = ch.getFreshLabel("else") - ch << ILoad(1) << Ldc(1) << If_ICmpGt(label) << Ldc(1) << - IRETURN << Label(label) << ILoad(1) << ALoad(0) << - ILoad(1) << Ldc(1) << ISUB << InvokeVirtual("Test", "fact", "(I)I") << - IMUL << IRETURN - - ch.freeze - } - - cf.writeToFile("./classfiles/Test.class") - - val classFile = new cafebabe.ClassFile("HWGenerated", None) - classFile.addDefaultConstructor - val codeHandler = classFile.addMainMethod.codeHandler - - codeHandler << - GetStatic("java/lang/System", "out", "Ljava/io/PrintStream;") << - Ldc("Hello world!") << - InvokeVirtual("java/io/PrintStream", "println", "(Ljava/lang/String;)V") << - RETURN - - codeHandler.freeze - classFile.writeToFile("./classfiles/HWGenerated.class") - - System.out.println("written files.") - } -} diff --git a/src/main/scala/cafebabe/ClassFile.scala b/src/main/scala/cafebabe/ClassFile.scala index 7fbde22..ee4a0ae 100644 --- a/src/main/scala/cafebabe/ClassFile.scala +++ b/src/main/scala/cafebabe/ClassFile.scala @@ -109,12 +109,9 @@ class ClassFile(val className: String, parentName: Option[String] = None) extend /** Loads the class using the current class loader. */ def dynamicallyLoad : Unit = { - throw new Error("Not supported yet.") - /* val byteStream = (new ByteStream) << this val bytes : Array[Byte] = byteStream.getBytes CustomClassLoader.registerClass(className, bytes) - */ } def toStream(byteStream: ByteStream): ByteStream = { diff --git a/src/main/scala/cafebabe/Defaults.scala b/src/main/scala/cafebabe/Defaults.scala index 3e5fcfd..2f1429b 100644 --- a/src/main/scala/cafebabe/Defaults.scala +++ b/src/main/scala/cafebabe/Defaults.scala @@ -8,7 +8,7 @@ object Defaults { val defaultMinor: U2 = 0 val defaultMajor: U2 = 49 // J2SE 6.0=50, J2SE 5.0=49, JDK 1.4=48, JDK 1.3=47, JDK 1.2=46, JDK 1.1=45 - val defaultClassAccessFlags: U2 = /* CLASS_ACC_PUBLIC | */ CLASS_ACC_SUPER + val defaultClassAccessFlags: U2 = CLASS_ACC_PUBLIC | CLASS_ACC_SUPER val defaultMethodAccessFlags: U2 = METHOD_ACC_PUBLIC val defaultFieldAccessFlags: U2 = FIELD_ACC_PROTECTED diff --git a/src/test/scala/cafebabe/test/DynamicLoading.scala b/src/test/scala/cafebabe/test/DynamicLoading.scala new file mode 100644 index 0000000..f82b584 --- /dev/null +++ b/src/test/scala/cafebabe/test/DynamicLoading.scala @@ -0,0 +1,25 @@ +package cafebabe.test + +import cafebabe._ +import cafebabe.ByteCodes._ +import cafebabe.AbstractByteCodes._ + +import org.scalatest.FunSuite +class DynamicLoading extends FunSuite { + test("DL 1") { + val cf = new ClassFile("MyTest", None) + cf.addDefaultConstructor + val ch = cf.addMethod("I", "plusOne", "I").codeHandler + ch << ILoad(1) << Ldc(1) << IADD << IRETURN + ch.freeze + + cf.dynamicallyLoad + + val c = CustomClassLoader.loadClass("MyTest") + val o = c.newInstance().asInstanceOf[AnyRef] + val m = c.getMethod("plusOne", Integer.TYPE) + (m.invoke(o, 41 : java.lang.Integer) === 42) + } + + +}