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