[Cygwin] splitted big match expression into 3 parts in file ICodeReader.scala

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@8407 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
michelou 2006-08-18 10:07:34 +00:00
parent d82cbb4943
commit 30c8c9fbe5
1 changed files with 346 additions and 329 deletions

View File

@ -1,40 +1,49 @@
package scala.tools.nsc.symtab.classfile;
/* NSC -- new Scala compiler
* Copyright 2005-2006 LAMP/EPFL
* @author Iulian Dragos
*/
// $Id$
import scala.tools.nsc._;
import scala.tools.nsc.backend.icode._;
import scala.tools.nsc.util.Position;
package scala.tools.nsc.symtab.classfile
import java.io.IOException
import scala.collection.mutable._
import scala.tools.nsc._
import scala.tools.nsc.backend.icode._
import scala.tools.nsc.io._
import scala.tools.nsc.util.Position
import scala.collection.mutable._;
import ClassfileConstants._
import scala.tools.nsc.io._;
import Flags._
import java.io.IOException;
/** ICode reader from Java bytecode.
*
* @author Iulian Dragos
* @version 1.0
*/
abstract class ICodeReader extends ClassfileParser {
val global: Global;
import global._;
import icodes._;
val global: Global
import global._
import icodes._
var instanceCode: IClass = null // the ICode class for the current symbol
var staticCode: IClass = null // the ICode class static members
var method: IMethod = _ // the current IMethod
val OBJECT: TypeKind = REFERENCE(definitions.ObjectClass)
var instanceCode: IClass = null; // the ICode class for the current symbol
var staticCode: IClass = null; // the ICode class static members
var method: IMethod = _; // the current IMethod
val OBJECT: TypeKind = REFERENCE(definitions.ObjectClass);
/** Read back bytecode for the given class symbol. */
def readClass(cls: ClassSymbol): Pair[IClass, IClass] = {
assert(cls.classFile ne null, "No classfile for " + cls);
assert(cls.classFile ne null, "No classfile for " + cls)
this.instanceCode = new IClass(cls)
this.staticCode = new IClass(cls.linkedClassOfModule)
parse(cls.classFile, cls)
this.instanceCode = new IClass(cls);
this.staticCode = new IClass(cls.linkedClassOfModule);
parse(cls.classFile, cls);
Pair(staticCode, instanceCode)
}
override def parseClass(): Unit = {
val jflags = in.nextChar
val isAttribute = (jflags & JAVA_ACC_ANNOTATION) != 0
@ -43,25 +52,25 @@ abstract class ICodeReader extends ClassfileParser {
val c = pool.getClassSymbol(in.nextChar)
if (c != clazz)
throw new IOException("class file '" + in.file + "' contains wrong " + clazz)
in.skip(2); // super class
in.skip(2 * in.nextChar); // interfaces
val fieldCount = in.nextChar;
in.skip(2) // super class
in.skip(2 * in.nextChar) // interfaces
val fieldCount = in.nextChar
for (val i <- 0 until fieldCount) parseField();
val methodCount = in.nextChar;
val methodCount = in.nextChar
for (val i <- 0 until methodCount) parseMethod();
}
override def parseField(): Unit = {
val Pair(jflags, sym) = parseMember();
getCode(jflags).addField(new IField(sym));
skipAttributes();
val Pair(jflags, sym) = parseMember()
getCode(jflags).addField(new IField(sym))
skipAttributes()
}
private def parseMember(): Pair[Int, Symbol] = {
val jflags = in.nextChar;
val name = pool.getName(in.nextChar);
var tpe = pool.getType(in.nextChar);
val jflags = in.nextChar
val name = pool.getName(in.nextChar)
var tpe = pool.getType(in.nextChar)
if (name == nme.CONSTRUCTOR)
tpe match {
case MethodType(formals, restpe) =>
@ -70,86 +79,89 @@ abstract class ICodeReader extends ClassfileParser {
}
Console.println(getOwner(jflags).info.decls);
val sym = getOwner(jflags).info.decl(name).suchThat(old => old.tpe =:= tpe);
assert(sym != NoSymbol, "Could not find symbol for " + name + ": " + tpe + " in " + getOwner(jflags));
val sym = getOwner(jflags).info.decl(name).suchThat(old => old.tpe =:= tpe)
assert(sym != NoSymbol,
"Could not find symbol for " + name +
": " + tpe + " in " + getOwner(jflags))
Pair(jflags, sym)
}
override def parseMethod(): Unit = {
val Pair(jflags, sym) = parseMember();
this.method = new IMethod(sym);
getCode(jflags).addMethod(method);
val attributeCount = in.nextChar;
val Pair(jflags, sym) = parseMember()
this.method = new IMethod(sym)
getCode(jflags).addMethod(method)
val attributeCount = in.nextChar
for (val i <- 0 until attributeCount)
parseAttribute();
}
def parseAttribute(): Unit = {
val attrName = pool.getName(in.nextChar)
val attrLen = in.nextInt
attrName match {
case nme.CodeATTR =>
parseByteCode();
parseByteCode()
case _ =>
in.skip(attrLen)
}
}
var maxStack: Int = _;
var maxLocals: Int = _;
val JVM = ClassfileConstants; // shorter, uppercase alias for use in case patterns
def toUnsignedByte(b: Byte): Int = b.toInt & 0xff;
var maxStack: Int = _
var maxLocals: Int = _
val JVM = ClassfileConstants // shorter, uppercase alias for use in case patterns
def toUnsignedByte(b: Byte): Int = b.toInt & 0xff
/** Parse java bytecode into ICode */
def parseByteCode(): Unit = {
maxStack = in.nextChar;
maxLocals = in.nextChar;
val codeLength = in.nextInt;
var pc = 0;
val code = new LinearCode;
maxStack = in.nextChar
maxLocals = in.nextChar
val codeLength = in.nextInt
var pc = 0
val code = new LinearCode
def parseInstruction: Unit = {
import opcodes._;
import code._;
var size = 1; // instruction size
import opcodes._
import code._
var size = 1 // instruction size
/** Parse 16 bit jump target. */
def parseJumpTarget = {
size = size + 2;
val offset = in.nextChar;
val target = pc + offset;
assert(target >= 0 && target < codeLength, "Illegal jump target: " + target);
target
size = size + 2
val offset = in.nextChar
val target = pc + offset
assert(target >= 0 && target < codeLength, "Illegal jump target: " + target)
target
}
/** Parse 32 bit jump target. */
def parseJumpTargetW = {
size = size + 4;
val offset = in.nextInt;
val target = pc + offset;
assert(target >= 0 && target < codeLength, "Illegal jump target: " + target);
size = size + 4
val offset = in.nextInt
val target = pc + offset
assert(target >= 0 && target < codeLength, "Illegal jump target: " + target)
target
}
toUnsignedByte(in.nextByte) match {
case JVM.nop => parseInstruction;
case JVM.aconst_null => code.emit(CONSTANT(Constant(null)));
case JVM.iconst_m1 => code.emit(CONSTANT(Constant(-1)));
case JVM.iconst_0 => code.emit(CONSTANT(Constant(0)));
case JVM.iconst_1 => code.emit(CONSTANT(Constant(1)));
case JVM.iconst_2 => code.emit(CONSTANT(Constant(2)));
case JVM.iconst_3 => code.emit(CONSTANT(Constant(3)));
case JVM.iconst_4 => code.emit(CONSTANT(Constant(4)));
case JVM.iconst_5 => code.emit(CONSTANT(Constant(5)));
case JVM.lconst_0 => code.emit(CONSTANT(Constant(0l)));
case JVM.lconst_1 => code.emit(CONSTANT(Constant(1l)));
case JVM.fconst_0 => code.emit(CONSTANT(Constant(0.0f)));
case JVM.fconst_1 => code.emit(CONSTANT(Constant(1.0f)));
case JVM.fconst_2 => code.emit(CONSTANT(Constant(2.0f)));
case JVM.dconst_0 => code.emit(CONSTANT(Constant(0.0)));
case JVM.dconst_1 => code.emit(CONSTANT(Constant(1.0)));
val instr = toUnsignedByte(in.nextByte)
if (instr < JVM.pop) instr match {
case JVM.nop => parseInstruction
case JVM.aconst_null => code.emit(CONSTANT(Constant(null)))
case JVM.iconst_m1 => code.emit(CONSTANT(Constant(-1)))
case JVM.iconst_0 => code.emit(CONSTANT(Constant(0)))
case JVM.iconst_1 => code.emit(CONSTANT(Constant(1)))
case JVM.iconst_2 => code.emit(CONSTANT(Constant(2)))
case JVM.iconst_3 => code.emit(CONSTANT(Constant(3)))
case JVM.iconst_4 => code.emit(CONSTANT(Constant(4)))
case JVM.iconst_5 => code.emit(CONSTANT(Constant(5)))
case JVM.lconst_0 => code.emit(CONSTANT(Constant(0l)))
case JVM.lconst_1 => code.emit(CONSTANT(Constant(1l)))
case JVM.fconst_0 => code.emit(CONSTANT(Constant(0.0f)))
case JVM.fconst_1 => code.emit(CONSTANT(Constant(1.0f)))
case JVM.fconst_2 => code.emit(CONSTANT(Constant(2.0f)))
case JVM.dconst_0 => code.emit(CONSTANT(Constant(0.0)))
case JVM.dconst_1 => code.emit(CONSTANT(Constant(1.0)))
case JVM.bipush => code.emit(CONSTANT(Constant(in.nextByte))); size = size + 1;
case JVM.sipush => code.emit(CONSTANT(Constant(in.nextChar))); size = size + 2;
@ -161,80 +173,81 @@ abstract class ICodeReader extends ClassfileParser {
case JVM.fload => code.emit(LOAD_LOCAL(code.getLocal(in.nextByte, FLOAT))); size = size + 1;
case JVM.dload => code.emit(LOAD_LOCAL(code.getLocal(in.nextByte, DOUBLE))); size = size + 1;
case JVM.aload =>
val local = in.nextByte; size = size + 1;
val local = in.nextByte; size = size + 1;
if (local == 0 && !method.isStatic)
code.emit(THIS(method.symbol.owner));
else
code.emit(LOAD_LOCAL(code.getLocal(local, OBJECT)));
case JVM.iload_0 => code.emit(LOAD_LOCAL(code.getLocal(0, INT)));
case JVM.iload_1 => code.emit(LOAD_LOCAL(code.getLocal(1, INT)));
case JVM.iload_2 => code.emit(LOAD_LOCAL(code.getLocal(2, INT)));
case JVM.iload_3 => code.emit(LOAD_LOCAL(code.getLocal(3, INT)));
case JVM.lload_0 => code.emit(LOAD_LOCAL(code.getLocal(0, LONG)));
case JVM.lload_1 => code.emit(LOAD_LOCAL(code.getLocal(1, LONG)));
case JVM.lload_2 => code.emit(LOAD_LOCAL(code.getLocal(2, LONG)));
case JVM.lload_3 => code.emit(LOAD_LOCAL(code.getLocal(3, LONG)));
case JVM.fload_0 => code.emit(LOAD_LOCAL(code.getLocal(0, FLOAT)));
case JVM.fload_1 => code.emit(LOAD_LOCAL(code.getLocal(1, FLOAT)));
case JVM.fload_2 => code.emit(LOAD_LOCAL(code.getLocal(2, FLOAT)));
case JVM.fload_3 => code.emit(LOAD_LOCAL(code.getLocal(3, FLOAT)));
case JVM.dload_0 => code.emit(LOAD_LOCAL(code.getLocal(0, DOUBLE)));
case JVM.dload_1 => code.emit(LOAD_LOCAL(code.getLocal(1, DOUBLE)));
case JVM.dload_2 => code.emit(LOAD_LOCAL(code.getLocal(2, DOUBLE)));
case JVM.dload_3 => code.emit(LOAD_LOCAL(code.getLocal(3, DOUBLE)));
case JVM.aload_0 =>
case JVM.iload_0 => code.emit(LOAD_LOCAL(code.getLocal(0, INT)))
case JVM.iload_1 => code.emit(LOAD_LOCAL(code.getLocal(1, INT)))
case JVM.iload_2 => code.emit(LOAD_LOCAL(code.getLocal(2, INT)))
case JVM.iload_3 => code.emit(LOAD_LOCAL(code.getLocal(3, INT)))
case JVM.lload_0 => code.emit(LOAD_LOCAL(code.getLocal(0, LONG)))
case JVM.lload_1 => code.emit(LOAD_LOCAL(code.getLocal(1, LONG)))
case JVM.lload_2 => code.emit(LOAD_LOCAL(code.getLocal(2, LONG)))
case JVM.lload_3 => code.emit(LOAD_LOCAL(code.getLocal(3, LONG)))
case JVM.fload_0 => code.emit(LOAD_LOCAL(code.getLocal(0, FLOAT)))
case JVM.fload_1 => code.emit(LOAD_LOCAL(code.getLocal(1, FLOAT)))
case JVM.fload_2 => code.emit(LOAD_LOCAL(code.getLocal(2, FLOAT)))
case JVM.fload_3 => code.emit(LOAD_LOCAL(code.getLocal(3, FLOAT)))
case JVM.dload_0 => code.emit(LOAD_LOCAL(code.getLocal(0, DOUBLE)))
case JVM.dload_1 => code.emit(LOAD_LOCAL(code.getLocal(1, DOUBLE)))
case JVM.dload_2 => code.emit(LOAD_LOCAL(code.getLocal(2, DOUBLE)))
case JVM.dload_3 => code.emit(LOAD_LOCAL(code.getLocal(3, DOUBLE)))
case JVM.aload_0 =>
if (!method.isStatic)
code.emit(THIS(method.symbol.owner));
else
code.emit(LOAD_LOCAL(code.getLocal(0, OBJECT)));
case JVM.aload_1 => code.emit(LOAD_LOCAL(code.getLocal(1, OBJECT)));
case JVM.aload_2 => code.emit(LOAD_LOCAL(code.getLocal(2, OBJECT)));
case JVM.aload_3 => code.emit(LOAD_LOCAL(code.getLocal(3, OBJECT)));
case JVM.aload_1 => code.emit(LOAD_LOCAL(code.getLocal(1, OBJECT)))
case JVM.aload_2 => code.emit(LOAD_LOCAL(code.getLocal(2, OBJECT)))
case JVM.aload_3 => code.emit(LOAD_LOCAL(code.getLocal(3, OBJECT)))
case JVM.iaload => code.emit(LOAD_ARRAY_ITEM(INT));
case JVM.laload => code.emit(LOAD_ARRAY_ITEM(LONG));
case JVM.faload => code.emit(LOAD_ARRAY_ITEM(FLOAT));
case JVM.daload => code.emit(LOAD_ARRAY_ITEM(DOUBLE));
case JVM.aaload => code.emit(LOAD_ARRAY_ITEM(OBJECT));
case JVM.baload => code.emit(LOAD_ARRAY_ITEM(BYTE));
case JVM.caload => code.emit(LOAD_ARRAY_ITEM(CHAR));
case JVM.saload => code.emit(LOAD_ARRAY_ITEM(SHORT));
case JVM.iaload => code.emit(LOAD_ARRAY_ITEM(INT))
case JVM.laload => code.emit(LOAD_ARRAY_ITEM(LONG))
case JVM.faload => code.emit(LOAD_ARRAY_ITEM(FLOAT))
case JVM.daload => code.emit(LOAD_ARRAY_ITEM(DOUBLE))
case JVM.aaload => code.emit(LOAD_ARRAY_ITEM(OBJECT))
case JVM.baload => code.emit(LOAD_ARRAY_ITEM(BYTE))
case JVM.caload => code.emit(LOAD_ARRAY_ITEM(CHAR))
case JVM.saload => code.emit(LOAD_ARRAY_ITEM(SHORT))
case JVM.istore => code.emit(STORE_LOCAL(code.getLocal(in.nextByte, INT))); size = size + 1;
case JVM.lstore => code.emit(STORE_LOCAL(code.getLocal(in.nextByte, LONG))); size = size + 1;
case JVM.fstore => code.emit(STORE_LOCAL(code.getLocal(in.nextByte, FLOAT))); size = size + 1;
case JVM.dstore => code.emit(STORE_LOCAL(code.getLocal(in.nextByte, DOUBLE))); size = size + 1;
case JVM.astore => code.emit(STORE_LOCAL(code.getLocal(in.nextByte, OBJECT))); size = size + 1;
case JVM.istore_0 => code.emit(STORE_LOCAL(code.getLocal(0, INT)));
case JVM.istore_1 => code.emit(STORE_LOCAL(code.getLocal(1, INT)));
case JVM.istore_2 => code.emit(STORE_LOCAL(code.getLocal(2, INT)));
case JVM.istore_3 => code.emit(STORE_LOCAL(code.getLocal(3, INT)));
case JVM.lstore_0 => code.emit(STORE_LOCAL(code.getLocal(0, LONG)));
case JVM.lstore_1 => code.emit(STORE_LOCAL(code.getLocal(1, LONG)));
case JVM.lstore_2 => code.emit(STORE_LOCAL(code.getLocal(2, LONG)));
case JVM.lstore_3 => code.emit(STORE_LOCAL(code.getLocal(3, LONG)));
case JVM.fstore_0 => code.emit(STORE_LOCAL(code.getLocal(0, FLOAT)));
case JVM.fstore_1 => code.emit(STORE_LOCAL(code.getLocal(1, FLOAT)));
case JVM.fstore_2 => code.emit(STORE_LOCAL(code.getLocal(2, FLOAT)));
case JVM.fstore_3 => code.emit(STORE_LOCAL(code.getLocal(3, FLOAT)));
case JVM.dstore_0 => code.emit(STORE_LOCAL(code.getLocal(0, DOUBLE)));
case JVM.dstore_1 => code.emit(STORE_LOCAL(code.getLocal(1, DOUBLE)));
case JVM.dstore_2 => code.emit(STORE_LOCAL(code.getLocal(2, DOUBLE)));
case JVM.dstore_3 => code.emit(STORE_LOCAL(code.getLocal(3, DOUBLE)));
case JVM.astore_0 => code.emit(STORE_LOCAL(code.getLocal(0, OBJECT)));
case JVM.astore_1 => code.emit(STORE_LOCAL(code.getLocal(1, OBJECT)));
case JVM.astore_2 => code.emit(STORE_LOCAL(code.getLocal(2, OBJECT)));
case JVM.astore_3 => code.emit(STORE_LOCAL(code.getLocal(3, OBJECT)));
case JVM.iastore => code.emit(STORE_ARRAY_ITEM(INT));
case JVM.lastore => code.emit(STORE_ARRAY_ITEM(LONG));
case JVM.fastore => code.emit(STORE_ARRAY_ITEM(FLOAT));
case JVM.dastore => code.emit(STORE_ARRAY_ITEM(DOUBLE));
case JVM.aastore => code.emit(STORE_ARRAY_ITEM(OBJECT));
case JVM.bastore => code.emit(STORE_ARRAY_ITEM(BYTE));
case JVM.castore => code.emit(STORE_ARRAY_ITEM(CHAR));
case JVM.sastore => code.emit(STORE_ARRAY_ITEM(SHORT));
case JVM.istore_0 => code.emit(STORE_LOCAL(code.getLocal(0, INT)))
case JVM.istore_1 => code.emit(STORE_LOCAL(code.getLocal(1, INT)))
case JVM.istore_2 => code.emit(STORE_LOCAL(code.getLocal(2, INT)))
case JVM.istore_3 => code.emit(STORE_LOCAL(code.getLocal(3, INT)))
case JVM.lstore_0 => code.emit(STORE_LOCAL(code.getLocal(0, LONG)))
case JVM.lstore_1 => code.emit(STORE_LOCAL(code.getLocal(1, LONG)))
case JVM.lstore_2 => code.emit(STORE_LOCAL(code.getLocal(2, LONG)))
case JVM.lstore_3 => code.emit(STORE_LOCAL(code.getLocal(3, LONG)))
case JVM.fstore_0 => code.emit(STORE_LOCAL(code.getLocal(0, FLOAT)))
case JVM.fstore_1 => code.emit(STORE_LOCAL(code.getLocal(1, FLOAT)))
case JVM.fstore_2 => code.emit(STORE_LOCAL(code.getLocal(2, FLOAT)))
case JVM.fstore_3 => code.emit(STORE_LOCAL(code.getLocal(3, FLOAT)))
case JVM.dstore_0 => code.emit(STORE_LOCAL(code.getLocal(0, DOUBLE)))
case JVM.dstore_1 => code.emit(STORE_LOCAL(code.getLocal(1, DOUBLE)))
case JVM.dstore_2 => code.emit(STORE_LOCAL(code.getLocal(2, DOUBLE)))
case JVM.dstore_3 => code.emit(STORE_LOCAL(code.getLocal(3, DOUBLE)))
case JVM.astore_0 => code.emit(STORE_LOCAL(code.getLocal(0, OBJECT)))
case JVM.astore_1 => code.emit(STORE_LOCAL(code.getLocal(1, OBJECT)))
case JVM.astore_2 => code.emit(STORE_LOCAL(code.getLocal(2, OBJECT)))
case JVM.astore_3 => code.emit(STORE_LOCAL(code.getLocal(3, OBJECT)))
case JVM.iastore => code.emit(STORE_ARRAY_ITEM(INT))
case JVM.lastore => code.emit(STORE_ARRAY_ITEM(LONG))
case JVM.fastore => code.emit(STORE_ARRAY_ITEM(FLOAT))
case JVM.dastore => code.emit(STORE_ARRAY_ITEM(DOUBLE))
case JVM.aastore => code.emit(STORE_ARRAY_ITEM(OBJECT))
case JVM.bastore => code.emit(STORE_ARRAY_ITEM(BYTE))
case JVM.castore => code.emit(STORE_ARRAY_ITEM(CHAR))
case JVM.sastore => code.emit(STORE_ARRAY_ITEM(SHORT))
}
else if (instr < JVM.goto) instr match {
case JVM.pop => code.emit(DROP(INT)); // any 1-word type would do
case JVM.pop2 => code.emit(DROP(LONG)); // any 2-word type would do
case JVM.dup => code.emit(DUP(OBJECT)); // TODO: Is the kind inside DUP ever needed?
@ -245,157 +258,160 @@ abstract class ICodeReader extends ClassfileParser {
case JVM.dup2_x2 => Predef.error("Unsupported JVM bytecode: dup2_x2")
case JVM.swap => Predef.error("Unsupported JVM bytecode: swap")
case JVM.iadd => code.emit(CALL_PRIMITIVE(Arithmetic(ADD, INT)));
case JVM.ladd => code.emit(CALL_PRIMITIVE(Arithmetic(ADD, LONG)));
case JVM.fadd => code.emit(CALL_PRIMITIVE(Arithmetic(ADD, FLOAT)));
case JVM.dadd => code.emit(CALL_PRIMITIVE(Arithmetic(ADD, DOUBLE)));
case JVM.isub => code.emit(CALL_PRIMITIVE(Arithmetic(SUB, INT)));
case JVM.lsub => code.emit(CALL_PRIMITIVE(Arithmetic(SUB, LONG)));
case JVM.fsub => code.emit(CALL_PRIMITIVE(Arithmetic(SUB, FLOAT)));
case JVM.dsub => code.emit(CALL_PRIMITIVE(Arithmetic(SUB, DOUBLE)));
case JVM.imul => code.emit(CALL_PRIMITIVE(Arithmetic(MUL, INT)));
case JVM.lmul => code.emit(CALL_PRIMITIVE(Arithmetic(MUL, LONG)));
case JVM.fmul => code.emit(CALL_PRIMITIVE(Arithmetic(MUL, FLOAT)));
case JVM.dmul => code.emit(CALL_PRIMITIVE(Arithmetic(MUL, DOUBLE)));
case JVM.idiv => code.emit(CALL_PRIMITIVE(Arithmetic(DIV, INT)));
case JVM.ldiv => code.emit(CALL_PRIMITIVE(Arithmetic(DIV, LONG)));
case JVM.fdiv => code.emit(CALL_PRIMITIVE(Arithmetic(DIV, FLOAT)));
case JVM.ddiv => code.emit(CALL_PRIMITIVE(Arithmetic(DIV, DOUBLE)));
case JVM.irem => code.emit(CALL_PRIMITIVE(Arithmetic(REM, INT)));
case JVM.lrem => code.emit(CALL_PRIMITIVE(Arithmetic(REM, LONG)));
case JVM.frem => code.emit(CALL_PRIMITIVE(Arithmetic(REM, FLOAT)));
case JVM.drem => code.emit(CALL_PRIMITIVE(Arithmetic(REM, DOUBLE)));
case JVM.iadd => code.emit(CALL_PRIMITIVE(Arithmetic(ADD, INT)))
case JVM.ladd => code.emit(CALL_PRIMITIVE(Arithmetic(ADD, LONG)))
case JVM.fadd => code.emit(CALL_PRIMITIVE(Arithmetic(ADD, FLOAT)))
case JVM.dadd => code.emit(CALL_PRIMITIVE(Arithmetic(ADD, DOUBLE)))
case JVM.isub => code.emit(CALL_PRIMITIVE(Arithmetic(SUB, INT)))
case JVM.lsub => code.emit(CALL_PRIMITIVE(Arithmetic(SUB, LONG)))
case JVM.fsub => code.emit(CALL_PRIMITIVE(Arithmetic(SUB, FLOAT)))
case JVM.dsub => code.emit(CALL_PRIMITIVE(Arithmetic(SUB, DOUBLE)))
case JVM.imul => code.emit(CALL_PRIMITIVE(Arithmetic(MUL, INT)))
case JVM.lmul => code.emit(CALL_PRIMITIVE(Arithmetic(MUL, LONG)))
case JVM.fmul => code.emit(CALL_PRIMITIVE(Arithmetic(MUL, FLOAT)))
case JVM.dmul => code.emit(CALL_PRIMITIVE(Arithmetic(MUL, DOUBLE)))
case JVM.idiv => code.emit(CALL_PRIMITIVE(Arithmetic(DIV, INT)))
case JVM.ldiv => code.emit(CALL_PRIMITIVE(Arithmetic(DIV, LONG)))
case JVM.fdiv => code.emit(CALL_PRIMITIVE(Arithmetic(DIV, FLOAT)))
case JVM.ddiv => code.emit(CALL_PRIMITIVE(Arithmetic(DIV, DOUBLE)))
case JVM.irem => code.emit(CALL_PRIMITIVE(Arithmetic(REM, INT)))
case JVM.lrem => code.emit(CALL_PRIMITIVE(Arithmetic(REM, LONG)))
case JVM.frem => code.emit(CALL_PRIMITIVE(Arithmetic(REM, FLOAT)))
case JVM.drem => code.emit(CALL_PRIMITIVE(Arithmetic(REM, DOUBLE)))
case JVM.ineg => code.emit(CALL_PRIMITIVE(Negation(INT)));
case JVM.lneg => code.emit(CALL_PRIMITIVE(Negation(LONG)));
case JVM.fneg => code.emit(CALL_PRIMITIVE(Negation(FLOAT)));
case JVM.dneg => code.emit(CALL_PRIMITIVE(Negation(DOUBLE)));
case JVM.ineg => code.emit(CALL_PRIMITIVE(Negation(INT)))
case JVM.lneg => code.emit(CALL_PRIMITIVE(Negation(LONG)))
case JVM.fneg => code.emit(CALL_PRIMITIVE(Negation(FLOAT)))
case JVM.dneg => code.emit(CALL_PRIMITIVE(Negation(DOUBLE)))
case JVM.ishl => code.emit(CALL_PRIMITIVE(Shift(LSL, INT)));
case JVM.lshl => code.emit(CALL_PRIMITIVE(Shift(LSL, LONG)));
case JVM.ishr => code.emit(CALL_PRIMITIVE(Shift(LSR, INT)));
case JVM.lshr => code.emit(CALL_PRIMITIVE(Shift(LSR, LONG)));
case JVM.iushr => code.emit(CALL_PRIMITIVE(Shift(ASR, INT)));
case JVM.lushr => code.emit(CALL_PRIMITIVE(Shift(ASR, LONG)));
case JVM.iand => code.emit(CALL_PRIMITIVE(Logical(AND, INT)));
case JVM.land => code.emit(CALL_PRIMITIVE(Logical(AND, LONG)));
case JVM.ior => code.emit(CALL_PRIMITIVE(Logical(OR, INT)));
case JVM.lor => code.emit(CALL_PRIMITIVE(Logical(OR, LONG)));
case JVM.ixor => code.emit(CALL_PRIMITIVE(Logical(XOR, INT)));
case JVM.lxor => code.emit(CALL_PRIMITIVE(Logical(XOR, LONG)));
case JVM.iinc =>
size = size + 2;
val local = code.getLocal(in.nextByte, INT);
code.emit(CONSTANT(Constant(in.nextByte)));
code.emit(CALL_PRIMITIVE(Arithmetic(ADD, INT)));
code.emit(STORE_LOCAL(local));
case JVM.ishl => code.emit(CALL_PRIMITIVE(Shift(LSL, INT)))
case JVM.lshl => code.emit(CALL_PRIMITIVE(Shift(LSL, LONG)))
case JVM.ishr => code.emit(CALL_PRIMITIVE(Shift(LSR, INT)))
case JVM.lshr => code.emit(CALL_PRIMITIVE(Shift(LSR, LONG)))
case JVM.iushr => code.emit(CALL_PRIMITIVE(Shift(ASR, INT)))
case JVM.lushr => code.emit(CALL_PRIMITIVE(Shift(ASR, LONG)))
case JVM.iand => code.emit(CALL_PRIMITIVE(Logical(AND, INT)))
case JVM.land => code.emit(CALL_PRIMITIVE(Logical(AND, LONG)))
case JVM.ior => code.emit(CALL_PRIMITIVE(Logical(OR, INT)))
case JVM.lor => code.emit(CALL_PRIMITIVE(Logical(OR, LONG)))
case JVM.ixor => code.emit(CALL_PRIMITIVE(Logical(XOR, INT)))
case JVM.lxor => code.emit(CALL_PRIMITIVE(Logical(XOR, LONG)))
case JVM.iinc =>
size = size + 2
val local = code.getLocal(in.nextByte, INT)
code.emit(CONSTANT(Constant(in.nextByte)))
code.emit(CALL_PRIMITIVE(Arithmetic(ADD, INT)))
code.emit(STORE_LOCAL(local))
case JVM.i2l => code.emit(CALL_PRIMITIVE(Conversion(INT, LONG)));
case JVM.i2f => code.emit(CALL_PRIMITIVE(Conversion(INT, FLOAT)));
case JVM.i2d => code.emit(CALL_PRIMITIVE(Conversion(INT, DOUBLE)));
case JVM.l2i => code.emit(CALL_PRIMITIVE(Conversion(LONG, INT)));
case JVM.l2f => code.emit(CALL_PRIMITIVE(Conversion(LONG, FLOAT)));
case JVM.l2d => code.emit(CALL_PRIMITIVE(Conversion(LONG, DOUBLE)));
case JVM.f2i => code.emit(CALL_PRIMITIVE(Conversion(FLOAT, INT)));
case JVM.f2l => code.emit(CALL_PRIMITIVE(Conversion(FLOAT, LONG)));
case JVM.f2d => code.emit(CALL_PRIMITIVE(Conversion(FLOAT, DOUBLE)));
case JVM.d2i => code.emit(CALL_PRIMITIVE(Conversion(DOUBLE, INT)));
case JVM.d2l => code.emit(CALL_PRIMITIVE(Conversion(DOUBLE, LONG)));
case JVM.d2f => code.emit(CALL_PRIMITIVE(Conversion(DOUBLE, FLOAT)));
case JVM.i2b => code.emit(CALL_PRIMITIVE(Conversion(INT, BYTE)));
case JVM.i2c => code.emit(CALL_PRIMITIVE(Conversion(INT, CHAR)));
case JVM.i2s => code.emit(CALL_PRIMITIVE(Conversion(INT, SHORT)));
case JVM.i2l => code.emit(CALL_PRIMITIVE(Conversion(INT, LONG)))
case JVM.i2f => code.emit(CALL_PRIMITIVE(Conversion(INT, FLOAT)))
case JVM.i2d => code.emit(CALL_PRIMITIVE(Conversion(INT, DOUBLE)))
case JVM.l2i => code.emit(CALL_PRIMITIVE(Conversion(LONG, INT)))
case JVM.l2f => code.emit(CALL_PRIMITIVE(Conversion(LONG, FLOAT)))
case JVM.l2d => code.emit(CALL_PRIMITIVE(Conversion(LONG, DOUBLE)))
case JVM.f2i => code.emit(CALL_PRIMITIVE(Conversion(FLOAT, INT)))
case JVM.f2l => code.emit(CALL_PRIMITIVE(Conversion(FLOAT, LONG)))
case JVM.f2d => code.emit(CALL_PRIMITIVE(Conversion(FLOAT, DOUBLE)))
case JVM.d2i => code.emit(CALL_PRIMITIVE(Conversion(DOUBLE, INT)))
case JVM.d2l => code.emit(CALL_PRIMITIVE(Conversion(DOUBLE, LONG)))
case JVM.d2f => code.emit(CALL_PRIMITIVE(Conversion(DOUBLE, FLOAT)))
case JVM.i2b => code.emit(CALL_PRIMITIVE(Conversion(INT, BYTE)))
case JVM.i2c => code.emit(CALL_PRIMITIVE(Conversion(INT, CHAR)))
case JVM.i2s => code.emit(CALL_PRIMITIVE(Conversion(INT, SHORT)))
case JVM.lcmp => code.emit(CALL_PRIMITIVE(Comparison(CMP, LONG)));
case JVM.fcmpl => code.emit(CALL_PRIMITIVE(Comparison(CMPL, FLOAT)));
case JVM.fcmpg => code.emit(CALL_PRIMITIVE(Comparison(CMPG, FLOAT)));
case JVM.dcmpl => code.emit(CALL_PRIMITIVE(Comparison(CMPL, DOUBLE)));
case JVM.dcmpg => code.emit(CALL_PRIMITIVE(Comparison(CMPG, DOUBLE)));
case JVM.lcmp => code.emit(CALL_PRIMITIVE(Comparison(CMP, LONG)))
case JVM.fcmpl => code.emit(CALL_PRIMITIVE(Comparison(CMPL, FLOAT)))
case JVM.fcmpg => code.emit(CALL_PRIMITIVE(Comparison(CMPG, FLOAT)))
case JVM.dcmpl => code.emit(CALL_PRIMITIVE(Comparison(CMPL, DOUBLE)))
case JVM.dcmpg => code.emit(CALL_PRIMITIVE(Comparison(CMPG, DOUBLE)))
case JVM.ifeq => code.emit(LCZJUMP(parseJumpTarget, pc + size, EQ, INT));
case JVM.ifne => code.emit(LCZJUMP(parseJumpTarget, pc + size, NE, INT));
case JVM.iflt => code.emit(LCZJUMP(parseJumpTarget, pc + size, LT, INT));
case JVM.ifge => code.emit(LCZJUMP(parseJumpTarget, pc + size, GE, INT));
case JVM.ifgt => code.emit(LCZJUMP(parseJumpTarget, pc + size, GT, INT));
case JVM.ifle => code.emit(LCZJUMP(parseJumpTarget, pc + size, LE, INT));
case JVM.ifeq => code.emit(LCZJUMP(parseJumpTarget, pc + size, EQ, INT))
case JVM.ifne => code.emit(LCZJUMP(parseJumpTarget, pc + size, NE, INT))
case JVM.iflt => code.emit(LCZJUMP(parseJumpTarget, pc + size, LT, INT))
case JVM.ifge => code.emit(LCZJUMP(parseJumpTarget, pc + size, GE, INT))
case JVM.ifgt => code.emit(LCZJUMP(parseJumpTarget, pc + size, GT, INT))
case JVM.ifle => code.emit(LCZJUMP(parseJumpTarget, pc + size, LE, INT))
case JVM.if_icmpeq => code.emit(LCJUMP(parseJumpTarget, pc + size, EQ, INT));
case JVM.if_icmpne => code.emit(LCJUMP(parseJumpTarget, pc + size, NE, INT));
case JVM.if_icmplt => code.emit(LCJUMP(parseJumpTarget, pc + size, LT, INT));
case JVM.if_icmpge => code.emit(LCJUMP(parseJumpTarget, pc + size, GE, INT));
case JVM.if_icmpgt => code.emit(LCJUMP(parseJumpTarget, pc + size, GT, INT));
case JVM.if_icmple => code.emit(LCJUMP(parseJumpTarget, pc + size, LE, INT));
case JVM.if_acmpeq => code.emit(LCJUMP(parseJumpTarget, pc + size, EQ, OBJECT));
case JVM.if_acmpne => code.emit(LCJUMP(parseJumpTarget, pc + size, NE, OBJECT));
case JVM.goto => emit(LJUMP(parseJumpTarget));
case JVM.jsr => Predef.error("Cannot handle jsr/ret");
case JVM.ret => Predef.error("Cannot handle jsr/ret");
case JVM.if_icmpeq => code.emit(LCJUMP(parseJumpTarget, pc + size, EQ, INT))
case JVM.if_icmpne => code.emit(LCJUMP(parseJumpTarget, pc + size, NE, INT))
case JVM.if_icmplt => code.emit(LCJUMP(parseJumpTarget, pc + size, LT, INT))
case JVM.if_icmpge => code.emit(LCJUMP(parseJumpTarget, pc + size, GE, INT))
case JVM.if_icmpgt => code.emit(LCJUMP(parseJumpTarget, pc + size, GT, INT))
case JVM.if_icmple => code.emit(LCJUMP(parseJumpTarget, pc + size, LE, INT))
case JVM.if_acmpeq => code.emit(LCJUMP(parseJumpTarget, pc + size, EQ, OBJECT))
case JVM.if_acmpne => code.emit(LCJUMP(parseJumpTarget, pc + size, NE, OBJECT))
}
else instr match {
case JVM.goto => emit(LJUMP(parseJumpTarget))
case JVM.jsr => Predef.error("Cannot handle jsr/ret")
case JVM.ret => Predef.error("Cannot handle jsr/ret")
case JVM.tableswitch =>
var byte1 = in.nextByte; size = size + 1;
while (byte1 == 0) { byte1 = in.nextByte; size = size + 1; }
val default = byte1 << 24 | in.nextByte << 16 | in.nextByte << 8 | in.nextByte;
size = size + 3;
val low = in.nextInt;
val high = in.nextInt;
size = size + 8;
assert(low <= high, "Value low not <= high for tableswitch.");
val tags = List.tabulate(high - low + 1, n => List(low + n));
val targets = for (val _ <- tags) yield parseJumpTargetW;
code.emit(LSWITCH(tags, targets ::: List(default)));
size = size + 3
val low = in.nextInt
val high = in.nextInt
size = size + 8
assert(low <= high, "Value low not <= high for tableswitch.")
val tags = List.tabulate(high - low + 1, n => List(low + n))
val targets = for (val _ <- tags) yield parseJumpTargetW
code.emit(LSWITCH(tags, targets ::: List(default)))
case JVM.lookupswitch =>
var byte1 = in.nextByte; size = size + 1;
while (byte1 == 0) { byte1 = in.nextByte; size = size + 1; }
val default = byte1 << 24 | in.nextByte << 16 | in.nextByte << 8 | in.nextByte;
size = size + 3;
val npairs = in.nextInt; size = size + 4;
var tags: List[List[Int]] = Nil;
var targets: List[Int] = Nil;
var i = 0;
size = size + 3
val npairs = in.nextInt; size = size + 4
var tags: List[List[Int]] = Nil
var targets: List[Int] = Nil
var i = 0
while (i < npairs) {
tags = List(in.nextInt) :: tags; size = size + 4;
targets = parseJumpTargetW :: targets; // parseJumpTargetW updates 'size' itself
i = i + 1;
}
targets = default :: targets;
code.emit(LSWITCH(tags.reverse, targets.reverse));
targets = default :: targets
code.emit(LSWITCH(tags.reverse, targets.reverse))
case JVM.ireturn => code.emit(RETURN(INT))
case JVM.lreturn => code.emit(RETURN(LONG))
case JVM.freturn => code.emit(RETURN(FLOAT))
case JVM.dreturn => code.emit(RETURN(DOUBLE))
case JVM.areturn => code.emit(RETURN(OBJECT))
case JVM.return_ => code.emit(RETURN(UNIT))
case JVM.ireturn => code.emit(RETURN(INT));
case JVM.lreturn => code.emit(RETURN(LONG));
case JVM.freturn => code.emit(RETURN(FLOAT));
case JVM.dreturn => code.emit(RETURN(DOUBLE));
case JVM.areturn => code.emit(RETURN(OBJECT));
case JVM.return_ => code.emit(RETURN(UNIT));
case JVM.gestatic =>
val field = pool.getMemberSymbol(in.nextChar, true); size = size + 2;
code.emit(LOAD_FIELD(field, true));
code.emit(LOAD_FIELD(field, true))
case JVM.putstatic =>
val field = pool.getMemberSymbol(in.nextChar, true); size = size + 2;
code.emit(STORE_FIELD(field, true));
code.emit(STORE_FIELD(field, true))
case JVM.getfield =>
val field = pool.getMemberSymbol(in.nextChar, false); size = size + 2;
code.emit(LOAD_FIELD(field, false));
code.emit(LOAD_FIELD(field, false))
case JVM.putfield =>
val field = pool.getMemberSymbol(in.nextChar, false); size = size + 2;
code.emit(STORE_FIELD(field, false));
code.emit(STORE_FIELD(field, false))
case JVM.invokevirtual | JVM.invokeinterface =>
val m = pool.getMemberSymbol(in.nextChar, false); size = size + 2;
code.emit(CALL_METHOD(m, Dynamic));
code.emit(CALL_METHOD(m, Dynamic))
case JVM.invokespecial =>
val m = pool.getMemberSymbol(in.nextChar, false); size = size + 2;
val style = if (m.name == nme.CONSTRUCTOR || m.hasFlag(Flags.PRIVATE)) Static(true)
else SuperCall(m.owner.name);
code.emit(CALL_METHOD(m, style));
code.emit(CALL_METHOD(m, style))
case JVM.invokestatic =>
val m = pool.getMemberSymbol(in.nextChar, false); size = size + 2;
code.emit(CALL_METHOD(m, Static(false)));
code.emit(CALL_METHOD(m, Static(false)))
case JVM.new_ => code.emit(NEW(REFERENCE(pool.getClassSymbol(in.nextChar)))); size = size + 2;
case JVM.newarray =>
case JVM.new_ =>
code.emit(NEW(REFERENCE(pool.getClassSymbol(in.nextChar))))
size = size + 2
case JVM.newarray =>
val kind = in.nextByte match {
case T_BOOLEAN => BOOL
case T_CHAR => CHAR
@ -406,13 +422,13 @@ abstract class ICodeReader extends ClassfileParser {
case T_INT => INT
case T_LONG => LONG
}
size = size + 1;
code.emit(CREATE_ARRAY(kind));
size = size + 1
code.emit(CREATE_ARRAY(kind))
case JVM.anewarray =>
val tpe = toTypeKind(pool.getType(in.nextChar)); size = size + 2;
code.emit(CREATE_ARRAY(tpe));
code.emit(CREATE_ARRAY(tpe))
case JVM.arraylength => code.emit(CALL_PRIMITIVE(ArrayLength(OBJECT))); // the kind does not matter
case JVM.athrow => code.emit(THROW());
case JVM.checkcast => code.emit(CHECK_CAST(toTypeKind(pool.getType(in.nextChar)))); size = size + 2;
@ -432,121 +448,122 @@ abstract class ICodeReader extends ClassfileParser {
case JVM.fstore => code.emit(STORE_LOCAL(code.getLocal(in.nextChar, FLOAT))); size = size + 2;
case JVM.dstore => code.emit(STORE_LOCAL(code.getLocal(in.nextChar, DOUBLE))); size = size + 2;
case JVM.astore => code.emit(STORE_LOCAL(code.getLocal(in.nextChar, OBJECT))); size = size + 2;
case JVM.ret => Predef.error("Cannot handle jsr/ret");
case JVM.ret => Predef.error("Cannot handle jsr/ret")
case JVM.iinc =>
size = size + 4;
val local = code.getLocal(in.nextChar, INT);
code.emit(CONSTANT(Constant(in.nextChar)));
code.emit(CALL_PRIMITIVE(Arithmetic(ADD, INT)));
code.emit(STORE_LOCAL(local));
case _ => Predef.error("Invalid 'wide' operand");
size = size + 4
val local = code.getLocal(in.nextChar, INT)
code.emit(CONSTANT(Constant(in.nextChar)))
code.emit(CALL_PRIMITIVE(Arithmetic(ADD, INT)))
code.emit(STORE_LOCAL(local))
case _ => Predef.error("Invalid 'wide' operand")
}
case JVM.multianewarray =>
size = size + 3;
val tpe = toTypeKind(pool.getType(in.nextChar));
val dim = in.nextByte;
assert(dim == 1, "Cannot handle multidimensional arrays yet.");
code.emit(CREATE_ARRAY(tpe));
case JVM.ifnull => code.emit(LCZJUMP(parseJumpTarget, pc + size, EQ, OBJECT));
case JVM.ifnonnull => code.emit(LCZJUMP(parseJumpTarget, pc + size, NE, OBJECT));
case JVM.goto_w => code.emit(LJUMP(parseJumpTargetW));
case JVM.jsr_w => Predef.error("Cannot handle jsr/ret");
size = size + 3
val tpe = toTypeKind(pool.getType(in.nextChar))
val dim = in.nextByte
assert(dim == 1, "Cannot handle multidimensional arrays yet.")
code.emit(CREATE_ARRAY(tpe))
case JVM.ifnull => code.emit(LCZJUMP(parseJumpTarget, pc + size, EQ, OBJECT))
case JVM.ifnonnull => code.emit(LCZJUMP(parseJumpTarget, pc + size, NE, OBJECT))
case JVM.goto_w => code.emit(LJUMP(parseJumpTargetW))
case JVM.jsr_w => Predef.error("Cannot handle jsr/ret")
case _ => Predef.error("Unknown bytecode")
}
pc = pc + size;
pc = pc + size
}
while (pc < codeLength) {
parseInstruction;
parseInstruction
}
val exceptionEntries = in.nextChar;
in.skip(8 * exceptionEntries);
skipAttributes();
Console.println(code.toString());
val exceptionEntries = in.nextChar
in.skip(8 * exceptionEntries)
skipAttributes()
Console.println(code.toString())
}
/** Return the icode class that should include members with the given flags.
* There are two possible classes, the static part and the instance part.
*/
def getCode(flags: Int): IClass =
if ((flags & JAVA_ACC_STATIC) != 0) staticCode else instanceCode;
def getCode(flags: Int): IClass =
if ((flags & JAVA_ACC_STATIC) != 0) staticCode else instanceCode
class LinearCode {
var instrs: ListBuffer[Instruction] = new ListBuffer;
var jmpTargets: Set[Int] = new HashSet[Int];
var locals: Map[Int, Local] = new HashMap();
def emit(i: Instruction) = instrs += i;
var instrs: ListBuffer[Instruction] = new ListBuffer
var jmpTargets: Set[Int] = new HashSet[Int]
var locals: Map[Int, Local] = new HashMap()
def emit(i: Instruction) = instrs += i
/** Return the local at given index, with the given type. */
def getLocal(idx: Int, kind: TypeKind): Local = {
assert(idx < maxLocals, "Index too large for local variable.");
def checkValidIndex: Unit = {
locals.get(idx - 1) match {
case Some(other) if (other.kind == LONG || other.kind == DOUBLE) =>
error("Illegal index: " + idx + " points in the middle of " + other);
case _ => ();
error("Illegal index: " + idx + " points in the middle of " + other)
case _ => ()
}
kind match {
case LONG | DOUBLE if (locals.isDefinedAt(idx + 1)) =>
error("Illegal index: " + idx + " overlaps " + locals(idx + 1));
case _ => ();
error("Illegal index: " + idx + " overlaps " + locals(idx + 1))
case _ => ()
}
}
locals.get(idx) match {
case Some(l) =>
assert(l.kind == kind, "Expected kind " + kind + " for local " + l + " but " + l.kind + " found.");
case Some(l) =>
assert(l.kind == kind, "Expected kind " +
kind + " for local " + l + " but " + l.kind + " found.")
l
case None =>
checkValidIndex;
val l = freshLocal(idx, kind);
locals += idx -> l;
checkValidIndex
val l = freshLocal(idx, kind)
locals += idx -> l
l
}
}
override def toString(): String = instrs.toList.mkString("", "\n", "");
override def toString(): String = instrs.toList.mkString("", "\n", "")
/** Return a fresh Local variable.
* TODO: 'isArgument' is always false, should be modified accordingly.
*/
def freshLocal(idx: Int, kind: TypeKind) = {
val sym = method.symbol.newVariable(Position.NOPOS, "loc" + idx).setInfo(kind.toType);
new Local(sym, kind, false);
new Local(sym, kind, false)
}
/** Base class for branch instructions that take addresses. */
abstract class LazyJump(pc: Int) extends Instruction {
override def toString() = "LazyJump " + pc;
jmpTargets += pc;
override def toString() = "LazyJump " + pc
jmpTargets += pc
}
case class LJUMP(pc: Int) extends LazyJump(pc);
case class LCJUMP(success: Int, failure: Int, cond: TestOp, kind: TypeKind)
extends LazyJump(success) {
override def toString(): String ="LCJUMP (" + kind + ") " + success + " : " + failure;
jmpTargets += failure;
jmpTargets += failure
}
case class LCZJUMP(success: Int, failure: Int, cond: TestOp, kind: TypeKind)
extends LazyJump(success) {
override def toString(): String ="LCZJUMP (" + kind + ") " + success + " : " + failure;
jmpTargets += failure;
jmpTargets += failure
}
case class LSWITCH(tags: List[List[Int]], targets: List[Int]) extends LazyJump(targets.head) {
override def toString(): String ="LSWITCH (tags: " + tags + ") targets: " + targets;
targets.tail.foreach(t => jmpTargets += t);
targets.tail.foreach(t => jmpTargets += t)
}
}
}