From f0ca26ab84172034f3ac41639d1a5dce242f9a5a Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 11 Jun 2011 20:32:55 +0000 Subject: A third round of optimizations from Tiark, no r... A third round of optimizations from Tiark, no review. --- src/compiler/scala/reflect/internal/Types.scala | 52 ++++++++++++++++------ .../scala/tools/nsc/backend/jvm/GenJVM.scala | 15 ++++--- .../scala/tools/nsc/backend/jvm/GenJVMUtil.scala | 10 ++++- .../scala/tools/nsc/settings/ScalaSettings.scala | 1 + .../scala/tools/nsc/transform/Erasure.scala | 2 +- 5 files changed, 57 insertions(+), 23 deletions(-) diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 1459371349..cb3ec1bfeb 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -877,11 +877,12 @@ trait Types /*extends reflect.generic.Types*/ { self: SymbolTable => // For now I modified it as below, which achieves the same without error. // // make each type var in this type use its original type for comparisons instead of collecting constraints - suspension = new mutable.HashSet + val susp = new mutable.HashSet[TypeVar] // use a local val so it remains unboxed this foreach { - case tv: TypeVar => tv.suspended = true; suspension += tv + case tv: TypeVar => tv.suspended = true; susp += tv case _ => } + suspension = susp } incCounter(findMemberCount) @@ -930,12 +931,14 @@ trait Types /*extends reflect.generic.Types*/ { self: SymbolTable => } } else { var prevEntry = members.lookupEntry(sym.name) + var symtpe: Type = null while ((prevEntry ne null) && !(prevEntry.sym == sym || prevEntry.sym.owner != sym.owner && !sym.hasFlag(PRIVATE) && { if (self eq null) self = this.narrow - self.memberType(prevEntry.sym) matches self.memberType(sym) + if (symtpe eq null) symtpe = self.memberType(sym) + self.memberType(prevEntry.sym) matches symtpe })) { prevEntry = members lookupNextEntry prevEntry } @@ -1844,9 +1847,9 @@ A type's typeSymbol should never be inspected directly. val substTps = formals.intersect(typeParams) if (sameLength(substTps, typeParams)) - typeRef(pre, sym, actuals) + copyTypeRef(this, pre, sym, actuals) else if (sameLength(formals, actuals)) // partial application (needed in infer when bunching type arguments from classes and methods together) - typeRef(pre, sym, dummyArgs).subst(formals, actuals) + copyTypeRef(this, pre, sym, dummyArgs).subst(formals, actuals) else ErrorType } else @@ -1864,7 +1867,7 @@ A type's typeSymbol should never be inspected directly. // @M: initialize (by sym.info call) needed (see test/files/pos/ticket0137.scala) @inline private def etaExpand: Type = { val tpars = sym.info.typeParams // must go through sym.info for typeParams to initialise symbol - typeFunAnon(tpars, typeRef(pre, sym, tpars map (_.tpeHK))) // todo: also beta-reduce? + typeFunAnon(tpars, copyTypeRef(this, pre, sym, tpars map (_.tpeHK))) // todo: also beta-reduce? } override def dealias: Type = @@ -2748,6 +2751,27 @@ A type's typeSymbol should never be inspected directly. } } + def copyTypeRef(tp: Type, pre: Type, sym: Symbol, args: List[Type]): Type = tp match { + case TypeRef(pre0, sym0, args0) => + if ((pre == pre0) && (sym.name == sym0.name)) { + + val sym1 = sym + // we require that object is initialized, thus info.typeParams instead of typeParams. + if (sym1.isAliasType && sameLength(sym1.info.typeParams, args)) { + if (sym1.lockOK) TypeRef(pre, sym1, args) // don't expand type alias (cycles checked by lockOK) + else throw new TypeError("illegal cyclic reference involving " + sym1) + } + else { + TypeRef(pre, sym1, args) + } + + } else + typeRef(pre, sym, args) + } + + + + /** The canonical creator for implicit method types */ def JavaMethodType(params: List[Symbol], resultType: Type): JavaMethodType = new JavaMethodType(params, resultType) // don't unique this! @@ -2794,8 +2818,8 @@ A type's typeSymbol should never be inspected directly. def appliedType(tycon: Type, args: List[Type]): Type = if (args.isEmpty) tycon //@M! `if (args.isEmpty) tycon' is crucial (otherwise we create new types in phases after typer and then they don't get adapted (??)) else tycon match { - case TypeRef(pre, sym @ (NothingClass|AnyClass), _) => typeRef(pre, sym, Nil) //@M drop type args to Any/Nothing - case TypeRef(pre, sym, _) => typeRef(pre, sym, args) + case TypeRef(pre, sym @ (NothingClass|AnyClass), _) => copyTypeRef(tycon, pre, sym, Nil) //@M drop type args to Any/Nothing + case TypeRef(pre, sym, _) => copyTypeRef(tycon, pre, sym, args) case PolyType(tparams, restpe) => restpe.instantiateTypeParams(tparams, args) case ExistentialType(tparams, restpe) => ExistentialType(tparams, appliedType(restpe, args)) case st: SingletonType => appliedType(st.widen, args) // @M TODO: what to do? see bug1 @@ -3079,7 +3103,7 @@ A type's typeSymbol should never be inspected directly. else mapOverArgs(args, tparams) } if ((pre1 eq pre) && (args1 eq args)) tp - else typeRef(pre1, coevolveSym(pre, pre1, sym), args1) + else copyTypeRef(tp, pre1, coevolveSym(pre, pre1, sym), args1) case ThisType(_) => tp case SingleType(pre, sym) => if (sym.isPackageClass) tp // short path @@ -3548,7 +3572,7 @@ A type's typeSymbol should never be inspected directly. /** A map to implement the `substSym' method. */ class SubstSymMap(from: List[Symbol], to: List[Symbol]) extends SubstMap(from, to) { protected def toType(fromtp: Type, sym: Symbol) = fromtp match { - case TypeRef(pre, _, args) => typeRef(pre, sym, args) + case TypeRef(pre, _, args) => copyTypeRef(fromtp, pre, sym, args) case SingleType(pre, _) => singleType(pre, sym) } override def apply(tp: Type): Type = if (from.isEmpty) tp else { @@ -3561,7 +3585,7 @@ A type's typeSymbol should never be inspected directly. case TypeRef(pre, sym, args) if pre ne NoPrefix => val newSym = subst(sym, from, to) // assert(newSym.typeParams.length == sym.typeParams.length, "typars mismatch in SubstSymMap: "+(sym, sym.typeParams, newSym, newSym.typeParams)) - mapOver(typeRef(pre, newSym, args)) // mapOver takes care of subst'ing in args + mapOver(copyTypeRef(tp, pre, newSym, args)) // mapOver takes care of subst'ing in args case SingleType(pre, sym) if pre ne NoPrefix => mapOver(singleType(pre, subst(sym, from, to))) case _ => @@ -3945,7 +3969,7 @@ A type's typeSymbol should never be inspected directly. try { val sym1 = adaptToNewRun(pre1, sym) if ((pre1 eq pre) && (sym1 eq sym) && (args1 eq args)/* && sym.isExternal*/) tp - else typeRef(pre1, sym1, args1) + else copyTypeRef(tp, pre1, sym1, args1) } catch { case ex: MissingAliasControl => apply(tp.dealias) @@ -4087,7 +4111,7 @@ A type's typeSymbol should never be inspected directly. patType match { case TypeRef(pre, sym, args) => val pre1 = maybeCreateDummyClone(pre, sym) - (pre1 ne NoType) && isPopulated(typeRef(pre1, sym, args), selType) + (pre1 ne NoType) && isPopulated(copyTypeRef(patType, pre1, sym, args), selType) case _ => false } @@ -4512,7 +4536,7 @@ A type's typeSymbol should never be inspected directly. def instTypeVar(tp: Type): Type = tp match { case TypeRef(pre, sym, args) => - typeRef(instTypeVar(pre), sym, args) + copyTypeRef(tp, instTypeVar(pre), sym, args) case SingleType(pre, sym) => singleType(instTypeVar(pre), sym) case TypeVar(_, constr) => diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 3ab1a637fa..5b4e783db0 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -255,7 +255,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with parents = parents.distinct if (parents.tail.nonEmpty) - ifaces = parents drop 1 map (x => javaName(x.typeSymbol)) toArray; + ifaces = mkArray(parents drop 1 map (x => javaName(x.typeSymbol))) jclass = fjbgContext.JClass(javaFlags(c.symbol), name, @@ -573,7 +573,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with * in which case we treat every signature as valid. Medium term we * should certainly write independent signature validation. */ - if (SigParser.isParserAvailable && !isValidSignature(sym, sig)) { + if (settings.Xverify.value && SigParser.isParserAvailable && !isValidSignature(sym, sig)) { clasz.cunit.warning(sym.pos, """|compiler bug: created invalid generic signature for %s in %s |signature: %s @@ -750,8 +750,8 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with jmethod = jclass.addNewMethod(flags, javaName(m.symbol), resTpe, - m.params map (p => javaType(p.kind)) toArray, - m.params map (p => javaName(p.sym)) toArray) + mkArray(m.params map (p => javaType(p.kind))), + mkArray(m.params map (p => javaName(p.sym)))) addRemoteException(jmethod, m.symbol) @@ -953,8 +953,8 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with accessFlags, javaName(m), javaType(methodInfo.resultType), - paramJavaTypes.toArray, - paramNames.toArray) + mkArray(paramJavaTypes), + mkArray(paramNames)) val mirrorCode = mirrorMethod.getCode().asInstanceOf[JExtendedCode] mirrorCode.emitGETSTATIC(moduleName, nme.MODULE_INSTANCE_FIELD.toString, @@ -1497,8 +1497,9 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with // assert(instr.pos.source.isEmpty || instr.pos.source.get == (clasz.cunit.source), "sources don't match") // val crtLine = instr.pos.line.get(lastLineNr); + val crtLine = try { - (instr.pos).line + if (instr.pos == NoPosition) lastLineNr else (instr.pos).line // check NoPosition to avoid costly exception } catch { case _: UnsupportedOperationException => log("Warning: wrong position in: " + method) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala index 6ff5d42e55..418dbea9e1 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala @@ -68,6 +68,14 @@ trait GenJVMUtil { GE -> LT ) + /** Specialized array conversion to prevent calling + * java.lang.reflect.Array.newInstance via TraversableOnce.toArray + */ + + def mkArray(xs: Traversable[JType]): Array[JType] = { val a = new Array[JType](xs.size); xs.copyToArray(a); a } + def mkArray(xs: Traversable[String]): Array[String] = { val a = new Array[String](xs.size); xs.copyToArray(a); a } + + /** Return the a name of this symbol that can be used on the Java * platform. It removes spaces from names. * @@ -109,7 +117,7 @@ trait GenJVMUtil { if (s.isMethod) new JMethodType( if (s.isClassConstructor) JType.VOID else javaType(s.tpe.resultType), - s.tpe.paramTypes map javaType toArray + mkArray(s.tpe.paramTypes map javaType) ) else javaType(s.tpe) diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 2ab933f5ba..3dab85f77c 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -61,6 +61,7 @@ trait ScalaSettings extends AbsScalaSettings with StandardScalaSettings { val Xmigration28 = BooleanSetting ("-Xmigration", "Warn about constructs whose behavior may have changed between 2.7 and 2.8.") val nouescape = BooleanSetting ("-Xno-uescape", "Disable handling of \\u unicode escapes.") val Xnojline = BooleanSetting ("-Xnojline", "Do not use JLine for editing.") + val Xverify = BooleanSetting ("-Xverify", "Verify generic signatures in generated bytecode.") val plugin = MultiStringSetting("-Xplugin", "file", "Load one or more plugins from files.") val disable = MultiStringSetting("-Xplugin-disable", "plugin", "Disable the given plugin(s).") val showPlugins = BooleanSetting ("-Xplugin-list", "Print a synopsis of loaded plugins.") diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 2cf3d06866..c5c03b9181 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -230,7 +230,7 @@ abstract class Erasure extends AddInterfaces } } // for debugging signatures: traces logic given system property - private val traceProp = sys.BooleanProp keyExists "scalac.sigs.trace" + private val traceProp = (sys.BooleanProp keyExists "scalac.sigs.trace").value // performance: get the value here private val traceSig = util.Tracer(traceProp) /** This object is only used for sanity testing when -check:genjvm is set. -- cgit v1.2.3