Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stack overflow on Eclipse Golo generated bytecode with invokedynamic #341

Closed
jponge opened this Issue Apr 18, 2018 · 8 comments

Comments

3 participants
@jponge
Copy link

jponge commented Apr 18, 2018

Playing with a JDK 10 ea I found a stack overflow when running a simple recursion-based Fibonacci sample.

Apparently inlining of invokedynamic callsites causes problems with deep recursion stacks.
Here is a small part of the stack trace:

at jdk.internal.vm.compiler@10/org.graalvm.compiler.replacements.MethodHandlePlugin.handleInvoke(MethodHandlePlugin.java:90)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.tryNodePluginForInvocation(BytecodeParser.java:2047)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.appendInvoke(BytecodeParser.java:1579)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.genDynamicInvokeHelper(BytecodeParser.java:1432)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.genInvokeVirtualHelper(BytecodeParser.java:1460)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.genInvokeVirtual(BytecodeParser.java:1441)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.genInvokeVirtual(BytecodeParser.java:1387)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.processBytecode(BytecodeParser.java:4525)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.iterateBytecodesForBlock(BytecodeParser.java:2964)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.processBlock(BytecodeParser.java:2786)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.build(BytecodeParser.java:831)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.parseAndInlineCallee(BytecodeParser.java:2278)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.inline(BytecodeParser.java:2186)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.tryInline(BytecodeParser.java:2079)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.appendInvoke(BytecodeParser.java:1601)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.genDynamicInvokeHelper(BytecodeParser.java:1434)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.genInvokeDynamic(BytecodeParser.java:1380)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.genInvokeDynamic(BytecodeParser.java:1376)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.processBytecode(BytecodeParser.java:4529)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.iterateBytecodesForBlock(BytecodeParser.java:2964)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.processBlock(BytecodeParser.java:2786)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.build(BytecodeParser.java:831)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.parseAndInlineCallee(BytecodeParser.java:2278)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.inline(BytecodeParser.java:2186)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.tryInline(BytecodeParser.java:2068)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.appendInvoke(BytecodeParser.java:1601)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.handleReplacedInvoke(BytecodeParser.java:1532)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.replacements.MethodHandlePlugin.handleInvoke(MethodHandlePlugin.java:90)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.tryNodePluginForInvocation(BytecodeParser.java:2047)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.appendInvoke(BytecodeParser.java:1579)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.genInvokeStatic(BytecodeParser.java:1350)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.genInvokeStatic(BytecodeParser.java:1332)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.processBytecode(BytecodeParser.java:4527)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.iterateBytecodesForBlock(BytecodeParser.java:2964)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.processBlock(BytecodeParser.java:2786)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.build(BytecodeParser.java:831)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.parseAndInlineCallee(BytecodeParser.java:2278)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.inline(BytecodeParser.java:2186)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.tryInline(BytecodeParser.java:2079)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.appendInvoke(BytecodeParser.java:1601)
          	at jdk.internal.vm.compiler@10/org.graalvm.compiler.java.BytecodeParser.handleReplacedInvoke(BytecodeParser.java:1532)

Steps to reproduce

  1. Get Eclipse Golo
  2. cd to the Golo distribution folder.
  3. Run JAVA_OPTS='-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler' bin/golo golo --files samples/fibonacci.golo

Code

Here is the culprit program:

module samples.Fibonacci

import java.lang.System

function fib = |n| {
  if n <= 1 {
    return n
  } else {
    return fib(n - 1) + fib(n - 2)
  }
}

local function run = {
  let start = System.currentTimeMillis()
  let result = fib(40)
  let duration = System.currentTimeMillis() - start
  println(">>> " + result + " (took " + duration + "ms)")
}

function main = |args| {
  while true {
    run()
  }
}

It is important to note that most Golo call sites are using invokedynamic.

@dougxc

This comment has been minimized.

Copy link
Member

dougxc commented Apr 18, 2018

Hi @jponge , thanks for the report. Is this reproducible with the recently released GraalVM? I ask because the version of Graal in JDK 10 is somewhat behind GraalVM and this problem may have already been fixed.

@dougxc

This comment has been minimized.

Copy link
Member

dougxc commented Apr 18, 2018

I can confirm this fails on GraalVM. We will look into it.

@jponge

This comment has been minimized.

Copy link
Author

jponge commented Apr 18, 2018

@dougxc

This comment has been minimized.

Copy link
Member

dougxc commented Apr 18, 2018

This should be fixed by 2f1b863. To test this, you can build Graal on JVMCI JDK8 following the instructions at https://github.com/oracle/graal/blob/master/compiler/README.md and then:

compiler> mx makegraaljdk graaljdk
compiler> export JAVA_HOME=$PWD/graaljdk
compiler> cd /path/to/golo
golo> bin/golo golo --files samples/fibonacci.golo
>>> 102334155 (took 8919ms)
>>> 102334155 (took 462ms)
>>> 102334155 (took 441ms)
>>> 102334155 (took 443ms)
>>> 102334155 (took 444ms)

Once Graal is warmed up, it seems to compare favorably to C2 in this example:

golo> env JAVA_OPTS=-XX:-UseJVMCICompiler bin/golo golo --files samples/fibonacci.golo
>>> 102334155 (took 1330ms)
>>> 102334155 (took 1258ms)
>>> 102334155 (took 1261ms)
>>> 102334155 (took 1268ms)
>>> 102334155 (took 1283ms)
@jponge

This comment has been minimized.

Copy link
Author

jponge commented Apr 19, 2018

Thanks @dougxc I'll have a look in the next few days.

It surely looks impressive compared to C2!

@dougxc

This comment has been minimized.

Copy link
Member

dougxc commented Apr 19, 2018

Please re-open this issue if there are still problems.

@dougxc dougxc closed this Apr 19, 2018

@jponge

This comment has been minimized.

Copy link
Author

jponge commented Apr 23, 2018

I've built my own Graal JDK and I can confirm that:

  1. the issue has been fixed, and that
  2. performance is on par with Java.

Very impressive!

@dougxc

This comment has been minimized.

Copy link
Member

dougxc commented Apr 23, 2018

Great to hear - thanks for the feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.