Skip to content

Commit

Permalink
Break names out of the cake
Browse files Browse the repository at this point in the history
Allow names to be shared

adapted from retronym#43

adapted from
  • Loading branch information
mkeskells committed Apr 26, 2019
1 parent 2ed9ba0 commit 566cc73
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 82 deletions.
14 changes: 14 additions & 0 deletions src/compiler/scala/tools/nsc/Global.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import scala.tools.nsc.classpath._
import scala.tools.nsc.profile.Profiler
import scala.util.control.NonFatal
import java.io.Closeable
import java.util.concurrent.atomic.AtomicReference

import scala.annotation.tailrec

class Global(var currentSettings: Settings, reporter0: LegacyReporter)
Expand Down Expand Up @@ -1731,6 +1733,17 @@ class Global(var currentSettings: Settings, reporter0: LegacyReporter)
perRunCaches.clearAll()
closeableRegistry.close()
}
override protected def newNameTable: NameTable = {
if (currentSettings.YcacheNameTable) {
var shared: NameTable = null
do {
shared = Global.nameTableCache.get
if (shared == null) Global.nameTableCache.compareAndSet(null, new scala.reflect.internal.NameTable)
} while (shared == null)
shared
}
else super.newNameTable
}
}

object Global {
Expand All @@ -1743,4 +1756,5 @@ object Global {
override def keepsTypeParams = false
def run(): Unit = { throw new Error("InitPhase.run") }
}
private val nameTableCache = new AtomicReference[scala.reflect.internal.NameTable]
}
1 change: 1 addition & 0 deletions src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ trait ScalaSettings extends AbsScalaSettings
val YcachePluginClassLoader = CachePolicy.setting("plugin", "compiler plugins")
val YcacheMacroClassLoader = CachePolicy.setting("macro", "macros")
val YmacroClasspath = PathSetting ("-Ymacro-classpath", "The classpath used to reflectively load macro implementations, default is the compilation classpath.", "")
val YcacheNameTable = BooleanSetting ("-Ycache-name-table", "Share a single name table for concurrently running instances of the compiler")

val exposeEmptyPackage = BooleanSetting ("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly()
val Ydelambdafy = ChoiceSetting ("-Ydelambdafy", "strategy", "Strategy used for translating lambdas into JVM code.", List("inline", "method"), "method")
Expand Down
106 changes: 71 additions & 35 deletions src/reflect/scala/reflect/api/Names.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,30 +55,82 @@ trait Names {
// @deprecated("use explicit `TypeName(s)` instead", "2.11.0")
// implicit def stringToTypeName(s: String): TypeName = TypeName(s)

type NameTable <: NameTableApi

val nameTable: NameTable

/** The abstract type of names.
* @group Names
*/
type Name >: Null <: AnyRef with NameApi
type Name >: Null <: AnyRef with nameTable.NameApi

/** The abstract type of names representing terms.
* @group Names
*/
type TypeName >: Null <: TypeNameApi with Name
type TypeName >: Null <: nameTable.TypeNameApi with Name
/** The abstract type of names representing types.
* @group Names
*/
type TermName >: Null <: nameTable.TermNameApi with Name

/** The API of Name instances.
* @group API
*/
type NameApi <: nameTable.NameApi

/** Create a new term name.
* @group Names
*/
@deprecated("use TermName instead", "2.11.0")
def newTermName(s: String): TermName

/** Creates a new type name.
* @group Names
*/
@deprecated("use TypeName instead", "2.11.0")
def newTypeName(s: String): TypeName

/** The constructor/extractor for `TermName` instances.
* @group Extractors
*/
val TermName: TermNameExtractor

/** An extractor class to create and pattern match with syntax `TermName(s)`.
* @group Extractors
*/
abstract class TermNameExtractor {
def apply(s: String): TermName
def unapply(name: TermName): Option[String]
}

/** The constructor/extractor for `TypeName` instances.
* @group Extractors
*/
val TypeName: TypeNameExtractor

/** An extractor class to create and pattern match with syntax `TypeName(s)`.
* @group Extractors
*/
abstract class TypeNameExtractor {
def apply(s: String): TypeName
def unapply(name: TypeName): Option[String]
}
}

abstract class NameTableApi {
/** The abstract type of names.
* @group Names
*/
type Name >: Null <: AnyRef with NameApi

type TypeName >: Null <: TypeNameApi with Name

/** Has no special methods. Is here to provides erased identity for `TypeName`.
* @group API
*/
trait TypeNameApi

/** The abstract type of names representing types.
* @group Names
*/
type TermName >: Null <: TermNameApi with Name

/** Has no special methods. Is here to provides erased identity for `TermName`.
* @group API
*/
trait TermNameApi

/** The API of Name instances.
* @group API
Expand Down Expand Up @@ -116,6 +168,15 @@ trait Names {
*/
def encodedName: Name
}
/** Has no special methods. Is here to provides erased identity for `TypeName`.
* @group API
*/
trait TypeNameApi extends NameApi
/** Has no special methods. Is here to provides erased identity for `TermName`.
* @group API
*/
trait TermNameApi extends NameApi


/** Create a new term name.
* @group Names
Expand All @@ -129,29 +190,4 @@ trait Names {
@deprecated("use TypeName instead", "2.11.0")
def newTypeName(s: String): TypeName

/** The constructor/extractor for `TermName` instances.
* @group Extractors
*/
val TermName: TermNameExtractor

/** An extractor class to create and pattern match with syntax `TermName(s)`.
* @group Extractors
*/
abstract class TermNameExtractor {
def apply(s: String): TermName
def unapply(name: TermName): Option[String]
}

/** The constructor/extractor for `TypeName` instances.
* @group Extractors
*/
val TypeName: TypeNameExtractor

/** An extractor class to create and pattern match with syntax `TypeName(s)`.
* @group Extractors
*/
abstract class TypeNameExtractor {
def apply(s: String): TypeName
def unapply(name: TypeName): Option[String]
}
}
105 changes: 61 additions & 44 deletions src/reflect/scala/reflect/internal/Names.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,51 @@ package internal

import java.util.concurrent.ConcurrentHashMap

import scala.reflect.api.NameTableApi

trait Names extends api.Names {
def nameTableSize: Int = cache.size
type NameTable = scala.reflect.internal.NameTable
override val nameTable: NameTable = newNameTable

override final type Name = AName
override final type TypeName = TermNameImpl#TypeNameImpl
override final type TermName = TermNameImpl
protected def newNameTable: NameTable = new NameTable

def nameTableSize: Int = nameTable.nameTableSize
override final type Name = nameTable.AName
override final type TypeName = nameTable.TypeNameImpl
override final type TermName = nameTable.TermNameImpl

implicit final val NameTag = ClassTag[Name](classOf[Name])
implicit final val TermNameTag = ClassTag[TermName](classOf[TermName])
implicit final val TypeNameTag = ClassTag[TypeName](classOf[TypeName])


override object TermName extends TermNameExtractor {
@inline override def apply(s: String): TermName = newTermName(s)
override def unapply(name: TermName): Option[String] = Some(name.rawString)
override final def newTypeName(value: String): TypeName = nameTable.newTypeName(value)
override final def newTermName(value: String): TermName = nameTable.newTermName(value)
object TermName extends TermNameExtractor {
def apply(s: String) = newTermName(s)
def unapply(name: TermName): Option[String] = Some(name.toString)
}
override object TypeName extends TypeNameExtractor {
@inline override def apply(s: String): TypeName = newTypeName(s)
override def unapply(name: TypeName): Option[String] = Some(name.rawString)
object TypeName extends TypeNameExtractor {
def apply(s: String) = newTypeName(s)
def unapply(name: TypeName): Option[String] = Some(name.toString)
}
override final def newTypeName(value: String): TypeName = newTermName(value).companionName
//deprecated stuff
@deprecated
@inline final def newTermNameCached(s: String): TermName = newTermName(s)

@deprecated
@inline final def newTypeNameCached(s: String): TypeName = newTypeName(s)
}
class NameTable extends NameTableApi {
override final type Name = AName
override final type TypeName = TypeNameImpl
override final type TermName = TermNameImpl

def nameTableSize: Int = cache.size

private[this] final val cache = new ConcurrentHashMap[String, TermNameImpl](1000, 0.75F, 1)

override final def newTermName(value: String): TermName = {
//TODO consider a better structure to use than a CHM
override final def newTermName(value: String): TermNameImpl = {
//TODO consider a better structure to use than a CHM
var res = cache.get(value)
if (res eq null) {
val next = new TermNameImpl(value)
Expand All @@ -50,25 +71,22 @@ trait Names extends api.Names {
res
//same as cache.computeIfAbsent(value, new NameHolder(_)) but faster
}
private[this] final val cache = new ConcurrentHashMap[String, TermName](1000, 0.75F, 1)
//deprecated stuff
@deprecated @inline final def newTermNameCached(s: String): TermName = newTermName(s)
@deprecated @inline final def newTypeNameCached(s: String): TypeName = newTypeName(s)
final def newTypeName(value:String): TypeName = newTermName(value).companionName

abstract sealed class AName extends NameApi with CharSequence {
type ThisNameType <: AName
@inline override final def length(): Int = value.length
override final def subSequence(start: Int, end: Int): CharSequence = value.subSequence(start, end)
override def decoded: String = decodedName.toString
override def encoded: String = encodedName.toString
@inline private[Names] def rawString = value
override def decodedName: ThisNameType
override def encodedName: ThisNameType
@inline private[NameTable] def rawString = value
def decodedName: ThisNameType
def encodedName: ThisNameType

//non API methods
protected def value: String

def companionName: Name
def companionName: AName

/** Return the subname with characters from from to to-1. */
def subName(from: Int, to: Int): ThisNameType =
Expand Down Expand Up @@ -250,12 +268,12 @@ trait Names extends api.Names {
}
final class TermNameImpl(override val toString: String) extends AName with TermNameApi {
type ThisNameType = TermName

override def isTermName = true
override def isTypeName = false

override protected def value: String = toString


override def toTermName: TermName = this
override def toTypeName: TypeName = typeName

Expand All @@ -269,7 +287,7 @@ trait Names extends api.Names {
def identifier = identifier_ & 0x80FF
def markAsIdentifier(java: Boolean, newIdentifier: Int) {
require((identifier.toShort & 0x80FF) == identifier.toShort)
val flag = (if (java) 0x1000 else 0x2000).toShort
val flag = (if (java) 0x1000 else 0x2000).toShort
if (identifier_ == 0) {
//first call
this.identifier_ = (newIdentifier | flag).toShort
Expand All @@ -290,31 +308,30 @@ trait Names extends api.Names {
else this
}
override lazy final val encodedName: TermName = {
val res = NameTransformer.encode(value)
if (res == value) this else newName(res)
}

private lazy val typeName:TypeName = new TypeNameImpl
val res = NameTransformer.encode(value)
if (res == value) this else newName(res)
}

private[NameTable] lazy val typeName: TypeNameImpl = new TypeNameImpl(this)

final class TypeNameImpl extends AName with TypeNameApi {
type ThisNameType = TypeName
override def isTermName = false
override def isTypeName = true
override def decodedName: TypeName = TermNameImpl.this.decodedName.typeName
override def encodedName: TypeName = TermNameImpl.this.encodedName.typeName
}
final class TypeNameImpl(term: TermNameImpl) extends AName with TypeNameApi {
type ThisNameType = TypeName
override def isTermName = false
override def isTypeName = true
override def decodedName: TypeName = term.decodedName.typeName
override def encodedName: TypeName = term.encodedName.typeName


override protected def value: String = TermNameImpl.this.toString
override def toString: String = TermNameImpl.this.toString
override protected def value: String = term.toString
override def toString: String = term.toString

override def toTermName: TermName = TermNameImpl.this
override def toTypeName: TypeName = this
override def toTermName: TermName = term
override def toTypeName: TypeName = this

override def companionName = TermNameImpl.this
override def newName(str: String) = newTypeName(str)
override def nameKind = "type"
def debugString = decoded + "!"
}
override def companionName = term
override def newName(str: String) = newTypeName(str)
override def nameKind = "type"
def debugString = decoded + "!"
}
}
6 changes: 3 additions & 3 deletions test/files/run/reflection-names.check
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(java.lang.String,bc)
(scala.reflect.internal.Names$TermName_R,bc)
(scala.reflect.internal.Names$TypeName_R,bc)
(scala.reflect.internal.Names$TypeName_R,bc)
(scala.reflect.internal.NameTable$TermNameImpl,bc)
(scala.reflect.internal.NameTable$TypeNameImpl,bc)
(scala.reflect.internal.NameTable$TypeNameImpl,bc)

0 comments on commit 566cc73

Please sign in to comment.