Clojure

Clojure resolves to wrong deftype classes when AOT compiling or reloading

Details

  • Type: Defect Defect
  • Status: Closed Closed
  • Priority: Critical Critical
  • Resolution: Completed
  • 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:
    Ok

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 with the [optional] on-disk interface so that the in-memory class is always updated.

Patch: CLJ-979-v7.patch

Screened by: Alex Miller

  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 -
Summary map->R returns different class when invoked from AOT ccode map->R returns different class when invoked from AOT code
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


Ambrose Bonnaire-Sergeant made changes -
Attachment clj-979-symptoms.patch [ 12903 ]
Ambrose Bonnaire-Sergeant made changes -
Affects Version/s Release 1.5 [ 10150 ]
Affects Version/s Release 1.6 [ 10157 ]
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}
Nicola Mometto made changes -
Attachment 0001-CLJ-979-make-clojure-resolve-to-the-correct-Class-in.patch [ 13577 ]
Alex Miller made changes -
Priority Major [ 3 ] Critical [ 2 ]
Approval Triaged [ 10120 ]
Nicola Mometto made changes -
Summary map->R returns different class when invoked from AOT code Clojure resolves to wrong deftype classes when AOT compiling or reloading
Labels aot aot classloader compiler
Affects Version/s Release 1.7 [ 10250 ]
Approval Triaged [ 10120 ]
Patch Code and Test [ 10002 ]
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 -
Environment Mac OS X 10.5, lein 1.7 and lein 2.0
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.
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 -
Attachment CLJ-979-v3.patch [ 13613 ]
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.
Nicola Mometto made changes -
Attachment CLJ-979-v4.patch [ 13614 ]
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.
Nicola Mometto made changes -
Attachment CLJ-979-v5.patch [ 13615 ]
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.
Alex Miller made changes -
Approval Triaged [ 10120 ] Incomplete [ 10006 ]
Nicola Mometto made changes -
Attachment CLJ-979-v6.patch [ 13627 ]
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.
Nicola Mometto made changes -
Attachment CLJ-979-v7.patch [ 13631 ]
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.
Alex Miller made changes -
Fix Version/s Release 1.7 [ 10250 ]
Approval Incomplete [ 10006 ] Vetted [ 10003 ]
Alex Miller 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 ;; 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.
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 with the [optional] on-disk interface so that the in-memory class is always updated.

*Patch:* CLJ-979-v7.patch

*Screened by:* Alex Miller
Approval Vetted [ 10003 ] Screened [ 10004 ]
Rich Hickey made changes -
Approval Screened [ 10004 ] Ok [ 10007 ]
Stuart Halloway made changes -
Status Open [ 1 ] Closed [ 6 ]
Resolution Completed [ 1 ]

People

Vote (14)
Watch (10)

Dates

  • Created:
    Updated:
    Resolved: