diff --git a/compiler/src/dotty/tools/backend/jvm/AsmUtils.scala b/compiler/src/dotty/tools/backend/jvm/AsmUtils.scala index 47d5c1e41361..7f5887d99a7f 100644 --- a/compiler/src/dotty/tools/backend/jvm/AsmUtils.scala +++ b/compiler/src/dotty/tools/backend/jvm/AsmUtils.scala @@ -2,7 +2,7 @@ package dotty.tools package backend package jvm -import scala.tools.asm.tree.{AbstractInsnNode, ClassNode, MethodNode} +import scala.tools.asm.tree.{AbstractInsnNode} import java.io.PrintWriter import scala.tools.asm.util.{TraceClassVisitor, TraceMethodVisitor, Textifier} import scala.tools.asm.ClassReader @@ -31,7 +31,7 @@ object AsmUtils { final val traceSerializedClassEnabled = false final val traceSerializedClassPattern = "" - def traceMethod(mnode: MethodNode): Unit = { + def traceMethod(mnode: MethodNode1): Unit = { println(s"Bytecode for method ${mnode.name}") val p = new Textifier val tracer = new TraceMethodVisitor(p) @@ -41,7 +41,7 @@ object AsmUtils { w.flush() } - def traceClass(cnode: ClassNode): Unit = { + def traceClass(cnode: ClassNode1): Unit = { println(s"Bytecode for class ${cnode.name}") val w = new PrintWriter(System.out) cnode.accept(new TraceClassVisitor(w)) @@ -50,8 +50,8 @@ object AsmUtils { def traceClass(bytes: Array[Byte]): Unit = traceClass(readClass(bytes)) - def readClass(bytes: Array[Byte]): ClassNode = { - val node = new ClassNode() + def readClass(bytes: Array[Byte]): ClassNode1 = { + val node = new ClassNode1() new ClassReader(bytes).accept(node, 0) node } diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala b/compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala index 32e676098b33..dea4cf7cb69a 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala @@ -3,6 +3,7 @@ package backend package jvm import scala.tools.asm +import scala.tools.asm.ClassWriter import scala.collection.mutable import dotty.tools.io.AbstractFile @@ -126,6 +127,20 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters { } } + /* + * can-multi-thread + */ + def createJAttribute(name: String, b: Array[Byte], offset: Int, len: Int): asm.Attribute = { + new asm.Attribute(name) { + override def write(classWriter: ClassWriter, code: Array[Byte], + codeLength: Int, maxStack: Int, maxLocals: Int): asm.ByteVector = { + val byteVector = new asm.ByteVector(len) + byteVector.putByteArray(b, offset, len) + byteVector + } + } + } + /* * Custom attribute (JVMS 4.7.1) "ScalaSig" used as marker only * i.e., the pickle is contained in a custom annotation, see: @@ -151,15 +166,6 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters { vp } - /* - * can-multi-thread - */ - def createJAttribute(name: String, b: Array[Byte], offset: Int, len: Int): asm.Attribute = { - val dest = new Array[Byte](len) - System.arraycopy(b, offset, dest, 0, len) - new asm.CustomAttr(name, dest) - } - /* * can-multi-thread */ diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala index c6c6d92fdd9c..691571012ccc 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala @@ -53,7 +53,7 @@ trait BCodeSkelBuilder extends BCodeHelpers { final val MaximumJvmParameters = 254 // current class - var cnode: asm.tree.ClassNode = null + var cnode: ClassNode1 = null var thisName: String = null // the internal name of the class being emitted var claszSymbol: Symbol = null @@ -88,7 +88,7 @@ trait BCodeSkelBuilder extends BCodeHelpers { isCZStaticModule = claszSymbol.isStaticModuleClass thisName = internalName(claszSymbol) - cnode = new asm.tree.ClassNode() + cnode = new ClassNode1() initJClass(cnode) @@ -245,7 +245,7 @@ trait BCodeSkelBuilder extends BCodeHelpers { } // end of method addClassFields() // current method - var mnode: asm.tree.MethodNode = null + var mnode: MethodNode1 = null var jMethodName: String = null var isMethSymStaticCtor = false var returnType: BType = null @@ -524,7 +524,7 @@ trait BCodeSkelBuilder extends BCodeHelpers { mdesc, jgensig, mkArrayS(thrownExceptions) - ).asInstanceOf[asm.tree.MethodNode] + ).asInstanceOf[MethodNode1] // TODO param names: (m.params map (p => javaName(p.sym))) diff --git a/compiler/src/dotty/tools/backend/jvm/BytecodeWriters.scala b/compiler/src/dotty/tools/backend/jvm/BytecodeWriters.scala index 8a82b6dcc444..54183186dd2e 100644 --- a/compiler/src/dotty/tools/backend/jvm/BytecodeWriters.scala +++ b/compiler/src/dotty/tools/backend/jvm/BytecodeWriters.scala @@ -84,7 +84,7 @@ trait BytecodeWriters { private def emitAsmp(jclassBytes: Array[Byte], asmpFile: dotty.tools.io.File): Unit = { val pw = asmpFile.printWriter() try { - val cnode = new asm.tree.ClassNode() + val cnode = new ClassNode1() val cr = new asm.ClassReader(jclassBytes) cr.accept(cnode, 0) val trace = new scala.tools.asm.util.TraceClassVisitor(new java.io.PrintWriter(new java.io.StringWriter())) diff --git a/compiler/src/dotty/tools/backend/jvm/ClassNode1.java b/compiler/src/dotty/tools/backend/jvm/ClassNode1.java new file mode 100644 index 000000000000..c5594ae3dea6 --- /dev/null +++ b/compiler/src/dotty/tools/backend/jvm/ClassNode1.java @@ -0,0 +1,39 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. + * + * Licensed under Apache License 2.0 + * (http://www.apache.org/licenses/LICENSE-2.0). + * + * See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + */ + +package dotty.tools.backend.jvm; + +import scala.tools.asm.MethodVisitor; +import scala.tools.asm.Opcodes; +import scala.tools.asm.tree.ClassNode; +import scala.tools.asm.tree.MethodNode; + +/** + * A subclass of {@link ClassNode} to customize the representation of + * label nodes with {@link LabelNode1}. + */ +public class ClassNode1 extends ClassNode { + public ClassNode1() { + this(Opcodes.ASM6); + } + + public ClassNode1(int api) { + super(api); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { + MethodNode method = new MethodNode1(access, name, descriptor, signature, exceptions); + methods.add(method); + return method; + } +} diff --git a/compiler/src/dotty/tools/backend/jvm/GenBCode.scala b/compiler/src/dotty/tools/backend/jvm/GenBCode.scala index ed0e8b14be79..950478dcaabe 100644 --- a/compiler/src/dotty/tools/backend/jvm/GenBCode.scala +++ b/compiler/src/dotty/tools/backend/jvm/GenBCode.scala @@ -7,7 +7,6 @@ import dotty.tools.dotc.core.Phases.Phase import scala.collection.mutable import scala.collection.JavaConverters._ -import scala.tools.asm.CustomAttr import dotty.tools.dotc.transform.SymUtils._ import dotty.tools.dotc.interfaces import dotty.tools.dotc.util.SourceFile @@ -240,7 +239,7 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter getFileForClassfile(outF, store.name, ".hasTasty") binary } - val dataAttr = new CustomAttr(nme.TASTYATTR.mangledString, tasty) + val dataAttr = createJAttribute(nme.TASTYATTR.mangledString, tasty, 0, tasty.length) store.visitAttribute(dataAttr) } diff --git a/compiler/src/dotty/tools/backend/jvm/LabelNode1.java b/compiler/src/dotty/tools/backend/jvm/LabelNode1.java new file mode 100644 index 000000000000..cf91fe619f5d --- /dev/null +++ b/compiler/src/dotty/tools/backend/jvm/LabelNode1.java @@ -0,0 +1,31 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. + * + * Licensed under Apache License 2.0 + * (http://www.apache.org/licenses/LICENSE-2.0). + * + * See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + */ + +package dotty.tools.backend.jvm; + +import scala.tools.asm.Label; +import scala.tools.asm.tree.ClassNode; +import scala.tools.asm.tree.LabelNode; + +/** + * A subclass of {@link LabelNode} to add user-definable flags. + */ +public class LabelNode1 extends LabelNode { + public LabelNode1() { + } + + public LabelNode1(Label label) { + super(label); + } + + public int flags; +} diff --git a/compiler/src/dotty/tools/backend/jvm/MethodNode1.java b/compiler/src/dotty/tools/backend/jvm/MethodNode1.java new file mode 100644 index 000000000000..bfa4401830ba --- /dev/null +++ b/compiler/src/dotty/tools/backend/jvm/MethodNode1.java @@ -0,0 +1,47 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. + * + * Licensed under Apache License 2.0 + * (http://www.apache.org/licenses/LICENSE-2.0). + * + * See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + */ + +package dotty.tools.backend.jvm; + +import scala.tools.asm.Label; +import scala.tools.asm.Opcodes; +import scala.tools.asm.tree.LabelNode; +import scala.tools.asm.tree.MethodNode; +/** + * A subclass of {@link MethodNode} to customize the representation of + * label nodes with {@link LabelNode1}. + */ +public class MethodNode1 extends MethodNode { + public MethodNode1(int api, int access, String name, String descriptor, String signature, String[] exceptions) { + super(api, access, name, descriptor, signature, exceptions); + } + + public MethodNode1(int access, String name, String descriptor, String signature, String[] exceptions) { + this(Opcodes.ASM6, access, name, descriptor, signature, exceptions); + } + + public MethodNode1(int api) { + super(api); + } + + public MethodNode1() { + this(Opcodes.ASM6); + } + + @Override + protected LabelNode getLabelNode(Label label) { + if (!(label.info instanceof LabelNode)) { + label.info = new LabelNode1(label); + } + return (LabelNode) label.info; + } +} diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index 49963b836b85..12644be88966 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -324,7 +324,8 @@ trait ParallelTesting extends RunnerOrchestration { self => protected def compile(files0: Array[JFile], flags0: TestFlags, suppressErrors: Boolean, targetDir: JFile): TestReporter = { - val flags = flags0 and ("-d", targetDir.getAbsolutePath) + val flags = flags0.and("-d", targetDir.getAbsolutePath) + .withClasspath(targetDir.getAbsolutePath) def flattenFiles(f: JFile): Array[JFile] = if (f.isDirectory) f.listFiles.flatMap(flattenFiles) @@ -336,9 +337,7 @@ trait ParallelTesting extends RunnerOrchestration { self => val fullArgs = Array( "javac", "-encoding", "UTF-8", - "-classpath", - s"${Properties.scalaLibrary}${JFile.pathSeparator}${targetDir.getAbsolutePath}" - ) ++ flags.all.takeRight(2) ++ fs + ) ++ flags.javacFlags ++ fs val process = Runtime.getRuntime.exec(fullArgs) val output = Source.fromInputStream(process.getErrorStream).mkString @@ -366,7 +365,7 @@ trait ParallelTesting extends RunnerOrchestration { self => } } - val allArgs = flags.withClasspath(targetDir.getAbsolutePath).all + val allArgs = flags.all // Compile with a try to catch any StackTrace generated by the compiler: try { diff --git a/compiler/test/dotty/tools/vulpix/TestFlags.scala b/compiler/test/dotty/tools/vulpix/TestFlags.scala index ac7770c1a8e2..92bd878264e9 100644 --- a/compiler/test/dotty/tools/vulpix/TestFlags.scala +++ b/compiler/test/dotty/tools/vulpix/TestFlags.scala @@ -20,6 +20,14 @@ final case class TestFlags( TestFlags(defaultClassPath, s"$runClassPath${JFile.pathSeparator}$classPath", options) def all: Array[String] = Array("-classpath", defaultClassPath) ++ options + + /** Subset of the flags that should be passed to javac. */ + def javacFlags: Array[String] = { + val flags = all + val cp = flags.dropWhile(_ != "-classpath").take(2) + val output = flags.dropWhile(_ != "-d").take(2) + cp ++ output + } } object TestFlags { diff --git a/project/Build.scala b/project/Build.scala index 1a1e67ec979f..8bd5da3d28f5 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -481,7 +481,7 @@ object Build { // get libraries onboard libraryDependencies ++= Seq( - "org.scala-lang.modules" % "scala-asm" % "6.0.0-scala-1", // used by the backend + "org.scala-lang.modules" % "scala-asm" % "7.0.0-scala-1", // used by the backend // FIXME: Not needed, but should be on the compiler CP ("org.scala-lang.modules" %% "scala-xml" % "1.1.0").withDottyCompat(scalaVersion.value), "org.scala-lang" % "scala-library" % scalacVersion % "test",