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