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

REPL :javap doesn't work on JDK 16+ unless you pass extra flags #12378

Open
lrytz opened this issue Apr 22, 2021 · 10 comments
Open

REPL :javap doesn't work on JDK 16+ unless you pass extra flags #12378

lrytz opened this issue Apr 22, 2021 · 10 comments

Comments

@lrytz
Copy link
Member

lrytz commented Apr 22, 2021

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

scala> :javap scala.Some
java.lang.IllegalAccessException: class scala.tools.nsc.interpreter.shell.JavapTask cannot access class com.sun.tools.javap.JavapFileManager (in module jdk.jdeps) because module jdk.jdeps does not export com.sun.tools.javap to unnamed module @324e4822
	at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:385)
	at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:687)
	at java.base/java.lang.reflect.Method.invoke(Method.java:559)
	at scala.tools.nsc.interpreter.shell.JavapTask.<init>(JavapClass.scala:498)

From what I understand, the complication is that we need to make javap read a class from the repl's in-memory representation / class loader.

It seems the only accessible API is ToolProvider which only has a run method. I assume we cannot make it search classes in a custom class loader through this.

Personally, I'd be fine throwing out :javap in favor of :asmp which would be easy to implement

scala> :power
Power mode enabled. :phase is at typer.
import scala.tools.nsc._, intp.global._, definitions._
Try :help or completions for vals._ and power._

scala> class HalloVelo
class HalloVelo

scala> scala.tools.nsc.backend.jvm.AsmUtils.traceClass(intp.classLoader.classBytes("HalloVelo"))
Bytecode for class $line31/$read$$iw$HalloVelo
// class version 52.0 (52)
// access flags 0x21
public class $line31/$read$$iw$HalloVelo {

  // compiled from: <console>

  ATTRIBUTE Scala : unknown

  ATTRIBUTE ScalaInlineInfo : unknown
  // access flags 0x1
  public INNERCLASS $line31/$read$$iw $line31/$read $iw
  // access flags 0x1
  public INNERCLASS $line31/$read$$iw$HalloVelo $line31/$read$$iw HalloVelo

  // access flags 0x1011
  public final synthetic L$line31/$read$$iw; $outer

  // access flags 0x1001
  public synthetic $line31$$read$$iw$HalloVelo$$$outer()L$line31/$read$$iw;
   L0
    LINENUMBER 1 L0
    ALOAD 0
    GETFIELD $line31/$read$$iw$HalloVelo.$outer : L$line31/$read$$iw;
    ARETURN
   L1
    LOCALVARIABLE this L$line31/$read$$iw$HalloVelo; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x1
  public <init>(L$line31/$read$$iw;)V
    // parameter final synthetic  $outer
   L0
    LINENUMBER 1 L0
    ALOAD 1
    IFNONNULL L1
    ACONST_NULL
    ATHROW
   L1
   FRAME SAME
    ALOAD 0
    ALOAD 1
    PUTFIELD $line31/$read$$iw$HalloVelo.$outer : L$line31/$read$$iw;
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L2
    LOCALVARIABLE this L$line31/$read$$iw$HalloVelo; L0 L2 0
    LOCALVARIABLE $outer L$line31/$read$$iw; L0 L2 1
    MAXSTACK = 2
    MAXLOCALS = 2
}
@som-snytt
Copy link

Agreed! Wanted this a long time.

@michelou
Copy link

michelou commented Apr 22, 2021

I guess Scala 2 doesn't make use of the Java module system.
For inside thoughts, see these articles :

@harpocrates
Copy link

:asmp sounds like it would be also be easier to port over to Scala 3 than :javap.

@jxnu-liguobin
Copy link
Member

Personally, I'd be fine throwing out :javap in favor of :asmp which would be easy to implement

It seems that asm does not rely on JDK classes, So our solution to this problem is to give up javap and add asmp command?

@som-snytt
Copy link

or both. scala 2 repl has a classloader issue that requires -nobootcp, so there may be the same issue with scala 3. I like the idea of having many tools in the tool belt.

@jxnu-liguobin
Copy link
Member

I will refer to dotty to implement asmp for scala2. Any interested volunteers can pick it up before I submit pr.

@ches
Copy link

ches commented Oct 15, 2021

For reference until we have a lasting answer for the Scala 2 REPL, @retronym pointed out the escape hatch for the module access on a previous tromp down this lane, still an applicable workaround in JDK 17: scala/scala#8400 (comment)

$ scala -nobootcp -J--add-exports=jdk.jdeps/com.sun.tools.javap=ALL-UNNAMED

which could be set in JAVA_OPTS more persistently.

@SethTisue SethTisue modified the milestones: 2.13.7, 2.13.8 Oct 21, 2021
@SethTisue SethTisue modified the milestones: 2.13.8, 2.13.9 Dec 15, 2021
@SethTisue SethTisue modified the milestones: 2.13.9, 2.13.10 Apr 25, 2022
@SethTisue SethTisue modified the milestones: 2.13.10, Backlog Sep 23, 2022
@SethTisue
Copy link
Member

here's the Scala-CLI form of the workaround:

scala-cli repl -S 2 -J --add-exports=jdk.jdeps/com.sun.tools.javap=ALL-UNNAMED

(-nobootcp doesn't seem to be necessary? 🤷)

@SethTisue SethTisue changed the title REPL :javap disallowed by module system on JDK 16 REPL :javap doesn't work on JDK 16+ unless you pass extra flags Sep 16, 2023
@som-snytt
Copy link

The "workaround" for -nobootcp mentioned in the error message:

scala -Dscala.repl.info -Xsource:3 -J--add-exports -Jjdk.jdeps/com.sun.tools.javap=ALL-UNNAMED -Yrepl-outdir myreplout -toolcp myreplout

in other words

➜  snips scala -Dscala.repl.info -Xsource:3 -J--add-exports -Jjdk.jdeps/com.sun.tools.javap=ALL-UNNAMED
[info] started at Sat Sep 16 10:39:25 PDT 2023
Welcome to Scala 2.13.12 (OpenJDK 64-Bit Server VM, Java 20.0.2).
Type in expressions for evaluation. Or try :help.

scala 2.13.12> class C
class C

scala 2.13.12> :javap C
On JDK 9 or higher, use -nobootcp to enable :javap, or set -Yrepl-outdir to a file system path on the tool class path with -toolcp.

scala 2.13.12>
:quit
➜  snips scala -Dscala.repl.info -Xsource:3 -J--add-exports -Jjdk.jdeps/com.sun.tools.javap=ALL-UNNAMED -Yrepl-outdir myreplout -toolcp myreplout
[info] started at Sat Sep 16 10:39:50 PDT 2023
Welcome to Scala 2.13.12 (OpenJDK 64-Bit Server VM, Java 20.0.2).
Type in expressions for evaluation. Or try :help.

scala 2.13.12> class C
class C

scala 2.13.12> :javap -public C
Compiled from "<console>"
public class C {
  public final $iw $outer;
  public $iw C$$$outer();
  public C($iw);
}

scala 2.13.12>

where myreplout is a real directory mentioned by both options.

I don't know if there is a use case where it's not feasible to use -nobootcp, such that this mode is necessary.

I see that :paste -raw class output goes directly under -Yrepl-outdir. But I also see :paste -java output is only virtual.

@som-snytt
Copy link

They don't want either of them in dotty scala/scala3#12210

Scrolling way back, I see that was linked in 2021.

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

No branches or pull requests

8 participants