changeset 14049:786c857536a9

Add a Main launcher for the interpreter; Main [ -cp classpath ] [ -trace ] main-class [ args ... ]
author briangoetz
date Thu, 09 Jun 2016 12:44:49 -0400
parents cf12b592bf8e
children 2c3e092e1b5d
files interpreter/src/valhalla/interpreter/Interpreter.java interpreter/src/valhalla/interpreter/InterpreterEvent.java interpreter/src/valhalla/interpreter/Main.java interpreter/src/valhalla/interpreter/StandardInterpreter.java interpreter/test/valhalla/interpreter/InterpretBootclassTest.java interpreter/test/valhalla/interpreter/InterpreterTest.java
diffstat 6 files changed, 94 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/interpreter/src/valhalla/interpreter/Interpreter.java	Thu Jun 09 11:04:48 2016 -0400
+++ b/interpreter/src/valhalla/interpreter/Interpreter.java	Thu Jun 09 12:44:49 2016 -0400
@@ -26,6 +26,8 @@
 
 import jdk.internal.org.objectweb.asm.Opcodes;
 import jdk.internal.org.objectweb.asm.Type;
+import sun.misc.Resource;
+import sun.misc.URLClassPath;
 import valhalla.interpreter.OpcodeHandler.HandlerAction;
 
 import java.io.File;
@@ -57,11 +59,10 @@
  * @author John Rose
  */
 public abstract class Interpreter {
-    static boolean TRACING = false;
+    boolean TRACING = false;
 
     private final Class<?>[] primClasses = new Class<?>[16];
-    private final List<File> classPath = new ArrayList<>();
-    final ClassLoader classLoader;
+    final InterpreterClassLoader classLoader;
 
     // Mutable state
     private final Map<String, ClassModel> systemDictionary = new ConcurrentHashMap<>();
@@ -72,10 +73,11 @@
     public final List<InterpreterEvent> log = new ArrayList<>();
 
 
-    public Interpreter(String... paths) {
-        for (String p : paths)
-            classPath.add(new File(p));
-        classLoader = new InterpreterClassLoader(this, new URL[0], Interpreter.class.getClassLoader());
+    public Interpreter(String... paths) throws IOException {
+        URL[] urls = new URL[paths.length];
+        for (int i=0; i<paths.length; i++)
+            urls[i] = new File(paths[i]).toURI().toURL();
+        classLoader = new InterpreterClassLoader(this, urls, Interpreter.class.getClassLoader());
     }
 
     public abstract Insn recognizeInstruction(byte[] bytes, int offset);
@@ -92,10 +94,12 @@
 
     private static class InterpreterClassLoader extends URLClassLoader {
         public final Interpreter interpreter;
+        public final URLClassPath ucp;
 
         public InterpreterClassLoader(Interpreter interpreter, URL[] urls, ClassLoader parent) {
             super(urls, parent);
             this.interpreter = interpreter;
+            this.ucp = new URLClassPath(urls);
         }
     }
 
@@ -562,27 +566,17 @@
             return model;
 
         try {
-            for (File dir : classPath) {
-                File f = new File(dir, binaryName + ".class");
-                if (f.exists()) {
-                    FileInputStream fis = new FileInputStream(f);
-                    byte[] bytes = new byte[(int) f.length()];
-                    if (fis.read(bytes) != bytes.length)
-                        throw new IOException("Cannot read file " + f + " fully");
+            Resource r = classLoader.ucp.getResource(binaryName + ".class");
+            ClassModel classModel = newClassModel(binaryName, r.getBytes());
+            systemDictionary.put(humanName, classModel);
+            logEvent(InterpreterEvent.load(humanName));
+            // Run <clinit> by forced interpretation
+            classModel.methods()
+                      .filter(m -> m.getName().equals("<clinit>") && m.getDesc().equals("()V"))
+                      .findFirst()
+                      .ifPresent(m -> forceInterpret(INVOKESTATIC, binaryName, "<clinit>", "()V") );
 
-                    ClassModel classModel = newClassModel(binaryName, bytes);
-                    systemDictionary.put(humanName, classModel);
-                    logEvent(InterpreterEvent.load(humanName));
-                    // Run <clinit> by forced interpretation
-                    classModel.methods()
-                              .filter(m -> m.getName().equals("<clinit>") && m.getDesc().equals("()V"))
-                              .findFirst()
-                              .ifPresent(m -> forceInterpret(INVOKESTATIC, binaryName, "<clinit>", "()V") );
-
-                    return classModel;
-                }
-            }
-            throw new InterpreterError("Cannot resolve class " + binaryName);
+            return classModel;
         }
         catch (IOException e) {
             throw new InterpreterError("Cannot resolve class " + binaryName, e);
--- a/interpreter/src/valhalla/interpreter/InterpreterEvent.java	Thu Jun 09 11:04:48 2016 -0400
+++ b/interpreter/src/valhalla/interpreter/InterpreterEvent.java	Thu Jun 09 12:44:49 2016 -0400
@@ -36,7 +36,7 @@
  */
 public class InterpreterEvent {
     public enum Kind { LOAD, INTERPRET, EXECUTE }
-    private static final Pattern pattern = Pattern.compile("(\\w+) ([a-zA-Z0-9_.]+):(.*)");
+    private static final Pattern pattern = Pattern.compile("(\\w+) ([a-zA-Z0-9$_.]+):(.*)");
 
     public final Kind kind;
     public final String clazz;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/interpreter/src/valhalla/interpreter/Main.java	Thu Jun 09 12:44:49 2016 -0400
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package valhalla.interpreter;
+
+import java.io.File;
+
+/**
+ * Main
+ *
+ * @author Brian Goetz
+ */
+public class Main {
+    public static void main(String[] args) throws Throwable {
+        String mainClass = null;
+        String[] classPath = new String[0];
+        String[] programArgs = null;
+        boolean trace = false;
+
+        for (int i=0; i<args.length; i++) {
+            if (args[i].equals("-cp"))
+                classPath = args[++i].split(File.pathSeparator);
+            else if (args[i].equals("-trace"))
+                trace = true;
+            else {
+                mainClass = args[i];
+                programArgs = new String[args.length - i - 1];
+                System.arraycopy(args, i+1, programArgs, 0, programArgs.length);
+                break;
+            }
+        }
+
+        if (mainClass == null) {
+            System.err.println("Usage: Main [ -trace ] [ -cp path ] main-class program-args...");
+            System.exit(0);
+        }
+
+        Interpreter interpreter = new StandardInterpreter(classPath);
+        interpreter.TRACING = trace;
+        if (trace)
+            interpreter.setEventListener(System.err::println);
+        interpreter.invokestatic(mainClass.replace('.', '/'), "main", "([Ljava/lang/String;)V", (Object) programArgs);
+    }
+}
--- a/interpreter/src/valhalla/interpreter/StandardInterpreter.java	Thu Jun 09 11:04:48 2016 -0400
+++ b/interpreter/src/valhalla/interpreter/StandardInterpreter.java	Thu Jun 09 12:44:49 2016 -0400
@@ -24,6 +24,8 @@
  */
 package valhalla.interpreter;
 
+import java.io.IOException;
+
 import com.sun.tools.classfile.Opcode;
 
 import static java.util.Objects.requireNonNull;
@@ -46,7 +48,7 @@
     private final OpcodeHandler[] handlers = new OpcodeHandler[255];
     private final int[] opcodeLen = new int[255];
 
-    public StandardInterpreter(String... paths) {
+    public StandardInterpreter(String... paths) throws IOException {
         super(paths);
     }
 
--- a/interpreter/test/valhalla/interpreter/InterpretBootclassTest.java	Thu Jun 09 11:04:48 2016 -0400
+++ b/interpreter/test/valhalla/interpreter/InterpretBootclassTest.java	Thu Jun 09 12:44:49 2016 -0400
@@ -24,6 +24,7 @@
  */
 package valhalla.interpreter;
 
+import java.io.IOException;
 import java.util.AbstractList;
 import java.util.ArrayList;
 import java.util.EnumSet;
@@ -48,7 +49,7 @@
     Interpreter interpreter;
 
     @BeforeMethod
-    public void setUp() {
+    public void setUp() throws IOException {
         interpreter = new StandardInterpreter("out/test/test-helpers");
         interpreter.setEventFilter(EnumSet.allOf(InterpreterEvent.Kind.class));
         // interpreter.setEventListener(System.err::println);
--- a/interpreter/test/valhalla/interpreter/InterpreterTest.java	Thu Jun 09 11:04:48 2016 -0400
+++ b/interpreter/test/valhalla/interpreter/InterpreterTest.java	Thu Jun 09 12:44:49 2016 -0400
@@ -24,6 +24,7 @@
  */
 package valhalla.interpreter;
 
+import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.util.EnumSet;
@@ -51,7 +52,7 @@
     Interpreter interpreter;
 
     @BeforeMethod
-    public void setUp() {
+    public void setUp() throws IOException {
         interpreter = new StandardInterpreter("out/test/test-helpers");
         // interpreter.setEventListener(e -> System.err.println(e));
         interpreter.setEventFilter(EnumSet.allOf(InterpreterEvent.Kind.class));