genjvm.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 1,594 行 · 第 1/4 页
SCALA
1,594 行
case StringTag => jcode.emitPUSH(const.stringValue) case NullTag => jcode.emitACONST_NULL() case ClassTag => val kind = toTypeKind(const.typeValue); if (kind.isValueType) jcode.emitPUSH(classLiteral(kind)); else jcode.emitPUSH(javaType(kind).asInstanceOf[JReferenceType]); case EnumTag => val sym = const.symbolValue jcode.emitGETSTATIC(javaName(sym.owner), javaName(sym), javaType(const.tpe)) case _ => abort("Unknown constant value: " + const); } case LOAD_ARRAY_ITEM(kind) => jcode.emitALOAD(javaType(kind)) case LOAD_LOCAL(local) => jcode.emitLOAD(indexOf(local), javaType(local.kind)) case LOAD_FIELD(field, isStatic) => var owner = javaName(field.owner);// if (field.owner.hasFlag(Flags.MODULE)) owner = owner + "$"; if (settings.debug.value) log("LOAD_FIELD with owner: " + owner + " flags: " + Flags.flagsToString(field.owner.flags)) if (isStatic) jcode.emitGETSTATIC(owner, javaName(field), javaType(field)) else jcode.emitGETFIELD(owner, javaName(field), javaType(field)) case LOAD_MODULE(module) =>// assert(module.isModule, "Expected module: " + module) if (settings.debug.value) log("genearting LOAD_MODULE for: " + module + " flags: " + Flags.flagsToString(module.flags)); if (clasz.symbol == module.moduleClass && jmethod.getName() != nme.readResolve.toString) jcode.emitALOAD_0() else jcode.emitGETSTATIC(javaName(module) /* + "$" */ , nme.MODULE_INSTANCE_FIELD.toString, javaType(module)); case STORE_ARRAY_ITEM(kind) => jcode.emitASTORE(javaType(kind)) case STORE_LOCAL(local) => jcode.emitSTORE(indexOf(local), javaType(local.kind)) 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. jcode.emitASTORE_0() case STORE_FIELD(field, isStatic) => val owner = javaName(field.owner) // + (if (field.owner.hasFlag(Flags.MODULE)) "$" else ""); if (isStatic) jcode.emitPUTSTATIC(owner, javaName(field), javaType(field)) else jcode.emitPUTFIELD(owner, javaName(field), javaType(field)) case CALL_PRIMITIVE(primitive) => genPrimitive(primitive, instr.pos) case call @ CALL_METHOD(method, style) => val owner: String = javaName(method.owner); //reference the type of the receiver instead of the method owner (if not an interface!) val dynamicOwner = if (needsInterfaceCall(call.hostClass)) owner else javaName(call.hostClass) style match { case Dynamic => if (needsInterfaceCall(method.owner)) jcode.emitINVOKEINTERFACE(owner, javaName(method), javaType(method).asInstanceOf[JMethodType]) else jcode.emitINVOKEVIRTUAL(dynamicOwner, javaName(method), javaType(method).asInstanceOf[JMethodType]); case Static(instance) => if (instance) { jcode.emitINVOKESPECIAL(owner, javaName(method), javaType(method).asInstanceOf[JMethodType]); } else jcode.emitINVOKESTATIC(owner, javaName(method), javaType(method).asInstanceOf[JMethodType]); case SuperCall(_) => jcode.emitINVOKESPECIAL(owner, javaName(method), javaType(method).asInstanceOf[JMethodType]); // we initialize the MODULE$ field immediately after the super ctor if (isStaticModule(clasz.symbol) && !isModuleInitialized && jmethod.getName() == JMethod.INSTANCE_CONSTRUCTOR_NAME && javaName(method) == JMethod.INSTANCE_CONSTRUCTOR_NAME) { isModuleInitialized = true; jcode.emitALOAD_0(); jcode.emitPUTSTATIC(jclass.getName(), nme.MODULE_INSTANCE_FIELD.toString, jclass.getType()); } } case BOX(kind) => val boxedType = definitions.boxedClass(kind.toType.typeSymbol) val mtype = new JMethodType(javaType(boxedType), Array(javaType(kind))) jcode.emitINVOKESTATIC(BoxesRunTime, "boxTo" + boxedType.nameString, mtype) case UNBOX(kind) => val mtype = new JMethodType(javaType(kind), Array(JObjectType.JAVA_LANG_OBJECT)) jcode.emitINVOKESTATIC(BoxesRunTime, "unboxTo" + kind.toType.typeSymbol.nameString, mtype) case NEW(REFERENCE(cls)) => val className = javaName(cls) jcode.emitNEW(className) case CREATE_ARRAY(elem, 1) => elem match { case REFERENCE(_) | ARRAY(_) => jcode.emitANEWARRAY(javaType(elem).asInstanceOf[JReferenceType]) case _ => jcode.emitNEWARRAY(javaType(elem)) } case CREATE_ARRAY(elem, dims) => jcode.emitMULTIANEWARRAY(javaType(ArrayN(elem, dims)).asInstanceOf[JReferenceType], dims) case IS_INSTANCE(tpe) => tpe match { case REFERENCE(cls) => jcode.emitINSTANCEOF(new JObjectType(javaName(cls))) case ARRAY(elem) => jcode.emitINSTANCEOF(new JArrayType(javaType(elem))) case _ => abort("Unknown reference type in IS_INSTANCE: " + tpe) } case CHECK_CAST(tpe) => tpe match { case REFERENCE(cls) => jcode.emitCHECKCAST(new JObjectType(javaName(cls))) case ARRAY(elem) => jcode.emitCHECKCAST(new JArrayType(javaType(elem))) case _ => abort("Unknown reference type in IS_INSTANCE: " + tpe) } case SWITCH(tags, branches) => val tagArray = new Array[Array[Int]](tags.length) var caze = tags var i = 0 while (i < tagArray.length) { tagArray(i) = new Array[Int](caze.head.length) caze.head.copyToArray(tagArray(i), 0) i = i + 1 caze = caze.tail } val branchArray = new Array[JCode$Label](tagArray.length) if (settings.debug.value) log("Emitting SWITHCH:\ntags: " + tags + "\nbranches: " + branches); jcode.emitSWITCH(tagArray, { (branches map labels dropRight 1).copyToArray(branchArray, 0); branchArray }, labels(branches.last), MIN_SWITCH_DENSITY); case JUMP(whereto) => if (nextBlock != whereto) jcode.emitGOTO_maybe_W(labels(whereto), false); // default to short jumps case CJUMP(success, failure, cond, kind) => kind match { case BOOL | BYTE | CHAR | SHORT | INT => if (nextBlock == success) { jcode.emitIF_ICMP(conds(negate(cond)), labels(failure)) // .. and fall through to success label } else { jcode.emitIF_ICMP(conds(cond), labels(success)) if (nextBlock != failure) jcode.emitGOTO_maybe_W(labels(failure), false); } case REFERENCE(_) | ARRAY(_) => if (nextBlock == success) { jcode.emitIF_ACMP(conds(negate(cond)), labels(failure)) // .. and fall through to success label } else { jcode.emitIF_ACMP(conds(cond), labels(success)) if (nextBlock != failure) jcode.emitGOTO_maybe_W(labels(failure), false); } case _ => (kind: @unchecked) match { case LONG => jcode.emitLCMP() case FLOAT => if (cond == LT || cond == LE) jcode.emitFCMPG() else jcode.emitFCMPL() case DOUBLE => if (cond == LT || cond == LE) jcode.emitDCMPG() else jcode.emitDCMPL() } if (nextBlock == success) { jcode.emitIF(conds(negate(cond)), labels(failure)); // .. and fall through to success label } else { jcode.emitIF(conds(cond), labels(success)); if (nextBlock != failure) jcode.emitGOTO_maybe_W(labels(failure), false); } } case CZJUMP(success, failure, cond, kind) => kind match { case BOOL | BYTE | CHAR | SHORT | INT => if (nextBlock == success) { jcode.emitIF(conds(negate(cond)), labels(failure)); } else { jcode.emitIF(conds(cond), labels(success)) if (nextBlock != failure) jcode.emitGOTO_maybe_W(labels(failure), false); } case REFERENCE(_) | ARRAY(_) => if (nextBlock == success) { jcode.emitIFNONNULL(labels(failure)) } else { jcode.emitIFNULL(labels(success)); if (nextBlock != failure) jcode.emitGOTO_maybe_W(labels(failure), false); } case _ => (kind: @unchecked) match { case LONG => jcode.emitLCONST_0(); jcode.emitLCMP() case FLOAT => jcode.emitFCONST_0(); if (cond == LT || cond == LE) jcode.emitFCMPG() else jcode.emitFCMPL() case DOUBLE => jcode.emitDCONST_0(); if (cond == LT || cond == LE) jcode.emitDCMPG() else jcode.emitDCMPL() } if (nextBlock == success) { jcode.emitIF(conds(negate(cond)), labels(failure)) } else { jcode.emitIF(conds(cond), labels(success)) if (nextBlock != failure) jcode.emitGOTO_maybe_W(labels(failure), false); } } case RETURN(kind) => jcode.emitRETURN(javaType(kind)) case THROW() => jcode.emitATHROW() case DROP(kind) => kind match { case LONG | DOUBLE => jcode.emitPOP2() case _ => jcode.emitPOP() } case DUP(kind) => kind match { case LONG | DOUBLE => jcode.emitDUP2() case _ => jcode.emitDUP() } case MONITOR_ENTER() => jcode.emitMONITORENTER() case MONITOR_EXIT() => jcode.emitMONITOREXIT() case SCOPE_ENTER(lv) => varsInBlock += lv lv.start = jcode.getPC() case SCOPE_EXIT(lv) => if (varsInBlock contains lv) { lv.ranges = (lv.start, jcode.getPC()) :: lv.ranges varsInBlock -= lv } else if (b.varsInScope contains lv) { lv.ranges = (labels(b).getAnchor(), jcode.getPC()) :: lv.ranges b.varsInScope -= lv } else assert(false, "Illegal local var nesting: " + method) case LOAD_EXCEPTION() => () } crtPC = jcode.getPC() // assert(instr.pos.source.isEmpty || instr.pos.source.get == (clasz.cunit.source), "sources don't match")// val crtLine = instr.pos.line.get(lastLineNr); val crtLine = try { (instr.pos).line.get } catch { case _: NoSuchElementException => log("Warning: wrong position in: " + method) lastLineNr } if (b.lastInstruction == instr) endPC(b) = jcode.getPC(); //System.err.println("CRTLINE: " + instr.pos + " " + // /* (if (instr.pos < clasz.cunit.source.content.length) clasz.cunit.source.content(instr.pos) else '*') + */ " " + crtLine); if (crtPC > lastMappedPC) { jcode.completeLineNumber(lastMappedPC, crtPC, crtLine) lastMappedPC = crtPC lastLineNr = crtLine } }); // b.traverse // local vars that survived this basic block for (val lv <- varsInBlock) { lv.ranges = (lv.start, jcode.getPC()) :: lv.ranges } for (val lv <- b.varsInScope) { lv.ranges = (labels(b).getAnchor(), jcode.getPC()) :: lv.ranges } } /** * @param primitive ... * @param pos ... */ def genPrimitive(primitive: Primitive, pos: Position) { primitive match { case Negation(kind) => kind match { case BOOL | BYTE | CHAR | SHORT | INT => jcode.emitINEG() case LONG => jcode.emitLNEG() case FLOAT => jcode.emitFNEG() case DOUBLE => jcode.emitDNEG() case _ => abort("Impossible to negate a " + kind) } case Arithmetic(op, kind) => op match { case ADD => jcode.emitADD(javaType(kind)) case SUB => (kind: @unchecked) match { case BOOL | BYTE | CHAR | SHORT | INT => jcode.emitISUB() case LONG => jcode.emitLSUB() case FLOAT => jcode.emitFSUB() case DOUBLE => jcode.emitDSUB() } case MUL => (kind: @unchecked) match { case BOOL | BYTE | CHAR | SHORT | INT => jcode.emitIMUL() case LONG => jcode.emitLMUL() case FLOAT => jcode.emitFMUL() case DOUBLE => jcode.emitDMUL() } case DIV => (kind: @unchecked) match { case BOOL | BYTE | CHAR | SHORT | INT => jcode.emitIDIV() case LONG => jcode.emitLDIV() case FLOAT => jcode.emitFDIV() case DOUBLE => jcode.emitDDIV() } case REM => (kind: @unchecked) match { case BOOL | BYTE | CHAR | SHORT | INT => jcode.emitIREM() case LONG => jcode.emitLREM() case FLOAT => jcode.emitFREM() case DOUBLE => jcode.emitDREM() } case NOT => kind match { case BOOL | BYTE | CHAR | SHORT | INT =>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?