Clojure

map->R returns different class when invoked from AOT code

Details

  • Type: Defect Defect
  • Status: Open Open
  • Priority: Major Major
  • Resolution: Unresolved
  • Affects Version/s: Release 1.3, Release 1.4, Release 1.5, Release 1.6
  • Fix Version/s: None
  • Component/s: None
  • Labels:
  • 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.

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

Activity

Hide
Scott Lowe added a comment -

I can't reproduce this under Clojure 1.3 or 1.4, and Leiningen 1.7.1 on either Java 1.7.0-jdk7u4-b21 OpenJDK 64-Bit or Java 1.6.0_31 Java HotSpot 64-Bit. OS is Mac OS X 10.7.

Edmund, how are you running this AOT code? I wrapped your code in a main function and built an uberjar from it.

Show
Scott Lowe added a comment - I can't reproduce this under Clojure 1.3 or 1.4, and Leiningen 1.7.1 on either Java 1.7.0-jdk7u4-b21 OpenJDK 64-Bit or Java 1.6.0_31 Java HotSpot 64-Bit. OS is Mac OS X 10.7. Edmund, how are you running this AOT code? I wrapped your code in a main function and built an uberjar from it.
Hide
Edmund Jackson added a comment -

Hi Scott,

Interesting.

I have two use cases
1. AOT compile and call from repl.
My steps: git clone, lein compile, lein repl, (use 'aots.death), (in-ns 'aots.death), (= (class (Dontwork. nil)) (class (map->Dontwork {:a 1}))) => false

2. My original use case, which I've minimised here, is an AOT ns, producing a genclass that is called instantiated from other Java (no main). This produces the same error. I will produce an example of this and post it too.

Show
Edmund Jackson added a comment - Hi Scott, Interesting. I have two use cases 1. AOT compile and call from repl. My steps: git clone, lein compile, lein repl, (use 'aots.death), (in-ns 'aots.death), (= (class (Dontwork. nil)) (class (map->Dontwork {:a 1}))) => false 2. My original use case, which I've minimised here, is an AOT ns, producing a genclass that is called instantiated from other Java (no main). This produces the same error. I will produce an example of this and post it too.
Hide
Edmund Jackson added a comment -

Hi Scott,

Here is an example of it failing in the interop case: https://github.com/ejackson/aotquestion2
The steps I'm following to compile this all up are

git clone git@github.com:ejackson/aotquestion2.git
cd aotquestion2/cljside/
lein uberjar
lein install
cd ../javaside/
mvn package
java -jar ./target/aotquestion-1.0-SNAPSHOT.jar

and it dies with this:

Exception in thread "main" java.lang.ClassCastException: cljside.core.Dontwork cannot be cast to cljside.core.Dontwork
at cljside.MyClass.makeDontwork(Unknown Source)
at aotquestion.App.main(App.java:8)

The error message is really confusing (to me, anyway), but I think its the same root problem as for the REPL case.

What do you see when you run the above ?

Show
Edmund Jackson added a comment - Hi Scott, Here is an example of it failing in the interop case: https://github.com/ejackson/aotquestion2 The steps I'm following to compile this all up are git clone git@github.com:ejackson/aotquestion2.git cd aotquestion2/cljside/ lein uberjar lein install cd ../javaside/ mvn package java -jar ./target/aotquestion-1.0-SNAPSHOT.jar and it dies with this: Exception in thread "main" java.lang.ClassCastException: cljside.core.Dontwork cannot be cast to cljside.core.Dontwork at cljside.MyClass.makeDontwork(Unknown Source) at aotquestion.App.main(App.java:8) The error message is really confusing (to me, anyway), but I think its the same root problem as for the REPL case. What do you see when you run the above ?
Hide
Scott Lowe added a comment -

Ah, yes, looks like my initial attempt to reproduce was too simplistic. I used your second git repo, and can now confirm that it's failing for me with the same error.

Show
Scott Lowe added a comment - Ah, yes, looks like my initial attempt to reproduce was too simplistic. I used your second git repo, and can now confirm that it's failing for me with the same error.
Hide
Scott Lowe added a comment -

I looked into this a little further and the AOT generated code looks correct, in the sense that both code paths appear to be returning the same type.

However, I wonder if this is really a ClassLoader issue, whereby two definitions of the same class are being loaded at different times, because that would cause the x.y.Class cannot be cast to x.y.Class exception that we're seeing here.

Show
Scott Lowe added a comment - I looked into this a little further and the AOT generated code looks correct, in the sense that both code paths appear to be returning the same type. However, I wonder if this is really a ClassLoader issue, whereby two definitions of the same class are being loaded at different times, because that would cause the x.y.Class cannot be cast to x.y.Class exception that we're seeing here.
Hide
Steve Miner added a comment -

This could be related to CLJ-1157 which deals with a ClassLoader issue with AOT compiled code.

Show
Steve Miner added a comment - This could be related to CLJ-1157 which deals with a ClassLoader issue with AOT compiled code.
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
Hide
Ambrose Bonnaire-Sergeant added a comment -

I've tried this patch attached to CLJ-1157 and it did not solve this issue.

Show
Ambrose Bonnaire-Sergeant added a comment - I've tried this patch attached to CLJ-1157 and it did not solve this issue.
Hide
Ambrose Bonnaire-Sergeant added a comment -

This bug seems to be rooted in different behaviour for do/let under compilation. Attached a patch showing these symptoms in the hope it helps people find the cause.

Show
Ambrose Bonnaire-Sergeant added a comment - This bug seems to be rooted in different behaviour for do/let under compilation. Attached a patch showing these symptoms in the hope it helps people find the cause.
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 ]
Hide
Peter Taoussanis added a comment -

Just a quick note to confirm that this still seems to be around as of Clojure 1.7.0-alpha2. Don't have any useful input on possible solutions, sorry.

Show
Peter Taoussanis added a comment - Just a quick note to confirm that this still seems to be around as of Clojure 1.7.0-alpha2. Don't have any useful input on possible solutions, sorry.

People

Vote (3)
Watch (6)

Dates

  • Created:
    Updated: