Skip to content

Commit

Permalink
Merge commit 'ecb62c552f' into merge-2.12.x-to-2.13.x-20180124
Browse files Browse the repository at this point in the history
  • Loading branch information
SethTisue committed Jan 25, 2018
2 parents 4503ad2 + ecb62c5 commit 30ddd7e
Show file tree
Hide file tree
Showing 44 changed files with 721 additions and 226 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ codebase and re-compiles too many files, resulting in long build times (check
meantime you can:
- Enable "Ant mode" in which sbt only re-compiles source files that were modified.
Create a file `local.sbt` containing the line `antStyle := true`.
Add an entry `local.sbt` to your `~/.gitignore`.
- Use IntelliJ IDEA for incremental compiles (see [IDE Setup](#ide-setup) below) - its
incremental compiler is a bit less conservative, but usually correct.

Expand Down Expand Up @@ -265,6 +264,10 @@ before the commit's PR has been merged. That commit is then used to
build a large number of open-source projects from source and run their
test suites.

To request a community build run on your PR, just ask in a comment on
the PR and a Scala team member will take care of
it. ([details](https://github.com/scala/community-builds/wiki#can-i-run-it-against-a-pull-request-in-scalascala))

Community builds run on the Scala Jenkins instance. The jobs are
named `..-integrate-community-build`. See the
[scala/community-builds](https://github.com/scala/community-builds)
Expand Down
2 changes: 1 addition & 1 deletion spec/07-implicits.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ sort(yss)
The call above will be completed by passing two nested implicit arguments:

```scala
sort(yss)(xs: List[Int] => list2ordered[Int](xs)(int2ordered))
sort(yss)((xs: List[Int]) => list2ordered[Int](xs)(int2ordered))
```

The possibility of passing implicit arguments to implicit arguments
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/Global.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1347,7 +1347,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
def compiles(sym: Symbol): Boolean =
if (sym == NoSymbol) false
else if (symSource.isDefinedAt(sym)) true
else if (!sym.isTopLevel) compiles(sym.enclosingTopLevelClassOrDummy)
else if (!sym.isTopLevel) compiles(sym.originalEnclosingTopLevelClassOrDummy)
else if (sym.isModuleClass) compiles(sym.sourceModule)
else false

Expand Down
12 changes: 6 additions & 6 deletions src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -571,12 +571,12 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {

val isNative = methSymbol.hasAnnotation(definitions.NativeAttr)
val isAbstractMethod = rhs == EmptyTree
val flags = GenBCode.mkFlags(
javaFlags(methSymbol),
if (isAbstractMethod) asm.Opcodes.ACC_ABSTRACT else 0,
if (methSymbol.isStrictFP) asm.Opcodes.ACC_STRICT else 0,
if (isNative) asm.Opcodes.ACC_NATIVE else 0 // native methods of objects are generated in mirror classes
)
val flags =
javaFlags(methSymbol) |
(if (isAbstractMethod) asm.Opcodes.ACC_ABSTRACT else 0) |
(if (methSymbol.isStrictFP) asm.Opcodes.ACC_STRICT else 0) |
(if (isNative) asm.Opcodes.ACC_NATIVE else 0) // native methods of objects are generated in mirror classes


initJMethod(flags, params.map(_.symbol))

Expand Down
133 changes: 99 additions & 34 deletions src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
package scala.tools.nsc
package backend.jvm

import scala.collection.concurrent.TrieMap
import scala.collection.{concurrent, mutable}
import scala.tools.asm
import scala.tools.asm.Opcodes
Expand Down Expand Up @@ -41,8 +40,8 @@ abstract class BTypes {

// Concurrent maps because stack map frames are computed when in the class writer, which
// might run on multiple classes concurrently.
val classBTypeCacheFromSymbol: concurrent.Map[InternalName, ClassBType] = recordPerRunCache(TrieMap.empty)
val classBTypeCacheFromClassfile: concurrent.Map[InternalName, ClassBType] = recordPerRunCache(TrieMap.empty)
val classBTypeCacheFromSymbol: concurrent.Map[InternalName, ClassBType] = recordPerRunCache(FlatConcurrentHashMap.empty)
val classBTypeCacheFromClassfile: concurrent.Map[InternalName, ClassBType] = recordPerRunCache(FlatConcurrentHashMap.empty)

/**
* A BType is either a primitive type, a ClassBType, an ArrayBType of one of these, or a MethodType
Expand Down Expand Up @@ -695,10 +694,9 @@ abstract class BTypes {
internalName,
outerName.orNull,
innerName.orNull,
GenBCode.mkFlags(
// the static flag in the InnerClass table has a special meaning, see InnerClass comment
i.flags & ~Opcodes.ACC_STATIC,
if (isStaticNestedClass) Opcodes.ACC_STATIC else 0
// the static flag in the InnerClass table has a special meaning, see InnerClass comment
( i.flags & ~Opcodes.ACC_STATIC |
(if (isStaticNestedClass) Opcodes.ACC_STATIC else 0)
) & BCodeHelpers.INNER_CLASSES_FLAGS
)
})
Expand Down Expand Up @@ -891,52 +889,114 @@ abstract class BTypes {
def isCompilingPrimitive: Boolean

// The [[Lazy]] and [[LazyVar]] classes would conceptually be better placed within
// PostProcessorFrontendAccess (they access the `frontendLock` defined in that class). However,
// PostProcessorFrontendAccess (they may access the `frontendLock` defined in that class). However,
// for every component in which we define nested classes, we need to make sure that the compiler
// knows that all component instances (val frontendAccess) in various classes are all the same,
// otherwise the prefixes don't match and we get type mismatch errors.
// Since we already do this dance (val bTypes: GenBCode.this.bTypes.type = GenBCode.this.bTypes)
// for BTypes, it's easier to add those nested classes to BTypes.

object Lazy {
def apply[T <: AnyRef](t: => T): Lazy[T] = new Lazy[T](() => t)
abstract sealed class Lazy[+T] {
/** get the result of the lazy value, calculating the result and performing the additional actions if the value
* is not already known.
*/
def force: T

/** add an accumulating action, which is performed when the result is forced.
* If the result is already known at the time of this call then perform the action immediately
*
* If the result is not known the action will be performed after the value is force.
* The order of application of multiple onForce definitions is undefined
*/
def onForce(f: T => Unit): Unit
}
object Lazy {

/**
* A lazy value that synchronizes on the `frontendLock`, and supports accumulating actions
* to be executed when it's forced.
*/
final class Lazy[T <: AnyRef](t: () => T) {
@volatile private var value: T = _
/**
* create a Lazy, whose calculation is performed with `frontendLock`
*/
def withLock[T <: AnyRef](t: => T): Lazy[T] = new LazyWithLock[T](() => t)

/**
* create a Lazy, whose calculation is conditionally performed with `frontendLock` or eagerly evaluated
*/
def withLockOrEager[T <: AnyRef](beLazy:Boolean, t: => T): Lazy[T] =
if (beLazy) new LazyWithLock[T](() => t)
else eager(t)
/**
* create a Lazy where the result is pre-determined, typically a constant, e.g. Nil None etc
*/
def eager[T <: AnyRef](value: T): Lazy[T] = new Eager[T](value)

private var initFunction = {
val tt = t // prevent allocating a field for t
() => { value = tt() }
/**
* create a Lazy, whose calculation is performed on demand
*/
def withoutLock[T <: AnyRef](t: => T): Lazy[T] = new LazyWithoutLock[T](() => t)

val eagerNil = eager(Nil)
val eagerNone = eager(None)

private final class Eager[T](val force: T) extends Lazy[T] {
def onForce(f: T => Unit): Unit = f(force)

override def toString = force.toString
}

override def toString = if (value == null) "<?>" else value.toString
private abstract class AbstractLazy[T <: AnyRef](private var t: () => T) extends Lazy[T] {
// value need be volatile to ensure that init doesn't expose incomplete results
// due to JVM inlining of init
@volatile protected var value: T = _

def onForce(f: T => Unit): Unit = {
if (value != null) f(value)
else frontendSynch {
override def toString = if (value == null) "<?>" else value.toString

private var postForce: List[T => Unit] = Nil

def onForce(f: T => Unit): Unit = {
if (value != null) f(value)
else this.synchronized {
if (value != null) f(value)
else postForce = f :: postForce
}
}

def force: T = {
// assign to local var to avoid volatile reads and associated memory barriers
var result = value
if (result != null) result
else {
val prev = initFunction
initFunction = () => {
prev()
f(value)
result = init(t)
t = null
this.synchronized {
postForce foreach (_.apply (result))
postForce = Nil
}
result
}
}

def init(t: () => T): T
}

def force: T = {
if (value != null) value
else frontendSynch {
if (value == null) {
initFunction()
initFunction = null
}
/**
* A lazy value that synchronizes on the `frontendLock`, and supports accumulating actions
* to be executed when it's forced.
*/
private final class LazyWithLock[T <: AnyRef](t: () => T) extends AbstractLazy[T](t) {

def init(t: () => T): T = frontendSynch {
if (value == null) value = t()
value
}
}

/**
* A lazy value that doesn't synchronize on the `frontendLock`, and supports accumulating actions
* to be executed when it's forced.
*/
private final class LazyWithoutLock[T <: AnyRef](t: () => T) extends AbstractLazy[T](t) {

def init(t: () => T): T = this.synchronized {
if (value == null) value = t()
value
}
}
Expand Down Expand Up @@ -1031,3 +1091,8 @@ object BTypes {
// when inlining, local variable names of the callee are prefixed with the name of the callee method
val InlinedLocalVariablePrefixMaxLength = 128
}
object FlatConcurrentHashMap {
import collection.JavaConverters._
def empty[K,V]: concurrent.Map[K,V] =
new java.util.concurrent.ConcurrentHashMap[K,V].asScala
}
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ abstract class BTypesFromClassfile {

val interfaces: List[ClassBType] = classNode.interfaces.asScala.map(classBTypeFromParsedClassfile)(collection.breakOut)

classBType.info = Right(ClassInfo(superClass, interfaces, flags, Lazy(nestedClasses), Lazy(nestedInfo), inlineInfo))
classBType.info = Right(ClassInfo(superClass, interfaces, flags, Lazy.withoutLock(nestedClasses), Lazy.withoutLock(nestedInfo), inlineInfo))
classBType
}

Expand Down
Loading

0 comments on commit 30ddd7e

Please sign in to comment.