genjvm.scala

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

SCALA
1,594
字号
      val attributes = for (attrs <- pattrss) yield        for (attr @ AnnotationInfo(tpe, _, _) <- attrs;             if attr.isConstant;             if tpe.typeSymbol isNonBottomSubClass definitions.ClassfileAnnotationClass) yield attr;      if (attributes.forall(_.isEmpty)) return;      val buf: ByteBuffer = ByteBuffer.allocate(2048)      // number of parameters      buf.put(attributes.length.toByte)      for (attrs <- attributes)        emitAttributes(jmethod.getConstantPool, buf, attrs)      addAttribute(jmethod, nme.RuntimeParamAnnotationATTR, buf)    }    def addAttribute(jmember: JMember, name: Name, buf: ByteBuffer) {      if (buf.position() <= 2)        return      val length = buf.position();      val arr = buf.array().subArray(0, length);      val attr = jmember.getContext().JOtherAttribute(jmember.getJClass(),                                                      jmember,                                                      name.toString,                                                      arr,                                                      length)      jmember.addAttribute(attr)    }    def addInnerClasses {      // add inner classes which might not have been referenced yet      atPhase(currentRun.erasurePhase) {        for (sym <- clasz.symbol.info.decls.elements if sym.isClass)          innerClasses = innerClasses + sym;      }      if (!innerClasses.isEmpty) {        val innerClassesAttr = jclass.getInnerClasses()        // sort them so inner classes succeed their enclosing class        // to satisfy the Eclipse Java compiler        for (innerSym <- innerClasses.toList.sort(_.name.length < _.name.length)) {          var outerName = javaName(innerSym.rawowner)          // remove the trailing '$'          if (outerName.endsWith("$"))             outerName = outerName.substring(0, outerName.length - 1)          innerClassesAttr.addEntry(javaName(innerSym),              outerName,              innerSym.rawname.toString,              javaFlags(innerSym));        }      }    }    def isTopLevelModule(sym: Symbol): Boolean =      atPhase (currentRun.refchecksPhase) {        sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass      }    def isStaticModule(sym: Symbol): Boolean = {      sym.isModuleClass && !sym.isImplClass && !sym.hasFlag(Flags.LIFTED)    }    def genField(f: IField) {      if (settings.debug.value)        log("Adding field: " + f.symbol.fullNameString);      var attributes = 0      f.symbol.attributes foreach { a => a match {        case AnnotationInfo(tp, _, _) if tp.typeSymbol == TransientAtt =>          attributes = attributes | JAccessFlags.ACC_TRANSIENT        case AnnotationInfo(tp, _, _) if tp.typeSymbol == VolatileAttr =>          attributes = attributes | JAccessFlags.ACC_VOLATILE        case _ => ();      }}      var flags = javaFlags(f.symbol)      if (!f.symbol.hasFlag(Flags.MUTABLE))         flags = flags | JAccessFlags.ACC_FINAL            val jfield =        jclass.addNewField(flags | attributes,                           javaName(f.symbol),                           javaType(f.symbol.tpe));      addAnnotations(jfield, f.symbol.attributes)    }    def genMethod(m: IMethod) {      log("Generating method " + m.symbol.fullNameString)      method = m      endPC.clear      computeLocalVarsIndex(m)      var resTpe = javaType(m.symbol.tpe.resultType)      if (m.symbol.isClassConstructor)        resTpe = JType.VOID;      var flags = javaFlags(m.symbol)      if (jclass.isInterface())        flags = flags | JAccessFlags.ACC_ABSTRACT;            // native methods of objects are generated in mirror classes      if (method.native)        flags = flags | JAccessFlags.ACC_NATIVE      jmethod = jclass.addNewMethod(flags,                                    javaName(m.symbol),                                    resTpe,                                    javaTypes(m.params map (_.kind)),                                    javaNames(m.params map (_.sym)));      if (m.symbol.hasFlag(Flags.BRIDGE) && settings.target.value == "jvm-1.4") {        jmethod.addAttribute(fjbgContext.JOtherAttribute(jclass, jmethod, "Bridge",                                                         new Array[Byte](0)))      }      if (remoteClass ||          (m.symbol.hasAttribute(RemoteAttr) && jmethod.isPublic() && !forCLDC)) {          val ainfo = AnnotationInfo(ThrowsAttr.tpe, List(new AnnotationArgument(Constant(RemoteException))), List())           m.symbol.attributes = ainfo :: m.symbol.attributes;        }      if (!jmethod.isAbstract() && !method.native) {        jcode = jmethod.getCode().asInstanceOf[JExtendedCode]        // add a fake local for debugging purpuses        if (emitVars && isClosureApply(method.symbol)) {          val outerField = clasz.symbol.info.decl(nme.getterToLocal(nme.OUTER))          if (outerField != NoSymbol) {            log("Adding fake local to represent outer 'this' for closure " + clasz)            val _this = new Local(              method.symbol.newVariable(NoPosition, "this$"), toTypeKind(outerField.tpe), false)            m.locals = m.locals ::: List(_this)            computeLocalVarsIndex(m) // since we added a new local, we need to recompute indexes            jcode.emitALOAD_0            jcode.emitGETFIELD(javaName(clasz.symbol),                               javaName(outerField),                               javaType(outerField))            jcode.emitSTORE(indexOf(_this), javaType(_this.kind))          }        }        for (val local <- m.locals; (! m.params.contains(local))) {          if (settings.debug.value)            log("add local var: " + local);          jmethod.addNewLocalVariable(javaType(local.kind), javaName(local.sym))        }        genCode(m)        if (emitVars)          genLocalVariableTable(m);      }            val (excs, others) = splitAnnotations(m.symbol.attributes, ThrowsAttr)      addExceptionsAttribute(jmethod, excs)      addAnnotations(jmethod, others)      addParamAnnotations(m.params.map(_.sym.attributes))    }        /** Return a pair of lists of annotations, first one containing all      *  annotations for the given symbol, and the rest.     */    private def splitAnnotations(annotations: List[AnnotationInfo], annotSym: Symbol): (List[AnnotationInfo], List[AnnotationInfo]) = {      annotations.partition { a => a match {        case AnnotationInfo(tp, _, _) if tp.typeSymbol == annotSym => true        case _ => false      }}    }    private def isClosureApply(sym: Symbol): Boolean = {      (sym.name == nme.apply) &&      sym.owner.hasFlag(Flags.SYNTHETIC) &&      sym.owner.tpe.parents.exists { t =>         val TypeRef(_, sym, _) = t;        definitions.FunctionClass exists sym.==      }    }    def addModuleInstanceField {      import JAccessFlags._      jclass.addNewField(ACC_PUBLIC | ACC_FINAL | ACC_STATIC,                        nme.MODULE_INSTANCE_FIELD.toString,                        jclass.getType())    }    def addStaticInit(cls: JClass) {      import JAccessFlags._      val clinitMethod = cls.addNewMethod(ACC_PUBLIC | ACC_STATIC,                                          "<clinit>",                                          JType.VOID,                                          JType.EMPTY_ARRAY,                                          new Array[String](0))      val clinit = clinitMethod.getCode().asInstanceOf[JExtendedCode]      if (isStaticModule(clasz.symbol)) {        clinit.emitNEW(cls.getName())        clinit.emitINVOKESPECIAL(cls.getName(),                                 JMethod.INSTANCE_CONSTRUCTOR_NAME,                                 JMethodType.ARGLESS_VOID_FUNCTION)      }      serialVUID match {        case Some(value) =>          val fieldName = "serialVersionUID"          jclass.addNewField(JAccessFlags.ACC_STATIC | JAccessFlags.ACC_PUBLIC | JAccessFlags.ACC_FINAL,                             fieldName,                             JType.LONG)          clinit.emitPUSH(value)          clinit.emitPUTSTATIC(jclass.getName(), fieldName, JType.LONG)        case None => ()      }      clinit.emitRETURN()    }    def dumpMirrorClass {      import JAccessFlags._      assert(clasz.symbol.isModuleClass)      if (settings.debug.value)        log("Dumping mirror class for object: " + clasz);      val moduleName = javaName(clasz.symbol) // + "$"      val mirrorName = moduleName.substring(0, moduleName.length() - 1)      val mirrorClass = fjbgContext.JClass(ACC_SUPER | ACC_PUBLIC | ACC_FINAL,                                           mirrorName,                                           "java.lang.Object",                                           JClass.NO_INTERFACES,                                           clasz.cunit.source.toString)      for (val m <- clasz.symbol.tpe.nonPrivateMembers;           m.owner != definitions.ObjectClass && !m.hasFlag(Flags.PROTECTED) &&           m.isMethod && !m.hasFlag(Flags.CASE) && !m.isConstructor && !isStaticSymbol(m) &&           !definitions.ObjectClass.info.nonPrivateMembers.exists(_.name == m.name))      {        val paramJavaTypes = m.tpe.paramTypes map (t => toTypeKind(t));        val paramNames: Array[String] = new Array[String](paramJavaTypes.length);        for (val i <- 0.until(paramJavaTypes.length))          paramNames(i) = "x_" + i        val mirrorMethod = mirrorClass        .addNewMethod(ACC_PUBLIC | ACC_FINAL | ACC_STATIC,                      javaName(m),                      javaType(m.tpe.resultType),                      javaTypes(paramJavaTypes),                      paramNames);        val mirrorCode = mirrorMethod.getCode().asInstanceOf[JExtendedCode];        mirrorCode.emitGETSTATIC(moduleName,                                 nme.MODULE_INSTANCE_FIELD.toString,                                 new JObjectType(moduleName));        var i = 0        var index = 0        var argTypes = mirrorMethod.getArgumentTypes()        while (i < argTypes.length) {          mirrorCode.emitLOAD(index, argTypes(i))          index = index + argTypes(i).getSize()          i += 1        }        mirrorCode.emitINVOKEVIRTUAL(moduleName, mirrorMethod.getName(), mirrorMethod.getType().asInstanceOf[JMethodType])        mirrorCode.emitRETURN(mirrorMethod.getReturnType())        val (throws, others) = splitAnnotations(m.attributes, ThrowsAttr)        addExceptionsAttribute(mirrorMethod, throws)        addAnnotations(mirrorMethod, others)      }      emitClass(mirrorClass, clasz.symbol)    }    var linearization: List[BasicBlock] = Nil    var isModuleInitialized = false    /**     *  @param m ...     */    def genCode(m: IMethod) {      labels.clear      isModuleInitialized = false      code = m.code      linearization = linearizer.linearize(m)      makeLabels(linearization)      genBlocks(linearization)      if (this.method.exh != Nil)        genExceptionHandlers;    }    var nextBlock: BasicBlock = _    def genBlocks(l: List[BasicBlock]): Unit = l match {      case Nil => ()      case x :: Nil => nextBlock = null; genBlock(x)      case x :: y :: ys => nextBlock = y; genBlock(x); genBlocks(y :: ys)    }    /** Generate exception handlers for the current method. */    def genExceptionHandlers {      /** Return a list of pairs of intervals where the handler is active.       *  The intervals in the list have to be inclusive in the beginning and       *  exclusive in the end: [start, end).       */      def ranges(e: ExceptionHandler): List[(Int, Int)] = {        var covered = e.covered        var ranges: List[(Int, Int)] = Nil        var start = -1        var end = -1        linearization foreach ((b) => {          if (! (covered contains b) ) {            if (start >= 0) { // we're inside a handler range              end = labels(b).getAnchor()              ranges = (start, end) :: ranges              start = -1            }          } else {            if (start >= 0) { // we're inside a handler range               end = endPC(b)            } else {              start = labels(b).getAnchor()              end   = endPC(b)            }            covered = covered remove b.==          }        });        /* Add the last interval. Note that since the intervals are          * open-ended to the right, we have to give a number past the actual         * code!         */        if (start >= 0) {          ranges = (start, jcode.getPC()) :: ranges;        }        if (covered != Nil)          if (settings.debug.value)            log("Some covered blocks were not found in method: " + method +                 " covered: " + covered + " not in " + linearization);        ranges      }            this.method.exh foreach { e =>         ranges(e).sort({ (p1, p2) => p1._1 < p2._1 })        .foreach { p =>           if (p._1 < p._2) {            if (settings.debug.value)              log("Adding exception handler " + e + "at block: " + e.startBlock + " for " + method +                   " from: " + p._1 + " to: " + p._2 + " catching: " + e.cls);            jcode.addExceptionHandler(p._1, p._2,                                       labels(e.startBlock).getAnchor(),                                      if (e.cls == NoSymbol) null else javaName(e.cls))          } else             log("Empty exception range: " + p)        }      }    }    /** local variables whose scope appears in this block. */    var varsInBlock: collection.mutable.Set[Local] = new HashSet    def genBlock(b: BasicBlock) {      labels(b).anchorToNext()      if (settings.debug.value)        log("Generating code for block: " + b + " at pc: " + labels(b).getAnchor());      var lastMappedPC = 0      var lastLineNr = 0      var crtPC = 0      varsInBlock.clear      b traverse ( instr => {        class CompilationError(msg: String) extends Error {          override def toString: String = {            msg +             "\nCurrent method: " + method +             "\nCurrent block: " + b +            "\nCurrent instruction: " + instr +            "\n---------------------" +            method.dump          }        }        def assert(cond: Boolean, msg: String) = if (!cond) throw new CompilationError(msg);        instr match {          case THIS(clasz) =>            jcode.emitALOAD_0()          case CONSTANT(const) =>            const.tag match {              case UnitTag    => ();              case BooleanTag => jcode.emitPUSH(const.booleanValue)              case ByteTag    => jcode.emitPUSH(const.byteValue)              case ShortTag   => jcode.emitPUSH(const.shortValue)              case CharTag    => jcode.emitPUSH(const.charValue)              case IntTag     => jcode.emitPUSH(const.intValue)              case LongTag    => jcode.emitPUSH(const.longValue)              case FloatTag   => jcode.emitPUSH(const.floatValue)              case DoubleTag  => jcode.emitPUSH(const.doubleValue)

⌨️ 快捷键说明

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