From 2e217be7e0ec4108b3cdb41e5214b95e94d048de Mon Sep 17 00:00:00 2001 From: Iulian Dragos Date: Thu, 26 Jun 2008 13:16:20 +0000 Subject: Added support for generating static forwarders ... Added support for generating static forwarders for objects that have companion classes (see #363). --- .../scala/tools/nsc/backend/jvm/GenJVM.scala | 110 ++++++++++++++------- 1 file changed, 72 insertions(+), 38 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 5252699198..0772a0507e 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -107,9 +107,11 @@ abstract class GenJVM extends SubComponent { val emitLines = settings.debuginfo.level >= 2 val emitVars = settings.debuginfo.level >= 3 - /** - * @param jclass ... - * @param sym ... + /** Write a class to disk, adding the Scala signature (pickled type information) and + * inner classes. + * + * @param jclass The FJBG class, where code was emitted + * @param sym The corresponding symbol, used for looking up pickled information */ def emitClass(jclass: JClass, sym: Symbol) { def addScalaAttr(sym: Symbol): Unit = currentRun.symData.get(sym) match { @@ -181,7 +183,6 @@ abstract class GenJVM extends SubComponent { javaName(parents(0).typeSymbol), ifaces, c.cunit.source.toString) - if (isStaticModule(c.symbol) || serialVUID != None) { if (isStaticModule(c.symbol)) addModuleInstanceField; @@ -189,16 +190,14 @@ abstract class GenJVM extends SubComponent { if (isTopLevelModule(c.symbol)) { if (c.symbol.linkedClassOfModule == NoSymbol) - dumpMirrorClass; - else if (c.symbol.linkedClassOfModule != NoSymbol && - !currentRun.compiles(c.symbol.linkedClassOfModule)) { - log("Dumping mirror class for " + c.symbol + " even though " + - "linked class exists, but is not compiled in this run") - dumpMirrorClass - } else + dumpMirrorClass(c.symbol, c.cunit.source.toString); + else log("No mirror class for module with linked class: " + c.symbol.fullNameString) } + } else if (c.symbol.linkedModuleOfClass != NoSymbol && !c.symbol.hasFlag(Flags.INTERFACE)) { + log("Adding forwarders to existing class " + c.symbol + " found in module " + c.symbol.linkedModuleOfClass) + addForwarders(jclass, c.symbol.linkedModuleOfClass.moduleClass) } clasz.fields foreach genField @@ -523,11 +522,8 @@ abstract class GenJVM extends SubComponent { jmethod.addAttribute(fjbgContext.JOtherAttribute(jclass, jmethod, "Bridge", new Array[Byte](0))) } - if (remoteClass || - (m.symbol.hasAttribute(RemoteAttr) && jmethod.isPublic() && !forCLDC)) { - val ainfo = AnnotationInfo(ThrowsAttr.tpe, List(new AnnotationArgument(Constant(RemoteException))), List()) - m.symbol.attributes = ainfo :: m.symbol.attributes; - } + + addRemoteException(m.symbol) if (!jmethod.isAbstract() && !method.native) { jcode = jmethod.getCode().asInstanceOf[JExtendedCode] @@ -567,6 +563,17 @@ abstract class GenJVM extends SubComponent { addParamAnnotations(m.params.map(_.sym.attributes)) } + private def addRemoteException(meth: Symbol) { + if (remoteClass || + (meth.hasAttribute(RemoteAttr) + && jmethod.isPublic() + && !forCLDC)) { + val ainfo = AnnotationInfo(ThrowsAttr.tpe, List(new AnnotationArgument(Constant(RemoteException))), List()) + if (!meth.attributes.contains(ainfo)) + meth.attributes = ainfo :: meth.attributes; + } + } + /** Return a pair of lists of annotations, first one containing all * annotations for the given symbol, and the rest. @@ -623,33 +630,43 @@ abstract class GenJVM extends SubComponent { clinit.emitRETURN() } - def dumpMirrorClass { + /** Add forwarders for all methods defined in `module' that don't conflict with + * methods in the companion class of `module'. A conflict arises when a method + * with the same name is defined both in a class and its companion object (method + * signature is not taken into account). + */ + def addForwarders(jclass: JClass, module: Symbol) { + def conflictsIn(cls: Symbol, name: Name) = + cls.info.nonPrivateMembers.exists(_.name == name) + + /** Should method `m' get a forwarder in the mirror class? */ + def shouldForward(m: Symbol): Boolean = + (m.owner != definitions.ObjectClass + && m.isMethod + && !m.hasFlag(Flags.CASE | Flags.PROTECTED) + && !m.isConstructor + && !m.isStaticMember + && !conflictsIn(definitions.ObjectClass, m.name) + && !conflictsIn(module.linkedClassOfModule, m.name)) + import JAccessFlags._ - assert(clasz.symbol.isModuleClass) + assert(module.isModuleClass) if (settings.debug.value) - log("Dumping mirror class for object: " + clasz); - val moduleName = javaName(clasz.symbol) // + "$" + log("Dumping mirror class for object: " + module); + + val moduleName = javaName(module) // + "$" val mirrorName = moduleName.substring(0, moduleName.length() - 1) - val mirrorClass = fjbgContext.JClass(ACC_SUPER | ACC_PUBLIC | ACC_FINAL, - mirrorName, - "java.lang.Object", - JClass.NO_INTERFACES, - clasz.cunit.source.toString) - for (val m <- clasz.symbol.tpe.nonPrivateMembers; - m.owner != definitions.ObjectClass && !m.hasFlag(Flags.PROTECTED) && - m.isMethod && !m.hasFlag(Flags.CASE) && !m.isConstructor && !m.isStaticMember && - !definitions.ObjectClass.info.nonPrivateMembers.exists(_.name == m.name)) - { - val paramJavaTypes = m.tpe.paramTypes map (t => toTypeKind(t)); + + for (m <- module.tpe.nonPrivateMembers; if shouldForward(m)) { + val paramJavaTypes = m.tpe.paramTypes map toTypeKind val paramNames: Array[String] = new Array[String](paramJavaTypes.length); for (val i <- 0.until(paramJavaTypes.length)) paramNames(i) = "x_" + i - val mirrorMethod = mirrorClass - .addNewMethod(ACC_PUBLIC | ACC_FINAL | ACC_STATIC, - javaName(m), - javaType(m.tpe.resultType), - javaTypes(paramJavaTypes), - paramNames); + val mirrorMethod = jclass.addNewMethod(ACC_PUBLIC | ACC_FINAL | ACC_STATIC, + javaName(m), + javaType(m.tpe.resultType), + javaTypes(paramJavaTypes), + paramNames); val mirrorCode = mirrorMethod.getCode().asInstanceOf[JExtendedCode]; mirrorCode.emitGETSTATIC(moduleName, nme.MODULE_INSTANCE_FIELD.toString, @@ -666,11 +683,28 @@ abstract class GenJVM extends SubComponent { mirrorCode.emitINVOKEVIRTUAL(moduleName, mirrorMethod.getName(), mirrorMethod.getType().asInstanceOf[JMethodType]) mirrorCode.emitRETURN(mirrorMethod.getReturnType()) + addRemoteException(m) val (throws, others) = splitAnnotations(m.attributes, ThrowsAttr) addExceptionsAttribute(mirrorMethod, throws) addAnnotations(mirrorMethod, others) } - emitClass(mirrorClass, clasz.symbol) + } + + /** Dump a mirror class for a top-level module. A mirror class is a class containing + * only static methods that forward to the corresponding method on the MODULE instance + * of the given Scala object. + */ + def dumpMirrorClass(clasz: Symbol, sourceFile: String) { + import JAccessFlags._ + val moduleName = javaName(clasz) // + "$" + val mirrorName = moduleName.substring(0, moduleName.length() - 1) + val mirrorClass = fjbgContext.JClass(ACC_SUPER | ACC_PUBLIC | ACC_FINAL, + mirrorName, + "java.lang.Object", + JClass.NO_INTERFACES, + sourceFile) + addForwarders(mirrorClass, clasz) + emitClass(mirrorClass, clasz) } var linearization: List[BasicBlock] = Nil -- cgit v1.2.3