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