genmsil.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 1,568 行 · 第 1/5 页
SCALA
1,568 行
case NullTag => mcode.Emit(OpCodes.Ldnull) case ClassTag => mcode.Emit(OpCodes.Ldtoken, msilType(const.typeValue)) mcode.Emit(OpCodes.Call, TYPE_FROM_HANDLE) case _ => abort("Unknown constant value: " + const) } case LOAD_ARRAY_ITEM(kind) => (kind: @unchecked) match { case BOOL => mcode.Emit(OpCodes.Ldelem_I1) case BYTE => mcode.Emit(OpCodes.Ldelem_U1) case SHORT => mcode.Emit(OpCodes.Ldelem_I2) case CHAR => mcode.Emit(OpCodes.Ldelem_U2) case INT => mcode.Emit(OpCodes.Ldelem_I4) case LONG => mcode.Emit(OpCodes.Ldelem_I8) case FLOAT => mcode.Emit(OpCodes.Ldelem_R4) case DOUBLE => mcode.Emit(OpCodes.Ldelem_R8) case REFERENCE(cls) => mcode.Emit(OpCodes.Ldelem_Ref) // case ARRAY(elem) is not possible, for Array[Array[Int]], the // load will be case REFERENCE(java.lang.Object) // case UNIT is not possible: an Array[Unit] will be an // Array[scala.runtime.BoxedUnit] (-> case REFERENCE) } case LOAD_LOCAL(local) => if (settings.debug.value) log("load_local for " + local) val isArg: Boolean = local.arg val i = local.index if (isArg) { loadArg(mcode)(i) } else { loadLocal(i, local, mcode) } case LOAD_FIELD(field, isStatic) => if (settings.debug.value) log("LOAD_FIELD with owner: " + field.owner + " flags: " + Flags.flagsToString(field.owner.flags)) var fieldInfo: FieldInfo = fields.get(field.asInstanceOf[clrTypes.global.Symbol]) match { case Some(fInfo) => fInfo case None => val fInfo = getType(field.owner).GetField(msilName(field)) fields(field.asInstanceOf[clrTypes.global.Symbol]) = fInfo fInfo } mcode.Emit(if (isStatic) OpCodes.Ldsfld else OpCodes.Ldfld, fieldInfo) case LOAD_MODULE(module) => if (settings.debug.value) log("Generating LOAD_MODULE for: " + showsym(module)) mcode.Emit(OpCodes.Ldsfld, getModuleInstanceField(module)) case STORE_ARRAY_ITEM(kind) => (kind: @unchecked) match { case BOOL => mcode.Emit(OpCodes.Stelem_I1) case BYTE => mcode.Emit(OpCodes.Stelem_I1) case SHORT => mcode.Emit(OpCodes.Stelem_I2) case CHAR => mcode.Emit(OpCodes.Stelem_I2) case INT => mcode.Emit(OpCodes.Stelem_I4) case LONG => mcode.Emit(OpCodes.Stelem_I8) case FLOAT => mcode.Emit(OpCodes.Stelem_R4) case DOUBLE => mcode.Emit(OpCodes.Stelem_R8) case REFERENCE(cls) => mcode.Emit(OpCodes.Stelem_Ref) // case UNIT / ARRRAY are not possible (see comment at LOAD_ARRAY_ITEM) } case STORE_LOCAL(local) => val isArg: Boolean = local.arg val i = local.index if (settings.debug.value) log("store_local for " + local + ", index " + i) // there are some locals defined by the compiler that // are isArg and are need to be stored. if (isArg) { if (i >= -128 && i <= 127) mcode.Emit(OpCodes.Starg_S, i) else mcode.Emit(OpCodes.Starg, i) } else { i match { case 0 => mcode.Emit(OpCodes.Stloc_0) case 1 => mcode.Emit(OpCodes.Stloc_1) case 2 => mcode.Emit(OpCodes.Stloc_2) case 3 => mcode.Emit(OpCodes.Stloc_3) case _ => if (i >= -128 && i <= 127) mcode.Emit(OpCodes.Stloc_S, localBuilders(local)) else mcode.Emit(OpCodes.Stloc, localBuilders(local)) } } case STORE_THIS(_) => // this only works for impl classes because the self parameter comes first // in the method signature. If that changes, this code has to be revisited. mcode.Emit(OpCodes.Starg_S, 0) case STORE_FIELD(field, isStatic) => val fieldInfo: FieldInfo = fields.get(field.asInstanceOf[clrTypes.global.Symbol]) match { case Some(fInfo) => fInfo case None => val fInfo = getType(field.owner).GetField(msilName(field)) fields(field.asInstanceOf[clrTypes.global.Symbol]) = fInfo fInfo } mcode.Emit(if (isStatic) OpCodes.Stsfld else OpCodes.Stfld, fieldInfo) case CALL_PRIMITIVE(primitive) => genPrimitive(primitive, instr.pos) case CALL_METHOD(msym, style) => if (msym.isClassConstructor) { val constructorInfo: ConstructorInfo = getConstructor(msym) (style: @unchecked) match { // normal constructor calls are Static.. case Static(_) => if (method.symbol.isClassConstructor && method.symbol.owner == msym.owner) mcode.Emit(OpCodes.Call, constructorInfo) else mcode.Emit(OpCodes.Newobj, constructorInfo) case SuperCall(_) => mcode.Emit(OpCodes.Call, constructorInfo) if (isStaticModule(clasz.symbol) && notInitializedModules.contains(clasz.symbol)) { notInitializedModules -= clasz.symbol mcode.Emit(OpCodes.Ldarg_0) mcode.Emit(OpCodes.Stsfld, getModuleInstanceField(clasz.symbol)) } } } else { // java.lang.String.substring(int start_incl, int end_excl) // System.String.Substring(int start_incl, int length) if (msym == JSTRING_SUBSTRING_INT_INT) { val endLocal = mcode.DeclareLocal(MINT) endLocal.SetLocalSymInfo("$substring_end") mcode.Emit(OpCodes.Stloc, endLocal) mcode.Emit(OpCodes.Dup) // duplicate start_incl mcode.Emit(OpCodes.Neg) mcode.Emit(OpCodes.Ldloc, endLocal) // load end_excl mcode.Emit(OpCodes.Add) // compute length (-start + end) } var doEmit: Boolean = true types.get(msym.owner.asInstanceOf[clrTypes.global.Symbol]) match { case Some(typ) if (typ.IsEnum) => { def negBool = { mcode.Emit(OpCodes.Ldc_I4_0) mcode.Emit(OpCodes.Ceq) } doEmit = false val name = msym.name if (name eq nme.EQ) { mcode.Emit(OpCodes.Ceq) } else if (name eq nme.NE) { mcode.Emit(OpCodes.Ceq); negBool } else if (name eq nme.LT) { mcode.Emit(OpCodes.Clt) } else if (name eq nme.LE) { mcode.Emit(OpCodes.Cgt); negBool } else if (name eq nme.GT) { mcode.Emit(OpCodes.Cgt) } else if (name eq nme.GE) { mcode.Emit(OpCodes.Clt); negBool } else if (name eq nme.OR) { mcode.Emit(OpCodes.Or) } else if (name eq nme.AND) { mcode.Emit(OpCodes.And) } else if (name eq nme.XOR) { mcode.Emit(OpCodes.Xor) } else doEmit = true } case _ => () } // method: implicit view(FunctionX[PType0, PType1, ...,PTypeN, ResType]):DelegateType val (isDelegateView, paramType, resType) = atPhase(currentRun.typerPhase){ msym.tpe match { case MethodType(parameterTypes, resultType) if (parameterTypes.length == 1 && msym.name == nme.view_) => val isDel = definitions.isCorrespondingDelegate(resultType, parameterTypes(0)) (isDel, parameterTypes(0), resultType) case _ => (false, null, null) } } if (doEmit && isDelegateView) { doEmit = false createDelegateCaller(paramType, resType) } if (doEmit && (msym.name == nme.PLUS || msym.name == nme.MINUS) && clrTypes.isDelegateType(msilType(msym.owner.tpe))) { doEmit = false val methodInfo: MethodInfo = getMethod(msym) // call it as a static method, even if the compiler (symbol) thinks it's virtual mcode.Emit(OpCodes.Call, methodInfo) mcode.Emit(OpCodes.Castclass, msilType(msym.owner.tpe)) } if (doEmit && definitions.Delegate_scalaCallers.contains(msym)) { doEmit = false val methodSym: Symbol = definitions.Delegate_scalaCallerTargets(msym) val delegateType: Type = msym.tpe match { case MethodType(_, retType) => retType case _ => abort("not a method type: " + msym.tpe) } val method: MethodInfo = getMethod(methodSym) val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR)) if (methodSym.isStatic) { mcode.Emit(OpCodes.Ldftn, method) } else { mcode.Emit(OpCodes.Dup) mcode.Emit(OpCodes.Ldvirtftn, method) } mcode.Emit(OpCodes.Newobj, delegCtor) } if (doEmit) { val methodInfo: MethodInfo = getMethod(msym) style match { case SuperCall(_) => mcode.Emit(OpCodes.Call, methodInfo) case Dynamic => mcode.Emit(if (dynToStatMapped(msym)) OpCodes.Call else OpCodes.Callvirt, methodInfo) case Static(_) => mcode.Emit(OpCodes.Call, methodInfo) } } } case BOX(boxType) => emitBox(mcode, boxType) //mcode.Emit(OpCodes.Box, msilType(boxType)) case UNBOX(boxType) => emitUnbox(mcode, boxType) case NEW(REFERENCE(cls)) => ignoreNextDup = true // works also for arrays and reference-types case CREATE_ARRAY(elem, dims) => // TODO: handle multi dimensional arrays assert(dims == 1, "Can't handle multi dimensional arrays") mcode.Emit(OpCodes.Newarr, msilType(elem)) // works for arrays and reference-types case IS_INSTANCE(tpe) => mcode.Emit(OpCodes.Isinst, msilType(tpe)) mcode.Emit(OpCodes.Ldnull) mcode.Emit(OpCodes.Ceq) mcode.Emit(OpCodes.Ldc_I4_0) mcode.Emit(OpCodes.Ceq) // works for arrays and reference-types // part from the scala reference: "S <: T does not imply // Array[S] <: Array[T] in Scala. However, it is possible // to cast an array of S to an array of T if such a cast // is permitted in the host environment." case CHECK_CAST(tpe) => mcode.Emit(OpCodes.Castclass, msilType(tpe)) // no SWITCH is generated when there's // - a default case ("case _ => ...") in the matching expr // - OR is used ("case 1 | 2 => ...") case SWITCH(tags, branches) => // tags is List[List[Int]]; a list of integers for every label. // if the int on stack is 4, and 4 is in the second list => jump // to second label // branches is List[BasicBlock] // the labels to jump to (the last one ist the default one) val switchLocal = mcode.DeclareLocal(MINT) // several switch variables will appear with the same name in the // assembly code, but this makes no truble switchLocal.SetLocalSymInfo("$switch_var") mcode.Emit(OpCodes.Stloc, switchLocal) var i: Int = 0 for (l <- tags) { var targetLabel = labels(branches(i)) for (i <- l) { mcode.Emit(OpCodes.Ldloc, switchLocal) loadI4(i, mcode) mcode.Emit(OpCodes.Beq, targetLabel) } i += 1 } val defaultTarget = labels(branches(i)) if (nextBlock != defaultTarget && !omitJumpBlocks.contains(currentBlock)) mcode.Emit(OpCodes.Br, defaultTarget) case JUMP(whereto) => if (nextBlock != whereto && !omitJumpBlocks.contains(currentBlock)) mcode.Emit(OpCodes.Br, labels(whereto)) case CJUMP(success, failure, cond, kind) => // cond is TestOp (see Primitives.scala), and can take // values EQ, NE, LT, GE LE, GT // kind is TypeKind val isFloat = kind == FLOAT || kind == DOUBLE if (nextBlock == success || omitJumpBlocks.contains(currentBlock)) { emitBr(cond.negate, labels(failure), isFloat) } else { emitBr(cond, labels(success), isFloat) if (nextBlock != failure && !omitJumpBlocks.contains(c
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?