Clojure

Clojure resolves to wrong deftype classes when AOT compiling or reloading

Details

  • Type: Defect Defect
  • Status: Open Open
  • Priority: Critical Critical
  • Resolution: Unresolved
  • Affects Version/s: Release 1.3, Release 1.4, Release 1.5, Release 1.6, Release 1.7
  • Fix Version/s: Release 1.7
  • Component/s: None
  • Patch:
    Code and Test
  • Approval:
    Vetted

Description

Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239 ;; should be 16446700

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.

Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :

user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

Cause of the bug: currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

Approach: the current patch (CLJ-979-v7.patch) addresses this issue in multiple ways:

  • it makes RT.classForName/classForNameNonLoading look in the class cache before delegating to Class/forName if the current classloader is not a DynamicClassLoader (this incidentally addresses also CLJ-1457)
  • it makes clojure use RT.classForName/classForNameNonLoading instead of Class/forName
  • it overrides Classloader/loadClass so that it's class cache aware – this method is used by the jvm to load classes
  • it changes gen-interface to always emit an in-memory interface along the [optional] in disk interface so that the in-memory class is always updated.
  1. CLJ-979.patch
    11/Dec/14 1:40 PM
    8 kB
    Nicola Mometto
  2. clj-979-symptoms.patch
    29/Mar/14 2:27 PM
    2 kB
    Ambrose Bonnaire-Sergeant
  3. CLJ-979-v2.patch
    12/Dec/14 6:06 AM
    9 kB
    Nicola Mometto
  4. CLJ-979-v3.patch
    12/Dec/14 9:38 AM
    9 kB
    Nicola Mometto
  5. CLJ-979-v4.patch
    12/Dec/14 10:09 AM
    9 kB
    Nicola Mometto
  6. CLJ-979-v5.patch
    12/Dec/14 1:07 PM
    10 kB
    Nicola Mometto
  7. CLJ-979-v6.patch
    15/Dec/14 5:43 PM
    10 kB
    Nicola Mometto
  8. CLJ-979-v7.patch
    16/Dec/14 12:50 PM
    10 kB
    Nicola Mometto

Activity

Alex Miller made changes -
Field Original Value New Value
Labels aot
Alex Miller made changes -
Description (defrecord Dontwork [a])

(= (type (Dontwork. nil))
   (type (map->Dontwork {:a 1})))

Will return true if the namespace is not AOT compiled and false if it is.

I have created a small example project with AOT and non-AOT namespaces to demonstrate
https://github.com/ejackson/aotquestion


{code}
(defrecord Dontwork [a])

(= (type (Dontwork. nil))
   (type (map->Dontwork {:a 1})))
{code}

Will return true if the namespace is not AOT compiled and false if it is.

I have created a small example project with AOT and non-AOT namespaces to demonstrate
https://github.com/ejackson/aotquestion


Summary map->R returns different class when invoked from AOT ccode map->R returns different class when invoked from AOT code
Ambrose Bonnaire-Sergeant made changes -
Attachment clj-979-symptoms.patch [ 12903 ]
Ambrose Bonnaire-Sergeant made changes -
Description {code}
(defrecord Dontwork [a])

(= (type (Dontwork. nil))
   (type (map->Dontwork {:a 1})))
{code}

Will return true if the namespace is not AOT compiled and false if it is.

I have created a small example project with AOT and non-AOT namespaces to demonstrate
https://github.com/ejackson/aotquestion


Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}
Affects Version/s Release 1.6 [ 10157 ]
Affects Version/s Release 1.5 [ 10150 ]
Nicola Mometto made changes -
Attachment 0001-CLJ-979-make-clojure-resolve-to-the-correct-Class-in.patch [ 13577 ]
Alex Miller made changes -
Approval Triaged [ 10120 ]
Priority Major [ 3 ] Critical [ 2 ]
Nicola Mometto made changes -
Patch Code and Test [ 10002 ]
Approval Triaged [ 10120 ]
Affects Version/s Release 1.7 [ 10250 ]
Labels aot aot classloader compiler
Summary map->R returns different class when invoked from AOT code Clojure resolves to wrong deftype classes when AOT compiling or reloading
Nicola Mometto made changes -
Approval Triaged [ 10120 ]
Nicola Mometto made changes -
Description Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}
Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

Another demonstration of this classloader issue (from CLJ-1495) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a symbol, which ignores the class cache from DynamicClassLoader, thus deftype reloading or mixing AOT compilation at the repl with deftypes breaks.

*Approach:* the current patch (0001-CLJ-979-make-clojure-resolve-to-the-correct-Class-in.patch) works around this issue by making RT.classForName & variants check the DynamicClassLoader cache before delegating to Class.forName and replacing all the relevant usages of Class.forName with RT.classForName
Nicola Mometto made changes -
Description Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

Another demonstration of this classloader issue (from CLJ-1495) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a symbol, which ignores the class cache from DynamicClassLoader, thus deftype reloading or mixing AOT compilation at the repl with deftypes breaks.

*Approach:* the current patch (0001-CLJ-979-make-clojure-resolve-to-the-correct-Class-in.patch) works around this issue by making RT.classForName & variants check the DynamicClassLoader cache before delegating to Class.forName and replacing all the relevant usages of Class.forName with RT.classForName
Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (0001-CLJ-979-make-clojure-resolve-to-the-correct-Class-in.patch) works around this issue by making RT.classForName & variants look for the class in the DynamicClassLoader class cache before delegating to Class.forName and replacing all the relevant usages of Class.forName with RT.classForName
Nicola Mometto made changes -
Description Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (0001-CLJ-979-make-clojure-resolve-to-the-correct-Class-in.patch) works around this issue by making RT.classForName & variants look for the class in the DynamicClassLoader class cache before delegating to Class.forName and replacing all the relevant usages of Class.forName with RT.classForName
Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (0001-CLJ-979-make-clojure-resolve-to-the-correct-Class-in.patch) works around this issue by making RT.classForName & variants look for the class in the DynamicClassLoader class cache before delegating to Class.forName and replacing all the relevant usages of Class.forName with RT.classForName
Nicola Mometto made changes -
Attachment 0001-CLJ-979-make-clojure-resolve-to-the-correct-Class-in-v2.patch [ 13578 ]
Nicola Mometto made changes -
Description Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (0001-CLJ-979-make-clojure-resolve-to-the-correct-Class-in.patch) works around this issue by making RT.classForName & variants look for the class in the DynamicClassLoader class cache before delegating to Class.forName and replacing all the relevant usages of Class.forName with RT.classForName
Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (0001-CLJ-979-make-clojure-resolve-to-the-correct-Class-in.patch) works around this issue by making RT.classForName & variants look for the class in the DynamicClassLoader class cache before delegating to Class.forName and replacing all the relevant usages of Class.forName with RT.classForName
The alternative patch (0001-CLJ-979-make-clojure-resolve-to-the-correct-Class-in-v2.patch) works the same way but makes RT.classForName look for the class in the DynamicClassLoader class cache even if the baseLoader() is not a DynamicClassLoader, this fixes the bug reported in CLJ-1457
Nicola Mometto made changes -
Attachment CLJ-979.patch [ 13602 ]
Nicola Mometto made changes -
Description Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (0001-CLJ-979-make-clojure-resolve-to-the-correct-Class-in.patch) works around this issue by making RT.classForName & variants look for the class in the DynamicClassLoader class cache before delegating to Class.forName and replacing all the relevant usages of Class.forName with RT.classForName
The alternative patch (0001-CLJ-979-make-clojure-resolve-to-the-correct-Class-in-v2.patch) works the same way but makes RT.classForName look for the class in the DynamicClassLoader class cache even if the baseLoader() is not a DynamicClassLoader, this fixes the bug reported in CLJ-1457
Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979.patch) works around this issue by making RT.classForName & variants look for the class in the DynamicClassLoader class cache before delegating to Class.forName and replacing all the relevant usages of Class.forName with RT.classForName. It also overrides loadClass in DynamicClassLoader to look for the class in the class cache since the JVM uses loadClass to find the class to use in new/invokestatic instructions
Nicola Mometto made changes -
Attachment 0001-CLJ-979-make-clojure-resolve-to-the-correct-Class-in.patch [ 13577 ]
Nicola Mometto made changes -
Attachment 0001-CLJ-979-make-clojure-resolve-to-the-correct-Class-in-v2.patch [ 13578 ]
Nicola Mometto made changes -
Description Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979.patch) works around this issue by making RT.classForName & variants look for the class in the DynamicClassLoader class cache before delegating to Class.forName and replacing all the relevant usages of Class.forName with RT.classForName. It also overrides loadClass in DynamicClassLoader to look for the class in the class cache since the JVM uses loadClass to find the class to use in new/invokestatic instructions
Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979.patch) works around this issue by making RT.classForName & variants look for the class in the DynamicClassLoader class cache before delegating to Class.forName and replacing all the relevant usages of Class.forName with RT.classForName. It also overrides loadClass in DynamicClassLoader to look for the class in the class cache since the JVM uses loadClass to find the class to use in new/invokestatic instructions
Nicola Mometto made changes -
Attachment CLJ-979-v2.patch [ 13607 ]
Nicola Mometto made changes -
Description Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979.patch) works around this issue by making RT.classForName & variants look for the class in the DynamicClassLoader class cache before delegating to Class.forName and replacing all the relevant usages of Class.forName with RT.classForName. It also overrides loadClass in DynamicClassLoader to look for the class in the class cache since the JVM uses loadClass to find the class to use in new/invokestatic instructions
Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979.patch) addresses this issue in a multiple points:
- it makes RT.classForName/classForNameNonLoading look in the class cache before delegating to Class/forName if the current classloader is not a DynamicClassLoader (this incidentally addresses also CLJ-1457)
- it makes clojure use RT.classForName/classForNameNonLoading instead of Class/forName
- it overrides Classloader/loadClass so that it's class cache aware -- this method is used by the jvm to load classes
- it changes gen-interface to always emit an in-memory interface along the [optional] in disk interface so that the in-memory class is always updated.
Nicola Mometto made changes -
Description Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979.patch) addresses this issue in a multiple points:
- it makes RT.classForName/classForNameNonLoading look in the class cache before delegating to Class/forName if the current classloader is not a DynamicClassLoader (this incidentally addresses also CLJ-1457)
- it makes clojure use RT.classForName/classForNameNonLoading instead of Class/forName
- it overrides Classloader/loadClass so that it's class cache aware -- this method is used by the jvm to load classes
- it changes gen-interface to always emit an in-memory interface along the [optional] in disk interface so that the in-memory class is always updated.
Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979-v2.patch) addresses this issue in a multiple points:
- it makes RT.classForName/classForNameNonLoading look in the class cache before delegating to Class/forName if the current classloader is not a DynamicClassLoader (this incidentally addresses also CLJ-1457)
- it makes clojure use RT.classForName/classForNameNonLoading instead of Class/forName
- it overrides Classloader/loadClass so that it's class cache aware -- this method is used by the jvm to load classes
- it changes gen-interface to always emit an in-memory interface along the [optional] in disk interface so that the in-memory class is always updated.
Environment Mac OS X 10.5, lein 1.7 and lein 2.0
Nicola Mometto made changes -
Attachment CLJ-979-v2.patch [ 13607 ]
Nicola Mometto made changes -
Attachment CLJ-979-v2.patch [ 13608 ]
Nicola Mometto made changes -
Attachment CLJ-979-v2.patch [ 13608 ]
Nicola Mometto made changes -
Attachment CLJ-979-v2.patch [ 13609 ]
Nicola Mometto made changes -
Attachment CLJ-979-v2.patch [ 13609 ]
Nicola Mometto made changes -
Attachment CLJ-979-v2.patch [ 13610 ]
Nicola Mometto made changes -
Description Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979-v2.patch) addresses this issue in a multiple points:
- it makes RT.classForName/classForNameNonLoading look in the class cache before delegating to Class/forName if the current classloader is not a DynamicClassLoader (this incidentally addresses also CLJ-1457)
- it makes clojure use RT.classForName/classForNameNonLoading instead of Class/forName
- it overrides Classloader/loadClass so that it's class cache aware -- this method is used by the jvm to load classes
- it changes gen-interface to always emit an in-memory interface along the [optional] in disk interface so that the in-memory class is always updated.
Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979-v2.patch) addresses this issue in multiple ways:
- it makes RT.classForName/classForNameNonLoading look in the class cache before delegating to Class/forName if the current classloader is not a DynamicClassLoader (this incidentally addresses also CLJ-1457)
- it makes clojure use RT.classForName/classForNameNonLoading instead of Class/forName
- it overrides Classloader/loadClass so that it's class cache aware -- this method is used by the jvm to load classes
- it changes gen-interface to always emit an in-memory interface along the [optional] in disk interface so that the in-memory class is always updated.
Nicola Mometto made changes -
Description Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979-v2.patch) addresses this issue in multiple ways:
- it makes RT.classForName/classForNameNonLoading look in the class cache before delegating to Class/forName if the current classloader is not a DynamicClassLoader (this incidentally addresses also CLJ-1457)
- it makes clojure use RT.classForName/classForNameNonLoading instead of Class/forName
- it overrides Classloader/loadClass so that it's class cache aware -- this method is used by the jvm to load classes
- it changes gen-interface to always emit an in-memory interface along the [optional] in disk interface so that the in-memory class is always updated.
Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979-v3.patch) addresses this issue in multiple ways:
- it makes RT.classForName/classForNameNonLoading look in the class cache before delegating to Class/forName if the current classloader is not a DynamicClassLoader (this incidentally addresses also CLJ-1457)
- it makes clojure use RT.classForName/classForNameNonLoading instead of Class/forName
- it overrides Classloader/loadClass so that it's class cache aware -- this method is used by the jvm to load classes
- it changes gen-interface to always emit an in-memory interface along the [optional] in disk interface so that the in-memory class is always updated.
Attachment CLJ-979-v3.patch [ 13613 ]
Nicola Mometto made changes -
Description Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979-v3.patch) addresses this issue in multiple ways:
- it makes RT.classForName/classForNameNonLoading look in the class cache before delegating to Class/forName if the current classloader is not a DynamicClassLoader (this incidentally addresses also CLJ-1457)
- it makes clojure use RT.classForName/classForNameNonLoading instead of Class/forName
- it overrides Classloader/loadClass so that it's class cache aware -- this method is used by the jvm to load classes
- it changes gen-interface to always emit an in-memory interface along the [optional] in disk interface so that the in-memory class is always updated.
Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979-v4.patch) addresses this issue in multiple ways:
- it makes RT.classForName/classForNameNonLoading look in the class cache before delegating to Class/forName if the current classloader is not a DynamicClassLoader (this incidentally addresses also CLJ-1457)
- it makes clojure use RT.classForName/classForNameNonLoading instead of Class/forName
- it overrides Classloader/loadClass so that it's class cache aware -- this method is used by the jvm to load classes
- it changes gen-interface to always emit an in-memory interface along the [optional] in disk interface so that the in-memory class is always updated.
Attachment CLJ-979-v4.patch [ 13614 ]
Nicola Mometto made changes -
Description Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979-v4.patch) addresses this issue in multiple ways:
- it makes RT.classForName/classForNameNonLoading look in the class cache before delegating to Class/forName if the current classloader is not a DynamicClassLoader (this incidentally addresses also CLJ-1457)
- it makes clojure use RT.classForName/classForNameNonLoading instead of Class/forName
- it overrides Classloader/loadClass so that it's class cache aware -- this method is used by the jvm to load classes
- it changes gen-interface to always emit an in-memory interface along the [optional] in disk interface so that the in-memory class is always updated.
Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979-v5.patch) addresses this issue in multiple ways:
- it makes RT.classForName/classForNameNonLoading look in the class cache before delegating to Class/forName if the current classloader is not a DynamicClassLoader (this incidentally addresses also CLJ-1457)
- it makes clojure use RT.classForName/classForNameNonLoading instead of Class/forName
- it overrides Classloader/loadClass so that it's class cache aware -- this method is used by the jvm to load classes
- it changes gen-interface to always emit an in-memory interface along the [optional] in disk interface so that the in-memory class is always updated.
Attachment CLJ-979-v5.patch [ 13615 ]
Alex Miller made changes -
Approval Triaged [ 10120 ] Incomplete [ 10006 ]
Nicola Mometto made changes -
Description Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979-v5.patch) addresses this issue in multiple ways:
- it makes RT.classForName/classForNameNonLoading look in the class cache before delegating to Class/forName if the current classloader is not a DynamicClassLoader (this incidentally addresses also CLJ-1457)
- it makes clojure use RT.classForName/classForNameNonLoading instead of Class/forName
- it overrides Classloader/loadClass so that it's class cache aware -- this method is used by the jvm to load classes
- it changes gen-interface to always emit an in-memory interface along the [optional] in disk interface so that the in-memory class is always updated.
Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979-v6.patch) addresses this issue in multiple ways:
- it makes RT.classForName/classForNameNonLoading look in the class cache before delegating to Class/forName if the current classloader is not a DynamicClassLoader (this incidentally addresses also CLJ-1457)
- it makes clojure use RT.classForName/classForNameNonLoading instead of Class/forName
- it overrides Classloader/loadClass so that it's class cache aware -- this method is used by the jvm to load classes
- it changes gen-interface to always emit an in-memory interface along the [optional] in disk interface so that the in-memory class is always updated.
Attachment CLJ-979-v6.patch [ 13627 ]
Nicola Mometto made changes -
Description Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979-v6.patch) addresses this issue in multiple ways:
- it makes RT.classForName/classForNameNonLoading look in the class cache before delegating to Class/forName if the current classloader is not a DynamicClassLoader (this incidentally addresses also CLJ-1457)
- it makes clojure use RT.classForName/classForNameNonLoading instead of Class/forName
- it overrides Classloader/loadClass so that it's class cache aware -- this method is used by the jvm to load classes
- it changes gen-interface to always emit an in-memory interface along the [optional] in disk interface so that the in-memory class is always updated.
Compiling a class via `deftype` during AOT compilation gives different results for the different constructors. These hashes should be identical.

{code}
user=> (binding [*compile-files* true] (eval '(deftype Abc [])))
user.Abc
user=> (hash Abc)
16446700
user=> (hash (class (->Abc)))
31966239 ;; should be 16446700
{code}

This also means that whenever there's a stale AOT compiled deftype class in the classpath, that class will be used rather then the JIT compiled one, breaking repl interaction.


Another demonstration of this classloader issue (from CLJ-1495) when reloading deftypes (no AOT) :
{code}
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true
true
user> (defrecord Foo [bar])
user.Foo
user> (= (->Foo 42) #user.Foo{:bar 42}) ;;expect this to evaluate to true also -- but it doesn't!
false
user>
{code}

This bug also affects AOT compilation of multimethods that dispatch on a class, this affected core.match for years see http://dev.clojure.org/jira/browse/MATCH-86, http://dev.clojure.org/jira/browse/MATCH-98. David had to work-around this issue by using a bunch of protocols instead of multimethods.

*Cause of the bug:* currently clojure uses Class.forName to resolve a class from a class name, which ignores the class cache from DynamicClassLoader thus reloading deftypes or mixing AOT compilation at the repl with deftypes breaks, resolving to the wrong class.

*Approach:* the current patch (CLJ-979-v7.patch) addresses this issue in multiple ways:
- it makes RT.classForName/classForNameNonLoading look in the class cache before delegating to Class/forName if the current classloader is not a DynamicClassLoader (this incidentally addresses also CLJ-1457)
- it makes clojure use RT.classForName/classForNameNonLoading instead of Class/forName
- it overrides Classloader/loadClass so that it's class cache aware -- this method is used by the jvm to load classes
- it changes gen-interface to always emit an in-memory interface along the [optional] in disk interface so that the in-memory class is always updated.
Attachment CLJ-979-v7.patch [ 13631 ]
Alex Miller made changes -
Approval Incomplete [ 10006 ] Vetted [ 10003 ]
Fix Version/s Release 1.7 [ 10250 ]

People

Vote (13)
Watch (8)

Dates

  • Created:
    Updated: