From 76b8dc03eedcf586cf957f6efb12b87ffe657e09 Mon Sep 17 00:00:00 2001 From: Stefan O'Rear Date: Fri, 21 Jun 2013 11:34:19 -0700 Subject: [PATCH] jast2bc changes to actually emit jars --- src/vm/jvm/HLL/Backend.nqp | 2 +- .../perl6/nqp/jast2bc/JASTToJVMBytecode.java | 53 ++++++++++++++++--- .../org/perl6/nqp/jast2bc/JavaClass.java | 12 ++--- 3 files changed, 50 insertions(+), 17 deletions(-) diff --git a/src/vm/jvm/HLL/Backend.nqp b/src/vm/jvm/HLL/Backend.nqp index cdbdb6f035..e5800c31e5 100644 --- a/src/vm/jvm/HLL/Backend.nqp +++ b/src/vm/jvm/HLL/Backend.nqp @@ -40,7 +40,7 @@ class HLL::Backend::JVM { } method is_precomp_stage($stage) { - $stage eq 'classfile' + $stage eq 'classfile' || $stage eq 'jar' } method is_textual_stage($stage) { diff --git a/src/vm/jvm/runtime/org/perl6/nqp/jast2bc/JASTToJVMBytecode.java b/src/vm/jvm/runtime/org/perl6/nqp/jast2bc/JASTToJVMBytecode.java index 883046d76b..d4cc31ba5b 100644 --- a/src/vm/jvm/runtime/org/perl6/nqp/jast2bc/JASTToJVMBytecode.java +++ b/src/vm/jvm/runtime/org/perl6/nqp/jast2bc/JASTToJVMBytecode.java @@ -8,12 +8,17 @@ import java.lang.invoke.CallSite; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Stack; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassWriter; @@ -23,6 +28,8 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; +import org.perl6.nqp.runtime.Base64; + public class JASTToJVMBytecode { public static void main(String[] argv) { @@ -61,9 +68,30 @@ public static void writeClassFromString(String in, String filename) { try { BufferedReader br = new BufferedReader(new StringReader(in)); JavaClass c = buildClassFrom(br); + FileOutputStream fos = new FileOutputStream(filename); - fos.write(c.bytes); - fos.close(); + if (c.serialized == null) { + // we're writing a plain java class + + fos.write(c.bytes); + fos.close(); + } else { + // writing a jar + Manifest mf = new Manifest(); + + mf.getMainAttributes().put( Attributes.Name.MANIFEST_VERSION, "1.0" ); + if (c.hasMain) + mf.getMainAttributes().put( Attributes.Name.MAIN_CLASS, c.name ); + + JarOutputStream jos = new JarOutputStream(fos, mf); + + jos.putNextEntry(new JarEntry(c.name.replace('.','/') + ".class")); + jos.write(c.bytes); + jos.putNextEntry(new JarEntry(c.name.replace('.','/') + ".serialized")); + jos.write(c.serialized); + + jos.close(); + } } catch (Exception e) { throw new RuntimeException(e); @@ -72,16 +100,23 @@ public static void writeClassFromString(String in, String filename) { private static JavaClass buildClassFrom(BufferedReader in) throws Exception { + JavaClass c = new JavaClass(); // Read in class name, superclass and any fields. String curLine, className = null, superName = null, fileName = null; + byte[] serData = null; List fieldLines = new ArrayList(); while ((curLine = in.readLine()) != null) { if (curLine.startsWith("+ class ")) { - className = curLine.substring("+ class ".length()); + className = c.name = curLine.substring("+ class ".length()); } else if (curLine.startsWith("+ super ")) { superName = curLine.substring("+ super ".length()); } + else if (curLine.startsWith("+ serialized ")) { + ByteBuffer sbuf = Base64.decode(curLine.substring("+ serialized ".length())); + c.serialized = new byte[sbuf.remaining()]; + sbuf.get(c.serialized); + } else if (curLine.startsWith("+ filename ")) { fileName = curLine.substring("+ filename ".length()); } @@ -122,7 +157,7 @@ else if (curLine.equals("+ method")) { // Process all of the methods. if (!curLine.equals("+ method")) throw new Exception("Expected method after class configuration"); - while (processMethod(in, cw, className)) + while (processMethod(c, in, cw, className)) ; // Add empty constructor. @@ -136,8 +171,8 @@ else if (curLine.equals("+ method")) { constructor.visitEnd(); cw.visitEnd(); - - JavaClass c = new JavaClass(className, cw.toByteArray()); + c.bytes = cw.toByteArray(); + return c; } @@ -146,7 +181,7 @@ private static class LabelInfo { public boolean defined; } - private static boolean processMethod(BufferedReader in, ClassWriter c, String className) throws Exception { + private static boolean processMethod(JavaClass jcout, BufferedReader in, ClassWriter c, String className) throws Exception { String curLine, methodName = null, returnType = null, desc = null; String crName = null, crCuid = null, crOuter = null; int crOuterIx = -2; // not coderef @@ -238,7 +273,9 @@ else if (curLine.startsWith("++ handlers ")) { if (inMethodHeader) { // Transition to instructions mode. inMethodHeader = false; - + + if (methodName.equals("main")) jcout.hasMain = true; + // Create method object. desc = Type.getMethodDescriptor(processType(returnType), argTypes.toArray(new Type[0])); m = c.visitMethod( diff --git a/src/vm/jvm/runtime/org/perl6/nqp/jast2bc/JavaClass.java b/src/vm/jvm/runtime/org/perl6/nqp/jast2bc/JavaClass.java index 150492b107..1414b8f492 100644 --- a/src/vm/jvm/runtime/org/perl6/nqp/jast2bc/JavaClass.java +++ b/src/vm/jvm/runtime/org/perl6/nqp/jast2bc/JavaClass.java @@ -1,12 +1,8 @@ package org.perl6.nqp.jast2bc; public class JavaClass { - - public final String name; - public final byte[] bytes; - - public JavaClass(String name, byte[] bytes) { - this.name = name; - this.bytes = bytes; - } + public String name; + public byte[] bytes; + public byte[] serialized; + public boolean hasMain; }