|
Scala example source code file (BCodeSkelBuilder.scala)
The BCodeSkelBuilder.scala Scala example source code/* NSC -- new Scala compiler * Copyright 2005-2012 LAMP/EPFL * @author Martin Odersky */ package scala package tools.nsc package backend package jvm import scala.collection.{ mutable, immutable } import scala.tools.nsc.symtab._ import scala.annotation.switch import scala.tools.asm import scala.tools.asm.util.{TraceMethodVisitor, ASMifier} import java.io.PrintWriter /* * * @author Miguel Garcia, http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/ * @version 1.0 * */ abstract class BCodeSkelBuilder extends BCodeHelpers { import global._ /* * There's a dedicated PlainClassBuilder for each CompilationUnit, * which simplifies the initialization of per-class data structures in `genPlainClass()` which in turn delegates to `initJClass()` * * The entry-point to emitting bytecode instructions is `genDefDef()` where the per-method data structures are initialized, * including `resetMethodBookkeeping()` and `initJMethod()`. * Once that's been done, and assuming the method being visited isn't abstract, `emitNormalMethodBody()` populates * the ASM MethodNode instance with ASM AbstractInsnNodes. * * Given that CleanUp delivers trees that produce values on the stack, * the entry-point to all-things instruction-emit is `genLoad()`. * There, an operation taking N arguments results in recursively emitting instructions to lead each of them, * followed by emitting instructions to process those arguments (to be found at run-time on the operand-stack). * * In a few cases the above recipe deserves more details, as provided in the documentation for: * - `genLoadTry()` * - `genSynchronized() * - `jumpDest` , `cleanups` , `labelDefsAtOrUnder` */ abstract class PlainSkelBuilder(cunit: CompilationUnit) extends BCClassGen with BCAnnotGen with BCInnerClassGen with JAndroidBuilder with BCForwardersGen with BCPickles with BCJGenSigGen { // Strangely I can't find this in the asm code 255, but reserving 1 for "this" final val MaximumJvmParameters = 254 // current class var cnode: asm.tree.ClassNode = null var thisName: String = null // the internal name of the class being emitted var claszSymbol: Symbol = null var isCZParcelable = false var isCZStaticModule = false var isCZRemote = false /* ---------------- idiomatic way to ask questions to typer ---------------- */ def paramTKs(app: Apply): List[BType] = { val Apply(fun, _) = app val funSym = fun.symbol (funSym.info.paramTypes map toTypeKind) // this tracks mentioned inner classes (in innerClassBufferASM) } def symInfoTK(sym: Symbol): BType = { toTypeKind(sym.info) // this tracks mentioned inner classes (in innerClassBufferASM) } def tpeTK(tree: Tree): BType = { toTypeKind(tree.tpe) } def log(msg: => AnyRef) { global synchronized { global.log(msg) } } override def getCurrentCUnit(): CompilationUnit = { cunit } /* ---------------- helper utils for generating classes and fiels ---------------- */ def genPlainClass(cd: ClassDef) { assert(cnode == null, "GenBCode detected nested methods.") innerClassBufferASM.clear() claszSymbol = cd.symbol isCZParcelable = isAndroidParcelableClass(claszSymbol) isCZStaticModule = isStaticModule(claszSymbol) isCZRemote = isRemote(claszSymbol) thisName = internalName(claszSymbol) cnode = new asm.tree.ClassNode() initJClass(cnode) val hasStaticCtor = methodSymbols(cd) exists (_.isStaticConstructor) if (!hasStaticCtor) { // but needs one ... if (isCZStaticModule || isCZParcelable) { fabricateStaticInit() } } val optSerial: Option[Long] = serialVUID(claszSymbol) if (optSerial.isDefined) { addSerialVUID(optSerial.get, cnode)} addClassFields() innerClassBufferASM ++= trackMemberClasses(claszSymbol, Nil) gen(cd.impl) addInnerClassesASM(cnode, innerClassBufferASM.toList) if (AsmUtils.traceClassEnabled && cnode.name.contains(AsmUtils.traceClassPattern)) AsmUtils.traceClass(cnode) cnode.innerClasses assert(cd.symbol == claszSymbol, "Someone messed up BCodePhase.claszSymbol during genPlainClass().") } // end of method genPlainClass() /* * must-single-thread */ private def initJClass(jclass: asm.ClassVisitor) { val ps = claszSymbol.info.parents val superClass: String = if (ps.isEmpty) JAVA_LANG_OBJECT.getInternalName else internalName(ps.head.typeSymbol); val ifaces: Array[String] = { val arrIfacesTr: Array[Tracked] = exemplar(claszSymbol).ifaces val arrIfaces = new Array[String](arrIfacesTr.length) var i = 0 while (i < arrIfacesTr.length) { val ifaceTr = arrIfacesTr(i) val bt = ifaceTr.c if (ifaceTr.isInnerClass) { innerClassBufferASM += bt } arrIfaces(i) = bt.getInternalName i += 1 } arrIfaces } // `internalName()` tracks inner classes. val flags = mkFlags( javaFlags(claszSymbol), if (isDeprecated(claszSymbol)) asm.Opcodes.ACC_DEPRECATED else 0 // ASM pseudo access flag ) val thisSignature = getGenericSignature(claszSymbol, claszSymbol.owner) cnode.visit(classfileVersion, flags, thisName, thisSignature, superClass, ifaces) if (emitSource) { cnode.visitSource(cunit.source.toString, null /* SourceDebugExtension */) } val enclM = getEnclosingMethodAttribute(claszSymbol) if (enclM != null) { val EnclMethodEntry(className, methodName, methodType) = enclM cnode.visitOuterClass(className, methodName, methodType.getDescriptor) } val ssa = getAnnotPickle(thisName, claszSymbol) cnode.visitAttribute(if (ssa.isDefined) pickleMarkerLocal else pickleMarkerForeign) emitAnnotations(cnode, claszSymbol.annotations ++ ssa) if (isCZStaticModule || isCZParcelable) { if (isCZStaticModule) { addModuleInstanceField() } } else { val skipStaticForwarders = (claszSymbol.isInterface || settings.noForwarders) if (!skipStaticForwarders) { val lmoc = claszSymbol.companionModule // add static forwarders if there are no name conflicts; see bugs #363 and #1735 if (lmoc != NoSymbol) { // it must be a top level class (name contains no $s) val isCandidateForForwarders = { exitingPickler { !(lmoc.name.toString contains '$') && lmoc.hasModuleFlag && !lmoc.isImplClass && !lmoc.isNestedClass } } if (isCandidateForForwarders) { log(s"Adding static forwarders from '$claszSymbol' to implementations in '$lmoc'") addForwarders(isRemote(claszSymbol), cnode, thisName, lmoc.moduleClass) } } } } // the invoker is responsible for adding a class-static constructor. } // end of method initJClass /* * can-multi-thread */ private def addModuleInstanceField() { val fv = cnode.visitField(PublicStaticFinal, // TODO confirm whether we really don't want ACC_SYNTHETIC nor ACC_DEPRECATED strMODULE_INSTANCE_FIELD, "L" + thisName + ";", null, // no java-generic-signature null // no initial value ) fv.visitEnd() } /* * must-single-thread */ private def fabricateStaticInit() { val clinit: asm.MethodVisitor = cnode.visitMethod( PublicStatic, // TODO confirm whether we really don't want ACC_SYNTHETIC nor ACC_DEPRECATED CLASS_CONSTRUCTOR_NAME, "()V", null, // no java-generic-signature null // no throwable exceptions ) clinit.visitCode() /* "legacy static initialization" */ if (isCZStaticModule) { clinit.visitTypeInsn(asm.Opcodes.NEW, thisName) clinit.visitMethodInsn(asm.Opcodes.INVOKESPECIAL, thisName, INSTANCE_CONSTRUCTOR_NAME, "()V") } if (isCZParcelable) { legacyAddCreatorCode(clinit, cnode, thisName) } clinit.visitInsn(asm.Opcodes.RETURN) clinit.visitMaxs(0, 0) // just to follow protocol, dummy arguments clinit.visitEnd() } def addClassFields() { /* Non-method term members are fields, except for module members. Module * members can only happen on .NET (no flatten) for inner traits. There, * a module symbol is generated (transformInfo in mixin) which is used * as owner for the members of the implementation class (so that the * backend emits them as static). * No code is needed for this module symbol. */ for (f <- fieldSymbols(claszSymbol)) { val javagensig = getGenericSignature(f, claszSymbol) val flags = mkFlags( javaFieldFlags(f), if (isDeprecated(f)) asm.Opcodes.ACC_DEPRECATED else 0 // ASM pseudo access flag ) val jfield = new asm.tree.FieldNode( flags, f.javaSimpleName.toString, symInfoTK(f).getDescriptor, javagensig, null // no initial value ) cnode.fields.add(jfield) emitAnnotations(jfield, f.annotations) } } // end of method addClassFields() // current method var mnode: asm.tree.MethodNode = null var jMethodName: String = null var isMethSymStaticCtor = false var returnType: BType = null var methSymbol: Symbol = null // in GenASM this is local to genCode(), ie should get false whenever a new method is emitted (including fabricated ones eg addStaticInit()) var isModuleInitialized = false // used by genLoadTry() and genSynchronized() var earlyReturnVar: Symbol = null var shouldEmitCleanup = false var insideCleanupBlock = false // line numbers var lastEmittedLineNr = -1 object bc extends JCodeMethodN { override def jmethod = PlainSkelBuilder.this.mnode } /* ---------------- Part 1 of program points, ie Labels in the ASM world ---------------- */ /* * A jump is represented as an Apply node whose symbol denotes a LabelDef, the target of the jump. * The `jumpDest` map is used to: * (a) find the asm.Label for the target, given an Apply node's symbol; * (b) anchor an asm.Label in the instruction stream, given a LabelDef node. * In other words, (a) is necessary when visiting a jump-source, and (b) when visiting a jump-target. * A related map is `labelDef`: it has the same keys as `jumpDest` but its values are LabelDef nodes not asm.Labels. * */ var jumpDest: immutable.Map[ /* LabelDef */ Symbol, asm.Label ] = null def programPoint(labelSym: Symbol): asm.Label = { assert(labelSym.isLabel, s"trying to map a non-label symbol to an asm.Label, at: ${labelSym.pos}") jumpDest.getOrElse(labelSym, { val pp = new asm.Label jumpDest += (labelSym -> pp) pp }) } /* * A program point may be lexically nested (at some depth) * (a) in the try-clause of a try-with-finally expression * (b) in a synchronized block. * Each of the constructs above establishes a "cleanup block" to execute upon * both normal-exit, early-return, and abrupt-termination of the instructions it encloses. * * The `cleanups` LIFO queue represents the nesting of active (for the current program point) * pending cleanups. For each such cleanup an asm.Label indicates the start of its cleanup-block. * At any given time during traversal of the method body, * the head of `cleanups` denotes the cleanup-block for the closest enclosing try-with-finally or synchronized-expression. * * `cleanups` is used: * * (1) upon visiting a Return statement. * In case of pending cleanups, we can't just emit a RETURN instruction, but must instead: * - store the result (if any) in `earlyReturnVar`, and * - jump to the next pending cleanup. * See `genReturn()` * * (2) upon emitting a try-with-finally or a synchronized-expr, * In these cases, the targets of the above jumps are emitted, * provided an early exit was actually encountered somewhere in the protected clauses. * See `genLoadTry()` and `genSynchronized()` * * The code thus emitted for jumps and targets covers the early-return case. * The case of abrupt (ie exceptional) termination is covered by exception handlers * emitted for that purpose as described in `genLoadTry()` and `genSynchronized()`. */ var cleanups: List[asm.Label] = Nil def registerCleanup(finCleanup: asm.Label) { if (finCleanup != null) { cleanups = finCleanup :: cleanups } } def unregisterCleanup(finCleanup: asm.Label) { if (finCleanup != null) { assert(cleanups.head eq finCleanup, s"Bad nesting of cleanup operations: $cleanups trying to unregister: $finCleanup") cleanups = cleanups.tail } } /* ---------------- local variables and params ---------------- */ case class Local(tk: BType, name: String, idx: Int, isSynth: Boolean) /* * Bookkeeping for method-local vars and method-params. */ object locals { private val slots = mutable.Map.empty[Symbol, Local] // (local-or-param-sym -> Local(BType, name, idx, isSynth)) private var nxtIdx = -1 // next available index for local-var def reset(isStaticMethod: Boolean) { slots.clear() nxtIdx = if (isStaticMethod) 0 else 1 } def contains(locSym: Symbol): Boolean = { slots.contains(locSym) } def apply(locSym: Symbol): Local = { slots.apply(locSym) } /* Make a fresh local variable, ensuring a unique name. * The invoker must make sure inner classes are tracked for the sym's tpe. */ def makeLocal(tk: BType, name: String): Symbol = { val locSym = methSymbol.newVariable(cunit.freshTermName(name), NoPosition, Flags.SYNTHETIC) // setInfo tpe makeLocal(locSym, tk) locSym } def makeLocal(locSym: Symbol): Local = { makeLocal(locSym, symInfoTK(locSym)) } def getOrMakeLocal(locSym: Symbol): Local = { // `getOrElse` below has the same effect as `getOrElseUpdate` because `makeLocal()` adds an entry to the `locals` map. slots.getOrElse(locSym, makeLocal(locSym)) } private def makeLocal(sym: Symbol, tk: BType): Local = { assert(!slots.contains(sym), "attempt to create duplicate local var.") assert(nxtIdx != -1, "not a valid start index") val loc = Local(tk, sym.javaSimpleName.toString, nxtIdx, sym.isSynthetic) slots += (sym -> loc) assert(tk.getSize > 0, "makeLocal called for a symbol whose type is Unit.") nxtIdx += tk.getSize loc } // not to be confused with `fieldStore` and `fieldLoad` which also take a symbol but a field-symbol. def store(locSym: Symbol) { val Local(tk, _, idx, _) = slots(locSym) bc.store(idx, tk) } def load(locSym: Symbol) { val Local(tk, _, idx, _) = slots(locSym) bc.load(idx, tk) } } /* ---------------- Part 2 of program points, ie Labels in the ASM world ---------------- */ /* * The semantics of try-with-finally and synchronized-expr require their cleanup code * to be present in three forms in the emitted bytecode: * (a) as normal-exit code, reached via fall-through from the last program point being protected, * (b) as code reached upon early-return from an enclosed return statement. * The only difference between (a) and (b) is their next program-point: * the former must continue with fall-through while * the latter must continue to the next early-return cleanup (if any, otherwise return from the method). * Otherwise they are identical. * (c) as exception-handler, reached via exceptional control flow, * which rethrows the caught exception once it's done with the cleanup code. * * A particular cleanup may in general contain LabelDefs. Care is needed when duplicating such jump-targets, * so as to preserve agreement wit the (also duplicated) jump-sources. * This is achieved based on the bookkeeping provided by two maps: * - `labelDefsAtOrUnder` lists all LabelDefs enclosed by a given Tree node (the key) * - `labelDef` provides the LabelDef node whose symbol is used as key. * As a sidenote, a related map is `jumpDest`: it has the same keys as `labelDef` but its values are asm.Labels not LabelDef nodes. * * Details in `emitFinalizer()`, which is invoked from `genLoadTry()` and `genSynchronized()`. */ var labelDefsAtOrUnder: scala.collection.Map[Tree, List[LabelDef]] = null var labelDef: scala.collection.Map[Symbol, LabelDef] = null// (LabelDef-sym -> LabelDef) // bookkeeping the scopes of non-synthetic local vars, to emit debug info (`emitVars`). var varsInScope: List[Tuple2[Symbol, asm.Label]] = null // (local-var-sym -> start-of-scope) // helpers around program-points. def lastInsn: asm.tree.AbstractInsnNode = { mnode.instructions.getLast } def currProgramPoint(): asm.Label = { lastInsn match { case labnode: asm.tree.LabelNode => labnode.getLabel case _ => val pp = new asm.Label mnode visitLabel pp pp } } def markProgramPoint(lbl: asm.Label) { val skip = (lbl == null) || isAtProgramPoint(lbl) if (!skip) { mnode visitLabel lbl } } def isAtProgramPoint(lbl: asm.Label): Boolean = { (lastInsn match { case labnode: asm.tree.LabelNode => (labnode.getLabel == lbl); case _ => false } ) } def lineNumber(tree: Tree) { if (!emitLines || !tree.pos.isDefined) return; val nr = tree.pos.finalPosition.line if (nr != lastEmittedLineNr) { lastEmittedLineNr = nr lastInsn match { case lnn: asm.tree.LineNumberNode => // overwrite previous landmark as no instructions have been emitted for it lnn.line = nr case _ => mnode.visitLineNumber(nr, currProgramPoint()) } } } // on entering a method def resetMethodBookkeeping(dd: DefDef) { locals.reset(isStaticMethod = methSymbol.isStaticMember) jumpDest = immutable.Map.empty[ /* LabelDef */ Symbol, asm.Label ] // populate labelDefsAtOrUnder val ldf = new LabelDefsFinder ldf.traverse(dd.rhs) labelDefsAtOrUnder = ldf.result.withDefaultValue(Nil) labelDef = labelDefsAtOrUnder(dd.rhs).map(ld => (ld.symbol -> ld)).toMap // check previous invocation of genDefDef exited as many varsInScope as it entered. assert(varsInScope == null, "Unbalanced entering/exiting of GenBCode's genBlock().") // check previous invocation of genDefDef unregistered as many cleanups as it registered. assert(cleanups == Nil, "Previous invocation of genDefDef didn't unregister as many cleanups as it registered.") isModuleInitialized = false earlyReturnVar = null shouldEmitCleanup = false lastEmittedLineNr = -1 } /* ---------------- top-down traversal invoking ASM Tree API along the way ---------------- */ def gen(tree: Tree) { tree match { case EmptyTree => () case _: ModuleDef => abort(s"Modules should have been eliminated by refchecks: $tree") case ValDef(mods, name, tpt, rhs) => () // fields are added in `genPlainClass()`, via `addClassFields()` case dd : DefDef => genDefDef(dd) case Template(_, _, body) => body foreach gen case _ => abort(s"Illegal tree in gen: $tree") } } /* * must-single-thread */ def initJMethod(flags: Int, paramAnnotations: List[List[AnnotationInfo]]) { val jgensig = getGenericSignature(methSymbol, claszSymbol) addRemoteExceptionAnnot(isCZRemote, hasPublicBitSet(flags), methSymbol) val (excs, others) = methSymbol.annotations partition (_.symbol == definitions.ThrowsClass) val thrownExceptions: List[String] = getExceptions(excs) val bytecodeName = if (isMethSymStaticCtor) CLASS_CONSTRUCTOR_NAME else jMethodName val mdesc = asmMethodType(methSymbol).getDescriptor mnode = cnode.visitMethod( flags, bytecodeName, mdesc, jgensig, mkArray(thrownExceptions) ).asInstanceOf[asm.tree.MethodNode] // TODO param names: (m.params map (p => javaName(p.sym))) emitAnnotations(mnode, others) emitParamAnnotations(mnode, paramAnnotations) } // end of method initJMethod def genDefDef(dd: DefDef) { // the only method whose implementation is not emitted: getClass() if (definitions.isGetClass(dd.symbol)) { return } assert(mnode == null, "GenBCode detected nested method.") methSymbol = dd.symbol jMethodName = methSymbol.javaSimpleName.toString returnType = asmMethodType(dd.symbol).getReturnType isMethSymStaticCtor = methSymbol.isStaticConstructor resetMethodBookkeeping(dd) // add method-local vars for params val DefDef(_, _, _, vparamss, _, rhs) = dd assert(vparamss.isEmpty || vparamss.tail.isEmpty, s"Malformed parameter list: $vparamss") val params = if (vparamss.isEmpty) Nil else vparamss.head for (p <- params) { locals.makeLocal(p.symbol) } // debug assert((params.map(p => locals(p.symbol).tk)) == asmMethodType(methSymbol).getArgumentTypes.toList, "debug") if (params.size > MaximumJvmParameters) { // SI-7324 cunit.error(methSymbol.pos, s"Platform restriction: a parameter list's length cannot exceed $MaximumJvmParameters.") return } val isNative = methSymbol.hasAnnotation(definitions.NativeAttr) val isAbstractMethod = (methSymbol.isDeferred || methSymbol.owner.isInterface) val flags = mkFlags( javaFlags(methSymbol), if (claszSymbol.isInterface) asm.Opcodes.ACC_ABSTRACT else 0, if (methSymbol.isStrictFP) asm.Opcodes.ACC_STRICT else 0, if (isNative) asm.Opcodes.ACC_NATIVE else 0, // native methods of objects are generated in mirror classes if (isDeprecated(methSymbol)) asm.Opcodes.ACC_DEPRECATED else 0 // ASM pseudo access flag ) // TODO needed? for(ann <- m.symbol.annotations) { ann.symbol.initialize } initJMethod(flags, params.map(p => p.symbol.annotations)) /* Add method-local vars for LabelDef-params. * * This makes sure that: * (1) upon visiting any "forward-jumping" Apply (ie visited before its target LabelDef), and after * (2) grabbing the corresponding param symbols, * those param-symbols can be used to access method-local vars. * * When duplicating a finally-contained LabelDef, another program-point is needed for the copy (each such copy has its own asm.Label), * but the same vars (given by the LabelDef's params) can be reused, * because no LabelDef ends up nested within itself after such duplication. */ for(ld <- labelDefsAtOrUnder(dd.rhs); ldp <- ld.params; if !locals.contains(ldp.symbol)) { // the tail-calls xform results in symbols shared btw method-params and labelDef-params, thus the guard above. locals.makeLocal(ldp.symbol) } if (!isAbstractMethod && !isNative) { def emitNormalMethodBody() { val veryFirstProgramPoint = currProgramPoint() genLoad(rhs, returnType) rhs match { case Block(_, Return(_)) => () case Return(_) => () case EmptyTree => globalError("Concrete method has no definition: " + dd + ( if (settings.debug) "(found: " + methSymbol.owner.info.decls.toList.mkString(", ") + ")" else "") ) case _ => bc emitRETURN returnType } if (emitVars) { // add entries to LocalVariableTable JVM attribute val onePastLastProgramPoint = currProgramPoint() val hasStaticBitSet = ((flags & asm.Opcodes.ACC_STATIC) != 0) if (!hasStaticBitSet) { mnode.visitLocalVariable( "this", "L" + thisName + ";", null, veryFirstProgramPoint, onePastLastProgramPoint, 0 ) } for (p <- params) { emitLocalVarScope(p.symbol, veryFirstProgramPoint, onePastLastProgramPoint, force = true) } } if (isMethSymStaticCtor) { appendToStaticCtor(dd) } } // end of emitNormalMethodBody() lineNumber(rhs) emitNormalMethodBody() // Note we don't invoke visitMax, thus there are no FrameNode among mnode.instructions. // The only non-instruction nodes to be found are LabelNode and LineNumberNode. } if (AsmUtils.traceMethodEnabled && mnode.name.contains(AsmUtils.traceMethodPattern)) AsmUtils.traceMethod(mnode) mnode = null } // end of method genDefDef() /* * must-single-thread * * TODO document, explain interplay with `fabricateStaticInit()` */ private def appendToStaticCtor(dd: DefDef) { def insertBefore( location: asm.tree.AbstractInsnNode, i0: asm.tree.AbstractInsnNode, i1: asm.tree.AbstractInsnNode) { if (i0 != null) { mnode.instructions.insertBefore(location, i0.clone(null)) mnode.instructions.insertBefore(location, i1.clone(null)) } } // collect all return instructions var rets: List[asm.tree.AbstractInsnNode] = Nil mnode foreachInsn { i => if (i.getOpcode() == asm.Opcodes.RETURN) { rets ::= i } } if (rets.isEmpty) { return } var insnModA: asm.tree.AbstractInsnNode = null var insnModB: asm.tree.AbstractInsnNode = null // call object's private ctor from static ctor if (isCZStaticModule) { // NEW `moduleName` val className = internalName(methSymbol.enclClass) insnModA = new asm.tree.TypeInsnNode(asm.Opcodes.NEW, className) // INVOKESPECIAL <init> val callee = methSymbol.enclClass.primaryConstructor val jname = callee.javaSimpleName.toString val jowner = internalName(callee.owner) val jtype = asmMethodType(callee).getDescriptor insnModB = new asm.tree.MethodInsnNode(asm.Opcodes.INVOKESPECIAL, jowner, jname, jtype) } var insnParcA: asm.tree.AbstractInsnNode = null var insnParcB: asm.tree.AbstractInsnNode = null // android creator code if (isCZParcelable) { // add a static field ("CREATOR") to this class to cache android.os.Parcelable$Creator val andrFieldDescr = asmClassType(AndroidCreatorClass).getDescriptor cnode.visitField( asm.Opcodes.ACC_STATIC | asm.Opcodes.ACC_FINAL, "CREATOR", andrFieldDescr, null, null ) // INVOKESTATIC CREATOR(): android.os.Parcelable$Creator; -- TODO where does this Android method come from? val callee = definitions.getMember(claszSymbol.companionModule, androidFieldName) val jowner = internalName(callee.owner) val jname = callee.javaSimpleName.toString val jtype = asmMethodType(callee).getDescriptor insnParcA = new asm.tree.MethodInsnNode(asm.Opcodes.INVOKESTATIC, jowner, jname, jtype) // PUTSTATIC `thisName`.CREATOR; insnParcB = new asm.tree.FieldInsnNode(asm.Opcodes.PUTSTATIC, thisName, "CREATOR", andrFieldDescr) } // insert a few instructions for initialization before each return instruction for(r <- rets) { insertBefore(r, insnModA, insnModB) insertBefore(r, insnParcA, insnParcB) } } def emitLocalVarScope(sym: Symbol, start: asm.Label, end: asm.Label, force: Boolean = false) { val Local(tk, name, idx, isSynth) = locals(sym) if (force || !isSynth) { mnode.visitLocalVariable(name, tk.getDescriptor, null, start, end, idx) } } def genLoad(tree: Tree, expectedType: BType) } // end of class PlainSkelBuilder } Other Scala source code examplesHere is a short list of links related to this Scala BCodeSkelBuilder.scala source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.