Search code examples
graalvmkotlin-jsduktape

Why is my Kotlin/JS program failing with "RangeError: Maximum call stack size exceeded"?


I’ve written a Kotlin/JS program that is crashing on some JavaScript engines.

It’s crashing on GraalVM like this:

RangeError: Maximum call stack size exceeded
    at <js> 839(myprogram.js:394:1174923-1174934)
    at <js> e(myprogram.js:394:1175309-1175342)
    at <js> 724(myprogram.js:394:1174990-1174995)
    at <js> e(myprogram.js:394:1175309-1175342)
    at <js> :anonymous(myprogram.js:394:1175222-1175358)
    at <js> :program(myprogram.js:394:13041-1175382)
    at org.graalvm.polyglot.Context.eval(Context.java:345)

On Duktape it’s failing like this:

com.squareup.duktape.DuktapeException: RangeError: compiler recursion limit (line 1)
    at com.squareup.duktape.Duktape.evaluate(Native Method)
    at com.squareup.duktape.Duktape.evaluate(Duktape.java:60)

This crash was introduced by upgrading from Kotlin 1.4.10 to 1.6.21.


Solution

  • Kotlin/JS uses a code shrinker in production builds. The code shrinker, Terser, produces very long statements that exceed the default limits of certain compilers.

    To fix this problem, configure Terser to produce smaller lines. Create a file, subproject/webpack.config.d/myWebpackConfig.js where subproject is the Gradle module that produces the Kotlin/JS executable.

    In that file, paste the following:

    config.optimization = config.optimization || {};
    const TerserPlugin = require("terser-webpack-plugin");
    config.optimization.minimizer = [
        new TerserPlugin({
            terserOptions: {
                compress: {
                    sequences: 10
                },
            },
        }),
    ];
    

    Changing the value of the sequences option is the key. The default value, 200, fits 200 logical statements into each line. By scaling this down to 10 Terser emits smaller statements.