summaryrefslogtreecommitdiff
path: root/src/partest-extras/scala/tools/partest
diff options
context:
space:
mode:
Diffstat (limited to 'src/partest-extras/scala/tools/partest')
-rw-r--r--src/partest-extras/scala/tools/partest/ASMConverters.scala54
1 files changed, 35 insertions, 19 deletions
diff --git a/src/partest-extras/scala/tools/partest/ASMConverters.scala b/src/partest-extras/scala/tools/partest/ASMConverters.scala
index f4a90d9acf..d443a31112 100644
--- a/src/partest-extras/scala/tools/partest/ASMConverters.scala
+++ b/src/partest-extras/scala/tools/partest/ASMConverters.scala
@@ -3,7 +3,6 @@ package scala.tools.partest
import scala.collection.JavaConverters._
import scala.tools.asm
import asm.{tree => t}
-import scala.tools.asm.tree.LabelNode
/** Makes using ASM from ByteCodeTests more convenient.
*
@@ -15,13 +14,9 @@ object ASMConverters {
/**
* Transform the instructions of an ASM Method into a list of [[Instruction]]s.
*/
- def instructionsFromMethod(meth: t.MethodNode): List[Instruction] = {
- val insns = meth.instructions
- val asmToScala = new AsmToScala {
- def labelIndex(l: t.LabelNode) = insns.indexOf(l)
- }
- asmToScala.convert(insns.iterator.asScala.toList)
- }
+ def instructionsFromMethod(meth: t.MethodNode): List[Instruction] = new AsmToScala(meth).instructions
+
+ def convertMethod(meth: t.MethodNode): Method = new AsmToScala(meth).method
implicit class RichInstructionLists(val self: List[Instruction]) extends AnyVal {
def === (other: List[Instruction]) = equivalentBytecode(self, other)
@@ -61,6 +56,8 @@ object ASMConverters {
}
}
+ case class Method(instructions: List[Instruction], handlers: List[ExceptionHandler], localVars: List[LocalVariable])
+
case class Field (opcode: Int, owner: String, name: String, desc: String) extends Instruction
case class Incr (opcode: Int, `var`: Int, incr: Int) extends Instruction
case class Op (opcode: Int) extends Instruction
@@ -69,7 +66,7 @@ object ASMConverters {
case class Ldc (opcode: Int, cst: Any) extends Instruction
case class LookupSwitch(opcode: Int, dflt: Label, keys: List[Int], labels: List[Label]) extends Instruction
case class TableSwitch (opcode: Int, min: Int, max: Int, dflt: Label, labels: List[Label]) extends Instruction
- case class Method (opcode: Int, owner: String, name: String, desc: String, itf: Boolean) extends Instruction
+ case class Invoke (opcode: Int, owner: String, name: String, desc: String, itf: Boolean) extends Instruction
case class NewArray (opcode: Int, desc: String, dims: Int) extends Instruction
case class TypeOp (opcode: Int, desc: String) extends Instruction
case class VarOp (opcode: Int, `var`: Int) extends Instruction
@@ -77,13 +74,18 @@ object ASMConverters {
case class FrameEntry (`type`: Int, local: List[Any], stack: List[Any]) extends Instruction { def opcode: Int = -1 }
case class LineNumber (line: Int, start: Label) extends Instruction { def opcode: Int = -1 }
- abstract class AsmToScala {
+ case class ExceptionHandler(start: Label, end: Label, handler: Label, desc: Option[String])
+ case class LocalVariable(name: String, desc: String, signature: Option[String], start: Label, end: Label, index: Int)
- def labelIndex(l: t.LabelNode): Int
+ class AsmToScala(asmMethod: t.MethodNode) {
- def op(i: t.AbstractInsnNode): Int = i.getOpcode
+ def instructions: List[Instruction] = asmMethod.instructions.iterator.asScala.toList map apply
- def convert(instructions: List[t.AbstractInsnNode]): List[Instruction] = instructions map apply
+ def method: Method = Method(instructions, convertHandlers(asmMethod), convertLocalVars(asmMethod))
+
+ private def labelIndex(l: t.LabelNode): Int = asmMethod.instructions.indexOf(l)
+
+ private def op(i: t.AbstractInsnNode): Int = i.getOpcode
private def lst[T](xs: java.util.List[T]): List[T] = if (xs == null) Nil else xs.asScala.toList
@@ -108,7 +110,7 @@ object ASMConverters {
case i: t.LdcInsnNode => Ldc (op(i), i.cst: Any)
case i: t.LookupSwitchInsnNode => LookupSwitch (op(i), applyLabel(i.dflt), lst(i.keys) map (x => x: Int), lst(i.labels) map applyLabel)
case i: t.TableSwitchInsnNode => TableSwitch (op(i), i.min, i.max, applyLabel(i.dflt), lst(i.labels) map applyLabel)
- case i: t.MethodInsnNode => Method (op(i), i.owner, i.name, i.desc, i.itf)
+ case i: t.MethodInsnNode => Invoke (op(i), i.owner, i.name, i.desc, i.itf)
case i: t.MultiANewArrayInsnNode => NewArray (op(i), i.desc, i.dims)
case i: t.TypeInsnNode => TypeOp (op(i), i.desc)
case i: t.VarInsnNode => VarOp (op(i), i.`var`)
@@ -116,6 +118,14 @@ object ASMConverters {
case i: t.FrameNode => FrameEntry (i.`type`, mapOverFrameTypes(lst(i.local)), mapOverFrameTypes(lst(i.stack)))
case i: t.LineNumberNode => LineNumber (i.line, applyLabel(i.start))
}
+
+ private def convertHandlers(method: t.MethodNode): List[ExceptionHandler] = {
+ method.tryCatchBlocks.asScala.map(h => ExceptionHandler(applyLabel(h.start), applyLabel(h.end), applyLabel(h.handler), Option(h.`type`)))(collection.breakOut)
+ }
+
+ private def convertLocalVars(method: t.MethodNode): List[LocalVariable] = {
+ method.localVariables.asScala.map(v => LocalVariable(v.name, v.desc, Option(v.signature), applyLabel(v.start), applyLabel(v.end), v.index))(collection.breakOut)
+ }
}
import collection.mutable.{Map => MMap}
@@ -159,15 +169,21 @@ object ASMConverters {
}) && equivalentBytecode(as.tail, bs.tail, varMap, labelMap)
}
- /**
- * Convert back a list of [[Instruction]]s to ASM land. The code is emitted into the parameter
- * `method`.
- */
def applyToMethod(method: t.MethodNode, instructions: List[Instruction]): Unit = {
val asmLabel = createLabelNodes(instructions)
instructions.foreach(visitMethod(method, _, asmLabel))
}
+ /**
+ * Convert back a [[Method]] to ASM land. The code is emitted into the parameter `asmMethod`.
+ */
+ def applyToMethod(asmMethod: t.MethodNode, method: Method): Unit = {
+ val asmLabel = createLabelNodes(method.instructions)
+ method.instructions.foreach(visitMethod(asmMethod, _, asmLabel))
+ method.handlers.foreach(h => asmMethod.visitTryCatchBlock(asmLabel(h.start), asmLabel(h.end), asmLabel(h.handler), h.desc.orNull))
+ method.localVars.foreach(v => asmMethod.visitLocalVariable(v.name, v.desc, v.signature.orNull, asmLabel(v.start), asmLabel(v.end), v.index))
+ }
+
private def createLabelNodes(instructions: List[Instruction]): Map[Label, asm.Label] = {
val labels = instructions collect {
case l: Label => l
@@ -190,7 +206,7 @@ object ASMConverters {
case Ldc(op, cst) => method.visitLdcInsn(cst)
case LookupSwitch(op, dflt, keys, labels) => method.visitLookupSwitchInsn(asmLabel(dflt), keys.toArray, (labels map asmLabel).toArray)
case TableSwitch(op, min, max, dflt, labels) => method.visitTableSwitchInsn(min, max, asmLabel(dflt), (labels map asmLabel).toArray: _*)
- case Method(op, owner, name, desc, itf) => method.visitMethodInsn(op, owner, name, desc, itf)
+ case Invoke(op, owner, name, desc, itf) => method.visitMethodInsn(op, owner, name, desc, itf)
case NewArray(op, desc, dims) => method.visitMultiANewArrayInsn(desc, dims)
case TypeOp(op, desc) => method.visitTypeInsn(op, desc)
case VarOp(op, vr) => method.visitVarInsn(op, vr)