package scala.tools.nsc
package backend
package icode
import scala.tools.nsc.ast._
import scala.tools.nsc.util.{Position,NoPosition}
trait Opcodes { self: ICodes =>
import global.{Symbol, NoSymbol, Type, Name, Constant};
abstract class Instruction extends Cloneable {
def consumed : Int = 0
def produced : Int = 0
def consumedTypes: List[TypeKind] = Nil
def producedTypes: List[TypeKind] = Nil
def difference = produced-consumed
private var _pos: Position = NoPosition
def pos: Position = _pos
var useful: Boolean = false
def setPos(p: Position): this.type = {
_pos = p
this
}
override def clone: Instruction =
super.clone.asInstanceOf[Instruction]
}
object opcodes {
def mayThrow(i: Instruction): Boolean = i match {
case LOAD_LOCAL(_) | STORE_LOCAL(_) | CONSTANT(_) | THIS(_) | CZJUMP(_, _, _, _)
| DROP(_) | DUP(_) | RETURN(_) | LOAD_EXCEPTION(_) | JUMP(_) | CJUMP(_, _, _, _) => false
case _ => true
}
case class THIS(clasz: Symbol) extends Instruction {
override def toString = "THIS(" + clasz.name + ")"
override def consumed = 0
override def produced = 1
override def producedTypes = List(REFERENCE(clasz))
}
case class CONSTANT(constant: Constant) extends Instruction {
override def toString = "CONSTANT(" + constant.escapedStringValue + ")"
override def consumed = 0
override def produced = 1
override def producedTypes = List(toTypeKind(constant.tpe))
}
case class LOAD_ARRAY_ITEM(kind: TypeKind) extends Instruction {
override def consumed = 2
override def produced = 1
override def consumedTypes = List(ARRAY(kind), INT)
override def producedTypes = List(kind)
}
case class LOAD_LOCAL(local: Local) extends Instruction {
override def consumed = 0
override def produced = 1
override def producedTypes = List(local.kind)
}
case class LOAD_FIELD(field: Symbol, isStatic: Boolean) extends Instruction {
override def toString(): String =
"LOAD_FIELD " + (if (isStatic) field.fullName else field.toString());
override def consumed = if (isStatic) 0 else 1
override def produced = 1
override def consumedTypes = if (isStatic) Nil else List(REFERENCE(field.owner));
override def producedTypes = List(toTypeKind(field.tpe));
var hostClass: Symbol = field.owner
def setHostClass(cls: Symbol): this.type = { hostClass = cls; this }
}
case class LOAD_MODULE(module: Symbol) extends Instruction {
assert(module != NoSymbol, "Invalid module symbol")
override def toString(): String = "LOAD_MODULE " + module
override def consumed = 0
override def produced = 1
override def producedTypes = List(REFERENCE(module))
}
case class STORE_ARRAY_ITEM(kind: TypeKind) extends Instruction {
override def consumed = 3
override def produced = 0
override def consumedTypes = List(ARRAY(kind), INT, kind)
}
case class STORE_LOCAL(local: Local) extends Instruction {
override def consumed = 1
override def produced = 0
override def consumedTypes = List(local.kind)
}
case class STORE_FIELD(field: Symbol, isStatic: Boolean) extends Instruction {
override def toString(): String =
"STORE_FIELD "+field + (if (isStatic) " (static)" else " (dynamic)");
override def consumed = if(isStatic) 1 else 2;
override def produced = 0;
override def consumedTypes =
if (isStatic)
List(toTypeKind(field.tpe))
else
List(REFERENCE(field.owner), toTypeKind(field.tpe));
}
case class STORE_THIS(kind: TypeKind) extends Instruction {
override def consumed = 1
override def produced = 0
override def consumedTypes = List(kind)
}
case class CALL_PRIMITIVE(primitive: Primitive) extends Instruction {
override def consumed = primitive match {
case Negation(_) => 1
case Test(_,_, true) => 1
case Test(_,_, false) => 2
case Comparison(_,_) => 2
case Arithmetic(NOT,_) => 1
case Arithmetic(_,_) => 2
case Logical(_,_) => 2
case Shift(_,_) => 2
case Conversion(_,_) => 1
case ArrayLength(_) => 1
case StringConcat(_) => 2
case StartConcat => 0
case EndConcat => 1
}
override def produced = 1
override def consumedTypes = primitive match {
case Negation(kind) => List(kind)
case Test(_, kind, true) => List(kind)
case Test(_, kind, false) => List(kind, kind)
case Comparison(_, kind) => List(kind, kind)
case Arithmetic(NOT, kind) => List(kind)
case Arithmetic(_, kind) => List(kind, kind)
case Logical(_, kind) => List(kind, kind)
case Shift(_, kind) => List(kind, INT)
case Conversion(from, _) => List(from)
case ArrayLength(kind) => List(ARRAY(kind))
case StringConcat(kind) => List(ConcatClass, kind)
case StartConcat => Nil
case EndConcat => List(ConcatClass)
}
override def producedTypes = primitive match {
case Negation(kind) => List(kind)
case Test(_, _, true) => List(BOOL)
case Test(_, _, false) => List(BOOL)
case Comparison(_, _) => List(INT)
case Arithmetic(_, kind) => List(kind)
case Logical(_, kind) => List(kind)
case Shift(_, kind) => List(kind)
case Conversion(_, to) => List(to)
case ArrayLength(_) => List(INT)
case StringConcat(_) => List(ConcatClass)
case StartConcat => List(ConcatClass)
case EndConcat => List(REFERENCE(global.definitions.StringClass))
}
}
case class CALL_METHOD(method: Symbol, style: InvokeStyle) extends Instruction with ReferenceEquality {
def toShortString =
"CALL_METHOD " + method.name +" ("+style+")"
override def toString(): String =
"CALL_METHOD " + method.fullName +" ("+style+")"
var hostClass: Symbol = method.owner
def setHostClass(cls: Symbol): this.type = { hostClass = cls; this }
var targetTypeKind: TypeKind = UNIT
def setTargetTypeKind(tk: TypeKind) = targetTypeKind = tk
private def params = method.info.paramTypes
private def consumesInstance = style match {
case Static(false) => 0
case _ => 1
}
override def consumed = params.length + consumesInstance
override def consumedTypes = {
val args = params map toTypeKind
if (consumesInstance > 0) ObjectReference :: args
else args
}
override def produced =
if (producedType == UNIT || method.isConstructor) 0
else 1
private def producedType: TypeKind = toTypeKind(method.info.resultType)
override def producedTypes =
if (produced == 0) Nil
else List(producedType)
}
case class BOX(boxType: TypeKind) extends Instruction {
override def toString(): String = "BOX " + boxType
override def consumed = 1
override def consumedTypes = boxType :: Nil
override def produced = 1
}
case class UNBOX(boxType: TypeKind) extends Instruction {
override def toString(): String = "UNBOX " + boxType
override def consumed = 1
override def consumedTypes = ObjectReference :: Nil
override def produced = 1
}
case class NEW(kind: REFERENCE) extends Instruction {
override def toString(): String = "NEW "+ kind;
override def consumed = 0;
override def produced = 1;
var init: CALL_METHOD = _
}
case class CREATE_ARRAY(elem: TypeKind, dims: Int) extends Instruction {
override def toString(): String ="CREATE_ARRAY "+elem + " x " + dims;
override def consumed = dims;
override def consumedTypes = List.fill(dims)(INT)
override def produced = 1;
}
case class IS_INSTANCE(typ: TypeKind) extends Instruction {
override def toString(): String ="IS_INSTANCE "+typ
override def consumed = 1
override def consumedTypes = ObjectReference :: Nil
override def produced = 1
}
case class CHECK_CAST(typ: TypeKind) extends Instruction {
override def toString(): String ="CHECK_CAST "+typ
override def consumed = 1
override def produced = 1
override val consumedTypes = List(ObjectReference)
override def producedTypes = List(typ)
}
case class SWITCH(tags: List[List[Int]], labels: List[BasicBlock]) extends Instruction {
override def toString(): String ="SWITCH ..."
override def consumed = 1
override def produced = 0
}
case class JUMP(whereto: BasicBlock) extends Instruction {
override def toString(): String ="JUMP "+whereto.label
override def consumed = 0
override def produced = 0
}
case class CJUMP(successBlock: BasicBlock,
failureBlock: BasicBlock,
cond: TestOp,
kind: TypeKind) extends Instruction
{
override def toString(): String = (
"CJUMP (" + kind + ")" +
cond + " ? "+successBlock.label+" : "+failureBlock.label
);
override def consumed = 2
override def produced = 0
}
case class CZJUMP(successBlock: BasicBlock,
failureBlock: BasicBlock,
cond: TestOp,
kind: TypeKind) extends Instruction {
override def toString(): String = (
"CZJUMP (" + kind + ")" +
cond + " ? "+successBlock.label+" : "+failureBlock.label
);
override def consumed = 1
override def produced = 0
}
case class RETURN(kind: TypeKind) extends Instruction {
override def consumed = if (kind == UNIT) 0 else 1
override def produced = 0
}
case class THROW(clasz: Symbol) extends Instruction {
override def toString = "THROW(" + clasz.name + ")"
override def consumed = 1
override def produced = 0
}
case class DROP (typ: TypeKind) extends Instruction {
override def toString(): String ="DROP "+typ
override def consumed = 1
override def produced = 0
}
case class DUP (typ: TypeKind) extends Instruction {
override def consumed = 1
override def produced = 2
}
case class MONITOR_ENTER() extends Instruction {
override def toString(): String ="MONITOR_ENTER"
override def consumed = 1
override def produced = 0
}
case class MONITOR_EXIT() extends Instruction {
override def toString(): String ="MONITOR_EXIT";
override def consumed = 1;
override def produced = 0;
}
case class SCOPE_ENTER(lv: Local) extends Instruction {
override def toString(): String = "SCOPE_ENTER " + lv
override def consumed = 0
override def produced = 0
}
case class SCOPE_EXIT(lv: Local) extends Instruction {
override def toString(): String = "SCOPE_EXIT " + lv
override def consumed = 0
override def produced = 0
}
case class LOAD_EXCEPTION(clasz: Symbol) extends Instruction {
override def consumed = sys.error("LOAD_EXCEPTION does clean the whole stack, no idea how many things it consumes!")
override def produced = 1
override def producedTypes = REFERENCE(clasz) :: Nil
}
sealed abstract class InvokeStyle {
def isDynamic: Boolean = this match {
case Dynamic => true
case _ => false
}
def isStatic: Boolean = this match {
case Static(_) => true
case _ => false
}
def isSuper: Boolean = this match {
case SuperCall(_) => true
case _ => false
}
def hasInstance: Boolean = this match {
case Static(false) => false
case _ => true
}
override def toString(): String = this match {
case Dynamic => "dynamic"
case InvokeDynamic => "invoke-dynamic"
case Static(false) => "static-class"
case Static(true) => "static-instance"
case SuperCall(mix) => "super(" + mix + ")"
}
}
case object Dynamic extends InvokeStyle
case object InvokeDynamic extends InvokeStyle
case class Static(onInstance: Boolean) extends InvokeStyle
case class SuperCall(mix: Name) extends InvokeStyle
case class CIL_LOAD_LOCAL_ADDRESS(local: Local) extends Instruction {
override def toString(): String = "CIL_LOAD_LOCAL_ADDRESS "+local
override def consumed = 0
override def produced = 1
override def producedTypes = List(msil_mgdptr(local.kind))
}
case class CIL_LOAD_FIELD_ADDRESS(field: Symbol, isStatic: Boolean) extends Instruction {
override def toString(): String =
"CIL_LOAD_FIELD_ADDRESS " + (if (isStatic) field.fullName else field.toString)
override def consumed = if (isStatic) 0 else 1
override def produced = 1
override def consumedTypes = if (isStatic) Nil else List(REFERENCE(field.owner));
override def producedTypes = List(msil_mgdptr(REFERENCE(field.owner)));
}
case class CIL_LOAD_ARRAY_ITEM_ADDRESS(kind: TypeKind) extends Instruction {
override def toString(): String = "CIL_LOAD_ARRAY_ITEM_ADDRESS (" + kind + ")"
override def consumed = 2
override def produced = 1
override def consumedTypes = List(ARRAY(kind), INT)
override def producedTypes = List(msil_mgdptr(kind))
}
case class CIL_UNBOX(valueType: TypeKind) extends Instruction {
override def toString(): String = "CIL_UNBOX " + valueType
override def consumed = 1
override def consumedTypes = ObjectReference :: Nil
override def produced = 1
override def producedTypes = List(msil_mgdptr(valueType))
}
case class CIL_INITOBJ(valueType: TypeKind) extends Instruction {
override def toString(): String = "CIL_INITOBJ " + valueType
override def consumed = 1
override def consumedTypes = ObjectReference :: Nil
override def produced = 0
}
case class CIL_NEWOBJ(method: Symbol) extends Instruction {
override def toString(): String = "CIL_NEWOBJ " + hostClass.fullName + method.fullName
var hostClass: Symbol = method.owner;
override def consumed = method.tpe.paramTypes.length
override def consumedTypes = method.tpe.paramTypes map toTypeKind
override def produced = 1
override def producedTypes = List(toTypeKind(method.tpe.resultType))
}
}
}