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