genicode.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 1,653 行 · 第 1/5 页
SCALA
1,653 行
caseCtx.bb.close case _ => abort("Invalid case statement in switch-like pattern match: " + tree + " at: " + (tree.pos)) } ctx1.bb.emit(SWITCH(tags.reverse map (x => List(x)), (default :: targets).reverse), tree.pos) ctx1.bb.close afterCtx case EmptyTree => if (expectedType != UNIT) ctx.bb.emit(getZeroOf(expectedType)) ctx case _ => abort("Unexpected tree in genLoad: " + tree + " at: " + (tree.pos)) } // emit conversion if (generatedType != expectedType) adapt(generatedType, expectedType, resCtx, tree); resCtx } private def adapt(from: TypeKind, to: TypeKind, ctx: Context, tree: Tree): Unit = { if (!(from <:< to) && !(from == SCALA_ALLREF && to == SCALA_ALL)) { to match { case UNIT => ctx.bb.emit(DROP(from), tree.pos) if (settings.debug.value) log("Dropped an " + from); case _ => if (settings.debug.value) assert(from != UNIT, "Can't convert from UNIT to " + to + tree + " at: " + (tree.pos)); assert(!from.isReferenceType && !to.isReferenceType, "type error: can't convert from " + from + " to " + to +" in unit "+this.unit) ctx.bb.emit(CALL_PRIMITIVE(Conversion(from, to)), tree.pos); } } else if (from == SCALA_ALL) { ctx.bb.emit(DROP(from)) ctx.bb.emit(getZeroOf(ctx.method.returnType)) ctx.bb.emit(RETURN(ctx.method.returnType)) ctx.bb.enterIgnoreMode } else if (from == SCALA_ALLREF) { ctx.bb.emit(DROP(from)) ctx.bb.emit(CONSTANT(Constant(null))) } else (from, to) match { case (BYTE, LONG) | (SHORT, LONG) | (CHAR, LONG) | (INT, LONG) => ctx.bb.emit(CALL_PRIMITIVE(Conversion(INT, LONG))) case _ => () } } /** Load the qualifier of `tree' on top of the stack. */ private def genLoadQualifier(tree: Tree, ctx: Context): Context = tree match { case Select(qualifier, _) => genLoad(qualifier, ctx, ANY_REF_CLASS) // !! case _ => abort("Unknown qualifier " + tree) } /** Is this symbol static in the Java sense? */ def isStaticSymbol(s: Symbol): Boolean = s.hasFlag(Flags.STATIC) || s.hasFlag(Flags.STATICMEMBER) || s.owner.isImplClass /** * Generate code that loads args into label parameters. */ private def genLoadLabelArguments(args: List[Tree], label: Label, ctx: Context): Context = { if (settings.debug.value) assert(args.length == label.params.length, "Wrong number of arguments in call to label " + label.symbol) var ctx1 = ctx var arg = args var param = label.params val stores: ListBuffer[Instruction] = new ListBuffer // store arguments in reverse order on the stack while (arg != Nil) { arg.head match { case This(_) if param.head.name == nme.THIS => //println("skipping trivial argument for " + param.head) () // skip trivial arguments case Ident(_) if arg.head.symbol == param.head => //println("skipping trivial argument for " + param.head) () // skip trivial arguments case _ => val Some(l) = ctx.method.lookupLocal(param.head) ctx1 = genLoad(arg.head, ctx1, l.kind) if (param.head.name == nme.THIS) STORE_THIS(toTypeKind(ctx1.clazz.symbol.tpe)).setPos(arg.head.pos) +: stores else { STORE_LOCAL(l).setPos(arg.head.pos) +: stores } } arg = arg.tail param = param.tail } //println("stores: " + stores) ctx1.bb.emit(stores) ctx1 } private def genLoadArguments(args: List[Tree], tpes: List[Type], ctx: Context): Context = { var ctx1 = ctx var arg = args var tpe = tpes while (arg != Nil) { ctx1 = genLoad(arg.head, ctx1, toTypeKind(tpe.head)) arg = arg.tail tpe = tpe.tail } ctx1 } def genConversion(from: TypeKind, to: TypeKind, ctx: Context, cast: Boolean) = { if (cast) ctx.bb.emit(CALL_PRIMITIVE(Conversion(from, to))) else { ctx.bb.emit(DROP(from)) ctx.bb.emit(CONSTANT(Constant(from == to))) } } def genCast(from: TypeKind, to: TypeKind, ctx: Context, cast: Boolean) = ctx.bb.emit(if (cast) CHECK_CAST(to) else IS_INSTANCE(to)) def zeroOf(k: TypeKind): Tree = k match { case UNIT => Literal(()) case BOOL => Literal(false) case BYTE => Literal(0: Byte) case SHORT => Literal(0: Short) case CHAR => Literal(0: Char) case INT => Literal(0: Int) case LONG => Literal(0: Long) case FLOAT => Literal(0.0f) case DOUBLE => Literal(0.0d) case REFERENCE(cls) => Literal(null: Any) case ARRAY(elem) => Literal(null: Any) case BOXED(_) => Literal(null: Any) case ConcatClass => abort("no zero of ConcatClass") } def getZeroOf(k: TypeKind): Instruction = k match { case UNIT => CONSTANT(Constant(())) case BOOL => CONSTANT(Constant(false)) case BYTE => CONSTANT(Constant(0: Byte)) case SHORT => CONSTANT(Constant(0: Short)) case CHAR => CONSTANT(Constant(0: Char)) case INT => CONSTANT(Constant(0: Int)) case LONG => CONSTANT(Constant(0: Long)) case FLOAT => CONSTANT(Constant(0.0f)) case DOUBLE => CONSTANT(Constant(0.0d)) case REFERENCE(cls) => CONSTANT(Constant(null: Any)) case ARRAY(elem) => CONSTANT(Constant(null: Any)) case BOXED(_) => CONSTANT(Constant(null: Any)) case ConcatClass => abort("no zero of ConcatClass") } /** Is the given symbol a primitive operation? */ def isPrimitive(fun: Symbol): Boolean = scalaPrimitives.isPrimitive(fun) /** Generate coercion denoted by "code" */ def genCoercion(tree: Tree, ctx: Context, code: Int) = { import scalaPrimitives._ code match { case B2B => () case B2C => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, CHAR)), tree.pos) case B2S => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, SHORT)), tree.pos) case B2I => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, INT)), tree.pos) case B2L => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, LONG)), tree.pos) case B2F => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, FLOAT)), tree.pos) case B2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, DOUBLE)), tree.pos) case S2B => ctx.bb.emit(CALL_PRIMITIVE(Conversion(SHORT, BYTE)), tree.pos) case S2S => () case S2C => ctx.bb.emit(CALL_PRIMITIVE(Conversion(SHORT, CHAR)), tree.pos) case S2I => ctx.bb.emit(CALL_PRIMITIVE(Conversion(SHORT, INT)), tree.pos) case S2L => ctx.bb.emit(CALL_PRIMITIVE(Conversion(SHORT, LONG)), tree.pos) case S2F => ctx.bb.emit(CALL_PRIMITIVE(Conversion(SHORT, FLOAT)), tree.pos) case S2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(SHORT, DOUBLE)), tree.pos) case C2B => ctx.bb.emit(CALL_PRIMITIVE(Conversion(CHAR, BYTE)), tree.pos) case C2S => ctx.bb.emit(CALL_PRIMITIVE(Conversion(CHAR, SHORT)), tree.pos) case C2C => () case C2I => ctx.bb.emit(CALL_PRIMITIVE(Conversion(CHAR, INT)), tree.pos) case C2L => ctx.bb.emit(CALL_PRIMITIVE(Conversion(CHAR, LONG)), tree.pos) case C2F => ctx.bb.emit(CALL_PRIMITIVE(Conversion(CHAR, FLOAT)), tree.pos) case C2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(CHAR, DOUBLE)), tree.pos) case I2B => ctx.bb.emit(CALL_PRIMITIVE(Conversion(INT, BYTE)), tree.pos) case I2S => ctx.bb.emit(CALL_PRIMITIVE(Conversion(INT, SHORT)), tree.pos) case I2C => ctx.bb.emit(CALL_PRIMITIVE(Conversion(INT, CHAR)), tree.pos) case I2I => () case I2L => ctx.bb.emit(CALL_PRIMITIVE(Conversion(INT, LONG)), tree.pos) case I2F => ctx.bb.emit(CALL_PRIMITIVE(Conversion(INT, FLOAT)), tree.pos) case I2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(INT, DOUBLE)), tree.pos) case L2B => ctx.bb.emit(CALL_PRIMITIVE(Conversion(LONG, BYTE)), tree.pos) case L2S => ctx.bb.emit(CALL_PRIMITIVE(Conversion(LONG, SHORT)), tree.pos) case L2C => ctx.bb.emit(CALL_PRIMITIVE(Conversion(LONG, CHAR)), tree.pos) case L2I => ctx.bb.emit(CALL_PRIMITIVE(Conversion(LONG, INT)), tree.pos) case L2L => () case L2F => ctx.bb.emit(CALL_PRIMITIVE(Conversion(LONG, FLOAT)), tree.pos) case L2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(LONG, DOUBLE)), tree.pos) case F2B => ctx.bb.emit(CALL_PRIMITIVE(Conversion(FLOAT, BYTE)), tree.pos) case F2S => ctx.bb.emit(CALL_PRIMITIVE(Conversion(FLOAT, SHORT)), tree.pos) case F2C => ctx.bb.emit(CALL_PRIMITIVE(Conversion(FLOAT, CHAR)), tree.pos) case F2I => ctx.bb.emit(CALL_PRIMITIVE(Conversion(FLOAT, INT)), tree.pos) case F2L => ctx.bb.emit(CALL_PRIMITIVE(Conversion(FLOAT, LONG)), tree.pos) case F2F => () case F2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(FLOAT, DOUBLE)), tree.pos) case D2B => ctx.bb.emit(CALL_PRIMITIVE(Conversion(DOUBLE, BYTE)), tree.pos) case D2S => ctx.bb.emit(CALL_PRIMITIVE(Conversion(DOUBLE, SHORT)), tree.pos) case D2C => ctx.bb.emit(CALL_PRIMITIVE(Conversion(DOUBLE, CHAR)), tree.pos) case D2I => ctx.bb.emit(CALL_PRIMITIVE(Conversion(DOUBLE, INT)), tree.pos) case D2L => ctx.bb.emit(CALL_PRIMITIVE(Conversion(DOUBLE, LONG)), tree.pos) case D2F => ctx.bb.emit(CALL_PRIMITIVE(Conversion(DOUBLE, FLOAT)), tree.pos) case D2D => () case _ => abort("Unknown coercion primitive: " + code) } } /** Generate string concatenation. * * @param tree ... * @param ctx ... * @return ... */ def genStringConcat(tree: Tree, ctx: Context): Context = { val Apply(Select(larg, _), rarg) = tree var ctx1 = ctx val concatenations = liftStringConcat(tree) if (settings.debug.value) log("Lifted string concatenations for " + tree + "\n to: " + concatenations); ctx1.bb.emit(CALL_PRIMITIVE(StartConcat), tree.pos); for (elem <- concatenations) { val kind = toTypeKind(elem.tpe) ctx1 = genLoad(elem, ctx1, kind) ctx1.bb.emit(CALL_PRIMITIVE(StringConcat(kind)), elem.pos) } ctx1.bb.emit(CALL_PRIMITIVE(EndConcat), tree.pos) ctx1 } /** * Returns a list of trees that each should be concatenated, from * left to right. It turns a chained call like "a".+("b").+("c") into * a list of arguments. */ def liftStringConcat(tree: Tree): List[Tree] = tree match { case Apply(fun @ Select(larg, method), rarg) => if (isPrimitive(fun.symbol) && scalaPrimitives.getPrimitive(fun.symbol) == scalaPrimitives.CONCAT) liftStringConcat(larg) ::: rarg else List(tree) case _ => List(tree) } /** * Traverse the tree and store label stubs in the context. This is * necessary to handle forward jumps, because at a label application * with arguments, the symbols of the corresponding LabelDef parameters * are not yet known. * * Since it is expensive to traverse each method twice, this method is called * only when forward jumps really happen, and then it re-traverses the whole * method, scanning for LabelDefs. * * TODO: restrict the scanning to smaller subtrees than the whole method. * It is sufficient to scan the trees of the innermost enclosing block. */ private def scanForLabels(tree: Tree, ctx: Context): Unit = new Traverser() { override def traverse(tree: Tree): Unit = tree match { case LabelDef(name, params, rhs) => if (!ctx.labels.contains(tree.symbol)) { ctx.labels += (tree.symbol -> (new Label(tree.symbol) setParams(params map (_.symbol)))); ctx.method.addLocals(params map (p => new Local(p.symbol, toTypeKind(p.symbol.info), false))); } super.traverse(rhs) case _ => super.traverse(tree) } } traverse(tree); /** * Generate code for conditional expressions. The two basic blocks * represent the continuation in case of success/failure of the * test. */ private def genCond(tree: Tree, ctx: Context, thenCtx: Context, elseCtx: Context): Unit = { def genComparisonOp(l: Tree, r: Tree, code: Int) { // special-case reference (in)equality test for null if (code == scalaPrimitives.ID || code == scalaPrimitives.NI) { val expr: Tree = (l, r) match { case (Literal(Constant(null)), expr) => expr case (expr, Literal(Constant(null))) => expr case _ => null } if (expr ne null) { val ctx1 = genLoad(expr, ctx, ANY_REF_CLASS) if (code == scalaPrimitives.ID) ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS)) else ctx1.bb.emit(CZJUMP(elseCtx.bb, thenCtx.bb, EQ, ANY_REF_CLASS)) ctx1.bb.close return
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?