Skip to content

Commit 7cb938b

Browse files
authored
Merge pull request scala#6625 from SethTisue/merge-2.12.x-to-2.13.x-20180511
Merge 2.12.x to 2.13.x (May 11, 2018) [ci: last-only]
2 parents 6901521 + fdeb07b commit 7cb938b

File tree

4 files changed

+47
-46
lines changed

4 files changed

+47
-46
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ cache:
1212

1313

1414
before_script:
15-
- (cd admin && ./init.sh)
15+
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then (cd admin && ./init.sh); fi'
1616

1717
stages:
1818
- name: build # also builds the spec using jekyll

src/compiler/scala/tools/nsc/typechecker/Namers.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -1428,7 +1428,7 @@ trait Namers extends MethodSynthesis {
14281428
* flag.
14291429
*/
14301430
private def addDefaultGetters(meth: Symbol, ddef: DefDef, vparamss: List[List[ValDef]], tparams: List[TypeDef], overridden: Symbol): Unit = {
1431-
val DefDef(_, _, rtparams0, rvparamss0, _, _) = resetAttrs(ddef.duplicate)
1431+
val DefDef(_, _, rtparams0, rvparamss0, _, _) = resetAttrs(deriveDefDef(ddef)(_ => EmptyTree).duplicate)
14321432
// having defs here is important to make sure that there's no sneaky tree sharing
14331433
// in methods with multiple default parameters
14341434
def rtparams = rtparams0.map(_.duplicate)
@@ -1514,7 +1514,7 @@ trait Namers extends MethodSynthesis {
15141514
return // fix #3649 (prevent crash in erroneous source code)
15151515
}
15161516
}
1517-
val ClassDef(_, _, rtparams, _) = resetAttrs(cdef.duplicate)
1517+
val ClassDef(_, _, rtparams, _) = resetAttrs(deriveClassDef(cdef)(_ => Template(Nil, noSelfType, Nil)).duplicate)
15181518
defTparams = rtparams.map(rt => copyTypeDef(rt)(mods = rt.mods &~ (COVARIANT | CONTRAVARIANT)))
15191519
nmr
15201520
}

src/compiler/scala/tools/nsc/typechecker/Unapplies.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ trait Unapplies extends ast.TreeDSL {
6060
}
6161

6262
private def constrTparamsInvariant(cdef: ClassDef): List[TypeDef] = {
63-
val ClassDef(_, _, tparams, _) = resetAttrs(cdef.duplicate)
63+
val prunedClassDef = deriveClassDef(cdef)(tmpl => Template(Nil, noSelfType, Nil))
64+
val ClassDef(_, _, tparams, _) = resetAttrs(prunedClassDef.duplicate)
6465
val tparamsInvariant = tparams.map(tparam => copyTypeDef(tparam)(mods = tparam.mods &~ (COVARIANT | CONTRAVARIANT)))
6566
tparamsInvariant
6667
}

src/library/scala/concurrent/impl/ExecutionContextImpl.scala

+42-42
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
package scala.concurrent.impl
1010

1111
import java.util.concurrent.{ ForkJoinPool, ForkJoinWorkerThread, ForkJoinTask, Callable, Executor, ExecutorService, ThreadFactory, TimeUnit }
12-
import java.util.concurrent.atomic.AtomicInteger
12+
import java.util.concurrent.atomic.{AtomicInteger, AtomicReference}
1313
import java.util.Collection
1414
import scala.concurrent.{ BlockContext, ExecutionContext, CanAwait, ExecutionContextExecutor, ExecutionContextExecutorService }
1515
import scala.annotation.tailrec
@@ -24,26 +24,25 @@ private[scala] class ExecutionContextImpl private[impl] (val executor: Executor,
2424

2525
private[concurrent] object ExecutionContextImpl {
2626

27-
// Implement BlockContext on FJP threads
2827
final class DefaultThreadFactory(
2928
daemonic: Boolean,
30-
maxThreads: Int,
29+
maxBlockers: Int,
3130
prefix: String,
3231
uncaught: Thread.UncaughtExceptionHandler) extends ThreadFactory with ForkJoinPool.ForkJoinWorkerThreadFactory {
3332

3433
require(prefix ne null, "DefaultThreadFactory.prefix must be non null")
35-
require(maxThreads > 0, "DefaultThreadFactory.maxThreads must be greater than 0")
34+
require(maxBlockers >= 0, "DefaultThreadFactory.maxBlockers must be greater-or-equal-to 0")
3635

37-
private final val currentNumberOfThreads = new AtomicInteger(0)
36+
private final val currentNumberOfBlockers = new AtomicInteger(0)
3837

39-
@tailrec private final def reserveThread(): Boolean = currentNumberOfThreads.get() match {
40-
case `maxThreads` | Int.`MaxValue` => false
41-
case other => currentNumberOfThreads.compareAndSet(other, other + 1) || reserveThread()
38+
@tailrec private final def newBlocker(): Boolean = currentNumberOfBlockers.get() match {
39+
case `maxBlockers` | Int.`MaxValue` => false
40+
case other => currentNumberOfBlockers.compareAndSet(other, other + 1) || newBlocker()
4241
}
4342

44-
@tailrec private final def deregisterThread(): Boolean = currentNumberOfThreads.get() match {
43+
@tailrec private final def freeBlocker(): Boolean = currentNumberOfBlockers.get() match {
4544
case 0 => false
46-
case other => currentNumberOfThreads.compareAndSet(other, other - 1) || deregisterThread()
45+
case other => currentNumberOfBlockers.compareAndSet(other, other - 1) || freeBlocker()
4746
}
4847

4948
def wire[T <: Thread](thread: T): T = {
@@ -53,39 +52,42 @@ private[concurrent] object ExecutionContextImpl {
5352
thread
5453
}
5554

56-
// As per ThreadFactory contract newThread should return `null` if cannot create new thread.
57-
def newThread(runnable: Runnable): Thread =
58-
if (reserveThread())
59-
wire(new Thread(new Runnable {
60-
// We have to decrement the current thread count when the thread exits
61-
override def run() = try runnable.run() finally deregisterThread()
62-
})) else null
55+
def newThread(runnable: Runnable): Thread = wire(new Thread(runnable))
6356

6457
def newThread(fjp: ForkJoinPool): ForkJoinWorkerThread =
65-
if (reserveThread()) {
66-
wire(new ForkJoinWorkerThread(fjp) with BlockContext {
67-
// We have to decrement the current thread count when the thread exits
68-
final override def onTermination(exception: Throwable): Unit = deregisterThread()
69-
final override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = {
70-
var result: T = null.asInstanceOf[T]
71-
ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker {
72-
@volatile var isdone = false
73-
override def block(): Boolean = {
74-
result = try {
75-
// When we block, switch out the BlockContext temporarily so that nested blocking does not created N new Threads
76-
BlockContext.withBlockContext(BlockContext.defaultBlockContext) { thunk }
77-
} finally {
78-
isdone = true
58+
wire(new ForkJoinWorkerThread(fjp) with BlockContext {
59+
private[this] var isBlocked: Boolean = false // This is only ever read & written if this thread is the current thread
60+
final override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T =
61+
if ((Thread.currentThread eq this) && !isBlocked && newBlocker()) {
62+
try {
63+
isBlocked = true
64+
val b: ForkJoinPool.ManagedBlocker with (() => T) =
65+
new ForkJoinPool.ManagedBlocker with (() => T) {
66+
private[this] var result: T = null.asInstanceOf[T]
67+
private[this] var done: Boolean = false
68+
final override def block(): Boolean = {
69+
try {
70+
if (!done)
71+
result = thunk
72+
} finally {
73+
done = true
74+
}
75+
76+
true
7977
}
8078

81-
true
82-
}
83-
override def isReleasable = isdone
84-
})
85-
result
86-
}
87-
})
88-
} else null
79+
final override def isReleasable = done
80+
81+
final override def apply(): T = result
82+
}
83+
ForkJoinPool.managedBlock(b)
84+
b()
85+
} finally {
86+
isBlocked = false
87+
freeBlocker()
88+
}
89+
} else thunk // Unmanaged blocking
90+
})
8991
}
9092

9193
def createDefaultExecutorService(reporter: Throwable => Unit): ExecutorService = {
@@ -99,8 +101,6 @@ private[concurrent] object ExecutionContextImpl {
99101
def range(floor: Int, desired: Int, ceiling: Int) = scala.math.min(scala.math.max(floor, desired), ceiling)
100102
val numThreads = getInt("scala.concurrent.context.numThreads", "x1")
101103
// The hard limit on the number of active threads that the thread factory will produce
102-
// scala/bug#8955 Deadlocks can happen if maxNoOfThreads is too low, although we're currently not sure
103-
// about what the exact threshold is. numThreads + 256 is conservatively high.
104104
val maxNoOfThreads = getInt("scala.concurrent.context.maxThreads", "x1")
105105

106106
val desiredParallelism = range(
@@ -116,7 +116,7 @@ private[concurrent] object ExecutionContextImpl {
116116
}
117117

118118
val threadFactory = new ExecutionContextImpl.DefaultThreadFactory(daemonic = true,
119-
maxThreads = maxNoOfThreads + maxExtraThreads,
119+
maxBlockers = maxExtraThreads,
120120
prefix = "scala-execution-context-global",
121121
uncaught = uncaughtExceptionHandler)
122122

0 commit comments

Comments
 (0)