genicode.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 1,653 行 · 第 1/5 页
SCALA
1,653 行
ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(DOUBLE)), tree.pos) case OARRAY_LENGTH => ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(ANY_REF_CLASS)), tree.pos) case ZARRAY_GET => ctx1.bb.emit(LOAD_ARRAY_ITEM(BOOL), tree.pos) case BARRAY_GET => ctx1.bb.emit(LOAD_ARRAY_ITEM(BYTE), tree.pos) case SARRAY_GET => ctx1.bb.emit(LOAD_ARRAY_ITEM(SHORT), tree.pos) case CARRAY_GET => ctx1.bb.emit(LOAD_ARRAY_ITEM(CHAR), tree.pos) case IARRAY_GET => ctx1.bb.emit(LOAD_ARRAY_ITEM(INT), tree.pos) case LARRAY_GET => ctx1.bb.emit(LOAD_ARRAY_ITEM(LONG), tree.pos) case FARRAY_GET => ctx1.bb.emit(LOAD_ARRAY_ITEM(FLOAT), tree.pos) case DARRAY_GET => ctx1.bb.emit(LOAD_ARRAY_ITEM(DOUBLE), tree.pos) case OARRAY_GET => ctx1.bb.emit(LOAD_ARRAY_ITEM(ANY_REF_CLASS), tree.pos) case ZARRAY_SET => ctx1.bb.emit(STORE_ARRAY_ITEM(BOOL), tree.pos) case BARRAY_SET => ctx1.bb.emit(STORE_ARRAY_ITEM(BYTE), tree.pos) case SARRAY_SET => ctx1.bb.emit(STORE_ARRAY_ITEM(SHORT), tree.pos) case CARRAY_SET => ctx1.bb.emit(STORE_ARRAY_ITEM(CHAR), tree.pos) case IARRAY_SET => ctx1.bb.emit(STORE_ARRAY_ITEM(INT), tree.pos) case LARRAY_SET => ctx1.bb.emit(STORE_ARRAY_ITEM(LONG), tree.pos) case FARRAY_SET => ctx1.bb.emit(STORE_ARRAY_ITEM(FLOAT), tree.pos) case DARRAY_SET => ctx1.bb.emit(STORE_ARRAY_ITEM(DOUBLE), tree.pos) case OARRAY_SET => ctx1.bb.emit(STORE_ARRAY_ITEM(ANY_REF_CLASS), tree.pos) case _ => abort("Unknown operation on arrays: " + tree + " code: " + code) } ctx1 } // genLoad val resCtx: Context = tree match { case LabelDef(name, params, rhs) => val ctx1 = ctx.newBlock if (isLoopHeaderLabel(name)) ctx1.bb.loopHeader = true; ctx1.labels.get(tree.symbol) match { case Some(label) => label.anchor(ctx1.bb) label.patch(ctx.method.code) case None => ctx1.labels += (tree.symbol -> (new Label(tree.symbol) anchor ctx1.bb setParams (params map (_.symbol)))); ctx.method.addLocals(params map (p => new Local(p.symbol, toTypeKind(p.symbol.info), false))); if (settings.debug.value) log("Adding label " + tree.symbol); } ctx.bb.emit(JUMP(ctx1.bb), tree.pos) ctx.bb.close genLoad(rhs, ctx1, expectedType /*toTypeKind(tree.symbol.info.resultType)*/) case ValDef(_, nme.THIS, _, _) => if (settings.debug.value) log("skipping trivial assign to _$this: " + tree) ctx case ValDef(_, _, _, rhs) => val sym = tree.symbol val local = ctx.method.addLocal(new Local(sym, toTypeKind(sym.info), false)) ctx.scope.add(local) ctx.bb.emit(SCOPE_ENTER(local)) if (rhs == EmptyTree) { if (settings.debug.value) log("Uninitialized variable " + tree + " at: " + (tree.pos)); ctx.bb.emit(getZeroOf(local.kind)) } var ctx1 = ctx if (rhs != EmptyTree) ctx1 = genLoad(rhs, ctx, local.kind); ctx1.bb.emit(STORE_LOCAL(local), tree.pos) generatedType = UNIT ctx1 case If(cond, thenp, elsep) => var thenCtx = ctx.newBlock var elseCtx = ctx.newBlock val contCtx = ctx.newBlock genCond(cond, ctx, thenCtx, elseCtx) val ifKind = toTypeKind(tree.tpe) val thenKind = toTypeKind(thenp.tpe) val elseKind = if (elsep == EmptyTree) UNIT else toTypeKind(elsep.tpe) generatedType = ifKind // we need to drop unneeded results, if one branch gives // unit and the other gives something on the stack, because // the type of 'if' is scala.Any, and its erasure would be Object. // But unboxed units are not Objects... if (thenKind == UNIT || elseKind == UNIT) { if (settings.debug.value) log("Will drop result from an if branch"); thenCtx = genLoad(thenp, thenCtx, UNIT) elseCtx = genLoad(elsep, elseCtx, UNIT) if (settings.debug.value) assert(expectedType == UNIT, "I produce UNIT in a context where " + expectedType + " is expected!") generatedType = UNIT } else { thenCtx = genLoad(thenp, thenCtx, ifKind) elseCtx = genLoad(elsep, elseCtx, ifKind) } thenCtx.bb.emit(JUMP(contCtx.bb)) thenCtx.bb.close if (elsep == EmptyTree) elseCtx.bb.emit(JUMP(contCtx.bb), tree.pos) else elseCtx.bb.emit(JUMP(contCtx.bb)) elseCtx.bb.close contCtx case Return(expr) => val returnedKind = toTypeKind(expr.tpe) var ctx1 = genLoad(expr, ctx, returnedKind) val oldcleanups = ctx1.cleanups lazy val tmp = ctx1.makeLocal(tree.pos, expr.tpe, "tmp") var saved = false for (op <- ctx1.cleanups) op match { case MonitorRelease(m) => if (settings.debug.value) log("removing " + m + " from cleanups: " + ctx1.cleanups) ctx1.bb.emit(LOAD_LOCAL(m)) ctx1.bb.emit(MONITOR_EXIT()) ctx1.exitSynchronized(m) case Finalizer(f) => if (settings.debug.value) log("removing " + f + " from cleanups: " + ctx1.cleanups) if (returnedKind != UNIT && mayCleanStack(f) && !saved) { ctx1.bb.emit(STORE_LOCAL(tmp)) saved = true } // we have to run this without the same finalizer in // the list, otherwise infinite recursion happens for // finalizers that contain 'return' ctx1 = genLoad(f, ctx1.removeFinalizer(f), UNIT) } ctx1.cleanups = oldcleanups if (saved) ctx1.bb.emit(LOAD_LOCAL(tmp)) ctx1.bb.emit(RETURN(returnedKind), tree.pos) ctx1.bb.enterIgnoreMode generatedType = expectedType ctx1 case Try(block, catches, finalizer) => val kind = toTypeKind(tree.tpe) var tmp: Local = null val guardResult = kind != UNIT && mayCleanStack(finalizer) if (guardResult) { tmp = ctx.makeLocal(tree.pos, tree.tpe, "tmp") } var handlers = for (CaseDef(pat, _, body) <- catches.reverse) yield pat match { case Typed(Ident(nme.WILDCARD), tpt) => (tpt.tpe.typeSymbol, kind, { ctx: Context => ctx.bb.emit(DROP(REFERENCE(tpt.tpe.typeSymbol))); val ctx1 = genLoad(body, ctx, kind); if (guardResult) { ctx1.bb.emit(STORE_LOCAL(tmp)) val ctx2 = genLoad(finalizer, ctx1, UNIT) ctx2.bb.emit(LOAD_LOCAL(tmp)) ctx2 } else genLoad(finalizer, ctx1, UNIT); }) case Ident(nme.WILDCARD) => (definitions.ThrowableClass, kind, { ctx: Context => ctx.bb.emit(DROP(REFERENCE(definitions.ThrowableClass))) val ctx1 = genLoad(body, ctx, kind) if (guardResult) { ctx1.bb.emit(STORE_LOCAL(tmp)) val ctx2 = genLoad(finalizer, ctx1, UNIT) ctx2.bb.emit(LOAD_LOCAL(tmp)) ctx2 } else genLoad(finalizer, ctx1, UNIT) }) case Bind(name, _) => val exception = ctx.method.addLocal(new Local(pat.symbol, toTypeKind(pat.symbol.tpe), false)) (pat.symbol.tpe.typeSymbol, kind, { ctx: Context => ctx.bb.emit(STORE_LOCAL(exception), pat.pos); val ctx1 = genLoad(body, ctx, kind); if (guardResult) { ctx1.bb.emit(STORE_LOCAL(tmp)) val ctx2 = genLoad(finalizer, ctx1, UNIT) ctx2.bb.emit(LOAD_LOCAL(tmp)) ctx2 } else genLoad(finalizer, ctx1, UNIT); }) } val duppedFinalizer = (new DuplicateLabels(ctx.labels.keySet))(ctx, finalizer) if (settings.debug.value) log("Duplicated finalizer: " + duppedFinalizer) ctx.Try( bodyCtx => { generatedType = kind; //toTypeKind(block.tpe); val ctx1 = genLoad(block, bodyCtx, generatedType); if (guardResult) { val tmp = ctx1.makeLocal(tree.pos, tree.tpe, "tmp") ctx1.bb.emit(STORE_LOCAL(tmp)) val ctx2 = genLoad(duppedFinalizer, ctx1, UNIT) ctx2.bb.emit(LOAD_LOCAL(tmp)) ctx2 } else genLoad(duppedFinalizer, ctx1, UNIT) }, handlers, finalizer) case Throw(expr) => val ctx1 = genLoad(expr, ctx, THROWABLE) ctx1.bb.emit(THROW(), tree.pos) ctx1.bb.enterIgnoreMode generatedType = SCALA_ALL ctx1 case New(tpt) => abort("Unexpected New") case Apply(TypeApply(fun, targs), _) => val sym = fun.symbol var ctx1 = ctx var cast = false if (sym == definitions.Object_isInstanceOf) cast = false else if (sym == definitions.Object_asInstanceOf) cast = true else abort("Unexpected type application " + fun + "[sym: " + sym.fullNameString + "]" + " in: " + tree) val Select(obj, _) = fun val l = toTypeKind(obj.tpe) val r = toTypeKind(targs.head.tpe) ctx1 = genLoadQualifier(fun, ctx) if (l.isValueType && r.isValueType) genConversion(l, r, ctx1, cast) else if (l.isValueType) { ctx1.bb.emit(DROP(l), fun.pos) if (cast) { ctx1.bb.emit(NEW(REFERENCE(definitions.getClass("ClassCastException")))) ctx1.bb.emit(DUP(ANY_REF_CLASS)) ctx1.bb.emit(THROW()) } else ctx1.bb.emit(CONSTANT(Constant(false))) } else if (r.isValueType && cast) { assert(false) /* Erasure should have added an unboxing operation to prevent that. */ } else if (r.isValueType) ctx.bb.emit(IS_INSTANCE(REFERENCE(definitions.boxedClass(r.toType.typeSymbol)))) else genCast(l, r, ctx1, cast); generatedType = if (cast) r else BOOL; ctx1 // 'super' call: Note: since constructors are supposed to // return an instance of what they construct, we have to take // special care. On JVM they are 'void', and Scala forbids (syntactically) // to call super constructors explicitly and/or use their 'returned' value. // therefore, we can ignore this fact, and generate code that leaves nothing // on the stack (contrary to what the type in the AST says). case Apply(fun @ Select(Super(_, mix), _), args) => if (settings.debug.value) log("Call to super: " + tree); val invokeStyle = SuperCall(mix)// if (fun.symbol.isConstructor) Static(true) else SuperCall(mix); ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos) val ctx1 = genLoadArguments(args, fun.symbol.info.paramTypes, ctx) ctx1.bb.emit(CALL_METHOD(fun.symbol, invokeStyle), tree.pos) generatedType = if (fun.symbol.isConstructor) UNIT else toTypeKind(fun.symbol.info.resultType) ctx1 // 'new' constructor call: Note: since constructors are // thought to return an instance of what they construct, // we have to 'simulate' it by DUPlicating the freshly created // instance (on JVM, <init> methods return VOID). case Apply(fun @ Select(New(tpt), nme.CONSTRUCTOR), args) => val ctor = fun.symbol if (settings.debug.value) assert(ctor.isClassConstructor, "'new' call to non-constructor: " + ctor.name) generatedType = toTypeKind(fun.tpe.resultType) if (settings.debug.value) assert(generatedType.isReferenceType || generatedType.isArrayType, "Non reference type cannot be instantiated: " + generatedType) var ctx1 = ctx generatedType match { case arr @ ARRAY(elem) => ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?