summaryrefslogtreecommitdiff
path: root/src/jvm/clojure
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2008-11-10 23:43:53 +0000
committerRich Hickey <richhickey@gmail.com>2008-11-10 23:43:53 +0000
commit240969a3af34ff0661238d03c006cc5a74dc1698 (patch)
treeeec677998e7aa5697ea87e8fb41fb8b3efa9a880 /src/jvm/clojure
parent22a2d9080da1ab1761306f0171d85c5464d82096 (diff)
Interim checkin - DO NOT USE!!
Unless you are interested in helping test: AOT compiler! build and start Clojure with: -cp ./classes:./src/clj:clojure.jar try: (do (compile 'clojure.core) (compile 'clojure.set) (compile 'clojure.xml) (compile 'clojure.zip)) restart Clojure - faster? rebuild Clojure w/o clean, should get faster start from jar alone deleted set/xml etc dirs Moved clojure ns to clojure.core, moved set/xml etc up out of dirs New binding syntax (breaking change) for: doseq dotimes with-open when-first if-let when-let plus: new print-dup functionality for replica generation of compilation constants new *print-dup* flag, prints duplicators back to simplified readably printing for repl readable fns, as long as they are not closures
Diffstat (limited to 'src/jvm/clojure')
-rw-r--r--src/jvm/clojure/lang/Compiler.java211
-rw-r--r--src/jvm/clojure/lang/LispReader.java3
-rw-r--r--src/jvm/clojure/lang/RT.java90
-rw-r--r--src/jvm/clojure/lang/Repl.java2
4 files changed, 158 insertions, 148 deletions
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index ace59409..de686e7a 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -180,6 +180,13 @@ static final public Var SOURCE = Var.create("NO_SOURCE_FILE");
static final public Var SOURCE_PATH = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")),
Symbol.create("*file*"), null);
+//String
+static final public Var COMPILE_PATH = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")),
+ Symbol.create("*compile-path*"), null);
+//boolean
+static final public Var COMPILE_FILES = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")),
+ Symbol.create("*compile-files*"), RT.F);
+
//Integer
static final public Var LINE = Var.create(0);
@@ -2970,7 +2977,7 @@ static public class FnExpr implements Expr{
return ret;
}
- private void compile() throws IOException{
+ private void compile() throws Exception{
//create bytecode for a class
//with name current_ns.defname[$letname]+
//anonymous fns get names fn__id
@@ -3035,57 +3042,9 @@ static public class FnExpr implements Expr{
if(constants.count() > 0)
{
-
-// clinitgen.mark(begin);
-// clinitgen.visitLdcInsn(fntype);
-// clinitgen.invokeVirtual(CLASS_TYPE, getClassLoaderMethod);
-// clinitgen.checkCast(DYNAMIC_CLASSLOADER_TYPE);
-// clinitgen.push(constantsID);
-// clinitgen.invokeVirtual(DYNAMIC_CLASSLOADER_TYPE, getConstantsMethod);
- try{
- Var.pushThreadBindings(RT.map(RT.PRINT_DUP, RT.T));
-
- for(int i = 0; i < constants.count(); i++)
- {
- String cs = RT.printString(constants.nth(i));
- if(cs.length() == 0)
- throw new RuntimeException("Can't embed unreadable object in code: " + constants.nth(i));
-
- if(cs.startsWith("#<"))
- throw new RuntimeException("Can't embed unreadable object in code: " + cs);
- clinitgen.push(cs);
- clinitgen.invokeStatic(RT_TYPE, readStringMethod);
-// clinitgen.dup();
-// clinitgen.push(i);
-// clinitgen.arrayLoad(OBJECT_TYPE);
- clinitgen.checkCast(constantType(i));
- clinitgen.putStatic(fntype, constantName(i), constantType(i));
- }
+ emitConstants(clinitgen);
}
- finally{
- Var.popThreadBindings();
- }
- }
-// for(ISeq s = RT.keys(keywords); s != null; s = s.rest())
-// {
-// Keyword k = (Keyword) s.first();
-// clinitgen.push(k.sym.ns);
-// clinitgen.push(k.sym.name);
-// clinitgen.invokeStatic(KEYWORD_TYPE, kwintern);
-// clinitgen.putStatic(fntype, munge(k.sym.toString()), KEYWORD_TYPE);
-// }
-// for(ISeq s = RT.keys(vars); s != null; s = s.rest())
-// {
-// Var v = (Var) s.first();
-// clinitgen.push(v.ns.name.name);
-// clinitgen.invokeStatic(SYMBOL_TYPE, symcreate);
-// clinitgen.push(v.sym.name);
-// clinitgen.invokeStatic(SYMBOL_TYPE, symcreate);
-// clinitgen.invokeStatic(VAR_TYPE, varintern);
-// clinitgen.putStatic(fntype, munge(v.sym.toString()), VAR_TYPE);
-// }
-// clinitgen.mark(end);
-// clinitgen.visitLocalVariable("constants", "[Ljava/lang/Object;", null, begin, end, 0);
+
clinitgen.returnValue();
clinitgen.endMethod();
@@ -3170,29 +3129,47 @@ static public class FnExpr implements Expr{
//end of class
cv.visitEnd();
- loader = (DynamicClassLoader) LOADER.get();
bytecode = cw.toByteArray();
- String path = "gen" + File.separator + internalName + ".class";
- File cf = new File(path);
- cf.getParentFile().mkdirs();
- cf.createNewFile();
- OutputStream cfs = new FileOutputStream(cf);
- try
- {
- cfs.write(bytecode);
- }
- finally
+ if(RT.booleanCast(COMPILE_FILES.get()))
+ writeClassFile(internalName,bytecode);
+ else
+ getCompiledClass();
+ }
+
+
+ void emitConstants(GeneratorAdapter clinitgen){
+ try{
+ Var.pushThreadBindings(RT.map(RT.PRINT_DUP, RT.T));
+
+ for(int i = 0; i < constants.count(); i++)
{
- cfs.close();
+ String cs = RT.printString(constants.nth(i));
+ if(cs.length() == 0)
+ throw new RuntimeException("Can't embed unreadable object in code: " + constants.nth(i));
+
+ if(cs.startsWith("#<"))
+ throw new RuntimeException("Can't embed unreadable object in code: " + cs);
+ clinitgen.push(cs);
+ clinitgen.invokeStatic(RT_TYPE, readStringMethod);
+// clinitgen.dup();
+// clinitgen.push(i);
+// clinitgen.arrayLoad(OBJECT_TYPE);
+ clinitgen.checkCast(constantType(i));
+ clinitgen.putStatic(fntype, constantName(i), constantType(i));
}
+ }
+ finally{
+ Var.popThreadBindings();
+ }
}
synchronized Class getCompiledClass(){
if(compiledClass == null)
try
{
- compiledClass = RT.classForName(name);//loader.defineClass(name, bytecode);
- //compiledClass = loader.defineClass(name, bytecode);
+ //compiledClass = RT.classForName(name);//loader.defineClass(name, bytecode);
+ loader = (DynamicClassLoader) LOADER.get();
+ compiledClass = loader.defineClass(name, bytecode);
}
catch(Exception e)
{
@@ -3206,7 +3183,6 @@ static public class FnExpr implements Expr{
}
public void emit(C context, FnExpr fn, GeneratorAdapter gen){
- //getCompiledClass();
//emitting a Fn means constructing an instance, feeding closed-overs from enclosing scope, if any
//fn arg is enclosing fn, not this
gen.newInstance(fntype);
@@ -4459,7 +4435,29 @@ public static Object load(Reader rdr, String sourcePath, String sourceName) thro
return ret;
}
+static public void writeClassFile(String internalName, byte[] bytecode) throws Exception{
+ String genPath = (String) COMPILE_PATH.get();
+ if(genPath == null)
+ throw new Exception("*compile-path* not set");
+ String path = genPath + File.separator + internalName + ".class";
+ File cf = new File(path);
+ cf.getParentFile().mkdirs();
+ cf.createNewFile();
+ OutputStream cfs = new FileOutputStream(cf);
+ try
+ {
+ cfs.write(bytecode);
+ }
+ finally
+ {
+ cfs.close();
+ }
+}
+
public static Object compile(Reader rdr, String sourcePath, String sourceName) throws Exception{
+ if(COMPILE_PATH.get() == null)
+ throw new Exception("*compile-path* not set");
+
Object EOF = new Object();
Object ret = null;
LineNumberingPushbackReader pushbackReader =
@@ -4473,7 +4471,8 @@ public static Object compile(Reader rdr, String sourcePath, String sourceName) t
LINE_AFTER, pushbackReader.getLineNumber(),
CONSTANTS, PersistentVector.EMPTY,
KEYWORDS, PersistentHashMap.EMPTY,
- VARS, PersistentHashMap.EMPTY
+ VARS, PersistentHashMap.EMPTY,
+ COMPILE_FILES, RT.T
));
try
@@ -4484,7 +4483,7 @@ public static Object compile(Reader rdr, String sourcePath, String sourceName) t
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassVisitor cv = cw;
cv.visit(V1_5, ACC_PUBLIC + ACC_SUPER, fn.internalName, null,
- "java.lang.Object", null);
+ "java/lang/Object", null);
//static load method
GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC,
@@ -4526,13 +4525,7 @@ public static Object compile(Reader rdr, String sourcePath, String sourceName) t
clinitgen.visitCode();
if(fn.constants.count() > 0)
{
- for(int i = 0; i < fn.constants.count(); i++)
- {
- clinitgen.push(RT.printString(fn.constants.nth(i)));
- clinitgen.invokeStatic(RT_TYPE, FnExpr.readStringMethod);
- clinitgen.checkCast(fn.constantType(i));
- clinitgen.putStatic(fn.fntype, fn.constantName(i), fn.constantType(i));
- }
+ fn.emitConstants(clinitgen);
}
//end of static init
clinitgen.returnValue();
@@ -4540,6 +4533,8 @@ public static Object compile(Reader rdr, String sourcePath, String sourceName) t
//end of class
cv.visitEnd();
+
+ writeClassFile(fn.internalName,cw.toByteArray());
}
catch(LispReader.ReaderException e)
{
@@ -4552,70 +4547,4 @@ public static Object compile(Reader rdr, String sourcePath, String sourceName) t
return ret;
}
-/*
-public static void main(String[] args) throws Exception{
- RT.init();
- for(String file : args)
- try
- {
- loadFile(file);
- }
- catch(Exception e)
- {
- e.printStackTrace();
- }
-
- //repl
- LineNumberingPushbackReader rdr = (LineNumberingPushbackReader) RT.IN.get();
- OutputStreamWriter w = (OutputStreamWriter) RT.OUT.get();//new OutputStreamWriter(System.out);
-
- Object EOF = new Object();
- try
- {
- Var.pushThreadBindings(
- RT.map(
-// RT.NS_REFERS, RT.NS_REFERS.get(),
-// RT.NS_IMPORTS, RT.NS_IMPORTS.get(),
-RT.CURRENT_NS, RT.CURRENT_NS.get(),
-SOURCE, "REPL"
- ));
- w.write("Clojure\n");
- RT.inNamespace.invoke(Symbol.create("user"));
-
- for(; ;)
- {
- try
- {
- Var.pushThreadBindings(
- RT.map(LOADER, RT.makeClassLoader()));
- w.write(currentNS().name + "=> ");
- w.flush();
- Object r = LispReader.read(rdr, false, EOF, false);
- if(r == EOF)
- break;
- Object ret = eval(r);
- RT.print(ret, w);
- w.write('\n');
- //w.flush();
- }
- catch(Throwable e)
- {
- e.printStackTrace();
- }
- finally
- {
- Var.popThreadBindings();
- }
- }
- }
- catch(Exception e)
- {
- e.printStackTrace();
- }
- finally
- {
- Var.popThreadBindings();
- }
-}
-*/
}
diff --git a/src/jvm/clojure/lang/LispReader.java b/src/jvm/clojure/lang/LispReader.java
index 4847692d..c5a5c99c 100644
--- a/src/jvm/clojure/lang/LispReader.java
+++ b/src/jvm/clojure/lang/LispReader.java
@@ -888,7 +888,8 @@ static class EvalReader extends AFn{
Symbol fs = (Symbol) RT.first(o);
if(fs.equals(THE_VAR))
{
- return Compiler.resolve((Symbol) RT.second(o),true);
+ Symbol vs = (Symbol) RT.second(o);
+ return RT.var(vs.ns, vs.name); //Compiler.resolve((Symbol) RT.second(o),true);
}
if(fs.name.endsWith("."))
{
diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java
index 741dba22..048aaf43 100644
--- a/src/jvm/clojure/lang/RT.java
+++ b/src/jvm/clojure/lang/RT.java
@@ -15,6 +15,9 @@ package clojure.lang;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.Callable;
import java.util.*;
+import java.util.zip.ZipEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarEntry;
import java.util.regex.Matcher;
import java.io.*;
import java.lang.reflect.Array;
@@ -23,6 +26,8 @@ import java.math.BigInteger;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.net.URL;
+import java.net.URLConnection;
+import java.net.JarURLConnection;
import java.nio.charset.Charset;
public class RT{
@@ -376,13 +381,86 @@ static public void init() throws Exception{
((PrintWriter)RT.ERR.get()).println("No need to call RT.init() anymore");
}
+static public long lastModified(URL url,String libfile) throws Exception{
+ if(url.getProtocol().equals("jar"))
+ {
+ return ((JarURLConnection)url.openConnection()).getJarFile().getEntry(libfile).getTime();
+ }
+ else
+ {
+ File f = new File(url.toURI());
+ return f.lastModified();
+ }
+}
+static public void loadLib(String lib) throws Exception{
+ loadLib(lib, true);
+}
+
+static public void compileLib(String lib) throws Exception{
+ String libpath = lib.replace('.', '/');
+ String cljfile = libpath + ".clj";
+ InputStream ins = baseLoader().getResourceAsStream(cljfile);
+ if(ins != null)
+ {
+ Compiler.compile(new InputStreamReader(ins, UTF8), cljfile, cljfile.substring(cljfile.lastIndexOf("/")));
+ }
+ else
+ throw new FileNotFoundException("Could not locate Clojure resource on classpath: " + lib);
+}
+
+static public void loadLib(String lib, boolean failIfNotFound) throws Exception{
+ String libpath = lib.replace('.', '/');
+ String classfile = libpath + ".class";
+ String cljfile = libpath + ".clj";
+ URL classURL = baseLoader().getResource(classfile);
+ URL cljURL = baseLoader().getResource(cljfile);
+
+ if(classURL != null &&
+ (cljURL == null
+ || lastModified(classURL, classfile) > lastModified(cljURL, cljfile)))
+ {
+ try
+ {
+ Var.pushThreadBindings(
+ RT.map(CURRENT_NS, CURRENT_NS.get(),
+ WARN_ON_REFLECTION, WARN_ON_REFLECTION.get()));
+ Reflector.invokeStaticMethod(classForName(lib), "load", EMPTY_ARRAY);
+ }
+ finally
+ {
+ Var.popThreadBindings();
+ }
+ }
+ else if(cljURL != null)
+ {
+ loadResourceScript(RT.class, cljfile);
+ }
+ else if(failIfNotFound)
+ throw new FileNotFoundException("Could not locate Clojure resource on classpath: " + lib);
+
+}
static void doInit() throws Exception{
- loadResourceScript(RT.class, "clojure/core.clj");
- loadResourceScript(RT.class, "clojure/proxy.clj", false);
- loadResourceScript(RT.class, "clojure/genclass.clj", false);
- loadResourceScript(RT.class, "clojure/zip.clj", false);
- loadResourceScript(RT.class, "clojure/xml.clj", false);
- loadResourceScript(RT.class, "clojure/set.clj", false);
+ loadLib("clojure.core");
+ loadLib("clojure.zip",false);
+ loadLib("clojure.xml",false);
+ loadLib("clojure.set",false);
+// try
+// {
+// Reflector.invokeStaticMethod("clojure.core", "load", EMPTY_ARRAY);
+// Reflector.invokeStaticMethod("clojure.zip", "load", EMPTY_ARRAY);
+// Reflector.invokeStaticMethod("clojure.xml", "load", EMPTY_ARRAY);
+// Reflector.invokeStaticMethod("clojure.set", "load", EMPTY_ARRAY);
+// }
+// finally
+// {
+// Var.popThreadBindings();
+// }
+// loadResourceScript(RT.class, "clojure/core.clj");
+// loadResourceScript(RT.class, "clojure/proxy.clj", false);
+// loadResourceScript(RT.class, "clojure/genclass.clj", false);
+// loadResourceScript(RT.class, "clojure/zip.clj", false);
+// loadResourceScript(RT.class, "clojure/xml.clj", false);
+// loadResourceScript(RT.class, "clojure/set.clj", false);
Var.pushThreadBindings(
RT.map(CURRENT_NS, CURRENT_NS.get(),
diff --git a/src/jvm/clojure/lang/Repl.java b/src/jvm/clojure/lang/Repl.java
index 0c31d045..e5d16a40 100644
--- a/src/jvm/clojure/lang/Repl.java
+++ b/src/jvm/clojure/lang/Repl.java
@@ -23,6 +23,7 @@ static final Symbol CLOJURE = Symbol.create("clojure.core");
static final Var in_ns = RT.var("clojure.core", "in-ns");
static final Var refer = RT.var("clojure.core", "refer");
static final Var ns = RT.var("clojure.core", "*ns*");
+static final Var compile_path = RT.var("clojure.core", "*compile-path*");
static final Var warn_on_reflection = RT.var("clojure.core", "*warn-on-reflection*");
static final Var print_meta = RT.var("clojure.core", "*print-meta*");
static final Var print_length = RT.var("clojure.core", "*print-length*");
@@ -48,6 +49,7 @@ public static void main(String[] args) throws Exception{
print_meta, print_meta.get(),
print_length, print_length.get(),
print_level, print_level.get(),
+ compile_path, "classes",
star1, null,
star2, null,
star3, null,