genmsil.scala

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

SCALA
1,568
字号
        val attrType: TypeBuilder = getType(typ.typeSymbol).asInstanceOf[TypeBuilder]//        val attrType: MsilType = getType(typ.typeSymbol)        // Problem / TODO: i have no idea which constructor is used. This        // information should be available in AnnotationInfo.        attrType.CreateType() // else, GetConstructors can't be used        val constr: ConstructorInfo = attrType.GetConstructors()(0)        // prevent a second call of CreateType, only needed because there's no        // otehr way than GetConstructors()(0) to get the constructor, if there's        // no constructor symbol available.        val args: Array[Byte] =          getAttributeArgs(            annArgs map (_.constant.get),            (for((n,v) <- nvPairs) yield (n, v.constant.get)))        member.SetCustomAttribute(constr, args)      }    }    def getAttributeArgs(consts: List[Constant], nvPairs: List[(Name, Constant)]): Array[Byte] = {      val buf = ByteBuffer.allocate(2048) // FIXME: this may be not enough!      buf.order(ByteOrder.LITTLE_ENDIAN)      buf.putShort(1.toShort) // signature      def emitSerString(str: String) = {          // this is wrong, it has to be the length of the UTF-8 byte array, which          // may be longer (see clr-book on page 302)//          val length: Int = str.length            val strBytes: Array[Byte] = try {              str.getBytes("UTF-8")            } catch {              case _: Error => abort("could not get byte-array for string: " + str)            }            val length: Int = strBytes.length //this length is stored big-endian            if (length < 128)              buf.put(length.toByte)            else if (length < (1<<14)) {              buf.put(((length >> 8) | 0x80).toByte) // the bits 14 and 15 of length are '0'              buf.put((length | 0xff).toByte)            } else if (length < (1 << 29)) {              buf.put(((length >> 24) | 0xc0).toByte)              buf.put(((length >> 16) & 0xff).toByte)              buf.put(((length >>  8) & 0xff).toByte)              buf.put(((length      ) & 0xff).toByte)            } else              abort("string too long for attribute parameter: " + length)            buf.put(strBytes)      }      def emitConst(const: Constant): Unit = const.tag match {        case BooleanTag => buf.put((if (const.booleanValue) 1 else 0).toByte)        case ByteTag => buf.put(const.byteValue)        case ShortTag => buf.putShort(const.shortValue)        case CharTag => buf.putChar(const.charValue)        case IntTag => buf.putInt(const.intValue)        case LongTag => buf.putLong(const.longValue)        case FloatTag => buf.putFloat(const.floatValue)        case DoubleTag => buf.putDouble(const.doubleValue)        case StringTag =>          val str: String = const.stringValue          if (str == null) {            buf.put(0xff.toByte)          } else {            emitSerString(str)          }        case ArrayTag =>          val arr: Array[Constant] = const.arrayValue          if (arr == null) {            buf.putInt(0xffffffff)          } else {            buf.putInt(arr.length)            arr.foreach(emitConst)          }        // TODO: other Tags: NoTag, UnitTag, ClassTag, EnumTag, ArrayTag ???        case _ => abort("could not handle attribute argument: " + const)      }      consts foreach emitConst      buf.putShort(nvPairs.length.toShort)      def emitNamedArg(nvPair: (Name, Constant)) {        // the named argument is a property of the attribute (it can't be a field, since        //  all fields in scala are private)        buf.put(0x54.toByte)        def emitType(c: Constant) = c.tag match { // type of the constant, Ecma-335.pdf, page 151          case BooleanTag => buf.put(0x02.toByte)          case ByteTag =>    buf.put(0x05.toByte)          case ShortTag =>   buf.put(0x06.toByte)          case CharTag =>    buf.put(0x07.toByte)          case IntTag =>     buf.put(0x08.toByte)          case LongTag =>    buf.put(0x0a.toByte)          case FloatTag =>   buf.put(0x0c.toByte)          case DoubleTag =>  buf.put(0x0d.toByte)          case StringTag =>  buf.put(0x0e.toByte)          // TODO: other Tags: NoTag, UnitTag, ClassTag, EnumTag ???          // ArrayTag falls in here          case _ => abort("could not handle attribute argument: " + c)        }        val cnst: Constant = nvPair._2        if (cnst.tag == ArrayTag) {          buf.put(0x1d.toByte)          emitType(cnst.arrayValue(0)) // FIXME: will crash if array length = 0        } else if (cnst.tag == EnumTag) {          buf.put(0x55.toByte)          // TODO: put a SerString (don't know what exactly, names of the enums somehow..)              } else {          buf.put(0x51.toByte)          emitType(cnst)        }        emitSerString(nvPair._1.toString)        emitConst(nvPair._2)      }      val length = buf.position()      buf.array().subArray(0, length)    }    def writeAssembly() {      if (entryPoint != null) {        assert(entryPoint.enclClass.isModuleClass, "main-method not defined in a module")        val mainMethod = methods(entryPoint.asInstanceOf[clrTypes.global.Symbol])        val stringArrayTypes: Array[MsilType] = Array(MSTRING_ARRAY)        val globalMain = mmodule.DefineGlobalMethod(          "Main", MethodAttributes.Public | MethodAttributes.Static,          MVOID, stringArrayTypes)        globalMain.DefineParameter(0, ParameterAttributes.None, "args")        massembly.SetEntryPoint(globalMain)        val code = globalMain.GetILGenerator()        val moduleField = getModuleInstanceField(entryPoint.enclClass)        code.Emit(OpCodes.Ldsfld, moduleField)        code.Emit(OpCodes.Ldarg_0)        code.Emit(OpCodes.Callvirt, mainMethod)        code.Emit(OpCodes.Ret)      }      createTypes()      val filename = new File(outDir, assemName + ".msil").getPath()      if (settings.debug.value)        log("Output file name: " + filename)      try {        massembly.Save(filename)        val ilasm = Properties.msilILasm        if (ilasm != "") {          val cmd = ilasm + " " + filename          if (settings.debug.value)            log("Executing command: " + cmd)          try {            Runtime.getRuntime().exec(cmd)          } catch {            case _ =>              Console.println("Cannot run command: " + cmd)              exit(1)          }        }      } catch {        case _: Error => abort("Could not save file " + filename)      }    }    private def createTypes() {      for (sym <- classes.keys) {        if (settings.debug.value)          log("Calling CreatType for " +  sym + ", " + types(sym.asInstanceOf[clrTypes.global.Symbol]))        types(sym.asInstanceOf[clrTypes.global.Symbol]).asInstanceOf[TypeBuilder].CreateType()      }    }    private[GenMSIL] def genClass(iclass: IClass) {      val sym = iclass.symbol      if (settings.debug.value)        log("Generating class " + sym + " flags: " + Flags.flagsToString(sym.flags))      clasz = iclass      val tBuilder = getType(sym).asInstanceOf[TypeBuilder]      if (isCloneable(sym)){        // FIXME: why there's no nme.clone_ ?        // "Clone": if the code is non-portable, "Clone" is defined, not "clone"        // TODO: improve condition (should override AnyRef.clone)        if (iclass.methods.forall(m => {          !((m.symbol.name.toString() != "clone" || m.symbol.name.toString() != "Clone") &&            m.symbol.tpe.paramTypes.length != 0)        })) {          if (settings.debug.value)            log("auto-generating cloneable method for " + sym)          val attrs: Short = (MethodAttributes.Public | MethodAttributes.Virtual |                              MethodAttributes.HideBySig)          val cloneMethod = tBuilder.DefineMethod("Clone", attrs, MOBJECT,                                                  MsilType.EmptyTypes)          val clCode = cloneMethod.GetILGenerator()          clCode.Emit(OpCodes.Ldarg_0)          clCode.Emit(OpCodes.Call, MEMBERWISE_CLONE)          clCode.Emit(OpCodes.Ret)        }      }      val line = (sym.pos).line match {        case Some(l) => l        case None => 0      }      tBuilder.setPosition(line, iclass.cunit.source.file.name)      if (isTopLevelModule(sym)) {        if (settings.debug.value)          log("TopLevelModule: " + sym)        if (sym.linkedClassOfModule == NoSymbol) {          if (settings.debug.value)            log(" no linked class: " + sym)          dumpMirrorClass(sym)        } else if (!currentRun.compiles(sym.linkedClassOfModule)) {          if (settings.debug.value)            log(" not compiling linked class: " + sym)          dumpMirrorClass(sym)        }      }      // the pickling info is not written to the module class, but to it's      // linked class (the mirror class eventually dumped)      if (!(tBuilder.Name.endsWith("$") && sym.isModuleClass)){        // think the if inside could be removed, because in this case, addSymtabAttribute is        // called in the dumpMirrorClass method        addSymtabAttribute(if (isTopLevelModule(sym)) sym.sourceModule else sym, tBuilder)        // TODO: remove; check the above think:        assert(!isTopLevelModule(sym), "can't remove the 'if'")      }      addAttributes(tBuilder, sym.attributes)      if (iclass.symbol != definitions.ArrayClass)        iclass.methods foreach genMethod    } //genClass    private def genMethod(m: IMethod) {      if (settings.debug.value)        log("Generating method " + m.symbol + " flags: " + Flags.flagsToString(m.symbol.flags) +            " owner: " + m.symbol.owner)      method = m      localBuilders.clear      computeLocalVarsIndex(m)      if (m.symbol.isClassConstructor){        mcode = constructors(m.symbol.asInstanceOf[clrTypes.global.Symbol]).asInstanceOf[ConstructorBuilder].GetILGenerator()      } else {        val mBuilder = methods(m.symbol.asInstanceOf[clrTypes.global.Symbol]).asInstanceOf[MethodBuilder]        if (!mBuilder.IsAbstract())          try {            mcode = mBuilder.GetILGenerator()          } catch {            case e: Exception =>              System.out.println("m.symbol       = " + Flags.flagsToString(m.symbol.flags) + " " + m.symbol)              System.out.println("m.symbol.owner = " + Flags.flagsToString(m.symbol.owner.flags) + " " + m.symbol.owner)              System.out.println("mBuilder       = " + mBuilder)              System.out.println("mBuilder.DeclaringType = " +                                 TypeAttributes.toString(mBuilder.DeclaringType.Attributes) +                                 "::" + mBuilder.DeclaringType)              throw e          }          else            mcode = null      }      if (mcode != null) {        for (local <- m.locals -- m.params) {          if (settings.debug.value)            log("add local var: " + local + ", of kind " + local.kind)          val t: MsilType = msilType(local.kind)          val localBuilder = mcode.DeclareLocal(t)          localBuilder.SetLocalSymInfo(msilName(local.sym))          localBuilders(local) = localBuilder        }        genCode(m)      }    }    var linearization: List[BasicBlock] = Nil    // a "ret" instruction is needed (which is not present in    //  icode) if there's no code after a try-catch block    var needAdditionalRet: Boolean = false    def genCode(m: IMethod) {      code = m.code      labels.clear      linearization = linearizer.linearize(m)      val orderedBlocks = (if (m.exh != Nil) orderBlocksForExh(linearization, m.exh)                           else linearization)      makeLabels(orderedBlocks) // orderBlocksForExh may create new Blocks -> new Labels      genBlocks(orderedBlocks)      if (needAdditionalRet) {        mcode.Emit(OpCodes.Ret)        needAdditionalRet = false      }    }    abstract class ExHInstruction(handler: ExceptionHandler) { }    case class BeginExceptionBlock(handler: ExceptionHandler) extends ExHInstruction(handler)    case class BeginCatchBlock(handler: ExceptionHandler, exceptionType: MsilType) extends ExHInstruction(handler)    case class BeginFinallyBlock(handler: ExceptionHandler) extends ExHInstruction(handler)    case class EndExceptionBlock(handler: ExceptionHandler) extends ExHInstruction(handler)    abstract class Block {      var closed: Boolean = false      def parentBlockList: Option[BlockList0]      def firstBasicBlock: BasicBlock

⌨️ 快捷键说明

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