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