genjvm.scala

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

SCALA
1,594
字号
                  jcode.emitPUSH(-1)                  jcode.emitIXOR()                case LONG   =>                  jcode.emitPUSH(-1l)                  jcode.emitLXOR()                case _ =>                  abort("Impossible to negate an " + kind)              }            case _ =>              abort("Unknown arithmetic primitive " + primitive)          }        case Logical(op, kind) => (op, kind) match {          case (AND, LONG) =>            jcode.emitLAND()          case (AND, INT) =>            jcode.emitIAND()          case (AND, _) =>            jcode.emitIAND()            if (kind != BOOL)              jcode.emitT2T(javaType(INT), javaType(kind));          case (OR, LONG) =>            jcode.emitLOR()          case (OR, INT) =>            jcode.emitIOR()          case (OR, _) =>            jcode.emitIOR()            if (kind != BOOL)              jcode.emitT2T(javaType(INT), javaType(kind));          case (XOR, LONG) =>            jcode.emitLXOR()          case (XOR, INT) =>            jcode.emitIXOR()          case (XOR, _) =>            jcode.emitIXOR()            if (kind != BOOL)              jcode.emitT2T(javaType(INT), javaType(kind));        }        case Shift(op, kind) => (op, kind) match {          case (LSL, LONG) =>            jcode.emitLSHL()          case (LSL, INT) =>            jcode.emitISHL()          case (LSL, _) =>            jcode.emitISHL()            jcode.emitT2T(javaType(INT), javaType(kind))          case (ASR, LONG) =>            jcode.emitLSHR()          case (ASR, INT) =>            jcode.emitISHR()          case (ASR, _) =>            jcode.emitISHR()            jcode.emitT2T(javaType(INT), javaType(kind))          case (LSR, LONG) =>            jcode.emitLUSHR()          case (LSR, INT) =>            jcode.emitIUSHR()          case (LSR, _) =>            jcode.emitIUSHR()            jcode.emitT2T(javaType(INT), javaType(kind))        }        case Comparison(op, kind) => ((op, kind): @unchecked) match {          case (CMP, LONG)    => jcode.emitLCMP()          case (CMPL, FLOAT)  => jcode.emitFCMPL()          case (CMPG, FLOAT)  => jcode.emitFCMPG()          case (CMPL, DOUBLE) => jcode.emitDCMPL()          case (CMPG, DOUBLE) => jcode.emitDCMPL()        }        case Conversion(src, dst) =>          if (settings.debug.value)            log("Converting from: " + src + " to: " + dst);          if (dst == BOOL) {            Console.println("Illegal conversion at: " + clasz +                            " at: " + pos.source.get + ":" + pos.line.getOrElse(-1));          } else            jcode.emitT2T(javaType(src), javaType(dst));        case ArrayLength(_) =>          jcode.emitARRAYLENGTH()        case StartConcat =>          jcode.emitNEW(StringBuilderClass)          jcode.emitDUP()          jcode.emitINVOKESPECIAL(StringBuilderClass,                                  JMethod.INSTANCE_CONSTRUCTOR_NAME,                                  JMethodType.ARGLESS_VOID_FUNCTION)        case StringConcat(el) =>          val jtype = el match {            case REFERENCE(_) | ARRAY(_)=> JObjectType.JAVA_LANG_OBJECT            case _ => javaType(el)          }          jcode.emitINVOKEVIRTUAL(StringBuilderClass,                                  "append",                                  new JMethodType(StringBuilderType,                                  Array(jtype)))        case EndConcat =>          jcode.emitINVOKEVIRTUAL(StringBuilderClass,                                  "toString",                                  toStringType)        case _ =>          abort("Unimplemented primitive " + primitive)      }    }    /** For each basic block, the first PC address following it. */    val endPC: HashMap[BasicBlock, Int] = new HashMap()    val labels: HashMap[BasicBlock, JCode$Label] = new HashMap()    val conds: HashMap[TestOp, Int] = new HashMap()    conds += (EQ -> JExtendedCode.COND_EQ)    conds += (NE -> JExtendedCode.COND_NE)    conds += (LT -> JExtendedCode.COND_LT)    conds += (GT -> JExtendedCode.COND_GT)    conds += (LE -> JExtendedCode.COND_LE)    conds += (GE -> JExtendedCode.COND_GE)    val negate: HashMap[TestOp, TestOp] = new HashMap()    negate += (EQ -> NE)    negate += (NE -> EQ)    negate += (LT -> GE)    negate += (GT -> LE)    negate += (LE -> GT)    negate += (GE -> LT)    /** Map from type kinds to the Java reference types. It is used for     *  loading class constants. @see Predef.classOf. */    val classLiteral: Map[TypeKind, JObjectType] = new HashMap()    classLiteral += (UNIT   -> new JObjectType("java.lang.Void"))    classLiteral += (BOOL   -> new JObjectType("java.lang.Boolean"))    classLiteral += (BYTE   -> new JObjectType("java.lang.Byte"))    classLiteral += (SHORT  -> new JObjectType("java.lang.Short"))    classLiteral += (CHAR   -> new JObjectType("java.lang.Character"))    classLiteral += (INT    -> new JObjectType("java.lang.Integer"))    classLiteral += (LONG   -> new JObjectType("java.lang.Long"))    classLiteral += (FLOAT  -> new JObjectType("java.lang.Float"))    classLiteral += (DOUBLE -> new JObjectType("java.lang.Double"))    def makeLabels(bs: List[BasicBlock]) {      //labels.clear      if (settings.debug.value)        log("Making labels for: " + method);      bs foreach (bb => labels += (bb -> jcode.newLabel()) )    }    ////////////////////// local vars ///////////////////////    def sizeOf(sym: Symbol): Int = sizeOf(toTypeKind(sym.tpe))    def sizeOf(k: TypeKind): Int = k match {      case DOUBLE | LONG => 2      case _ => 1    }    def indexOf(m: IMethod, sym: Symbol): Int = {      val Some(local) = m.lookupLocal(sym)      indexOf(local)    }    def indexOf(local: Local): Int = {      assert(local.index >= 0,             "Invalid index for: " + local + "{" + local.hashCode + "}: ")      local.index    }    /**     * Compute the indexes of each local variable of the given     * method. Assumes parameters come first in the list of locals.     */    def computeLocalVarsIndex(m: IMethod) {      var idx = 1      if (isStaticSymbol(m.symbol))        idx = 0;      for (l <- m.locals) {        if (settings.debug.value)          log("Index value for " + l + "{" + l.hashCode + "}: " + idx)        l.index = idx        idx += sizeOf(l.kind)      }    }    ////////////////////// Utilities ////////////////////////    /**     * <p>     *   Return the a name of this symbol that can be used on the Java     *   platform. It removes spaces from names.     * </p>     * <p>     *   Special handling: scala.Nothing and <code>scala.Null</code> are     *   <em>erased</em> to <code>scala.runtime.Nothing$</code> and     *   </code>scala.runtime.Null$</code>. This is needed because they are     *   not real classes, and they mean 'abrupt termination upon evaluation     *   of that expression' or <code>null</code> respectively. This handling is      *   done already in <a href="../icode/GenIcode.html" target="contentFrame">     *   <code>GenICode</code></a>, but here we need to remove references     *   from method signatures to these types, because such classes can      *   not exist in the classpath: the type checker will be very confused.     * </p>     */    def javaName(sym: Symbol): String = {      val suffix = if (sym.hasFlag(Flags.MODULE) && !sym.isMethod &&                        !sym.isImplClass &&                         !sym.hasFlag(Flags.JAVA)) "$" else "";      if (sym == definitions.AllClass)        return "scala.runtime.Nothing$"      else if (sym == definitions.AllRefClass)        return "scala.runtime.Null$"      if (sym.isClass && !sym.rawowner.isPackageClass)        innerClasses = innerClasses + sym;      (if (sym.isClass || (sym.isModule && !sym.isMethod))        sym.fullNameString('/')      else        sym.simpleName.toString.trim()) + suffix    }    def javaNames(syms: List[Symbol]): Array[String] = {      val res = new Array[String](syms.length)      var i = 0      syms foreach (s => { res(i) = javaName(s); i += 1 })      res    }    /**     * Return the Java modifiers for the given symbol.     * Java modifiers for classes:     *  - public, abstract, final, strictfp (not used)     * for interfaces:     *  - the same as for classes, without 'final'     * for fields:     *  - public, private (*)     *  - static, final      * for methods:     *  - the same as for fields, plus:     *  - abstract, synchronized (not used), strictfp (not used), native (not used)     *      *  (*) protected cannot be used, since inner classes 'see' protected members,     *      and they would fail verification after lifted.     */    def javaFlags(sym: Symbol): Int = {      import JAccessFlags._      var jf: Int = 0      val f = sym.flags      jf = jf | (if (sym hasFlag Flags.SYNTHETIC) ACC_SYNTHETIC else 0)/*      jf = jf | (if (sym hasFlag Flags.PRIVATE) ACC_PRIVATE else                   if (sym hasFlag Flags.PROTECTED) ACC_PROTECTED else ACC_PUBLIC)*/      jf = jf | (if (sym hasFlag Flags.PRIVATE) ACC_PRIVATE else  ACC_PUBLIC)      jf = jf | (if ((sym hasFlag Flags.ABSTRACT) ||                     (sym hasFlag Flags.DEFERRED)) ACC_ABSTRACT else 0)      jf = jf | (if (sym hasFlag Flags.INTERFACE) ACC_INTERFACE else 0)      jf = jf | (if ((sym hasFlag Flags.FINAL)                       && !sym.enclClass.hasFlag(Flags.INTERFACE)                        && !sym.isClassConstructor) ACC_FINAL else 0)      jf = jf | (if (isStaticSymbol(sym)) ACC_STATIC else 0)      if (settings.target.value == "jvm-1.5")        jf = jf | (if (sym hasFlag Flags.BRIDGE) ACC_BRIDGE else 0)      if (sym.isClass && !sym.hasFlag(Flags.INTERFACE))        jf = jf | ACC_SUPER      jf    }    def isStaticSymbol(s: Symbol): Boolean =      s.hasFlag(Flags.STATIC) || s.hasFlag(Flags.STATICMEMBER) || s.owner.isImplClass;    /** Calls to methods in 'sym' need invokeinterface? */    def needsInterfaceCall(sym: Symbol): Boolean =      sym.hasFlag(Flags.INTERFACE) ||      (sym.hasFlag(Flags.JAVA) &&       sym.isNonBottomSubClass(definitions.ClassfileAnnotationClass))    def javaType(t: TypeKind): JType = (t: @unchecked) match {      case UNIT            => JType.VOID      case BOOL            => JType.BOOLEAN      case BYTE            => JType.BYTE      case SHORT           => JType.SHORT      case CHAR            => JType.CHAR      case INT             => JType.INT      case LONG            => JType.LONG      case FLOAT           => JType.FLOAT      case DOUBLE          => JType.DOUBLE      case REFERENCE(cls)  => new JObjectType(javaName(cls))      case ARRAY(elem)     => new JArrayType(javaType(elem))    }    def javaType(t: Type): JType = javaType(toTypeKind(t))    def javaType(s: Symbol): JType =      if (s.isMethod)        new JMethodType(          if (s.isClassConstructor) JType.VOID else javaType(s.tpe.resultType),          s.tpe.paramTypes.map(javaType).toArray)      else        javaType(s.tpe)    def javaTypes(ts: List[TypeKind]): Array[JType] = {      val res = new Array[JType](ts.length)      var i = 0      ts foreach ( t => { res(i) = javaType(t); i += 1 } );      res    }    def getFile(cls: JClass, suffix: String): String = {      val path = cls.getName().replace('.', File.separatorChar)      settings.outdir.value + File.separatorChar + path + suffix    }    /** Emit a Local variable table for debugging purposes.     *  Synthetic locals are skipped. All variables are method-scoped.     */    private def genLocalVariableTable(m: IMethod) {        var vars = m.locals.filter(l => !l.sym.hasFlag(Flags.SYNTHETIC))        if (vars.length == 0) return        val pool = jclass.getConstantPool()        val pc = jcode.getPC()        var anonCounter = 0        var entries = 0        vars.foreach { lv =>          lv.ranges = mergeEntries(lv.ranges.reverse);          entries += lv.ranges.length        }        if (!jmethod.isStatic()) entries += 1        val lvTab = ByteBuffer.allocate(2 + 10 * entries)        def emitEntry(name: String, signature: String, idx: Short, start: Short, end: Short) {          lvTab.putShort(start)          lvTab.putShort(end)          lvTab.putShort(pool.addUtf8(name).asInstanceOf[Short])          lvTab.putShort(pool.addUtf8(signature).asInstanceOf[Short])          lvTab.putShort(idx)        }        lvTab.putShort(entries.asInstanceOf[Short])        if (!jmethod.isStatic()) {          emitEntry("this", jclass.getType().getSignature(), 0, 0.asInstanceOf[Short], pc.asInstanceOf[Short])        }        for (lv <- vars) {            val name = if (javaName(lv.sym) eq null) {              anonCounter += 1              "<anon" + anonCounter + ">"            } else javaName(lv.sym)            val index = indexOf(lv).asInstanceOf[Short]            val tpe   = javaType(lv.kind).getSignature()            for ((start, end) <- lv.ranges) {              emitEntry(name, tpe, index, start.asInstanceOf[Short], (end - start).asInstanceOf[Short])            }        }        val attr =            fjbgContext.JOtherAttribute(jclass,                                        jmethod,                                        "LocalVariableTable",                                        lvTab.array())        jcode.addAttribute(attr)    }        /** Merge adjacent ranges. */    private def mergeEntries(ranges: List[(Int, Int)]): List[(Int, Int)] =       (ranges.foldLeft(Nil: List[(Int, Int)]) { (collapsed: List[(Int, Int)], p: (Int, Int)) => (collapsed, p) match {        case (Nil, _) => List(p)        case ((s1, e1) :: rest, (s2, e2)) if (e1 == s2) => (s1, e2) :: rest        case _ => p :: collapsed      }}).reverse    def assert(cond: Boolean, msg: String) = if (!cond) {      method.dump      throw new Error(msg + "\nMethod: " + method)    }    def assert(cond: Boolean) { assert(cond, "Assertion failed.") }  }}

⌨️ 快捷键说明

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