Skip to content

Commit

Permalink
CLJ-979: make clojure resolve to the correct Class instances
Browse files Browse the repository at this point in the history
Signed-off-by: Stuart Halloway <stu@cognitect.com>
  • Loading branch information
Bronsa authored and stuarthalloway committed Jan 10, 2015
1 parent e5a104e commit 9f277c8
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 29 deletions.
8 changes: 4 additions & 4 deletions src/clj/clojure/genclass.clj
Expand Up @@ -717,10 +717,10 @@
[& options]
(let [options-map (apply hash-map options)
[cname bytecode] (generate-interface options-map)]
(if *compile-files*
(clojure.lang.Compiler/writeClassFile cname bytecode)
(.defineClass ^DynamicClassLoader (deref clojure.lang.Compiler/LOADER)
(str (:name options-map)) bytecode options))))
(when *compile-files*
(clojure.lang.Compiler/writeClassFile cname bytecode))
(.defineClass ^DynamicClassLoader (deref clojure.lang.Compiler/LOADER)
(str (:name options-map)) bytecode options)))

(comment

Expand Down
2 changes: 1 addition & 1 deletion src/clj/clojure/reflect/java.clj
Expand Up @@ -166,7 +166,7 @@ the kinds of objects to which they can apply."}
(deftype JavaReflector [classloader]
Reflector
(do-reflect [_ typeref]
(let [cls (Class/forName (typename typeref) false classloader)]
(let [cls (clojure.lang.RT/classForName (typename typeref) false classloader)]
{:bases (not-empty (set (map typesym (bases cls))))
:flags (parse-flags (.getModifiers cls) :class)
:members (set/union (declared-fields cls)
Expand Down
13 changes: 6 additions & 7 deletions src/jvm/clojure/lang/Compiler.java
Expand Up @@ -1596,7 +1596,7 @@ static class StaticMethodExpr extends MethodExpr{
public final int column;
public final java.lang.reflect.Method method;
public final Symbol tag;
final static Method forNameMethod = Method.getMethod("Class forName(String)");
final static Method forNameMethod = Method.getMethod("Class classForName(String)");
final static Method invokeStaticMethodMethod =
Method.getMethod("Object invokeStaticMethod(Class,String,Object[])");
final static Keyword warnOnBoxedKeyword = Keyword.intern("warn-on-boxed");
Expand Down Expand Up @@ -1773,7 +1773,7 @@ else if(retClass != void.class)
else
{
gen.push(c.getName());
gen.invokeStatic(CLASS_TYPE, forNameMethod);
gen.invokeStatic(RT_TYPE, forNameMethod);
gen.push(methodName);
emitArgsAsArray(args, objx, gen);
if(context == C.RETURN)
Expand Down Expand Up @@ -2482,8 +2482,7 @@ public static class NewExpr implements Expr{
public final Class c;
final static Method invokeConstructorMethod =
Method.getMethod("Object invokeConstructor(Class,Object[])");
// final static Method forNameMethod = Method.getMethod("Class classForName(String)");
final static Method forNameMethod = Method.getMethod("Class forName(String)");
final static Method forNameMethod = Method.getMethod("Class classForName(String)");


public NewExpr(Class c, IPersistentVector args, int line, int column) {
Expand Down Expand Up @@ -2556,7 +2555,7 @@ public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
else
{
gen.push(destubClassName(c.getName()));
gen.invokeStatic(CLASS_TYPE, forNameMethod);
gen.invokeStatic(RT_TYPE, forNameMethod);
MethodExpr.emitArgsAsArray(args, objx, gen);
if(context == C.RETURN)
{
Expand Down Expand Up @@ -4601,7 +4600,7 @@ else if(value instanceof Class)
else
{
gen.push(destubClassName(cc.getName()));
gen.invokeStatic(Type.getType(Class.class), Method.getMethod("Class forName(String)"));
gen.invokeStatic(RT_TYPE, Method.getMethod("Class classForName(String)"));
}
}
else if(value instanceof Symbol)
Expand Down Expand Up @@ -7421,7 +7420,7 @@ CONSTANT_IDS, new IdentityHashMap(),
clinitgen.invokeStatic(objx.objtype, Method.getMethod("void __init" + n + "()"));

clinitgen.push(objx.internalName.replace('/','.'));
clinitgen.invokeStatic(CLASS_TYPE, Method.getMethod("Class forName(String)"));
clinitgen.invokeStatic(RT_TYPE, Method.getMethod("Class classForName(String)"));
clinitgen.invokeVirtual(CLASS_TYPE,Method.getMethod("ClassLoader getClassLoader()"));
clinitgen.invokeStatic(Type.getType(Compiler.class), Method.getMethod("void pushNSandLoader(ClassLoader)"));
clinitgen.mark(startTry);
Expand Down
24 changes: 22 additions & 2 deletions src/jvm/clojure/lang/DynamicClassLoader.java
Expand Up @@ -48,7 +48,7 @@ public Class defineClass(String name, byte[] bytes, Object srcForm){
return c;
}

protected Class<?> findClass(String name) throws ClassNotFoundException{
static Class<?> findInMemoryClass(String name) {
Reference<Class> cr = classCache.get(name);
if(cr != null)
{
Expand All @@ -58,7 +58,27 @@ protected Class<?> findClass(String name) throws ClassNotFoundException{
else
classCache.remove(name, cr);
}
return super.findClass(name);
return null;
}

protected Class<?>findClass(String name) throws ClassNotFoundException {
Class c = findInMemoryClass(name);
if (c != null)
return c;
else
return super.findClass(name);
}

protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class c = findLoadedClass(name);
if (c == null) {
c = findInMemoryClass(name);
if (c == null)
c = getParent().loadClass(name);
}
if (resolve)
resolveClass(c);
return c;
}

public void registerConstants(int id, Object[] val){
Expand Down
35 changes: 20 additions & 15 deletions src/jvm/clojure/lang/RT.java
Expand Up @@ -2106,39 +2106,44 @@ static public URL getResource(ClassLoader loader, String name){
}
}

static public Class classForName(String name) {
static public Class classForName(String name, boolean load, ClassLoader loader) {

try
{
return Class.forName(name, true, baseLoader());
Class c = null;
if (!(loader instanceof DynamicClassLoader))
c = DynamicClassLoader.findInMemoryClass(name);
if (c != null)
return c;
return Class.forName(name, load, loader);
}
catch(ClassNotFoundException e)
{
throw Util.sneakyThrow(e);
}
}

static public Class classForName(String name) {
return classForName(name, true, baseLoader());
}

static public Class classForNameNonLoading(String name) {
try
{
return Class.forName(name, false, baseLoader());
}
catch(ClassNotFoundException e)
{
throw Util.sneakyThrow(e);
}
return classForName(name, false, baseLoader());
}

static public Class loadClassForName(String name) throws ClassNotFoundException{
static public Class loadClassForName(String name) {
try
{
Class.forName(name, false, baseLoader());
classForNameNonLoading(name);
}
catch(ClassNotFoundException e)
catch(Exception e)
{
return null;
if (e instanceof ClassNotFoundException)
return null;
else
throw Util.sneakyThrow(e);
}
return Class.forName(name, true, baseLoader());
return classForName(name);
}

static public float aget(float[] xs, int i){
Expand Down
15 changes: 15 additions & 0 deletions test/clojure/test_clojure/compilation.clj
Expand Up @@ -249,3 +249,18 @@
(load-string "(.submit (java.util.concurrent.Executors/newCachedThreadPool) #())")))
(is (try (load-string "(.submit (java.util.concurrent.Executors/newCachedThreadPool) ^Runnable #())")
(catch Compiler$CompilerException e nil)))))

(defrecord Y [a])
#clojure.test_clojure.compilation.Y[1]
(defrecord Y [b])

(binding [*compile-path* "target/test-classes"]
(compile 'clojure.test-clojure.compilation.examples))

(deftest CLJ-979
(is (= clojure.test_clojure.compilation.examples.X
(class (clojure.test-clojure.compilation.examples/->X))))
(is (.b (clojure.test_clojure.compilation.Y. 1)))
(is (= clojure.test_clojure.compilation.examples.T
(class (clojure.test_clojure.compilation.examples.T.))
(class (clojure.test-clojure.compilation.examples/->T)))))
12 changes: 12 additions & 0 deletions test/clojure/test_clojure/compilation/examples.clj
@@ -0,0 +1,12 @@
;; Copyright (c) Rich Hickey. All rights reserved.
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.

(ns clojure.test-clojure.compilation.examples)

(eval '(deftype X []))
(deftype T [])

0 comments on commit 9f277c8

Please sign in to comment.