typelead / eta

The Eta Programming Language, a dialect of Haskell on the JVM
https://eta-lang.org
BSD 3-Clause "New" or "Revised" License
2.61k stars 141 forks source link

proguard run too slow and error finally. #958

Closed clojurians-org closed 5 years ago

clojurians-org commented 5 years ago

i use the proguard with eta-rules.pro config to reduce file size. it run for long time, and it fail finally.

i have no idea how to fix it

larrys-MBP:larluo larluo$ cat eta-rules.pro 
-injars javaCall.jar
-outjars javaCall-1.0.jar
-dontwarn **

-keep public class eta.runtime.stg.Closure
-keep public class eta.runtime.stg.StgContext

-keep public class ghc_prim.ghc.Types {
  eta.runtime.stg.Closure DFalse() ;
}

-keep public class base.ghc.TopHandler {
  eta.runtime.stg.Closure flushStdHandles() ;
}

-keep public class base.ghc.conc.Sync {
  eta.runtime.stg.Closure runSparks() ;
}

-keep public class base.control.exception.Base {
  eta.runtime.stg.Closure nonTermination();
  eta.runtime.stg.Closure nestedAtomically();
}

-keep public class base.ghc.io.Exception {
  eta.runtime.stg.Closure blockedIndefinitelyOnMVar();
  eta.runtime.stg.Closure blockedIndefinitelyOnSTM();
}

-keep public class base.ghc.Weak {
  eta.runtime.stg.Closure runFinalizzerBatch();
}

-keep public class ghc_prim.ghc.types.datacons.Izh {* ;}

-keep public class base.java.exception.datacons.JException {* ;}

-keep public class base.ghc.exception.datacons.SomeException {* ;}

-keep public class base.java.Exception {
  eta.runtime.stg.Closure $fException_JException();
  eta.runtime.stg.Closure showException();
}

the final log

Note: there were 17 accesses to class members by means of introspection.
      You should consider explicitly keeping the mentioned class members
      (using '-keep' or '-keepclassmembers').
      (http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclassmember)
Unexpected error while performing partial evaluation:
  Class       = [eta/runtime/exception/Exception]
  Method      = [throwToMsg(Leta/runtime/stg/Capability;Leta/runtime/message/MessageThrowTo;Z)Z]
  Exception   = [java.lang.IllegalArgumentException] (Can't find common super class of [eta/runtime/stg/Capability] (with 1 known super classes) and [eta/runtime/stg/TSO] (with 3 known super classes))
Error: java.lang.IllegalArgumentException: Can't find common super class of [eta/runtime/stg/Capability] (with 1 known super classes) and [eta/runtime/stg/TSO] (with 3 known super classes)
rahulmutt commented 5 years ago

Can you share the exact steps for reproducing this? Source code, what steps you used to build, and how you ran proguard.

clojurians-org commented 5 years ago

1. create the project

larrys-MBP:javaCall larluo$ cat javaCall.cabal
-- Initial javaCall.cabal generated by etlas init.  For further 
-- documentation, see http://eta-lang.org/docs/

name:                javaCall
version:             0.1.0.0
-- synopsis:            
-- description:         
license:             BSD3
license-file:        LICENSE
author:              clojurians-org
maintainer:          larluo@clojurians.org
-- copyright:           
-- category:            
build-type:          Simple
extra-source-files:  ChangeLog.md
cabal-version:       >=1.10

executable javaCall
  main-is:             Main.hs
  -- other-modules:       
  -- other-extensions:    
  build-depends:
      base >=4.11 && <4.12
    , bytestring
    , utf8-string
    , containers
    , aeson
    , connection
    , http-api-data
    , http-media
    , http-client
    , http-client-tls
    , servant
    , servant-client
    , cryptonite
    , base-compat >= 0.9.1 && <= 0.10.4
    , xmlbf
  hs-source-dirs:      src
  java-sources:
      java/my/HInterface.java
  default-language:    Haskell2010

2. create the java interface: java/my/HInterface.java

larrys-MBP:javaCall larluo$ cat java/my/HInterface.java 
package my ;
import java.util.Map ;

public interface HInterface {
  public Map<String, String> get(Map<String, String> params) ;
}

3. create the haskell code

larrys-MBP:javaCall larluo$ cat src/Main.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}

module Main where

import GHC.Base(Class)

import Data.String
import Java (Java(Java), Object, JString, Inherits)
import Java.Core (JavaConverter(toJava))
import Java.Collections(Map(..))

data HInterface = HInterface @my.HInterface deriving (Class)
data MyGet = MyGet @my.Get deriving (Class)

type instance Inherits MyGet = '[Object, HInterface]
foreign import java unsafe "new" newHInterface :: Java a MyGet
foreign export java myGet :: (Map JString JString) -> Java MyGet (Map JString JString)
foreign export java get :: (Map JString JString) -> Java MyGet (Map JString JString)
myGet m = return $ do
  let a :: [(JString, JString)] = [("aaa", "bbb")]
  toJava a :: Map JString JString
get = myGet

main :: IO ()
main = putStrLn "hello, haskell"

4. build the uberjar

    etlas build --enable-uberjar

5. test the uberjar

larrys-MBP:larluo larluo$ cat Test.java 
import java.util.Map ;
import java.util.HashMap ;
import my.HInterface ;
import my.Get ;

public class Test {
  public static void main(String[] args) {
    Map<String, String> a = new HashMap<String, String>() ;
    a.put("larluo-kk", "larluo-vv") ;
    HInterface myGet = new Get() ;
    Map<String, String> b = myGet.get(a) ;
    System.out.println(b.get("aaa")) ;
  }
}

6. download eta-rules.pro

add -injars javaCall.jar -outjars javaCall-1.0.jar

modity -dontwarn eta.** to modity -dontwarn **

larrys-MBP:larluo larluo$ cat eta-rules.pro 
-injars javaCall.jar
-outjars javaCall-1.0.jar
-dontwarn **

-keep public class eta.runtime.stg.Closure
-keep public class eta.runtime.stg.StgContext

-keep public class ghc_prim.ghc.Types {
  eta.runtime.stg.Closure DFalse() ;
}

-keep public class base.ghc.TopHandler {
  eta.runtime.stg.Closure flushStdHandles() ;
}

-keep public class base.ghc.conc.Sync {
  eta.runtime.stg.Closure runSparks() ;
}

-keep public class base.control.exception.Base {
  eta.runtime.stg.Closure nonTermination();
  eta.runtime.stg.Closure nestedAtomically();
}

-keep public class base.ghc.io.Exception {
  eta.runtime.stg.Closure blockedIndefinitelyOnMVar();
  eta.runtime.stg.Closure blockedIndefinitelyOnSTM();
}

-keep public class base.ghc.Weak {
  eta.runtime.stg.Closure runFinalizzerBatch();
}

-keep public class ghc_prim.ghc.types.datacons.Izh {* ;}

-keep public class base.java.exception.datacons.JException {* ;}

-keep public class base.ghc.exception.datacons.SomeException {* ;}

-keep public class base.java.Exception {
  eta.runtime.stg.Closure $fException_JException();
  eta.runtime.stg.Closure showException();
}

7. run the proguard

brew install proguard
progruad @eta-rules.pro
rahulmutt commented 5 years ago

You forgot to add

-libraryjars <java.home>/lib/rt.jar

in your proguard file.

Regarding speed, it's much faster to send a list of all the dependency jars to the -injars list of proguard instead of creating an uberjar and then proguarding it. This is precisely what the Gradle can enable you to do which is why I suggested it.

clojurians-org commented 5 years ago

i use nixos sometimes, the gradle [etlas/eta binary file] don't run on nixos.

thanks, i will try gradle now.

clojurians-org commented 5 years ago

it still fail...

larrys-MBP:larluo larluo$ java -cp javaCall-1.0.jar:. Test
FATAL ERROR: Failed to load base closures.
java.lang.ClassNotFoundException: ghc_prim.ghc.Classes
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at eta.runtime.stg.e.a(Unknown Source)
    at eta.runtime.stg.e.<clinit>(Unknown Source)
    at eta.runtime.a.a(Unknown Source)
    at my.Get.get(Unknown Source)
    at Test.main(Test.java:11)
larrys-MBP:larluo larluo$ cat eta-rules.pro 
-injars javaCall.jar
-outjars javaCall-1.0.jar
-libraryjars <java.home>/lib/rt.jar
-dontwarn **

-keep public interface my.HInterface { *; }
-keep public class my.Get { *; }
-keep public class eta.runtime.stg.Closure
-keep public class eta.runtime.stg.StgContext

-keep public class ghc_prim.ghc.Types {
  eta.runtime.stg.Closure DFalse() ;
}

-keep public class base.ghc.TopHandler {
  eta.runtime.stg.Closure flushStdHandles() ;
}

-keep public class base.ghc.conc.Sync {
  eta.runtime.stg.Closure runSparks() ;
}

-keep public class base.control.exception.Base {
  eta.runtime.stg.Closure nonTermination();
  eta.runtime.stg.Closure nestedAtomically();
}

-keep public class base.ghc.io.Exception {
  eta.runtime.stg.Closure blockedIndefinitelyOnMVar();
  eta.runtime.stg.Closure blockedIndefinitelyOnSTM();
}

-keep public class base.ghc.Weak {
  eta.runtime.stg.Closure runFinalizzerBatch();
}

-keep public class ghc_prim.ghc.types.datacons.Izh {* ;}

-keep public class base.java.exception.datacons.JException {* ;}

-keep public class base.ghc.exception.datacons.SomeException {* ;}

-keep public class base.java.Exception {
  eta.runtime.stg.Closure $fException_JException();
  eta.runtime.stg.Closure showException();
}
jneira commented 5 years ago

Hi, maybe you could start disabling optimizing and obfuscating:

-dontoptimize
-dontobfuscate

Proguard still will do shrinking, removing all not directly used classes. The examples of using proguard are disabling them: