summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIulian Dragos <jaguarul@gmail.com>2008-06-26 13:16:20 +0000
committerIulian Dragos <jaguarul@gmail.com>2008-06-26 13:16:20 +0000
commit2e217be7e0ec4108b3cdb41e5214b95e94d048de (patch)
tree1df5a1cbc908fd19926beb6ad6dc75f6a5af85f0
parent777083075664e39075c977a9bc47bf0379521611 (diff)
downloadscala-2e217be7e0ec4108b3cdb41e5214b95e94d048de.tar.gz
scala-2e217be7e0ec4108b3cdb41e5214b95e94d048de.tar.bz2
scala-2e217be7e0ec4108b3cdb41e5214b95e94d048de.zip
Added support for generating static forwarders ...
Added support for generating static forwarders for objects that have companion classes (see #363).
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala110
1 files 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