diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala | 473 |
1 files changed, 473 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala new file mode 100644 index 0000000000..24eb1132f6 --- /dev/null +++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala @@ -0,0 +1,473 @@ +/* NSC -- new scala compiler + * Copyright 2005 LAMP/EPFL + * @author Martin Odersky + */ + +// $Id$ + + +package scala.tools.nsc.backend.icode; + +import scala.tools.nsc.ast._; +import scala.tools.nsc.util.Position; + +/* + A pattern match + + case THIS(clasz) => + case CONSTANT(const) => + case LOAD_ARRAY_ITEM(kind) => + case LOAD_LOCAL(local, isArg) => + case LOAD_FIELD(field, isStatic) => + case LOAD_MODULE(module) => + case STORE_ARRAY_ITEM(kind) => + case STORE_LOCAL(local, isArg) => + case STORE_FIELD(field, isStatic) => + case CALL_PRIMITIVE(primitive) => + case CALL_METHOD(method, style) => + case NEW(kind) => + case CREATE_ARRAY(elem) => + case IS_INSTANCE(tpe) => + case CHECK_CAST(tpe) => + case SWITCH(tags, labels) => + case JUMP(where) => + case CJUMP(success, failure, cond, kind) => + case CZJUMP(success, failure, cond, kind) => + case RETURN(kind) => + case THROW() => + case DROP(kind) => + case DUP(kind) => + case MONITOR_ENTER() => + case MONITOR_EXIT() => +*/ + + +/** + * The ICode intermediate representation. It is a stack-based + * representation, very close to the JVM and .NET. It uses the + * erased types of Scala and references Symbols to refer named entities + * in the source files. + */ +[_trait_] abstract class Opcodes: ICodes { + import global.{Symbol, NoSymbol, Type, Name, Constant}; + + /** This class represents an instruction of the intermediate code. + * Each case subclass will represent a specific operation. + */ + abstract class Instruction { + + /** This abstract method returns the number of used elements on the stack */ + def consumed : Int = 0; + + /** This abstract method returns the number of produced elements on the stack */ + def produced : Int = 0; + + /** This method returns the difference of size of the stack when the instruction is used */ + def difference = produced-consumed; + + /** The corresponding position in the source file */ + var pos: Int = Position.NOPOS; + } + + object opcodes { + + /** Loads the "this" references on top of the stack. + * Stack: ... + * ->: ...:ref + */ + case class THIS(clasz: Symbol) extends Instruction { + /** Returns a string representation of this constant */ + override def toString(): String = "THIS"; + + override def consumed = 0; + override def produced = 1; + } + + /** Loads a constant on the stack. + * Stack: ... + * ->: ...:constant + */ + case class CONSTANT(constant: Constant) extends Instruction{ + /** Returns a string representation of this constant */ + override def toString(): String = "CONSTANT ("+constant.toString()+")"; + + override def consumed = 0; + override def produced = 1; + } + + /** Loads an element of an array. The array and the index should + * be on top of the stack. + * Stack: ...:array[a](Ref):index(Int) + * ->: ...:element(a) + */ + case class LOAD_ARRAY_ITEM(kind: TypeKind) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String = "LOAD_ARRAY_ITEM (" + kind + ")"; + + override def consumed = 2; + override def produced = 1; + } + + /** Load a local variable on the stack. It can be a method argument. + * Stack: ... + * ->: ...:value + */ + case class LOAD_LOCAL(local: Local, isArgument: boolean) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String = "LOAD_LOCAL "+local.toString(); //+isArgument?" (argument)":""; + + override def consumed = 0; + override def produced = 1; + } + + /** Load a field on the stack. The object to which it refers should be + * on the stack. + * Stack: ...:ref + * ->: ...:value + */ + case class LOAD_FIELD(field: Symbol, isStatic: boolean) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String = + "LOAD_FIELD " + (if (isStatic) field.fullNameString else field.toString()); + + override def consumed = 1; + override def produced = 1; + } + + case class LOAD_MODULE(module: Symbol) extends Instruction { + assert(module != NoSymbol, + "Invalid module symbol"); + /** Returns a string representation of this instruction */ + override def toString(): String = + "LOAD_MODULE " + module.toString(); + + override def consumed = 0; + override def produced = 1; + } + + /** Store a value into an array at a specified index. + * Stack: ...:array[a](Ref):index(Int):value(a) + * ->: ... + */ + case class STORE_ARRAY_ITEM(kind: TypeKind) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String = "STORE_ARRAY_ITEM (" + kind + ")"; + + override def consumed = 3; + override def produced = 0; + } + + /** Store a value into a local variable. It can be an argument. + * Stack: ...:value + * ->: ... + */ + case class STORE_LOCAL(local: Local, isArgument: boolean) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String = "STORE_LOCAL "+local.toString(); //+isArgument?" (argument)":""; + + override def consumed = 1; + override def produced = 0; + } + + /** Store a value into a field. + * Stack: ...:ref:value + * ->: ... + */ + case class STORE_FIELD(field: Symbol, isStatic: boolean) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String = "STORE_FIELD "+field.toString(); //+isStatic?" (static)":""; + + override def consumed = 2; + override def produced = 0; + } + + /** Call a primitive function. + * Stack: ...:arg1:arg2:...:argn + * ->: ...:result + */ + case class CALL_PRIMITIVE(primitive: Primitive) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String ="CALL_PRIMITIVE "+primitive.toString(); + + override def consumed = primitive match { + case Negation(_) => 1; + case Test(_,_,true) => 1; + case Test(_,_,false) => 2; + case Comparison(_,_) => 2; + 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; + } + + /** This class represents a CALL_METHOD instruction + * STYLE: dynamic / static(StaticInstance) + * Stack: ...:ref:arg1:arg2:...:argn + * ->: ...:result + * + * STYLE: static(StaticClass) + * Stack: ...:arg1:arg2:...:argn + * ->: ...:result + * + */ + case class CALL_METHOD(method: Symbol, style: InvokeStyle) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String = + "CALL_METHOD " + method.fullNameString +" ("+style.toString()+")"; + + override def consumed = { + var result = method.tpe.paramTypes.length; + result = result + (style match { + case Dynamic => 1 + case Static(true) => 1 + case _ => 0 + }); + + result; + } + override def produced = 1; + } + + /** Create a new instance of a class through the specified constructor + * Stack: ...:arg1:arg2:...:argn + * ->: ...:ref + */ + case class NEW(kind: TypeKind) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String = "NEW "+ kind; + + override def consumed = 0; + override def produced = 1; + } + + + /** This class represents a CREATE_ARRAY instruction + * Stack: ...:size(int) + * ->: ...:arrayref + */ + case class CREATE_ARRAY(element: TypeKind) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String ="CREATE_ARRAY "+element.toString(); + + override def consumed = 1; + override def produced = 1; + } + + /** This class represents a IS_INSTANCE instruction + * Stack: ...:ref + * ->: ...:result(boolean) + */ + case class IS_INSTANCE(typ: TypeKind) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String ="IS_INSTANCE "+typ.toString(); + + override def consumed = 1; + override def produced = 1; + } + + /** This class represents a CHECK_CAST instruction + * Stack: ...:ref(oldtype) + * ->: ...:ref(typ <=: oldtype) + */ + case class CHECK_CAST(typ: TypeKind) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String ="CHECK_CAST "+typ.toString(); + + override def consumed = 1; + override def produced = 1; + } + + /** This class represents a SWITCH instruction + * Stack: ...:index(int) + * ->: ...: + * + * The tags array contains one entry per label, each entry consisting of + * an array of ints, any of which will trigger the jump to the corresponding label. + * labels should contain an extra label, which is the 'default' jump. + */ + case class SWITCH(tags: List[List[Int]], labels: List[BasicBlock]) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String ="SWITCH ..."; + + override def consumed = 1; + override def produced = 0; + } + + /** This class represents a JUMP instruction + * Stack: ... + * ->: ... + */ + case class JUMP(where: BasicBlock) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String ="JUMP "+where.label; + + override def consumed = 0; + override def produced = 0; + } + + /** This class represents a CJUMP instruction + * It compares the two values on the stack with the 'cond' test operator + * Stack: ...:value1:value2 + * ->: ... + */ + case class CJUMP(successBlock: BasicBlock, + failureBlock: BasicBlock, + cond: TestOp, + kind: TypeKind) extends Instruction + { + + /** Returns a string representation of this instruction */ + override def toString(): String = ( + "CJUMP (" + kind + ")" + + cond.toString()+" ? "+successBlock.label+" : "+failureBlock.label + ); + + override def consumed = 2; + override def produced = 0; + } + + /** This class represents a CZJUMP instruction + * It compares the one value on the stack and zero with the 'cond' test operator + * Stack: ...:value: + * ->: ... + */ + case class CZJUMP(successBlock: BasicBlock, + failureBlock: BasicBlock, + cond: TestOp, + kind: TypeKind) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String = ( + "CZJUMP (" + kind + ")" + + cond.toString()+" ? "+successBlock.label+" : "+failureBlock.label + ); + + override def consumed = 1; + override def produced = 0; + } + + + /** This class represents a RETURN instruction + * Stack: ... + * ->: ... + */ + case class RETURN(kind: TypeKind) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String ="RETURN (" + kind + ")"; + + override def consumed = 0; + override def produced = 0; + } + + /** This class represents a THROW instruction + * Stack: ...:Throwable(Ref) + * ->: ...: + */ + case class THROW() extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String ="THROW"; + + override def consumed = 1; + override def produced = 0; + } + + /** This class represents a DROP instruction + * Stack: ...:something + * ->: ... + */ + case class DROP (typ: TypeKind) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String ="DROP "+typ.toString(); + + override def consumed = 1; + override def produced = 0; + } + + /** This class represents a DUP instruction + * Stack: ...:something + * ->: ...:something:something + */ + case class DUP (typ: TypeKind) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String ="DUP"; + + override def consumed = 1; + override def produced = 2; + } + + /** This class represents a MONITOR_ENTER instruction + * Stack: ...:object(ref) + * ->: ...: + */ + case class MONITOR_ENTER() extends Instruction { + + /** Returns a string representation of this instruction */ + override def toString(): String ="MONITOR_ENTER"; + + override def consumed = 1; + override def produced = 0; + } + + /** This class represents a MONITOR_EXIT instruction + * Stack: ...:object(ref) + * ->: ...: + */ + case class MONITOR_EXIT() extends Instruction { + + /** Returns a string representation of this instruction */ + override def toString(): String ="MONITOR_EXIT"; + + override def consumed = 1; + override def produced = 0; + } + + /** This class represents a method invocation style. */ + trait InvokeStyle { + + /** Is this a dynamic method call? */ + def isDynamic: Boolean = this match { + case Dynamic => true; + case _ => false; + } + + /** Is this a static method call? */ + def isStatic: Boolean = this match { + case Static(_) => true; + case _ => false; + } + + /** Is this an instance method call? */ + def hasInstance: Boolean = this match { + case Dynamic => true; + case Static(onInstance) => onInstance; + case SuperCall(_) => true; + case _ => false; + } + + /** Returns a string representation of this style. */ + override def toString(): String = this match { + case Dynamic => "dynamic"; + case Static(false) => "static-class"; + case Static(true) => "static-instance"; + case SuperCall(mixin) => "super(" + mixin + ")"; + } + } + + case object Dynamic extends InvokeStyle; + + /** + * Special invoke. Static(true) is used for calls to private + * members. + */ + case class Static(onInstance: Boolean) extends InvokeStyle; + + /** Call through super[mixin]. */ + case class SuperCall(mixin: Name) extends InvokeStyle; + + } +} |