summaryrefslogtreecommitdiff
path: root/src/msil
diff options
context:
space:
mode:
authorMiguel Garcia <magarcia@epfl.ch>2010-08-24 07:38:58 +0000
committerMiguel Garcia <magarcia@epfl.ch>2010-08-24 07:38:58 +0000
commite987f72df36f33bd40c99792b7b97aeebe2ef605 (patch)
treefb09417d3ec4f078ecb396774942f95ff6af88a5 /src/msil
parent79a7191e605d22ffe9d2142039f586682c6902d6 (diff)
downloadscala-e987f72df36f33bd40c99792b7b97aeebe2ef605.tar.gz
scala-e987f72df36f33bd40c99792b7b97aeebe2ef605.tar.bz2
scala-e987f72df36f33bd40c99792b7b97aeebe2ef605.zip
for MSIL:
(a) The bytecode that Scala.NET emitted had a tough time in passing peverify due to valuetypes (aka structs) and their related managed-pointer types. With these changes (details in [1] and [2]) external APIs exposing valuetypes can be used, yet the extra step of supporting defining valuetypes in Scala programs has been left for later. Supporting the unsigned integral valuetypes (used, among others, by IKVM) is also pending. (b) A very first step towards generics can be found in TypeParser.parseClass, for the time being commented out (search for the label "TODO CLR generics"). It's commented out because without CLRManifests codegen won't work as expected. Details in [3]. review by rytz Refs: [1] http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/2010Q3/Bootstr apping3.pdf [2] http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/2010Q3/Bootstr apping4.pdf [3] http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/2010Q2/SigToTy pe.pdf
Diffstat (limited to 'src/msil')
-rw-r--r--src/msil/ch/epfl/lamp/compiler/msil/ConstructorInfo.java20
-rw-r--r--src/msil/ch/epfl/lamp/compiler/msil/MethodBase.java54
-rw-r--r--src/msil/ch/epfl/lamp/compiler/msil/MethodInfo.java31
-rw-r--r--src/msil/ch/epfl/lamp/compiler/msil/Type.java22
-rw-r--r--src/msil/ch/epfl/lamp/compiler/msil/emit/ILPrinterVisitor.scala5
-rw-r--r--src/msil/ch/epfl/lamp/compiler/msil/emit/OpCode.scala4
-rw-r--r--src/msil/ch/epfl/lamp/compiler/msil/emit/OpCodes.scala10
7 files changed, 104 insertions, 42 deletions
diff --git a/src/msil/ch/epfl/lamp/compiler/msil/ConstructorInfo.java b/src/msil/ch/epfl/lamp/compiler/msil/ConstructorInfo.java
index 99e5c5fe69..69f5d6d32a 100644
--- a/src/msil/ch/epfl/lamp/compiler/msil/ConstructorInfo.java
+++ b/src/msil/ch/epfl/lamp/compiler/msil/ConstructorInfo.java
@@ -24,23 +24,23 @@ public class ConstructorInfo extends MethodBase {
protected static final String CTOR = ".ctor";
protected static final String CCTOR = ".cctor";
- protected static final ConstructorInfo[] EMPTY_ARRAY =
- new ConstructorInfo[0];
+ protected static final ConstructorInfo[] EMPTY_ARRAY = new ConstructorInfo[0];
protected static String getName(int attrs) {
- return (attrs & MethodAttributes.Static) == 0 ? CTOR : CCTOR;
+ return (attrs & MethodAttributes.Static) == 0 ? CTOR : CCTOR;
}
- /** Protected constructor */
- protected ConstructorInfo(Type declType, int attrs, Type[] paramTypes) {
- super(getName(attrs), declType, attrs, paramTypes);
- assert declType != null : "Owner can't be 'null' for a constructor!";
+ /** Public constructors */
+
+ public ConstructorInfo(Type declType, int attrs, Type[] paramTypes) {
+ super(getName(attrs), declType, attrs, paramTypes);
+ assert declType != null : "Owner can't be 'null' for a constructor!";
}
- protected ConstructorInfo(Type declType, int attrs, ParameterInfo[] params)
+ public ConstructorInfo(Type declType, int attrs, ParameterInfo[] params)
{
- super(getName(attrs), declType, attrs, params);
- assert declType != null : "Owner can't be 'null' for a constructor!";
+ super(getName(attrs), declType, attrs, params);
+ assert declType != null : "Owner can't be 'null' for a constructor!";
}
diff --git a/src/msil/ch/epfl/lamp/compiler/msil/MethodBase.java b/src/msil/ch/epfl/lamp/compiler/msil/MethodBase.java
index 793ee362e9..fe6404346e 100644
--- a/src/msil/ch/epfl/lamp/compiler/msil/MethodBase.java
+++ b/src/msil/ch/epfl/lamp/compiler/msil/MethodBase.java
@@ -5,6 +5,8 @@
package ch.epfl.lamp.compiler.msil;
+import java.util.Iterator;
+
/**
* The common superclass of MemberInfo and ConstructorInfo
*
@@ -16,6 +18,34 @@ public abstract class MethodBase extends MemberInfo {
//##########################################################################
// public interface
+ private java.util.List /* GenericParamAndConstraints */ mVars = new java.util.LinkedList();
+ private GenericParamAndConstraints[] sortedMVars = null;
+
+ public void addMVar(GenericParamAndConstraints tvarAndConstraints) {
+ sortedMVars = null;
+ mVars.add(tvarAndConstraints);
+ }
+
+ public GenericParamAndConstraints[] getSortedMVars() {
+ if(sortedMVars == null) {
+ sortedMVars = new GenericParamAndConstraints[mVars.size()];
+ for (int i = 0; i < sortedMVars.length; i ++){
+ Iterator iter = mVars.iterator();
+ while(iter.hasNext()) {
+ GenericParamAndConstraints tvC = (GenericParamAndConstraints)iter.next();
+ if(tvC.Number == i) {
+ sortedMVars[i] = tvC;
+ }
+ }
+ }
+ }
+ return sortedMVars;
+ }
+
+ public final boolean IsGeneric() {
+ return mVars.size() > 0;
+ }
+
/** The attributes associated with this method/constructor. */
public final short Attributes;
@@ -36,6 +66,10 @@ public abstract class MethodBase extends MemberInfo {
return (Attributes& MethodAttributes.Virtual) != 0;
}
+ public final boolean IsInstance() {
+ return !IsStatic() && !IsVirtual();
+ }
+
public final boolean IsStatic() {
return (Attributes & MethodAttributes.Static) != 0;
}
@@ -79,6 +113,26 @@ public abstract class MethodBase extends MemberInfo {
== MethodAttributes.FamANDAssem;
}
+ public boolean HasPtrParamOrRetType() {
+ // the override in MethodInfo checks the return type
+ ParameterInfo[] ps = GetParameters();
+ for (int i = 0; i < ps.length; i++) {
+ Type pT = ps[i].ParameterType;
+ if(pT.IsPointer()) {
+ // Type.mkPtr creates a msil.Type for a pointer type
+ return true;
+ }
+ if(pT.IsByRef() && !pT.GetElementType().CanBeTakenAddressOf()) {
+ /* TODO Cases where GenMSIL (so far) con't emit good bytecode:
+ the type being taken address of IsArray(), IsGeneric(), or IsTMVarUsage.
+ For example, System.Enum declares
+ public static bool TryParse<TEnum>(string value, out TEnum result) where TEnum : struct, new();
+ */
+ return true;
+ }
+ }
+ return false;
+ }
/** Returns the parameters of the method/constructor. */
public ParameterInfo[] GetParameters() {
diff --git a/src/msil/ch/epfl/lamp/compiler/msil/MethodInfo.java b/src/msil/ch/epfl/lamp/compiler/msil/MethodInfo.java
index 8c53a768fc..a415e7551f 100644
--- a/src/msil/ch/epfl/lamp/compiler/msil/MethodInfo.java
+++ b/src/msil/ch/epfl/lamp/compiler/msil/MethodInfo.java
@@ -15,32 +15,17 @@ import java.util.Iterator;
*/
public class MethodInfo extends MethodBase {
- private java.util.List /* GenericParamAndConstraints */ mVars = new java.util.LinkedList();
- private GenericParamAndConstraints[] sortedMVars = null;
-
- public void addMVar(GenericParamAndConstraints tvarAndConstraints) {
- sortedMVars = null;
- mVars.add(tvarAndConstraints);
- }
-
- public GenericParamAndConstraints[] getSortedMVars() {
- if(sortedMVars == null) {
- sortedMVars = new GenericParamAndConstraints[mVars.size()];
- for (int i = 0; i < sortedMVars.length; i ++){
- Iterator iter = mVars.iterator();
- while(iter.hasNext()) {
- GenericParamAndConstraints tvC = (GenericParamAndConstraints)iter.next();
- if(tvC.Number == i) {
- sortedMVars[i] = tvC;
- }
- }
- }
+ public boolean HasPtrParamOrRetType() {
+ if(ReturnType.IsByRef() && !(ReturnType.GetElementType().IsValueType())) {
+ /* A method returning ByRef won't pass peverify, so I guess this is dead code. */
+ return true;
}
- return sortedMVars;
+ if(ReturnType.IsPointer()) {
+ return true;
+ }
+ return super.HasPtrParamOrRetType();
}
-
-
//##########################################################################
// public members
diff --git a/src/msil/ch/epfl/lamp/compiler/msil/Type.java b/src/msil/ch/epfl/lamp/compiler/msil/Type.java
index 78704062b7..a4de4ae11b 100644
--- a/src/msil/ch/epfl/lamp/compiler/msil/Type.java
+++ b/src/msil/ch/epfl/lamp/compiler/msil/Type.java
@@ -285,6 +285,19 @@ public abstract class Type extends MemberInfo {
public final boolean IsEnum() {
return BaseType() == ENUM();
}
+ public boolean CanBeTakenAddressOf() {
+ /* TODO should be overridden in TMVarUsage,
+ but there's currently no way to bind a TMVarUsage to its GenericParamAndConstraints definition. Why?
+ Because of the way the msil library is organized (e.g., mkArray() returns the same !0[] representation
+ for all !0[] usages, irrespective of the scope of the !0 type-param)
+ This in turn is so because without generics there's no harm in using a type-def instance
+ where a type-ref should go (e.g., the ParameterType of a ParameterInfo nowadays may point to a PEType).
+ The net effect is that this method (CanBeTakenAddressOf) is conservative, it will answer "no"
+ for example for !0 where !0 refers to a type-param with the isValuetype constraint set.
+ The whole thing is ok at this point in time, where generics are not supported at the backend. */
+ return IsValueType() && (this != ENUM());
+ /* ENUM() is a singleton, i.e. System.Enum is not generic */
+ }
/** IsGeneric, true for a PEType or TypeBuilder (i.e., a type definition)
* containing one or more type params. Not to be called on a reference
@@ -325,7 +338,8 @@ public abstract class Type extends MemberInfo {
public final int Number;
public final boolean isTVar;
- /** Non-defining reference to either a TVar or an MVar */
+ /** Non-defining reference to either a TVar or an MVar.
+ * An instance of GenericParamAndConstraints represents a TVar or an MVar definition. */
public TMVarUsage(int Number, boolean isTVar) {
super(null, 0, ((isTVar ? "!" : "!!") + Number), null, null, null, AuxAttr.None, null);
this.Number = Number;
@@ -378,7 +392,7 @@ public abstract class Type extends MemberInfo {
if (array != null)
return array;
array = new PrimitiveType(elemType.Module,
- TypeAttributes.Public
+ elemType.Attributes
| TypeAttributes.Sealed
| TypeAttributes.Serializable,
elemType.FullName + arrSig,
@@ -393,7 +407,7 @@ public abstract class Type extends MemberInfo {
Type type = getType(name);
if (type != null) return type;
type = new PrimitiveType(elemType.Module,
- TypeAttributes.NotPublic,
+ elemType.Attributes,
name, null, EmptyTypes, null,
AuxAttr.Pointer, elemType);
return addType(type);
@@ -405,7 +419,7 @@ public abstract class Type extends MemberInfo {
Type type = getType(name);
if (type != null) return type;
type = new PrimitiveType(elemType.Module,
- TypeAttributes.NotPublic,
+ elemType.Attributes,
name, null, EmptyTypes, null,
AuxAttr.ByRef, elemType);
return addType(type);
diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/ILPrinterVisitor.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/ILPrinterVisitor.scala
index cc359b813f..66f53b8132 100644
--- a/src/msil/ch/epfl/lamp/compiler/msil/emit/ILPrinterVisitor.scala
+++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/ILPrinterVisitor.scala
@@ -450,7 +450,7 @@ abstract class ILPrinterVisitor extends Visitor {
def caseOpCode(opCode: OpCode) {
var opString = opCode.toString()
print(opString)
- pad(12 - opString.length())
+ pad(14 - opString.length())
// switch opcode
if (opCode == OpCode.Ldstr) {
@@ -484,9 +484,8 @@ abstract class ILPrinterVisitor extends Visitor {
print(" \'"); print(loc.name); print("\'")
//print("'") print(((LocalBuilder)argument).name) print("'")
} else if (opCode == OpCode.Readonly) {
- println("readonly. ")
+ // nothing to do
} else if (opCode == OpCode.Constrained) {
- print("constrained. ")
printReference(argument.asInstanceOf[Type])
} else if (opCode == OpCode.Ldelema) {
printReference(argument.asInstanceOf[Type])
diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/OpCode.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/OpCode.scala
index bfccc42214..fbcdbf893f 100644
--- a/src/msil/ch/epfl/lamp/compiler/msil/emit/OpCode.scala
+++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/OpCode.scala
@@ -805,13 +805,13 @@ object OpCode {
* constrained prefix
*/
final val Constrained = new OpCode()
-opcode(Constrained, CEE_CONSTRAINED , "constrained" , 0xFFFFFE16, POP_NONE, PUSH_NONE, INLINE_NONE , FLOW_NEXT)
+opcode(Constrained, CEE_CONSTRAINED , "constrained." , 0xFFFFFE16, POP_NONE, PUSH_NONE, INLINE_NONE , FLOW_NEXT)
/**
* readonly prefix
*/
final val Readonly = new OpCode()
-opcode(Readonly, CEE_READONLY , "readonly" , 0xFFFFFE1E, POP_NONE, PUSH_NONE, INLINE_NONE , FLOW_NEXT)
+opcode(Readonly, CEE_READONLY , "readonly." , 0xFFFFFE1E, POP_NONE, PUSH_NONE, INLINE_NONE , FLOW_NEXT)
/**
* Calls the method indicated on the evaluation stack (as a pointer to an entry point)
diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/OpCodes.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/OpCodes.scala
index db2a6fedc7..d486c31af0 100644
--- a/src/msil/ch/epfl/lamp/compiler/msil/emit/OpCodes.scala
+++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/OpCodes.scala
@@ -235,6 +235,16 @@ object OpCodes {
final val Call = OpCode.Call
/**
+ * constrained. prefix
+ */
+ final val Constrained = OpCode.Constrained
+
+ /**
+ * readonly. prefix
+ */
+ final val Readonly = OpCode.Readonly
+
+ /**
* Calls the method indicated on the evaluation stack (as a pointer to an entry point)
* with arguments described by a calling convention.
*/