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

VerifyError: Inconsistent stackmap frames at branch target #12993

Open
danissimo opened this issue May 4, 2024 · 3 comments
Open

VerifyError: Inconsistent stackmap frames at branch target #12993

danissimo opened this issue May 4, 2024 · 3 comments

Comments

@danissimo
Copy link

danissimo commented May 4, 2024

Reproduction steps

Java: Oracle HotSpot 17.0.6+9-LTS-190, OpenJDK Temurin-17.0.8+7.
Scala versions: 2.13.10, 2.13.14.

I faced the behaviour using spray json ("io.spray" %% "spray-json" % "1.3.6"), and I couldn't minimise the snippet to clean scala, but the hint to the nature of the bug is the two workarounds at the bottom of this report.

import spray.json.DefaultJsonProtocol._
import spray.json._

object BadScalac {
  def main(args: Array[String]): Unit = {
    val msg = (
      try Map("block" -> "try").toJson
      catch { case _: Throwable => Map("block" -> "catch").toJson }
    ).prettyPrint + "\n"
    println(msg)
  }
}

Problem

It gets compiled successfully, but when I run I get

Exception in thread "main" java.lang.VerifyError: Inconsistent stackmap frames at branch target 152
Exception Details:
  Location:
    BadScalac$.main([Ljava/lang/String;)V @149: goto
  Reason:
    Current frame's stack size doesn't match stackmap.
  Current Frame:
    bci: @149
    flags: { }
    locals: { 'BadScalac$', '[Ljava/lang/String;' }
    stack: { 'spray/json/JsValue' }
  Stackmap Frame:
    bci: @152
    flags: { }
    locals: { 'BadScalac$', '[Ljava/lang/String;' }
    stack: { 'java/lang/Object', 'spray/json/JsValue' }
  Bytecode:
    0000000: bb00 1f59 1220 b700 23b2 0028 b200 2db6
    0000010: 0031 b200 3604 bd00 3859 03b2 003b b200
    0000020: 2d12 3db6 0041 1243 b600 4753 c000 49b6
    0000030: 004d b600 53b6 0057 b200 5cb2 005c b600
    0000040: 60b2 005c b600 60b6 0064 b600 6aa7 004b
    0000050: 57b2 0028 b200 2db6 0031 b200 3604 bd00
    0000060: 3859 03b2 003b b200 2d12 3db6 0041 126c
    0000070: b600 4753 c000 49b6 004d b600 53b6 0057
    0000080: b200 5cb2 005c b600 60b2 005c b600 60b6
    0000090: 0064 b600 6aa7 0003 b600 72b6 0076 1278
    00000a0: b600 76b6 007b 4db2 002d 2cb6 007f b1  
  Exception Handler Table:
    bci [9, 77] => handler: 80
  Stackmap Table:
    same_locals_1_stack_item_extended(@80,Object[#29])
    full_frame(@152,{Object[#2],Object[#132]},{Object[#4],Object[#110]})

	at BadScalac.main(BadScalac.scala)

But it goes away when I rewrite the source code as

import spray.json.DefaultJsonProtocol._
import spray.json._

object BadScalac extends App {
  val msg = (
    try Map("block" -> "try").toJson
    catch { case _: Throwable => Map("block" -> "catch").toJson }
  ).prettyPrint + "\n"
  println(msg)
}

or even when I drop the last addition of the "\n" string:

object BadScalac {
  def main(args: Array[String]): Unit = {
    val msg = (
      try Map("block" -> "try").toJson
      catch { case _: Throwable => Map("block" -> "catch").toJson }
    ).prettyPrint
    println(msg)
  }
}

The both snippets above yield

{
  "block": "try"
}

with and without the last newline respectively.

@som-snytt
Copy link

String concat is handled in the backend. Variants that induce Uncurry to lift the try will work.

Other superficially similar ops such as * 2 will work.

Welcome to Scala 2.13.14 (OpenJDK 64-Bit Server VM, Java 21.0.2).
Type in expressions for evaluation. Or try :help.

scala> def f() = (try "try" catch { case _: Throwable => "catch" }).toString + "nope"
java.lang.VerifyError: Inconsistent stackmap frames at branch target 20
Exception Details:
  Location:
    f()Ljava/lang/String; @17: goto
  Reason:
    Current frame's stack size doesn't match stackmap.
  Current Frame:
    bci: @17
    flags: { }
    locals: { '$iw' }
    stack: { 'java/lang/String' }
  Stackmap Frame:
    bci: @20
    flags: { }
    locals: { '$iw' }
    stack: { 'java/lang/Object', 'java/lang/String' }
  Bytecode:
    0000000: bb00 1259 1213 b700 1712 19a7 0009 5712
    0000010: 1ba7 0003 b600 20b6 0024 1226 b600 24b6
    0000020: 0027 b0
  Exception Handler Table:
    bci [9, 11] => handler: 14
  Stackmap Table:
    same_locals_1_stack_item_frame(@14,Object[#16])
    full_frame(@20,{Object[#2]},{Object[#4],Object[#29]})

  ... 29 elided

scala>

@som-snytt
Copy link

just for fun

scala> object X { def f() = (try "try" catch (_ => "catch")).toString + "nope" }
-- [E008] Not Found Error: ---------------------------------------------------------------------------------------------
1 |object X { def f() = (try "try" catch (_ => "catch")).toString + "nope" }
  |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |           value toString is not a member of ?{ toString: ? }, but could be made available as an extension method.
  |
  |           The following import might fix the problem:
  |
  |             import scala.reflect.Selectable.reflectiveSelectable
  |
1 error found

@sjrd
Copy link
Member

sjrd commented May 5, 2024

I guess we could fix this by backporting scala/scala3#18619

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants