From 9ae096330d07c1a865b934bb2bc978464824bd7e Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 30 Dec 2011 11:14:38 -0800 Subject: Optimization in refchecks. addVarargBridges is extremely expensive to cover such a corner case (scala classes inheriting and overriding java varargs methods.) Added a fast path excluding every class which doesn't have a java varargs method somewhere amidst its ancestors. --- .../scala/reflect/internal/Definitions.scala | 1 + .../scala/tools/nsc/typechecker/RefChecks.scala | 86 +++++++++++++--------- 2 files changed, 51 insertions(+), 36 deletions(-) diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index fe20613c22..54c1153f81 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -296,6 +296,7 @@ trait Definitions extends reflect.api.StandardDefinitions { def isRepeatedParamType(tp: Type) = isScalaRepeatedParamType(tp) || isJavaRepeatedParamType(tp) def isCastSymbol(sym: Symbol) = sym == Any_asInstanceOf || sym == Object_asInstanceOf + def isJavaVarArgsMethod(m: Symbol) = m.isMethod && isJavaVarArgs(m.info.params) def isJavaVarArgs(params: List[Symbol]) = params.nonEmpty && isJavaRepeatedParamType(params.last.tpe) def isScalaVarArgs(params: List[Symbol]) = params.nonEmpty && isScalaRepeatedParamType(params.last.tpe) def isVarArgsList(params: List[Symbol]) = params.nonEmpty && isRepeatedParamType(params.last.tpe) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index f920f3c135..59a1a254c6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -150,49 +150,64 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R } // Override checking ------------------------------------------------------------ + + def isJavaVarargsAncestor(clazz: Symbol) = ( + clazz.isClass + && clazz.isJavaDefined + && (clazz.info.nonPrivateMembers exists isJavaVarArgsMethod) + ) /** Add bridges for vararg methods that extend Java vararg methods */ def addVarargBridges(clazz: Symbol): List[Tree] = { - val self = clazz.thisType - val bridges = new ListBuffer[Tree] - - def varargBridge(member: Symbol, bridgetpe: Type): Tree = { - val bridge = member.cloneSymbolImpl(clazz) - .setPos(clazz.pos).setFlag(member.flags | VBRIDGE) - bridge.setInfo(bridgetpe.cloneInfo(bridge)) - clazz.info.decls enter bridge - val List(params) = bridge.paramss - val TypeRef(_, JavaRepeatedParamClass, List(elemtp)) = params.last.tpe - val (initargs, List(lastarg0)) = (params map Ident) splitAt (params.length - 1) - val lastarg = gen.wildcardStar(gen.mkWrapArray(lastarg0, elemtp)) - val body = Apply(Select(This(clazz), member), initargs ::: List(lastarg)) - localTyper.typed { - /*util.trace("generating varargs bridge")*/(DefDef(bridge, body)) + // This is quite expensive, so attempt to skip it completely. + // Insist there at least be a java-defined ancestor which + // defines a varargs method. TODO: Find a cheaper way to exclude. + if (clazz.thisType.baseClasses exists isJavaVarargsAncestor) { + log("Found java varargs ancestor in " + clazz.fullLocationString + ".") + val self = clazz.thisType + val bridges = new ListBuffer[Tree] + + def varargBridge(member: Symbol, bridgetpe: Type): Tree = { + log("Generating varargs bridge for " + member.fullLocationString + " of type " + bridgetpe) + + val bridge = member.cloneSymbolImpl(clazz) + .setPos(clazz.pos).setFlag(member.flags | VBRIDGE) + bridge.setInfo(bridgetpe.cloneInfo(bridge)) + clazz.info.decls enter bridge + + val params = bridge.paramss.head + val elemtp = params.last.tpe.typeArgs.head + val idents = params map Ident + val lastarg = gen.wildcardStar(gen.mkWrapArray(idents.last, elemtp)) + val body = Apply(Select(This(clazz), member), idents.init :+ lastarg) + + localTyper typed DefDef(bridge, body) } - } - - // For all concrete non-private members that have a (Scala) repeated parameter: - // compute the corresponding method type `jtpe` with a Java repeated parameter - // if a method with type `jtpe` exists and that method is not a varargs bridge - // then create a varargs bridge of type `jtpe` that forwards to the - // member method with the Scala vararg type. - for (member <- clazz.info.nonPrivateMembers) { - if (!(member hasFlag DEFERRED) && hasRepeatedParam(member.info)) { - val jtpe = toJavaRepeatedParam(self.memberType(member)) - val inherited = clazz.info.nonPrivateMemberAdmitting(member.name, VBRIDGE) filter ( - sym => (self.memberType(sym) matches jtpe) && !(sym hasFlag VBRIDGE) - // this is a bit tortuous: we look for non-private members or bridges - // if we find a bridge everything is OK. If we find another member, - // we need to create a bridge - ) - if (inherited.exists) { - bridges += varargBridge(member, jtpe) + + // For all concrete non-private members that have a (Scala) repeated parameter: + // compute the corresponding method type `jtpe` with a Java repeated parameter + // if a method with type `jtpe` exists and that method is not a varargs bridge + // then create a varargs bridge of type `jtpe` that forwards to the + // member method with the Scala vararg type. + for (member <- clazz.info.nonPrivateMembers) { + if (!member.isDeferred && member.isMethod && hasRepeatedParam(member.info)) { + val inherited = clazz.info.nonPrivateMemberAdmitting(member.name, VBRIDGE) + // Delaying calling memberType as long as possible + if (inherited ne NoSymbol) { + val jtpe = toJavaRepeatedParam(self.memberType(member)) + // this is a bit tortuous: we look for non-private members or bridges + // if we find a bridge everything is OK. If we find another member, + // we need to create a bridge + if (inherited filter (sym => (self.memberType(sym) matches jtpe) && !(sym hasFlag VBRIDGE)) exists) + bridges += varargBridge(member, jtpe) + } } } + + bridges.toList } - - bridges.toList + else Nil } /** 1. Check all members of class `clazz` for overriding conditions. @@ -1549,7 +1564,6 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R checkOverloadedRestrictions(currentOwner) val bridges = addVarargBridges(currentOwner) checkAllOverrides(currentOwner) - if (bridges.nonEmpty) treeCopy.Template(tree, parents, self, body ::: bridges) else tree -- cgit v1.2.3