diff options
Diffstat (limited to 'src')
21 files changed, 226 insertions, 373 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index bab658e141..2fa9c076dd 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -121,44 +121,26 @@ abstract class GenICode extends SubComponent { m.native = m.symbol.hasAnnotation(definitions.NativeAttr) if (!m.isAbstractMethod && !m.native) { - val staticfield = if (m.symbol.isAccessor && m.symbol.accessed.hasStaticAnnotation) { - val compClass = m.symbol.owner.companionClass - compClass.info.findMember(m.symbol.accessed.name, NoFlags, NoFlags, false) - } else NoSymbol - if (staticfield != NoSymbol) { - // in companion object accessors to @static fields, we access the static field directly - val hostClass = m.symbol.owner.companionClass - if (m.symbol.isGetter) { - ctx1.bb.emit(LOAD_FIELD(staticfield, true) setHostClass hostClass, tree.pos) - ctx1.bb.closeWith(RETURN(m.returnType)) - } else if (m.symbol.isSetter) { - ctx1.bb.emit(LOAD_LOCAL(m.locals.head), tree.pos) - ctx1.bb.emit(STORE_FIELD(staticfield, true), tree.pos) + ctx1 = genLoad(rhs, ctx1, m.returnType); + + // reverse the order of the local variables, to match the source-order + m.locals = m.locals.reverse + + rhs match { + case Block(_, Return(_)) => () + case Return(_) => () + case EmptyTree => + globalError("Concrete method has no definition: " + tree + ( + if (settings.debug.value) "(found: " + m.symbol.owner.info.decls.toList.mkString(", ") + ")" + else "") + ) + case _ => if (ctx1.bb.isEmpty) + ctx1.bb.closeWith(RETURN(m.returnType), rhs.pos) + else ctx1.bb.closeWith(RETURN(m.returnType)) - } else assert(false, "unreachable") - } else { - ctx1 = genLoad(rhs, ctx1, m.returnType); - - // reverse the order of the local variables, to match the source-order - m.locals = m.locals.reverse - - rhs match { - case Block(_, Return(_)) => () - case Return(_) => () - case EmptyTree => - globalError("Concrete method has no definition: " + tree + ( - if (settings.debug.value) "(found: " + m.symbol.owner.info.decls.toList.mkString(", ") + ")" - else "") - ) - case _ => - if (ctx1.bb.isEmpty) - ctx1.bb.closeWith(RETURN(m.returnType), rhs.pos) - else - ctx1.bb.closeWith(RETURN(m.returnType)) - } - if (!ctx1.bb.closed) ctx1.bb.close - prune(ctx1.method) } + if (!ctx1.bb.closed) ctx1.bb.close + prune(ctx1.method) } else ctx1.method.setCode(NoCode) ctx1 @@ -900,47 +882,6 @@ abstract class GenICode extends SubComponent { generatedType = toTypeKind(fun.symbol.tpe.resultType) ctx1 - case app @ Apply(fun @ Select(qual, _), args) - if !ctx.method.symbol.isStaticConstructor - && fun.symbol.isAccessor && fun.symbol.accessed.hasStaticAnnotation - && qual.tpe.typeSymbol.orElse(fun.symbol.owner).companionClass != NoSymbol => - // bypass the accessor to the companion object and load the static field directly - // this bypass is not done: - // - if the static intializer for the static field itself - // - if there is no companion class of the object owner - this happens in the REPL - def genLoadApply5 = { - val sym = fun.symbol - generatedType = toTypeKind(sym.accessed.info) - val hostOwner = qual.tpe.typeSymbol.orElse(sym.owner) - val hostClass = hostOwner.companionClass - val staticfield = hostClass.info.findMember(sym.accessed.name, NoFlags, NoFlags, false) orElse { - if (!currentRun.compiles(hostOwner)) { - // hostOwner was separately compiled -- the static field symbol needs to be recreated in hostClass - import Flags._ - debuglog("recreating sym.accessed.name: " + sym.accessed.name) - val objectfield = hostOwner.info.findMember(sym.accessed.name, NoFlags, NoFlags, false) - val staticfield = hostClass.newVariable(newTermName(sym.accessed.name.toString), tree.pos, STATIC | SYNTHETIC | FINAL) setInfo objectfield.tpe - staticfield.addAnnotation(definitions.StaticClass) - hostClass.info.decls enter staticfield - staticfield - } else NoSymbol - } - - if (sym.isGetter) { - ctx.bb.emit(LOAD_FIELD(staticfield, true) setHostClass hostClass, tree.pos) - ctx - } else if (sym.isSetter) { - val ctx1 = genLoadArguments(args, sym.info.paramTypes, ctx) - ctx1.bb.emit(STORE_FIELD(staticfield, true), tree.pos) - ctx1.bb.emit(CONSTANT(Constant(false)), tree.pos) - ctx1 - } else { - assert(false, "supposedly unreachable") - ctx - } - } - genLoadApply5 - case app @ Apply(fun, args) => def genLoadApply6 = { val sym = fun.symbol @@ -1732,12 +1673,8 @@ abstract class GenICode extends SubComponent { * backend emits them as static). * No code is needed for this module symbol. */ - for ( - f <- cls.info.decls; - if !f.isMethod && f.isTerm && !f.isModule && !(f.owner.isModuleClass && f.hasStaticAnnotation) - ) { + for (f <- cls.info.decls ; if !f.isMethod && f.isTerm && !f.isModule) ctx.clazz addField new IField(f) - } } /** diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index 1653ca9c2a..28966eef08 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -1190,9 +1190,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { log(s"No forwarder for non-public member $m") else { log("Adding static forwarder for '%s' from %s to '%s'".format(m, jclassName, moduleClass)) - if (m.isAccessor && m.accessed.hasStaticAnnotation) { - log("@static: accessor " + m + ", accessed: " + m.accessed) - } else addForwarder(isRemoteClass, jclass, moduleClass, m) + addForwarder(isRemoteClass, jclass, moduleClass, m) } } } @@ -1697,7 +1695,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { jmethod = clinitMethod jMethodName = CLASS_CONSTRUCTOR_NAME jmethod.visitCode() - computeLocalVarsIndex(m) genCode(m, false, true) jmethod.visitMaxs(0, 0) // just to follow protocol, dummy arguments jmethod.visitEnd() diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index a2151633a7..62c281b82f 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -1023,8 +1023,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with method = m jmethod = clinitMethod - - computeLocalVarsIndex(m) genCode(m) case None => legacyStaticInitializer(cls, clinit) @@ -1126,9 +1124,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with log("No forwarder for " + m + " due to conflict with " + linkedClass.info.member(m.name)) else { log("Adding static forwarder for '%s' from %s to '%s'".format(m, className, moduleClass)) - if (m.isAccessor && m.accessed.hasStaticAnnotation) { - log("@static: accessor " + m + ", accessed: " + m.accessed) - } else addForwarder(jclass, moduleClass, m) + addForwarder(jclass, moduleClass, m) } } } diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index dff9a65649..fa7a53f888 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -23,12 +23,9 @@ abstract class CleanUp extends Transform with ast.TreeDSL { new CleanUpTransformer(unit) class CleanUpTransformer(unit: CompilationUnit) extends Transformer { - private val newStaticMembers = mutable.Buffer.empty[Tree] - private val newStaticInits = mutable.Buffer.empty[Tree] - private val symbolsStoredAsStatic = mutable.Map.empty[String, Symbol] - private val staticBodies = mutable.Map.empty[(Symbol, Symbol), Tree] - private val syntheticClasses = mutable.Map.empty[Symbol, mutable.Set[Tree]] // package and trees - private val classNames = mutable.Map.empty[Symbol, Set[Name]] + private val newStaticMembers = mutable.Buffer.empty[Tree] + private val newStaticInits = mutable.Buffer.empty[Tree] + private val symbolsStoredAsStatic = mutable.Map.empty[String, Symbol] private def clearStatics() { newStaticMembers.clear() newStaticInits.clear() @@ -48,9 +45,8 @@ abstract class CleanUp extends Transform with ast.TreeDSL { result } private def transformTemplate(tree: Tree) = { - val t @ Template(parents, self, body) = tree + val Template(parents, self, body) = tree clearStatics() - val newBody = transformTrees(body) val templ = deriveTemplate(tree)(_ => transformTrees(newStaticMembers.toList) ::: newBody) try addStaticInits(templ) // postprocess to include static ctors @@ -550,80 +546,6 @@ abstract class CleanUp extends Transform with ast.TreeDSL { else tree } - case DefDef(mods, name, tps, vps, tp, rhs) if tree.symbol.hasStaticAnnotation => - reporter.error(tree.pos, "The @static annotation is not allowed on method definitions.") - super.transform(tree) - - case ValDef(mods, name, tpt, rhs) if tree.symbol.hasStaticAnnotation => - def transformStaticValDef = { - log("moving @static valdef field: " + name + ", in: " + tree.symbol.owner) - val sym = tree.symbol - val owner = sym.owner - - val staticBeforeLifting = atPhase(currentRun.erasurePhase) { owner.isStatic } - val isPrivate = atPhase(currentRun.typerPhase) { sym.getter(owner).hasFlag(PRIVATE) } - val isProtected = atPhase(currentRun.typerPhase) { sym.getter(owner).hasFlag(PROTECTED) } - val isLazy = atPhase(currentRun.typerPhase) { sym.getter(owner).hasFlag(LAZY) } - if (!owner.isModuleClass || !staticBeforeLifting) { - if (!sym.isSynthetic) { - reporter.error(tree.pos, "Only members of top-level objects and their nested objects can be annotated with @static.") - tree.symbol.removeAnnotation(StaticClass) - } - super.transform(tree) - } else if (isPrivate || isProtected) { - reporter.error(tree.pos, "The @static annotation is only allowed on public members.") - tree.symbol.removeAnnotation(StaticClass) - super.transform(tree) - } else if (isLazy) { - reporter.error(tree.pos, "The @static annotation is not allowed on lazy members.") - tree.symbol.removeAnnotation(StaticClass) - super.transform(tree) - } else if (owner.isModuleClass) { - val linkedClass = owner.companionClass match { - case NoSymbol => - // create the companion class if it does not exist - val enclosing = owner.owner - val compclass = enclosing.newClass(newTypeName(owner.name.toString)) - compclass setInfo ClassInfoType(List(ObjectClass.tpe), newScope, compclass) - enclosing.info.decls enter compclass - - val compclstree = ClassDef(compclass, NoMods, ListOfNil, ListOfNil, List(), tree.pos) - - syntheticClasses.getOrElseUpdate(enclosing, mutable.Set()) += compclstree - - compclass - case comp => comp - } - - // create a static field in the companion class for this @static field - val stfieldSym = linkedClass.newValue(newTermName(name), tree.pos, STATIC | SYNTHETIC | FINAL) setInfo sym.tpe - if (sym.isMutable) stfieldSym.setFlag(MUTABLE) - stfieldSym.addAnnotation(StaticClass) - - val names = classNames.getOrElseUpdate(linkedClass, linkedClass.info.decls.collect { - case sym if sym.name.isTermName => sym.name - } toSet) - if (names(stfieldSym.name)) { - reporter.error( - tree.pos, - "@static annotated field " + tree.symbol.name + " has the same name as a member of class " + linkedClass.name - ) - } else { - linkedClass.info.decls enter stfieldSym - - val initializerBody = rhs - - // static field was previously initialized in the companion object itself, like this: - // staticBodies((linkedClass, stfieldSym)) = Select(This(owner), sym.getter(owner)) - // instead, we move the initializer to the static ctor of the companion class - // we save the entire ValDef/DefDef to extract the rhs later - staticBodies((linkedClass, stfieldSym)) = tree - } - } - super.transform(tree) - } - transformStaticValDef - /* MSIL requires that the stack is empty at the end of a try-block. * Hence, we here rewrite all try blocks with a result != {Unit, All} such that they * store their result in a local variable. The catch blocks are adjusted as well. @@ -738,11 +660,6 @@ abstract class CleanUp extends Transform with ast.TreeDSL { if (newStaticInits.isEmpty) template else { - val ctorBody = newStaticInits.toList flatMap { - case Block(stats, expr) => stats :+ expr - case t => List(t) - } - val newCtor = findStaticCtor(template) match { // in case there already were static ctors - augment existing ones // currently, however, static ctors aren't being generated anywhere else @@ -751,15 +668,15 @@ abstract class CleanUp extends Transform with ast.TreeDSL { deriveDefDef(ctor) { case block @ Block(stats, expr) => // need to add inits to existing block - treeCopy.Block(block, ctorBody ::: stats, expr) + treeCopy.Block(block, newStaticInits.toList ::: stats, expr) case term: TermTree => // need to create a new block with inits and the old term - treeCopy.Block(term, ctorBody, term) + treeCopy.Block(term, newStaticInits.toList, term) } case _ => // create new static ctor val staticCtorSym = currentClass.newStaticConstructor(template.pos) - val rhs = Block(ctorBody, Literal(Constant(()))) + val rhs = Block(newStaticInits.toList, Literal(Constant(()))) localTyper.typedPos(template.pos)(DefDef(staticCtorSym, rhs)) } @@ -767,62 +684,6 @@ abstract class CleanUp extends Transform with ast.TreeDSL { } } - private def addStaticDeclarations(tree: Template, clazz: Symbol) { - // add static field initializer statements for each static field in clazz - if (!clazz.isModuleClass) for { - staticSym <- clazz.info.decls - if staticSym.hasStaticAnnotation - } staticSym match { - case stfieldSym if (stfieldSym.isValue && !stfieldSym.isMethod) || stfieldSym.isVariable => - log(stfieldSym + " is value: " + stfieldSym.isValue) - val valdef = staticBodies((clazz, stfieldSym)) - val ValDef(_, _, _, rhs) = valdef - val fixedrhs = rhs.changeOwner((valdef.symbol, clazz.info.decl(nme.CONSTRUCTOR))) - - val stfieldDef = localTyper.typedPos(tree.pos)(VAL(stfieldSym) === EmptyTree) - val flattenedInit = fixedrhs match { - case Block(stats, expr) => Block(stats, REF(stfieldSym) === expr) - case rhs => REF(stfieldSym) === rhs - } - val stfieldInit = localTyper.typedPos(tree.pos)(flattenedInit) - - // add field definition to new defs - newStaticMembers append stfieldDef - newStaticInits append stfieldInit - case _ => // ignore @static on other members - } - } - - - - override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { - super.transformStats(stats, exprOwner) ++ { - // flush pending synthetic classes created in this owner - val synthclassdefs = syntheticClasses.get(exprOwner).toList.flatten - syntheticClasses -= exprOwner - synthclassdefs map { - cdef => localTyper.typedPos(cdef.pos)(cdef) - } - } map { - case clsdef @ ClassDef(mods, name, tparams, t @ Template(parent, self, body)) => - // process all classes in the package again to add static initializers - clearStatics() - - addStaticDeclarations(t, clsdef.symbol) - - val templ = deriveTemplate(t)(_ => transformTrees(newStaticMembers.toList) ::: body) - val ntempl = - try addStaticInits(templ) - finally clearStatics() - - val derived = deriveClassDef(clsdef)(_ => ntempl) - classNames.remove(clsdef.symbol) - derived - - case stat => stat - } - } - } // CleanUpTransformer } diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index afc109c47a..23b15a9033 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -186,15 +186,12 @@ abstract class Constructors extends Transform with ast.TreeDSL { // before the superclass constructor call, otherwise it goes after. // Lazy vals don't get the assignment in the constructor. if (!stat.symbol.tpe.isInstanceOf[ConstantType]) { - if (stat.symbol.hasStaticAnnotation) { - debuglog("@static annotated field initialization skipped.") - defBuf += deriveValDef(stat)(tree => tree) - } else if (rhs != EmptyTree && !stat.symbol.isLazy) { + if (rhs != EmptyTree && !stat.symbol.isLazy) { val rhs1 = intoConstructor(stat.symbol, rhs); (if (canBeMoved(stat)) constrPrefixBuf else constrStatBuf) += mkAssign( stat.symbol, rhs1) - defBuf += deriveValDef(stat)(_ => EmptyTree) } + defBuf += deriveValDef(stat)(_ => EmptyTree) } case ClassDef(_, _, _, _) => // classes are treated recursively, and left in the template diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index b6d54f114e..c41ff20229 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -154,7 +154,7 @@ abstract class LambdaLift extends InfoTransform { private def markCalled(sym: Symbol, owner: Symbol) { debuglog("mark called: " + sym + " of " + sym.owner + " is called by " + owner) symSet(called, owner) addEntry sym - if (sym.enclClass != owner.enclClass) calledFromInner addEntry sym + if (sym.enclClass != owner.enclClass) calledFromInner += sym } /** The traverse function */ diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index d941519958..091224c88a 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -175,7 +175,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => val thunks = freeTerms map (fte => () => fte.value) // need to be lazy in order not to distort evaluation order verify(expr) - def wrap(expr0: Tree): Tree = { + def wrap(expr0: Tree): ModuleDef = { val (expr, freeTerms) = extractFreeTerms(expr0, wrapFreeTermRefs = true) val (obj, mclazz) = rootMirror.EmptyPackageClass.newModuleAndClassSymbol( @@ -213,11 +213,11 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => var cleanedUp = resetLocalAttrs(moduledef) trace("cleaned up: ")(showAttributed(cleanedUp, true, true, settings.Yshowsymkinds.value)) - cleanedUp + cleanedUp.asInstanceOf[ModuleDef] } val mdef = wrap(expr) - val pdef = PackageDef(Ident(nme.EMPTY_PACKAGE_NAME), List(mdef)) + val pdef = PackageDef(Ident(mdef.name), List(mdef)) val unit = new CompilationUnit(NoSourceFile) unit.body = pdef diff --git a/src/library/scala/App.scala b/src/library/scala/App.scala index 85d2f9075e..a1e5e74e2f 100644 --- a/src/library/scala/App.scala +++ b/src/library/scala/App.scala @@ -22,6 +22,16 @@ import scala.collection.mutable.ListBuffer * * `args` returns the current command line arguments as an array. * + * ==Caveats== + * + * '''''It should be noted that this trait is implemented using the [[DelayedInit]] + * functionality, which means that fields of the object will not have been initialized + * before the main method has been executed.''''' + * + * It should also be noted that the `main` method will not normally need to be overridden: + * the purpose is to turn the whole class body into the “main method”. You should only + * chose to override it if you know what you are doing. + * * @author Martin Odersky * @version 2.1, 15/02/2011 */ diff --git a/src/library/scala/annotation/static.scala b/src/library/scala/annotation/static.scala deleted file mode 100644 index f2955c756c..0000000000 --- a/src/library/scala/annotation/static.scala +++ /dev/null @@ -1,20 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2002-2011, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.annotation - -/** - * An annotation that marks a member in the companion object as static - * and ensures that the compiler generates static fields/methods for it. - * This is important for Java interoperability and performance reasons. - * - * @since 2.10 - */ -final class static extends StaticAnnotation { - // TODO document exact semantics above! -} diff --git a/src/library/scala/collection/mutable/FlatHashTable.scala b/src/library/scala/collection/mutable/FlatHashTable.scala index 12066055e9..74f576b0f7 100644 --- a/src/library/scala/collection/mutable/FlatHashTable.scala +++ b/src/library/scala/collection/mutable/FlatHashTable.scala @@ -44,7 +44,7 @@ trait FlatHashTable[A] extends FlatHashTable.HashUtils[A] { */ @transient protected var sizemap: Array[Int] = null - @transient var seedvalue: Int = tableSizeSeed + @transient protected var seedvalue: Int = tableSizeSeed import HashTable.powerOfTwo @@ -109,7 +109,7 @@ trait FlatHashTable[A] extends FlatHashTable.HashUtils[A] { } /** Finds an entry in the hash table if such an element exists. */ - def findEntry(elem: A): Option[A] = { + protected def findEntry(elem: A): Option[A] = { var h = index(elemHashCode(elem)) var entry = table(h) while (null != entry && entry != elem) { @@ -120,7 +120,7 @@ trait FlatHashTable[A] extends FlatHashTable.HashUtils[A] { } /** Checks whether an element is contained in the hash table. */ - def containsEntry(elem: A): Boolean = { + protected def containsEntry(elem: A): Boolean = { var h = index(elemHashCode(elem)) var entry = table(h) while (null != entry && entry != elem) { @@ -133,7 +133,7 @@ trait FlatHashTable[A] extends FlatHashTable.HashUtils[A] { /** Add entry if not yet in table. * @return Returns `true` if a new entry was added, `false` otherwise. */ - def addEntry(elem: A) : Boolean = { + protected def addEntry(elem: A) : Boolean = { var h = index(elemHashCode(elem)) var entry = table(h) while (null != entry) { @@ -150,7 +150,7 @@ trait FlatHashTable[A] extends FlatHashTable.HashUtils[A] { } /** Removes an entry from the hash table, returning an option value with the element, or `None` if it didn't exist. */ - def removeEntry(elem: A) : Option[A] = { + protected def removeEntry(elem: A) : Option[A] = { if (tableDebug) checkConsistent() def precedes(i: Int, j: Int) = { val d = table.length >> 1 @@ -185,7 +185,7 @@ trait FlatHashTable[A] extends FlatHashTable.HashUtils[A] { None } - def iterator: Iterator[A] = new AbstractIterator[A] { + protected def iterator: Iterator[A] = new AbstractIterator[A] { private var i = 0 def hasNext: Boolean = { while (i < table.length && (null == table(i))) i += 1 diff --git a/src/library/scala/collection/mutable/HashMap.scala b/src/library/scala/collection/mutable/HashMap.scala index da486f4042..be85df3c28 100644 --- a/src/library/scala/collection/mutable/HashMap.scala +++ b/src/library/scala/collection/mutable/HashMap.scala @@ -49,7 +49,7 @@ extends AbstractMap[A, B] type Entry = DefaultEntry[A, B] override def empty: HashMap[A, B] = HashMap.empty[A, B] - override def clear() = clearTable() + override def clear() { clearTable() } override def size: Int = tableSize def this() = this(null) @@ -57,22 +57,23 @@ extends AbstractMap[A, B] override def par = new ParHashMap[A, B](hashTableContents) // contains and apply overridden to avoid option allocations. - override def contains(key: A) = findEntry(key) != null + override def contains(key: A): Boolean = findEntry(key) != null + override def apply(key: A): B = { val result = findEntry(key) - if (result == null) default(key) + if (result eq null) default(key) else result.value } def get(key: A): Option[B] = { val e = findEntry(key) - if (e == null) None + if (e eq null) None else Some(e.value) } override def put(key: A, value: B): Option[B] = { - val e = findEntry(key) - if (e == null) { addEntry(new Entry(key, value)); None } + val e = findOrAddEntry(key, value) + if (e eq null) None else { val v = e.value; e.value = value; Some(v) } } @@ -85,9 +86,8 @@ extends AbstractMap[A, B] } def += (kv: (A, B)): this.type = { - val e = findEntry(kv._1) - if (e == null) addEntry(new Entry(kv._1, kv._2)) - else e.value = kv._2 + val e = findOrAddEntry(kv._1, kv._2) + if (e ne null) e.value = kv._2 this } @@ -127,12 +127,19 @@ extends AbstractMap[A, B] if (!isSizeMapDefined) sizeMapInitAndRebuild } else sizeMapDisable + protected def createNewEntry[B1](key: A, value: B1): Entry = { + new Entry(key, value.asInstanceOf[B]) + } + private def writeObject(out: java.io.ObjectOutputStream) { - serializeTo(out, _.value) + serializeTo(out, { entry => + out.writeObject(entry.key) + out.writeObject(entry.value) + }) } private def readObject(in: java.io.ObjectInputStream) { - init[B](in, new Entry(_, _)) + init(in, createNewEntry(in.readObject().asInstanceOf[A], in.readObject())) } } diff --git a/src/library/scala/collection/mutable/HashSet.scala b/src/library/scala/collection/mutable/HashSet.scala index b263b46d36..a5b636c83d 100644 --- a/src/library/scala/collection/mutable/HashSet.scala +++ b/src/library/scala/collection/mutable/HashSet.scala @@ -53,7 +53,7 @@ extends AbstractSet[A] override def companion: GenericCompanion[HashSet] = HashSet - override def size = tableSize + override def size: Int = tableSize def contains(elem: A): Boolean = containsEntry(elem) @@ -67,7 +67,9 @@ extends AbstractSet[A] override def remove(elem: A): Boolean = removeEntry(elem).isDefined - override def clear() = clearTable() + override def clear() { clearTable() } + + override def iterator: Iterator[A] = super[FlatHashTable].iterator override def foreach[U](f: A => U) { var i = 0 diff --git a/src/library/scala/collection/mutable/HashTable.scala b/src/library/scala/collection/mutable/HashTable.scala index 968d99d042..eb6717393b 100644 --- a/src/library/scala/collection/mutable/HashTable.scala +++ b/src/library/scala/collection/mutable/HashTable.scala @@ -32,6 +32,9 @@ package mutable * @tparam A type of the elements contained in this hash table. */ trait HashTable[A, Entry >: Null <: HashEntry[A, Entry]] extends HashTable.HashUtils[A] { + // Replacing Entry type parameter by abstract type member here allows to not expose to public + // implementation-specific entry classes such as `DefaultEntry` or `LinkedEntry`. + // However, I'm afraid it's too late now for such breaking change. import HashTable._ @transient protected var _loadFactor = defaultLoadFactor @@ -52,7 +55,7 @@ trait HashTable[A, Entry >: Null <: HashEntry[A, Entry]] extends HashTable.HashU */ @transient protected var sizemap: Array[Int] = null - @transient var seedvalue: Int = tableSizeSeed + @transient protected var seedvalue: Int = tableSizeSeed protected def tableSizeSeed = Integer.bitCount(table.length - 1) @@ -75,11 +78,10 @@ trait HashTable[A, Entry >: Null <: HashEntry[A, Entry]] extends HashTable.HashU } /** - * Initializes the collection from the input stream. `f` will be called for each key/value pair - * read from the input stream in the order determined by the stream. This is useful for - * structures where iteration order is important (e.g. LinkedHashMap). + * Initializes the collection from the input stream. `readEntry` will be called for each + * entry to be read from the input stream. */ - private[collection] def init[B](in: java.io.ObjectInputStream, f: (A, B) => Entry) { + private[collection] def init(in: java.io.ObjectInputStream, readEntry: => Entry) { in.defaultReadObject _loadFactor = in.readInt() @@ -100,35 +102,34 @@ trait HashTable[A, Entry >: Null <: HashEntry[A, Entry]] extends HashTable.HashU var index = 0 while (index < size) { - addEntry(f(in.readObject().asInstanceOf[A], in.readObject().asInstanceOf[B])) + addEntry(readEntry) index += 1 } } /** * Serializes the collection to the output stream by saving the load factor, collection - * size, collection keys and collection values. `value` is responsible for providing a value - * from an entry. + * size and collection entries. `writeEntry` is responsible for writing an entry to the stream. * - * `foreach` determines the order in which the key/value pairs are saved to the stream. To + * `foreachEntry` determines the order in which the key/value pairs are saved to the stream. To * deserialize, `init` should be used. */ - private[collection] def serializeTo[B](out: java.io.ObjectOutputStream, value: Entry => B) { + private[collection] def serializeTo(out: java.io.ObjectOutputStream, writeEntry: Entry => Unit) { out.defaultWriteObject out.writeInt(_loadFactor) out.writeInt(tableSize) out.writeInt(seedvalue) out.writeBoolean(isSizeMapDefined) - foreachEntry { entry => - out.writeObject(entry.key) - out.writeObject(value(entry)) - } + + foreachEntry(writeEntry) } /** Find entry with given key in table, null if not found. */ - protected def findEntry(key: A): Entry = { - val h = index(elemHashCode(key)) + protected def findEntry(key: A): Entry = + findEntry0(key, index(elemHashCode(key))) + + private[this] def findEntry0(key: A, h: Int): Entry = { var e = table(h).asInstanceOf[Entry] while (e != null && !elemEquals(e.key, key)) e = e.next e @@ -138,7 +139,10 @@ trait HashTable[A, Entry >: Null <: HashEntry[A, Entry]] extends HashTable.HashU * pre: no entry with same key exists */ protected def addEntry(e: Entry) { - val h = index(elemHashCode(e.key)) + addEntry0(e, index(elemHashCode(e.key))) + } + + private[this] def addEntry0(e: Entry, h: Int) { e.next = table(h).asInstanceOf[Entry] table(h) = e tableSize = tableSize + 1 @@ -147,6 +151,24 @@ trait HashTable[A, Entry >: Null <: HashEntry[A, Entry]] extends HashTable.HashU resize(2 * table.length) } + /** Find entry with given key in table, or add new one if not found. + * May be somewhat faster then `findEntry`/`addEntry` pair as it + * computes entry's hash index only once. + * Returns entry found in table or null. + * New entries are created by calling `createNewEntry` method. + */ + protected def findOrAddEntry[B](key: A, value: B): Entry = { + val h = index(elemHashCode(key)) + val e = findEntry0(key, h) + if (e ne null) e else { addEntry0(createNewEntry(key, value), h); null } + } + + /** Creates new entry to be immediately inserted into the hashtable. + * This method is guaranteed to be called only once and in case that the entry + * will be added. In other words, an implementation may be side-effecting. + */ + protected def createNewEntry[B](key: A, value: B): Entry + /** Remove entry from table if present. */ protected def removeEntry(key: A) : Entry = { @@ -195,7 +217,7 @@ trait HashTable[A, Entry >: Null <: HashEntry[A, Entry]] extends HashTable.HashU } /** Avoid iterator for a 2x faster traversal. */ - protected def foreachEntry[C](f: Entry => C) { + protected def foreachEntry[U](f: Entry => U) { val iterTable = table var idx = lastPopulatedIndex var es = iterTable(idx) diff --git a/src/library/scala/collection/mutable/LinkedHashMap.scala b/src/library/scala/collection/mutable/LinkedHashMap.scala index 5643e070f8..5028884a8e 100644 --- a/src/library/scala/collection/mutable/LinkedHashMap.scala +++ b/src/library/scala/collection/mutable/LinkedHashMap.scala @@ -67,23 +67,9 @@ class LinkedHashMap[A, B] extends AbstractMap[A, B] } override def put(key: A, value: B): Option[B] = { - val e = findEntry(key) - if (e == null) { - val e = new Entry(key, value) - addEntry(e) - updateLinkedEntries(e) - None - } else { - val v = e.value - e.value = value - Some(v) - } - } - - private def updateLinkedEntries(e: Entry) { - if (firstEntry == null) firstEntry = e - else { lastEntry.later = e; e.earlier = lastEntry } - lastEntry = e + val e = findOrAddEntry(key, value) + if (e eq null) None + else { val v = e.value; e.value = value; Some(v) } } override def remove(key: A): Option[B] = { @@ -143,7 +129,7 @@ class LinkedHashMap[A, B] extends AbstractMap[A, B] else Iterator.empty.next } - override def foreach[U](f: ((A, B)) => U) = { + override def foreach[U](f: ((A, B)) => U) { var cur = firstEntry while (cur ne null) { f((cur.key, cur.value)) @@ -151,7 +137,7 @@ class LinkedHashMap[A, B] extends AbstractMap[A, B] } } - protected override def foreachEntry[C](f: Entry => C) { + protected override def foreachEntry[U](f: Entry => U) { var cur = firstEntry while (cur ne null) { f(cur) @@ -159,22 +145,29 @@ class LinkedHashMap[A, B] extends AbstractMap[A, B] } } + protected def createNewEntry[B1](key: A, value: B1): Entry = { + val e = new Entry(key, value.asInstanceOf[B]) + if (firstEntry eq null) firstEntry = e + else { lastEntry.later = e; e.earlier = lastEntry } + lastEntry = e + e + } + override def clear() { clearTable() firstEntry = null } private def writeObject(out: java.io.ObjectOutputStream) { - serializeTo(out, _.value) + serializeTo(out, { entry => + out.writeObject(entry.key) + out.writeObject(entry.value) + }) } private def readObject(in: java.io.ObjectInputStream) { firstEntry = null lastEntry = null - init[B](in, { (key, value) => - val entry = new Entry(key, value) - updateLinkedEntries(entry) - entry - }) + init(in, createNewEntry(in.readObject().asInstanceOf[A], in.readObject())) } } diff --git a/src/library/scala/collection/mutable/LinkedHashSet.scala b/src/library/scala/collection/mutable/LinkedHashSet.scala index 3f789f9fa2..88bad5ff9b 100644 --- a/src/library/scala/collection/mutable/LinkedHashSet.scala +++ b/src/library/scala/collection/mutable/LinkedHashSet.scala @@ -19,6 +19,7 @@ import generic._ * * @author Matthias Zenger * @author Martin Odersky + * @author Pavel Pavlov * @version 2.0, 31/12/2006 * @since 1 * @@ -43,46 +44,82 @@ class LinkedHashSet[A] extends AbstractSet[A] with Set[A] with GenericSetTemplate[A, LinkedHashSet] with SetLike[A, LinkedHashSet[A]] - with FlatHashTable[A] + with HashTable[A, LinkedHashSet.Entry[A]] with Serializable { override def companion: GenericCompanion[LinkedHashSet] = LinkedHashSet - @transient private[this] var ordered = new ListBuffer[A] + type Entry = LinkedHashSet.Entry[A] - override def size = tableSize + @transient protected var firstEntry: Entry = null + @transient protected var lastEntry: Entry = null - def contains(elem: A): Boolean = containsEntry(elem) + override def size: Int = tableSize + + def contains(elem: A): Boolean = findEntry(elem) ne null def += (elem: A): this.type = { add(elem); this } def -= (elem: A): this.type = { remove(elem); this } - override def add(elem: A): Boolean = - if (addEntry(elem)) { ordered += elem; true } - else false + override def add(elem: A): Boolean = findOrAddEntry(elem, null) eq null + + override def remove(elem: A): Boolean = { + val e = removeEntry(elem) + if (e eq null) false + else { + if (e.earlier eq null) firstEntry = e.later + else e.earlier.later = e.later + if (e.later eq null) lastEntry = e.earlier + else e.later.earlier = e.earlier + true + } + } - override def remove(elem: A): Boolean = - removeEntry(elem) match { - case None => false - case _ => ordered -= elem; true + def iterator: Iterator[A] = new AbstractIterator[A] { + private var cur = firstEntry + def hasNext = cur ne null + def next = + if (hasNext) { val res = cur.key; cur = cur.later; res } + else Iterator.empty.next + } + + override def foreach[U](f: A => U) { + var cur = firstEntry + while (cur ne null) { + f(cur.key) + cur = cur.later } + } - override def clear() { - ordered.clear() - clearTable() + protected override def foreachEntry[U](f: Entry => U) { + var cur = firstEntry + while (cur ne null) { + f(cur) + cur = cur.later + } } - override def iterator: Iterator[A] = ordered.iterator + protected def createNewEntry[B](key: A, dummy: B): Entry = { + val e = new Entry(key) + if (firstEntry eq null) firstEntry = e + else { lastEntry.later = e; e.earlier = lastEntry } + lastEntry = e + e + } - override def foreach[U](f: A => U) = ordered foreach f + override def clear() { + clearTable() + firstEntry = null + } - private def writeObject(s: java.io.ObjectOutputStream) { - serializeTo(s) + private def writeObject(out: java.io.ObjectOutputStream) { + serializeTo(out, { e => out.writeObject(e.key) }) } private def readObject(in: java.io.ObjectInputStream) { - ordered = new ListBuffer[A] - init(in, ordered += _) + firstEntry = null + lastEntry = null + init(in, createNewEntry(in.readObject().asInstanceOf[A], null)) } } @@ -93,5 +130,13 @@ class LinkedHashSet[A] extends AbstractSet[A] object LinkedHashSet extends MutableSetFactory[LinkedHashSet] { implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, LinkedHashSet[A]] = setCanBuildFrom[A] override def empty[A]: LinkedHashSet[A] = new LinkedHashSet[A] + + /** Class for the linked hash set entry, used internally. + * @since 2.10 + */ + private[scala] final class Entry[A](val key: A) extends HashEntry[A, Entry[A]] with Serializable { + var earlier: Entry[A] = null + var later: Entry[A] = null + } } diff --git a/src/library/scala/collection/parallel/mutable/ParHashMap.scala b/src/library/scala/collection/parallel/mutable/ParHashMap.scala index 1921727ce3..fad7ddad59 100644 --- a/src/library/scala/collection/parallel/mutable/ParHashMap.scala +++ b/src/library/scala/collection/parallel/mutable/ParHashMap.scala @@ -67,13 +67,13 @@ self => def get(key: K): Option[V] = { val e = findEntry(key) - if (e == null) None + if (e eq null) None else Some(e.value) } def put(key: K, value: V): Option[V] = { - val e = findEntry(key) - if (e == null) { addEntry(new Entry(key, value)); None } + val e = findOrAddEntry(key, value) + if (e eq null) None else { val v = e.value; e.value = value; Some(v) } } @@ -86,9 +86,8 @@ self => } def += (kv: (K, V)): this.type = { - val e = findEntry(kv._1) - if (e == null) addEntry(new Entry(kv._1, kv._2)) - else e.value = kv._2 + val e = findOrAddEntry(kv._1, kv._2) + if (e ne null) e.value = kv._2 this } @@ -103,12 +102,19 @@ self => new ParHashMapIterator(idxFrom, idxUntil, totalSz, es) } + protected def createNewEntry[V1](key: K, value: V1): Entry = { + new Entry(key, value.asInstanceOf[V]) + } + private def writeObject(out: java.io.ObjectOutputStream) { - serializeTo(out, _.value) + serializeTo(out, { entry => + out.writeObject(entry.key) + out.writeObject(entry.value) + }) } private def readObject(in: java.io.ObjectInputStream) { - init[V](in, new Entry(_, _)) + init(in, createNewEntry(in.readObject().asInstanceOf[K], in.readObject())) } private[parallel] override def brokenInvariants = { @@ -190,7 +196,9 @@ extends scala.collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], Defau // construct a normal table and fill it sequentially // TODO parallelize by keeping separate sizemaps and merging them object table extends HashTable[K, DefaultEntry[K, V]] { - def insertEntry(e: DefaultEntry[K, V]) = if (super.findEntry(e.key) eq null) super.addEntry(e) + type Entry = DefaultEntry[K, V] + def insertEntry(e: Entry) { super.findOrAddEntry(e.key, e) } + def createNewEntry[E](key: K, entry: E): Entry = entry.asInstanceOf[Entry] sizeMapInit(table.length) } var i = 0 @@ -251,6 +259,7 @@ extends scala.collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], Defau assert(h >= block * blocksize && h < (block + 1) * blocksize) } } + protected def createNewEntry[X](key: K, x: X) = ??? } /* tasks */ diff --git a/src/library/scala/collection/parallel/mutable/ParHashSet.scala b/src/library/scala/collection/parallel/mutable/ParHashSet.scala index 7b5b8e3ceb..aef9f6856b 100644 --- a/src/library/scala/collection/parallel/mutable/ParHashSet.scala +++ b/src/library/scala/collection/parallel/mutable/ParHashSet.scala @@ -158,12 +158,12 @@ with scala.collection.mutable.FlatHashTable.HashUtils[T] { val tbl = new FlatHashTable[T] { sizeMapInit(table.length) seedvalue = ParHashSetCombiner.this.seedvalue + for { + buffer <- buckets; + if buffer ne null; + elem <- buffer + } addEntry(elem.asInstanceOf[T]) } - for { - buffer <- buckets; - if buffer ne null; - elem <- buffer - } tbl.addEntry(elem.asInstanceOf[T]) tbl.hashTableContents } diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 4a5ace4248..48a658192b 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -932,7 +932,6 @@ trait Definitions extends api.StandardDefinitions { lazy val SwitchClass = requiredClass[scala.annotation.switch] lazy val TailrecClass = requiredClass[scala.annotation.tailrec] lazy val VarargsClass = requiredClass[scala.annotation.varargs] - lazy val StaticClass = requiredClass[scala.annotation.static] lazy val uncheckedStableClass = requiredClass[scala.annotation.unchecked.uncheckedStable] lazy val uncheckedVarianceClass = requiredClass[scala.annotation.unchecked.uncheckedVariance] diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 22f5b391b8..2f305296f5 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -246,7 +246,6 @@ trait StdNames { final val BeanPropertyAnnot: NameType = "BeanProperty" final val BooleanBeanPropertyAnnot: NameType = "BooleanBeanProperty" final val bridgeAnnot: NameType = "bridge" - final val staticAnnot: NameType = "static" // Classfile Attributes final val AnnotationDefaultATTR: NameType = "AnnotationDefault" diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index b04cf4ff9f..74f4769fec 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -697,7 +697,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => || hasAnnotation(SerializableAttr) // last part can be removed, @serializable annotation is deprecated ) def hasBridgeAnnotation = hasAnnotation(BridgeClass) - def hasStaticAnnotation = hasAnnotation(StaticClass) def isDeprecated = hasAnnotation(DeprecatedAttr) def deprecationMessage = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 0) def deprecationVersion = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 1) diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 47978821a3..0d9e90d3a6 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -148,8 +148,10 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { thisUnive object AnnotationClass { def unapply(x: jClass[_]) = x.isAnnotation } object ConstantArg { - def enumToSymbol(enum: Enum[_]): Symbol = - classToScala(enum.getClass).typeSignature.declaration(enum.name: TermName) + def enumToSymbol(enum: Enum[_]): Symbol = { + val staticPartOfEnum = classToScala(enum.getClass).companionSymbol + staticPartOfEnum.typeSignature.declaration(enum.name: TermName) + } def unapply(schemaAndValue: (jClass[_], Any)): Option[Any] = schemaAndValue match { case (StringClass | PrimitiveClass(), value) => Some(value) @@ -659,7 +661,6 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { thisUnive } override def complete(sym: Symbol): Unit = { - if (jclazz.isEnum) throw new ScalaReflectionException("implementation restriction: Java enums are not supported") load(sym) completeRest() } @@ -1024,13 +1025,12 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { thisUnive rawToExistential(typeRef(clazz.owner.thisType, clazz, List())) } case japplied: ParameterizedType => - val (pre, sym) = typeToScala(japplied.getRawType) match { - case ExistentialType(tparams, TypeRef(pre, sym, _)) => (pre, sym) - case TypeRef(pre, sym, _) => (pre, sym) - } + // http://stackoverflow.com/questions/5767122/parameterizedtype-getrawtype-returns-j-l-r-type-not-class + val sym = classToScala(japplied.getRawType.asInstanceOf[jClass[_]]) + val pre = sym.owner.thisType val args0 = japplied.getActualTypeArguments val (args, bounds) = targsToScala(pre.typeSymbol, args0.toList) - ExistentialType(bounds, typeRef(pre, sym, args)) + newExistentialType(bounds, typeRef(pre, sym, args)) case jarr: GenericArrayType => arrayType(typeToScala(jarr.getGenericComponentType)) case jtvar: jTypeVariable[_] => |