summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala')
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala473
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;
+
+ }
+}