diff options
author | Rich Hickey <richhickey@gmail.com> | 2008-11-10 23:43:53 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2008-11-10 23:43:53 +0000 |
commit | 240969a3af34ff0661238d03c006cc5a74dc1698 (patch) | |
tree | eec677998e7aa5697ea87e8fb41fb8b3efa9a880 /src/jvm/clojure | |
parent | 22a2d9080da1ab1761306f0171d85c5464d82096 (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.java | 211 | ||||
-rw-r--r-- | src/jvm/clojure/lang/LispReader.java | 3 | ||||
-rw-r--r-- | src/jvm/clojure/lang/RT.java | 90 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Repl.java | 2 |
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, |