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 + -
显示快捷键?