Frege / frege

Frege is a Haskell for the JVM. It brings purely functional programing to the Java platform.
https://github.com/Frege/frege/wiki/_pages
Other
3.64k stars 145 forks source link

Compiling big list results in error: code too large #287

Closed mabre closed 6 years ago

mabre commented 8 years ago

When compiling this code with Frege 3.23.451 which contains some big lists (automatically generated by the lexer generator Alex), I get this error when javac is called:

/tmp/frege/language/CSPM/Lexer.java:322: error: code too large
final public static IJ ij = new IJ();
                      ^
1 error
E Lexer.fr:59: java compiler errors are most likely caused by erroneous
    native definitions

This happens because all functions which return a list are translated to class variables which will hit the byte code limit of 65,535 byte. A workaround is giving those functions an unused parameter, such that those functions get translated to java functions.

When compiling the same code with Frege 3.24.100, I run out of heap space (set to 2 GB):

An exception has occurred in the compiler (9-ea). Please file a bug against the Java compiler via the Java bug reporting page (http://bugreport.java.com) after checking the Bug Database (http://bugs.java.com) for duplicates. Include your program and the following diagnostic in your report. Thank you.
java.lang.OutOfMemoryError: Java heap space
        at com.sun.tools.javac.util.Position$LineMapImpl.build(jdk.compiler@9-ea/Position.java:156)
        at com.sun.tools.javac.util.Position.makeLineMap(jdk.compiler@9-ea/Position.java:80)
        at com.sun.tools.javac.parser.JavadocTokenizer.getLineMap(jdk.compiler@9-ea/JavadocTokenizer.java:468)
        at com.sun.tools.javac.parser.Scanner.getLineMap(jdk.compiler@9-ea/Scanner.java:127)
        at com.sun.tools.javac.parser.JavacParser.parseCompilationUnit(jdk.compiler@9-ea/JavacParser.java:3172)
        at com.sun.tools.javac.main.JavaCompiler.parse(jdk.compiler@9-ea/JavaCompiler.java:620)
        at com.sun.tools.javac.main.JavaCompiler.parse(jdk.compiler@9-ea/JavaCompiler.java:657)
        at com.sun.tools.javac.main.JavaCompiler.parseFiles(jdk.compiler@9-ea/JavaCompiler.java:993)
        at com.sun.tools.javac.main.JavaCompiler.compile(jdk.compiler@9-ea/JavaCompiler.java:906)
        at com.sun.tools.javac.api.JavacTaskImpl$1.call(jdk.compiler@9-ea/JavacTaskImpl.java:104)
        at com.sun.tools.javac.api.JavacTaskImpl$1.call(jdk.compiler@9-ea/JavacTaskImpl.java:100)
        at com.sun.tools.javac.api.JavacTaskImpl.handleExceptions(jdk.compiler@9-ea/JavacTaskImpl.java:135)
        at com.sun.tools.javac.api.JavacTaskImpl.doCall(jdk.compiler@9-ea/JavacTaskImpl.java:100)
        at com.sun.tools.javac.api.JavacTaskImpl.call(jdk.compiler@9-ea/JavacTaskImpl.java:94)
        at frege.runtime.Javac.runJavac(Javac.java:46)
        at frege.compiler.Main.lambda$runJavac$36(Main.java:2512)
        at frege.compiler.Main$$Lambda$5666/1770154270.apply(Unknown Source)
        at frege.compiler.Main.lambda$null$152(Main.java:4795)
        at frege.compiler.Main$$Lambda$5657/995240428.apply(Unknown Source)
        at frege.compiler.Main.lambda$null$159(Main.java:5052)
        at frege.compiler.Main$$Lambda$5644/463728901.apply(Unknown Source)
        at frege.compiler.Main.lambda$null$162(Main.java:5137)
        at frege.compiler.Main$$Lambda$5645/1835531257.call(Unknown Source)
        at frege.run8.Thunk.call(Thunk.java:231)
        at frege.compiler.Main.lambda$null$34(Main.java:1991)
        at frege.compiler.Main$$Lambda$308/1265476088.apply(Unknown Source)
        at frege.compiler.types.Global.lambda$null$49(Global.java:7308)
        at frege.compiler.types.Global$$Lambda$284/1095293768.apply(Unknown Source)
        at frege.compiler.types.Global.lambda$null$48(Global.java:7320)
        at frege.compiler.types.Global$$Lambda$424/198002944.call(Unknown Source)
        at frege.run8.Thunk.call(Thunk.java:231)
        at frege.compiler.Main.lambda$null$347(Main.java:9261)
E Lexer.fr:59: java compiler errors are most likely caused
    by erroneous native definitions

The generated Java file contains 328,532,791 characters. After removing repeated spaces using sed "s/ +/ /g", it has only 2,035,731 characters and I get the code too large error again:

/tmp/frege/language/CSPM/Lexer.java:265: error: code too large
final public static PreludeBase.TList<Integer> alex_table9 = PreludeBase.TList.DCons.<
                                               ^
1 error

It would be nice if the compiler could find out if the generated static code is too large and put it into functions.

[btw: The original code only had two functions with two very big lists. When trying to compile that file with 2 GB heap space I get this error after 10 minutes:

java.lang.OutOfMemoryError: GC overhead limit exceeded
        at frege.runtime.Fun1.apply(Fun1.java:60)
        at frege.lib.PP.flatten(PP.java:1322)
        at frege.lib.PP$IJ$flattenƒ81eaf204.eval(PP.java:1693)
        at frege.lib.PP$IJ$flattenƒ81eaf204.eval(PP.java:1690)
        at frege.runtime.Fun1$1.eval(Fun1.java:63)
        at frege.runtime.Delayed.call(Delayed.java:198)
        at frege.runtime.Delayed.forced(Delayed.java:257)

But I think preventing these out-of-memory situations in the compiler might be hard/impossible.

Ingo60 commented 8 years ago

Yes, I know this error from the parser (frege.compiler.grammar.Frege), where I also have those huge tables.

I've thought about supporting this better by special handling of list literals that have only other literals in them. For example, making them into an array in an extra method. Still, there is a limit even for the size of such an array in Java.

Meanwhile, the easiest thing you can do is to transform

foo = [1,2,3,4,...,123456]

into

import Data.JSON

foo = unJust (parseJSON
             "[1,2,3,4,....,123456]"
             :: Maybe [Int])

Unfortunately, since we don't have mult-line string literals, the string must be all on one line, or constructed from multiple strings with (++).

Ingo60 commented 6 years ago

In the Frege compiler, I encode the parser tables in strings like so:

> foo = (map ord . unpacked) "\U1234\U4325\U...."