genicode.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 1,653 行 · 第 1/5 页
SCALA
1,653 行
} } val op: TestOp = code match { case scalaPrimitives.LT => LT case scalaPrimitives.LE => LE case scalaPrimitives.GT => GT case scalaPrimitives.GE => GE case scalaPrimitives.ID | scalaPrimitives.EQ => EQ case scalaPrimitives.NI | scalaPrimitives.NE => NE case _ => abort("Unknown comparison primitive: " + code) } val kind = getMaxType(l.tpe :: r.tpe :: Nil) var ctx1 = genLoad(l, ctx, kind); ctx1 = genLoad(r, ctx1, kind); ctx1.bb.emit(CJUMP(thenCtx.bb, elseCtx.bb, op, kind), r.pos) ctx1.bb.close } if (settings.debug.value) log("Entering genCond with tree: " + tree); tree match { case Apply(fun, args) if isPrimitive(fun.symbol) => val code = scalaPrimitives.getPrimitive(fun.symbol) if (code == scalaPrimitives.ZNOT) { val Select(leftArg, _) = fun genCond(leftArg, ctx, elseCtx, thenCtx) } else if ((code == scalaPrimitives.EQ || code == scalaPrimitives.NE)) { val Select(leftArg, _) = fun; if (toTypeKind(leftArg.tpe).isReferenceType) { if (code == scalaPrimitives.EQ) genEqEqPrimitive(leftArg, args.head, ctx, thenCtx, elseCtx) else genEqEqPrimitive(leftArg, args.head, ctx, elseCtx, thenCtx) } else genComparisonOp(leftArg, args.head, code); } else if (scalaPrimitives.isComparisonOp(code)) { val Select(leftArg, _) = fun genComparisonOp(leftArg, args.head, code) } else { code match { case scalaPrimitives.ZAND => val Select(leftArg, _) = fun val ctxInterm = ctx.newBlock genCond(leftArg, ctx, ctxInterm, elseCtx) genCond(args.head, ctxInterm, thenCtx, elseCtx) case scalaPrimitives.ZOR => val Select(leftArg, _) = fun val ctxInterm = ctx.newBlock genCond(leftArg, ctx, thenCtx, ctxInterm) genCond(args.head, ctxInterm, thenCtx, elseCtx) case _ => // TODO (maybe): deal with the equals case here // Current semantics: rich equals (from runtime.Comparator) only when == is used // See genEqEqPrimitive for implementation var ctx1 = genLoad(tree, ctx, BOOL) ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL), tree.pos) ctx1.bb.close } } case _ => var ctx1 = genLoad(tree, ctx, BOOL) ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL), tree.pos) ctx1.bb.close } } /** * Generate the "==" code for object references. It is equivalent of * if (l eq null) r eq null else l.equals(r); * * @param l left-hand side of the '==' * @param r right-hand side of the '==' * @param ctx current context * @param thenCtx target context if the comparison yields true * @param elseCtx target context if the comparison yields false */ def genEqEqPrimitive(l: Tree, r: Tree, ctx: Context, thenCtx: Context, elseCtx: Context): Unit = { def eqEqTempName: Name = "eqEqTemp$" def getTempLocal: Local = ctx.method.lookupLocal(eqEqTempName) match { case Some(local) => local case None => val local = ctx.makeLocal(l.pos, definitions.AnyRefClass.typeConstructor, eqEqTempName.toString) assert(l.pos.source.get == unit.source) assert(r.pos.source.get == unit.source) local.start = (l.pos).line.get local.end = (r.pos).line.get local } /** True if the equality comparison is between values that require the use of the rich equality * comparator (scala.runtime.Comparator.equals). This is the case when either side of the * comparison might have a run-time type subtype of java.lang.Number or java.lang.Character. * When it is statically known that both sides are equal and subtypes of Number of Character, * not using the rich equality is possible (their own equals method will do ok.)*/ def mustUseAnyComparator: Boolean = { def isBoxed(sym: Symbol): Boolean = if (forCLDC) { (sym isNonBottomSubClass definitions.ByteClass) || (sym isNonBottomSubClass definitions.ShortClass) || (sym isNonBottomSubClass definitions.CharClass) || (sym isNonBottomSubClass definitions.IntClass) || (sym isNonBottomSubClass definitions.LongClass) } else ((sym isNonBottomSubClass definitions.BoxedNumberClass) || (!forMSIL && (sym isNonBottomSubClass definitions.BoxedCharacterClass))) val lsym = l.tpe.typeSymbol val rsym = r.tpe.typeSymbol (lsym == definitions.ObjectClass) || (rsym == definitions.ObjectClass) || (lsym != rsym) && (isBoxed(lsym) || isBoxed(rsym)) } if (mustUseAnyComparator) { val ctx1 = genLoad(l, ctx, ANY_REF_CLASS) val ctx2 = genLoad(r, ctx1, ANY_REF_CLASS) ctx2.bb.emit(CALL_METHOD(BoxesRunTime_equals, Static(false))) ctx2.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)) ctx2.bb.close } else { (l, r) match { // null == expr -> expr eq null case (Literal(Constant(null)), expr) => val ctx1 = genLoad(expr, ctx, ANY_REF_CLASS) ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS)) ctx1.bb.close // expr == null -> if(expr eq null) true else expr.equals(null) case (expr, Literal(Constant(null))) => val eqEqTempLocal = getTempLocal var ctx1 = genLoad(expr, ctx, ANY_REF_CLASS) ctx1.bb.emit(DUP(ANY_REF_CLASS)) ctx1.bb.emit(STORE_LOCAL(eqEqTempLocal), l.pos) val nonNullCtx = ctx1.newBlock ctx1.bb.emit(CZJUMP(thenCtx.bb, nonNullCtx.bb, EQ, ANY_REF_CLASS)) ctx1.bb.close nonNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal), l.pos) nonNullCtx.bb.emit(CONSTANT(Constant(null)), r.pos) nonNullCtx.bb.emit(CALL_METHOD(definitions.Object_equals, Dynamic)) nonNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)) nonNullCtx.bb.close // l == r -> if (l eq null) r eq null else l.equals(r) case _ => val eqEqTempLocal = getTempLocal var ctx1 = genLoad(l, ctx, ANY_REF_CLASS) ctx1 = genLoad(r, ctx1, ANY_REF_CLASS) val nullCtx = ctx1.newBlock val nonNullCtx = ctx1.newBlock ctx1.bb.emit(STORE_LOCAL(eqEqTempLocal), l.pos) ctx1.bb.emit(DUP(ANY_REF_CLASS)) ctx1.bb.emit(CZJUMP(nullCtx.bb, nonNullCtx.bb, EQ, ANY_REF_CLASS)) ctx1.bb.close nullCtx.bb.emit(DROP(ANY_REF_CLASS), l.pos) // type of AnyRef nullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal)) nullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS)) nullCtx.bb.close nonNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal), l.pos) nonNullCtx.bb.emit(CALL_METHOD(definitions.Object_equals, Dynamic)) nonNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)) nonNullCtx.bb.close } } } /** * Add all fields of the given class symbol to the current ICode * class. */ private def addClassFields(ctx: Context, cls: Symbol) { if (settings.debug.value) assert(ctx.clazz.symbol eq cls, "Classes are not the same: " + ctx.clazz.symbol + ", " + cls) for (f <- cls.info.decls.elements) if (!f.isMethod && f.isTerm) ctx.clazz.addField(new IField(f)); } /** * Add parameters to the current ICode method. It is assumed the methods * have been uncurried, so the list of lists contains just one list. */ private def addMethodParams(ctx: Context, vparamss: List[List[ValDef]]) { vparamss match { case Nil => () case vparams :: Nil => for (p <- vparams) { val lv = new Local(p.symbol, toTypeKind(p.symbol.info), true) ctx.method.addParam(lv) ctx.scope.add(lv) ctx.bb.varsInScope += lv } ctx.method.params = ctx.method.params.reverse case _ => abort("Malformed parameter list: " + vparamss) } } /** Does this tree have a try-catch block? */ def mayCleanStack(tree: Tree): Boolean = { var hasTry = false new Traverser() { override def traverse(t: Tree) = t match { case Try(_, _, _) => hasTry = true case _ => super.traverse(t) } }.traverse(tree); hasTry } /** * If the block consists of a single unconditional jump, prune * it by replacing the instructions in the predecessor to jump * directly to the JUMP target of the block. * * @param method ... */ def prune(method: IMethod) = { var changed = false var n = 0 def prune0(block: BasicBlock): Unit = { val optCont = block.lastInstruction match { case JUMP(b) if (b != block) => Some(b); case _ => None } if (block.size == 1 && optCont != None) { val Some(cont) = optCont; val pred = block.predecessors; log("Preds: " + pred + " of " + block + " (" + optCont + ")"); pred foreach { p => p.lastInstruction match { case CJUMP(succ, fail, cond, kind) => if (settings.debug.value) log("Pruning empty if branch."); changed = true p.replaceInstruction(p.lastInstruction, if (block == succ) if (block == fail) CJUMP(cont, cont, cond, kind) else CJUMP(cont, fail, cond, kind) else if (block == fail) CJUMP(succ, cont, cond, kind) else abort("Could not find block in preds: " + method + " " + block + " " + pred + " " + p)) case CZJUMP(succ, fail, cond, kind) => if (settings.debug.value) log("Pruning empty ifz branch."); changed = true p.replaceInstruction(p.lastInstruction, if (block == succ) if (block == fail) CZJUMP(cont, cont, cond, kind) else CZJUMP(cont, fail, cond, kind) else if (block == fail) CZJUMP(succ, cont, cond, kind) else abort("Could not find block in preds")) case JUMP(b) => if (settings.debug.value) log("Pruning empty JMP branch."); changed = true val replaced = p.replaceInstruction(p.lastInstruction, JUMP(cont)) if (settings.debug.value) assert(replaced, "Didn't find p.lastInstruction") case SWITCH(tags, labels) => if (settings.debug.value) log("Pruning empty SWITCH branch."); changed = true p.replaceInstruction(p.lastInstruction, SWITCH(tags, labels map (l => if (l == block) cont else l))) } } if (changed) { log("Removing block: " + block) method.code.removeBlock(block) for (e <- method.exh) { e.covered = e.covered filter (_ != block) e.blocks = e.blocks filter (_ != block) if (e.startBlock eq block) e setStartBlock cont; } } } } do { changed = false n += 1 method.code traverse prune0 } while (changed)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?