genmsil.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 1,568 行 · 第 1/5 页

SCALA
1,568
字号
/* NSC -- new scala compiler * Copyright 2005-2008 LAMP/EPFL * @author Nikolay Mihaylov */// $Id: GenMSIL.scala 14110 2008-02-22 15:23:15Z michelou $package scala.tools.nsc.backend.msilimport java.io.Fileimport java.nio.{ByteBuffer, ByteOrder}import scala.collection.mutable.{Map, HashMap, HashSet, Stack}import scala.tools.nsc.symtab._import scala.tools.nsc.util.Positionimport ch.epfl.lamp.compiler.msil.{Type => MsilType, _}import ch.epfl.lamp.compiler.msil.emit._/** */abstract class GenMSIL extends SubComponent {  import global._  import loaders.clrTypes  import clrTypes.{types, constructors, methods, fields}  import icodes._  import icodes.opcodes._  /** Create a new phase */  override def newPhase(p: Phase) = new MsilPhase(p)  val phaseName = "msil"  /** MSIL code generation phase   */  class MsilPhase(prev: Phase) extends GlobalPhase(prev) {    def name = phaseName    override def newFlags = phaseNewFlags    override def erasedTypes = true    override def run {      if (settings.debug.value) inform("[running phase " + name + " on icode]")      val codeGenerator = new BytecodeGenerator      //classes is ICodes.classes, a HashMap[Symbol, IClass]      classes.values foreach codeGenerator.findEntryPoint      codeGenerator.initAssembly      classes.values foreach codeGenerator.createTypeBuilder      classes.values foreach codeGenerator.createClassMembers      try {        classes.values foreach codeGenerator.genClass      } finally {        codeGenerator.writeAssembly      }    }    override def apply(unit: CompilationUnit) {      abort("MSIL works on icode classes, not on compilation units!")    }  }  /**   * MSIL bytecode generator.   *   */  class BytecodeGenerator {    val MODULE_INSTANCE_NAME = "MODULE$"    import clrTypes.{VOID => MVOID, BOOLEAN => MBOOL, UBYTE => MBYTE, SHORT => MSHORT,                   CHAR => MCHAR, INT => MINT, LONG => MLONG, FLOAT => MFLOAT,                   DOUBLE => MDOUBLE, OBJECT => MOBJECT, STRING => MSTRING,                   STRING_ARRAY => MSTRING_ARRAY, SCALA_SYMTAB_ATTR => SYMTAB_ATTRIBUTE,                   SYMTAB_CONSTR => SYMTAB_ATTRIBUTE_CONSTRUCTOR,                   SYMTAB_DEFAULT_CONSTR => SYMTAB_ATTRIBUTE_EMPTY_CONSTRUCTOR}    val EXCEPTION = clrTypes.getType("System.Exception")    val MBYTE_ARRAY = clrTypes.mkArrayType(MBYTE)    val ICLONEABLE = clrTypes.getType("System.ICloneable")    val MEMBERWISE_CLONE = MOBJECT.GetMethod("MemberwiseClone", MsilType.EmptyTypes)    val MMONITOR       = clrTypes.getType("System.Threading.Monitor")    val MMONITOR_ENTER = MMONITOR.GetMethod("Enter", Array(MOBJECT))    val MMONITOR_EXIT  = MMONITOR.GetMethod("Exit", Array(MOBJECT))    val MSTRING_BUILDER = clrTypes.getType("System.Text.StringBuilder")    val MSTRING_BUILDER_CONSTR = MSTRING_BUILDER.GetConstructor(MsilType.EmptyTypes)    val MSTRING_BUILDER_TOSTRING = MSTRING_BUILDER.GetMethod("ToString",                                                             MsilType.EmptyTypes)    val TYPE_FROM_HANDLE =      clrTypes.getType("System.Type").GetMethod("GetTypeFromHandle", Array(clrTypes.getType("System.RuntimeTypeHandle")))    val INT_PTR = clrTypes.getType("System.IntPtr")    val JOBJECT = definitions.ObjectClass    val JSTRING = definitions.StringClass    var JSTRING_SUBSTRING_INT_INT: Symbol = _    val SystemConvert = clrTypes.getType("System.Convert")    val objParam = Array(MOBJECT)//     val toBool:   MethodInfo = SystemConvert.GetMethod("ToBoolean", objParam)    val toByte:   MethodInfo = SystemConvert.GetMethod("ToByte", objParam)    val toShort:  MethodInfo = SystemConvert.GetMethod("ToInt16", objParam)    val toChar:   MethodInfo = SystemConvert.GetMethod("ToChar", objParam)    val toInt:    MethodInfo = SystemConvert.GetMethod("ToInt32", objParam)    val toLong:   MethodInfo = SystemConvert.GetMethod("ToInt64", objParam)    val toFloat:  MethodInfo = SystemConvert.GetMethod("ToSingle", objParam)    val toDouble: MethodInfo = SystemConvert.GetMethod("ToDouble", objParam)    //val boxedUnit: FieldInfo = msilType(definitions.BoxedUnitModule.info).GetField("UNIT")    val boxedUnit: FieldInfo = fields(definitions.BoxedUnit_UNIT.asInstanceOf[clrTypes.global.Symbol])    // Scala attributes    // symtab.Definitions -> object (singleton..)    val SerializableAttr = definitions.SerializableAttr.tpe    val CloneableAttr    = definitions.getClass("scala.cloneable").tpe    val TransientAtt     = definitions.getClass("scala.transient").tpe    // remoting: the architectures are too different, no mapping (no portable code    // possible)    // java instance methods that are mapped to static methods in .net    // these will need to be called with OpCodes.Call (not Callvirt)    val dynToStatMapped: HashSet[Symbol] = new HashSet()    initMappings()    // ********************************************************************    // Create the mappings    private def initMappings() {      mapType(definitions.AnyClass, MOBJECT)      mapType(definitions.AnyRefClass, MOBJECT)      //mapType(definitions.AllRefClass, clrTypes.getType("scala.AllRef$"))      //mapType(definitions.AllClass, clrTypes.getType("scala.All$"))      // FIXME: for some reason the upper two lines map to null      mapType(definitions.AllRefClass, EXCEPTION)      mapType(definitions.AllClass, EXCEPTION)      val jEmpty = new Array[Type](0)      val jString1 = Array(JSTRING.tpe)      val jInt1 = Array(definitions.IntClass.tpe)      val jInt2 = Array(definitions.IntClass.tpe, definitions.IntClass.tpe)      val jLong1 = Array(definitions.LongClass.tpe)      val jStringInt = Array(JSTRING.tpe, definitions.IntClass.tpe)      val jChar2 = Array(definitions.CharClass.tpe, definitions.CharClass.tpe)      val mObject1 = Array(MOBJECT)      val mString1 = Array(MSTRING)      val mString2 = Array(MSTRING, MSTRING)      val mChar1 = Array(MCHAR)      val mCharInt = Array(MCHAR, MINT)      JSTRING_SUBSTRING_INT_INT = lookupMethod(JSTRING, "substring", jInt2)      mapMethod(JOBJECT, "clone", MOBJECT, "MemberwiseClone")      mapMethod(JOBJECT, nme.equals_, MOBJECT, "Equals")      mapMethod(JOBJECT, nme.hashCode_, MOBJECT, "GetHashCode")      mapMethod(JOBJECT, nme.toString_, MOBJECT, "ToString")      mapMethod(JOBJECT, nme.finalize_, MOBJECT, "Finalize")      mapMethod(JOBJECT, nme.wait_, jEmpty, MMONITOR, "Wait", mObject1)      mapMethod(JOBJECT, nme.wait_, jLong1, MMONITOR, "Wait", Array(MOBJECT, MINT))      mapMethod(JOBJECT, nme.notify_, jEmpty, MMONITOR, "Pulse", mObject1)      mapMethod(JOBJECT, nme.notifyAll_, jEmpty, MMONITOR, "PulseAll", mObject1)      mapMethod(JSTRING, "compareTo",MSTRING, "CompareTo")      mapMethod(JSTRING, "length", MSTRING, "get_Length")      mapMethod(JSTRING, "charAt", MSTRING, "get_Chars")      mapMethod(JSTRING, "concat", jString1, MSTRING, "Concat", mString2)      mapMethod(JSTRING, "indexOf", jInt1, MSTRING, "IndexOf", mChar1)      mapMethod(JSTRING, "indexOf", jInt2, MSTRING, "IndexOf", mCharInt)      mapMethod(JSTRING, "indexOf", jString1, MSTRING, "IndexOf")      mapMethod(JSTRING, "indexOf", jStringInt, MSTRING, "IndexOf")      mapMethod(JSTRING, "lastIndexOf", jInt1, MSTRING, "LastIndexOf", mChar1)      mapMethod(JSTRING, "lastIndexOf", jInt2, MSTRING, "LastIndexOf", mCharInt)      mapMethod(JSTRING, "lastIndexOf", jString1, MSTRING, "LastIndexOf")      mapMethod(JSTRING, "lastIndexOf", jStringInt, MSTRING, "LastIndexOf")      mapMethod(JSTRING, "toLowerCase", jEmpty, MSTRING, "ToLower")      mapMethod(JSTRING, "toUpperCase", jEmpty, MSTRING, "ToUpper")      mapMethod(JSTRING, "startsWith", jString1, MSTRING, "StartsWith")      mapMethod(JSTRING, "endsWith", jString1, MSTRING, "EndsWith")      mapMethod(JSTRING, "substring", jInt1, MSTRING, "Substring")      mapMethod(JSTRING, "substring", jInt2, MSTRING, "Substring")      mapMethod(JSTRING, "trim", jEmpty, MSTRING, "Trim")      mapMethod(JSTRING, "intern", jEmpty, MSTRING, "Intern", mString1)      mapMethod(JSTRING, "replace", jChar2, MSTRING, "Replace")      mapMethod(JSTRING, "toCharArray", MSTRING, "ToCharArray")      mapType(definitions.BooleanClass, MBOOL)      mapType(definitions.ByteClass, MBYTE)      mapType(definitions.ShortClass, MSHORT)      mapType(definitions.CharClass, MCHAR)      mapType(definitions.IntClass, MINT)      mapType(definitions.LongClass, MLONG)      mapType(definitions.FloatClass, MFLOAT)      mapType(definitions.DoubleClass, MDOUBLE)    }    var clasz: IClass = _    var method: IMethod = _    var code: Code = _    var massembly: AssemblyBuilder = _    var mmodule: ModuleBuilder = _    var mcode: ILGenerator = _    var assemName: String = _    var firstSourceName = ""    var outDir: File = _    def initAssembly() {      assemName = settings.assemname.value      if (assemName == "") {        if (entryPoint != null) {          assemName = msilName(entryPoint.enclClass)          // remove the $ at the end (from module-name)          assemName = assemName.substring(0, assemName.length() - 1)        } else {          // assuming filename of first source file          assert(firstSourceName.endsWith(".scala"), "Source file doesn't end with .scala")          assemName = firstSourceName.substring(0, firstSourceName.length() - 6)        }      } else {        if (assemName.endsWith(".msil"))          assemName = assemName.substring(0, assemName.length()-5)        if (assemName.endsWith(".il"))          assemName = assemName.substring(0, assemName.length()-3)        val f: File = new File(assemName)        outDir = f.getParentFile()        assemName = f.getName()      }      if (outDir == null)        outDir = new File(".")      val assemblyName = new AssemblyName()      assemblyName.Name = assemName      massembly = AssemblyBuilder.DefineDynamicAssembly(assemblyName)      val moduleName = assemName + (if (entryPoint == null) ".dll" else ".exe")      // filename here: .dll or .exe (in both parameters), second: give absolute-path      mmodule = massembly.DefineDynamicModule(moduleName,                                              new File(outDir, moduleName).getAbsolutePath())      assert (mmodule != null)      initMappings()    }    /**     * Form of the custom Attribute parameter (Ecma-335.pdf)     *      - p. 163 for CustomAttrib Form,     *      - p. 164 for FixedArg Form (Array and Element) (if array or not is known!)     *  !! least significant *byte* first if values longer than one byte !!     *     * 1: Prolog (unsigned int16, value 0x0001) -> symtab[0] = 0x01, symtab[1] = 0x00     * 2: FixedArgs (directly the data, get number and types from related constructor)     *  2.1: length of the array (unsigned int32, take care on order of the 4 bytes)     *  2.2: the byte array data     * 3: NumNamed (unsigned int16, number of named fields and properties, 0x0000)     *     **/    def addSymtabAttribute(sym: Symbol, tBuilder: TypeBuilder) {      currentRun.symData.get(sym) match {        case Some(pickle) =>          val symtab: Array[Byte] = new Array[Byte](pickle.writeIndex + 8)          symtab(0) = 1.toByte          var size:Int = pickle.writeIndex          for (i <- 2 until 6) {            symtab(i) = (size & 0xff).toByte            size = size >> 8          }          System.arraycopy(pickle.bytes, 0, symtab, 6, pickle.writeIndex)          tBuilder.SetCustomAttribute(SYMTAB_ATTRIBUTE_CONSTRUCTOR, symtab)          currentRun.symData -= sym          currentRun.symData -= sym.linkedSym          //log("Generated ScalaSig Attr for " + sym)//debug        case _ =>          log("Could not find pickle information for " + sym)      }    }    def addAttributes(member: ICustomAttributeSetter, attributes: List[AnnotationInfo]) {      return // FIXME      if (settings.debug.value)        log("creating attributes: " + attributes + " for member : " + member)      for (attr@ AnnotationInfo(typ, annArgs, nvPairs) <- attributes ;           if attr.isConstant)           /* !typ.typeSymbol.hasFlag(Flags.JAVA) */      {//        assert(consts.length <= 1,//               "too many constant arguments for attribute; "+consts.toString())        // Problem / TODO having the symbol of the attribute type would be nicer        // (i hope that type.typeSymbol is the same as the one in types2create)        // AND: this will crash if the attribute Type is already compiled (-> not a typeBuilder)        // when this is solved, types2create will be the same as icodes.classes, thus superfluous

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?