summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala37
-rw-r--r--src/library/scala/collection/parallel/Tasks.scala70
-rw-r--r--src/library/scala/concurrent/package.scala.disabled108
-rw-r--r--src/library/scala/parallel/package.scala.disabled (renamed from src/library/scala/parallel/package.scala)44
-rw-r--r--test/files/run/testblock.scala33
-rw-r--r--test/files/run/testpar.scala24
-rw-r--r--test/files/specialized/td3651.check2
-rw-r--r--test/files/specialized/td3651.scala19
8 files changed, 253 insertions, 84 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 42ccae9a76..e33491aa29 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -40,6 +40,11 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
case _ => false
}
+ private def specializedOn(sym: Symbol) = sym.getAnnotation(SpecializedClass) match {
+ case Some(AnnotationInfo(_, args, _)) => args
+ case _ => Nil
+ }
+
object TypeEnv {
/** Return a new type environment binding specialized type parameters of sym to
* the given args. Expects the lists to have the same length.
@@ -226,7 +231,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
val specializedType = new TypeMap {
override def apply(tp: Type): Type = tp match {
- case TypeRef(pre, sym, args) if !args.isEmpty =>
+ case TypeRef(pre, sym, args) if args.nonEmpty =>
val pre1 = this(pre)
// when searching for a specialized class, take care to map all
// type parameters that are subtypes of AnyRef to AnyRef
@@ -536,7 +541,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
var parents = List(applyContext(atPhase(currentRun.typerPhase)(clazz.tpe)))
- // log("Parent: " + parents.head + ", sym: " + parents.head.typeSymbol)
+ // log("!!! Parents: " + parents + ", sym: " + parents.map(_.typeSymbol))
if (parents.head.typeSymbol.isTrait)
parents = parents.head.parents.head :: parents
val extraSpecializedMixins = specializedParents(clazz.info.parents.map(applyContext))
@@ -859,7 +864,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
* this method will return List('apply$spec$II')
*/
private def specialOverrides(clazz: Symbol): List[Symbol] = {
- log("specialOverrides(" + clazz + ")")
+ // log("--> specialOverrides(" + clazz + ")")
/** Return the overridden symbol in syms that needs a specialized overriding symbol,
* together with its specialization environment. The overridden symbol may not be
@@ -886,6 +891,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
"types: " + missing.mkString("", ", ", ""))
}
+ // log("checking: " + overriding + " - isParamAccessor: " + overriding.isParamAccessor)
if (!overriding.isParamAccessor) for (overridden <- syms) {
if (settings.debug.value)
log("Overridden: " + overridden.fullName + ": " + overridden.info
@@ -1068,6 +1074,29 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
// decl
}
+ /** Checks if the type parameter symbol is not specialized
+ * and is used as type parameters when extending a class with a specialized
+ * type parameter.
+ * At some point we may remove this restriction.
+ *
+ * Example:
+ *
+ * class Base[@specialized T]
+ * class Derived[T] extends Base[T] // a non-specialized T is
+ * // used as a type param for Base
+ * // -> returning true
+ */
+ private def notSpecializedIn(tsym: Symbol, supertpe: Type) = supertpe match {
+ case TypeRef(_, supersym, supertargs) =>
+ val tspec = specializedOn(tsym).toSet
+ for (supt <- supersym.typeParams) {
+ val supspec = specializedOn(supt).toSet
+ if (tspec != supspec && tspec.subsetOf(supspec))
+ reporter.error(tsym.pos, "Type parameter has to be specialized at least for the same types as in the superclass. Missing types: " + (supspec.diff(tspec)).mkString(", "))
+ }
+ case _ => //log("nope")
+ }
+
/** Type transformation. It is applied to all symbols, compiled or loaded.
* If it is a 'no-specialization' run, it is applied only to loaded symbols.
*/
@@ -1078,6 +1107,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
&& clazz != JavaRepeatedParamClass
&& !clazz.isJavaDefined =>
val parents = base map specializedType
+ // log("!!! %s[%s]) Parents: %s -> %s".format(sym, targs, base, parents))
+ // for (t <- targs; p <- parents) notSpecializedIn(t, p)
if (settings.debug.value) log("transformInfo (poly) " + clazz + " with parents1: " + parents + " ph: " + phase)
// if (clazz.name.toString == "$colon$colon")
// (new Throwable).printStackTrace
diff --git a/src/library/scala/collection/parallel/Tasks.scala b/src/library/scala/collection/parallel/Tasks.scala
index 0b220a020f..80cdd31fa1 100644
--- a/src/library/scala/collection/parallel/Tasks.scala
+++ b/src/library/scala/collection/parallel/Tasks.scala
@@ -279,7 +279,9 @@ trait ThreadPoolTasks extends Tasks {
}
override def release = synchronized {
completed = true
- decrTasks
+ executor.synchronized {
+ decrTasks
+ }
this.notifyAll
}
}
@@ -352,6 +354,70 @@ object ThreadPoolTasks {
}
+/** An implementation of tasks objects based on the Java thread pooling API and synchronization using futures. */
+trait FutureThreadPoolTasks extends Tasks {
+ import java.util.concurrent._
+
+ trait TaskImpl[R, +Tp] extends Runnable with super.TaskImpl[R, Tp] {
+ @volatile var future: Future[_] = null
+
+ def start = {
+ executor.synchronized {
+ future = executor.submit(this)
+ }
+ }
+ def sync = future.get
+ def tryCancel = false
+ def run = {
+ compute
+ }
+ }
+
+ protected def newTaskImpl[R, Tp](b: Task[R, Tp]): TaskImpl[R, Tp]
+
+ var environment: AnyRef = FutureThreadPoolTasks.defaultThreadPool
+ def executor = environment.asInstanceOf[ThreadPoolExecutor]
+
+ def execute[R, Tp](task: Task[R, Tp]): () => R = {
+ val t = newTaskImpl(task)
+
+ // debuglog("-----------> Executing without wait: " + task)
+ t.start
+
+ () => {
+ t.sync
+ t.body.forwardThrowable
+ t.body.result
+ }
+ }
+
+ def executeAndWaitResult[R, Tp](task: Task[R, Tp]): R = {
+ val t = newTaskImpl(task)
+
+ // debuglog("-----------> Executing with wait: " + task)
+ t.start
+
+ t.sync
+ t.body.forwardThrowable
+ t.body.result
+ }
+
+ def parallelismLevel = FutureThreadPoolTasks.numCores
+
+}
+
+object FutureThreadPoolTasks {
+ import java.util.concurrent._
+
+ val numCores = Runtime.getRuntime.availableProcessors
+
+ val tcount = new atomic.AtomicLong(0L)
+
+ val defaultThreadPool = Executors.newCachedThreadPool()
+}
+
+
+
/**
* A trait describing objects that provide a fork/join pool.
*/
@@ -430,7 +496,7 @@ trait ForkJoinTasks extends Tasks with HavingForkJoinPool {
object ForkJoinTasks {
- val defaultForkJoinPool: ForkJoinPool = scala.parallel.forkjoinpool
+ val defaultForkJoinPool: ForkJoinPool = new ForkJoinPool() // scala.parallel.forkjoinpool
// defaultForkJoinPool.setParallelism(Runtime.getRuntime.availableProcessors)
// defaultForkJoinPool.setMaximumPoolSize(Runtime.getRuntime.availableProcessors)
}
diff --git a/src/library/scala/concurrent/package.scala.disabled b/src/library/scala/concurrent/package.scala.disabled
new file mode 100644
index 0000000000..42b4bf954c
--- /dev/null
+++ b/src/library/scala/concurrent/package.scala.disabled
@@ -0,0 +1,108 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+
+package scala
+
+
+
+
+/** This package object contains primitives for parallel programming.
+ */
+package object concurrent {
+
+ /** Performs a call which can potentially block execution.
+ *
+ * Example:
+ * {{{
+ * val lock = new ReentrantLock
+ *
+ * // ... do something ...
+ *
+ * blocking {
+ * if (!lock.hasLock) lock.lock()
+ * }
+ * }}}
+ *
+ * '''Note:''' calling methods that wait arbitrary amounts of time
+ * (e.g. for I/O operations or locks) may severely decrease performance
+ * or even result in deadlocks. This does not include waiting for
+ * results of futures.
+ *
+ * @tparam T the result type of the blocking operation
+ * @param body the blocking operation
+ * @param runner the runner used for parallel computations
+ * @return the result of the potentially blocking operation
+ */
+ def blocking[T](body: =>T)(implicit runner: TaskRunner): T = {
+ null.asInstanceOf[T]
+ }
+
+ /** Invokes a computation asynchronously. Does not wait for the computation
+ * to finish.
+ *
+ * @tparam U the result type of the operation
+ * @param p the computation to be invoked asynchronously
+ * @param runner the runner used for parallel computations
+ */
+ def spawn[U](p: =>U)(implicit runner: TaskRunner): Unit = {
+ }
+
+ /** Starts 2 parallel computations and returns once they are completed.
+ *
+ * $invokingPar
+ *
+ * @tparam T1 the type of the result of 1st the parallel computation
+ * @tparam T2 the type of the result of 2nd the parallel computation
+ * @param b1 the 1st computation to be invoked in parallel
+ * @param b2 the 2nd computation to be invoked in parallel
+ * @param runner the runner used for parallel computations
+ * @return a tuple of results corresponding to parallel computations
+ */
+ def par[T1, T2](b1: =>T1)(b2: =>T2)(implicit runner: TaskRunner): (T1, T2) = {
+ null
+ }
+
+ /** Starts 3 parallel computations and returns once they are completed.
+ *
+ * $invokingPar
+ *
+ * @tparam T1 the type of the result of 1st the parallel computation
+ * @tparam T2 the type of the result of 2nd the parallel computation
+ * @tparam T3 the type of the result of 3rd the parallel computation
+ * @param b1 the 1st computation to be invoked in parallel
+ * @param b2 the 2nd computation to be invoked in parallel
+ * @param b3 the 3rd computation to be invoked in parallel
+ * @param runner the runner used for parallel computations
+ * @return a tuple of results corresponding to parallel computations
+ */
+ def par[T1, T2, T3](b1: =>T1)(b2: =>T2)(b3: =>T3)(implicit runner: TaskRunner): (T1, T2, T3) = {
+ null
+ }
+
+ /** Starts 4 parallel computations and returns once they are completed.
+ *
+ * $invokingPar
+ *
+ * @tparam T1 the type of the result of 1st the parallel computation
+ * @tparam T2 the type of the result of 2nd the parallel computation
+ * @tparam T3 the type of the result of 3rd the parallel computation
+ * @tparam T4 the type of the result of 4th the parallel computation
+ * @param b1 the 1st computation to be invoked in parallel
+ * @param b2 the 2nd computation to be invoked in parallel
+ * @param b3 the 3rd computation to be invoked in parallel
+ * @param b4 the 4th computation to be invoked in parallel
+ * @param runner the runner used for parallel computations
+ * @return a tuple of results corresponding to parallel computations
+ */
+ def par[T1, T2, T3, T4](b1: =>T1)(b2: =>T2)(b3: =>T3)(b4: =>T4)(implicit runner: TaskRunner): (T1, T2, T3, T4) = {
+ null
+ }
+
+}
diff --git a/src/library/scala/parallel/package.scala b/src/library/scala/parallel/package.scala.disabled
index 4cae1ad4b1..45f5470d03 100644
--- a/src/library/scala/parallel/package.scala
+++ b/src/library/scala/parallel/package.scala.disabled
@@ -15,13 +15,13 @@ import scala.concurrent.forkjoin._
* chain obtained by querying results of unfinished futures can have
* arbitrary lengths. However, care must be taken not to create a
* circular dependency, as this will result in a deadlock.
- *
+ *
* Additionally, if the parallel computation performs a blocking call
* (e.g. an I/O operation or waiting for a lock) other than waiting for a future,
* it should do so by invoking the `block` method. This is another
* form of waiting that could potentially create a circular dependency,
* an the user should take care not to do this.
- *
+ *
* Users should be aware that invoking a parallel computation has a
* certain overhead. Parallel computations should not be invoked for
* small computations, as this can lead to bad performance. A rule of the
@@ -31,36 +31,36 @@ import scala.concurrent.forkjoin._
* computationally equivalent to a loop with 10000 arithmetic operations.
*/
package object parallel {
-
+
private[scala] val forkjoinpool = new ForkJoinPool()
-
+
private class Task[T](body: =>T) extends RecursiveTask[T] with Future[T] {
def compute = body
def apply() = join()
}
-
+
private final def newTask[T](body: =>T) = new Task[T](body)
-
+
private final def executeTask[T](task: RecursiveTask[T]) {
if (Thread.currentThread().isInstanceOf[ForkJoinWorkerThread]) task.fork
else forkjoinpool.execute(task)
}
-
+
/* public methods */
-
+
/** Performs a call which can potentially block execution.
- *
+ *
* Example:
* {{{
* val lock = new ReentrantLock
- *
+ *
* // ... do something ...
- *
+ *
* blocking {
* if (!lock.hasLock) lock.lock()
* }
* }}}
- *
+ *
* '''Note:''' calling methods that wait arbitrary amounts of time
* (e.g. for I/O operations or locks) may severely decrease performance
* or even result in deadlocks. This does not include waiting for
@@ -82,11 +82,11 @@ package object parallel {
blocker.result.asInstanceOf[T]
} else body
}
-
+
/** Starts a parallel computation and returns a future.
- *
+ *
* $invokingPar
- *
+ *
* @tparam T the type of the result of the parallel computation
* @param body the computation to be invoked in parallel
* @return a future with the result
@@ -96,9 +96,9 @@ package object parallel {
executeTask(task)
task
}
-
+
/** Starts 2 parallel computations and returns a future.
- *
+ *
* $invokingPar
*
* @tparam T1 the type of the result of 1st the parallel computation
@@ -114,9 +114,9 @@ package object parallel {
executeTask(t2)
(t1, t2)
}
-
+
/** Starts 3 parallel computations and returns a future.
- *
+ *
* $invokingPar
*
* @tparam T1 the type of the result of 1st the parallel computation
@@ -136,9 +136,9 @@ package object parallel {
executeTask(t3)
(t1, t2, t3)
}
-
+
/** Starts 4 parallel computations and returns a future.
- *
+ *
* $invokingPar
*
* @tparam T1 the type of the result of 1st the parallel computation
@@ -162,7 +162,7 @@ package object parallel {
executeTask(t4)
(t1, t2, t3, t4)
}
-
+
}
diff --git a/test/files/run/testblock.scala b/test/files/run/testblock.scala
deleted file mode 100644
index a334b668fd..0000000000
--- a/test/files/run/testblock.scala
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-import scala.parallel._
-
-
-
-
-object Test {
-
- def main(args: Array[String]) {
- if (util.Properties.isJavaAtLeast("1.6")) {
- val vendor = util.Properties.javaVmVendor
- if ((vendor contains "Sun") || (vendor contains "Apple")) blockcomp(10)
- }
- }
-
- val lock = new java.util.concurrent.locks.ReentrantLock
-
- def blockcomp(n: Int): Unit = if (n > 0) {
- val (x, y) = par(blockcomp(n - 1), blockcomp(n - 1))
- if (n == 8) blocking { // without this blocking block, deadlock occurs
- lock.lock()
- }
- x()
- y()
- if (n == 8) {
- lock.unlock()
- }
- }
-
-}
diff --git a/test/files/run/testpar.scala b/test/files/run/testpar.scala
deleted file mode 100644
index c4c813ee00..0000000000
--- a/test/files/run/testpar.scala
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-import scala.parallel._
-
-
-
-
-
-object Test {
-
- def main(args: Array[String]) {
- if (util.Properties.isJavaAtLeast("1.6")) {
- val vendor = util.Properties.javaVmVendor
- if ((vendor contains "Sun") || (vendor contains "Apple")) assert(fib(40) == 102334155)
- }
- }
-
- def fib(n: Int): Int = if (n < 3) 1 else if (n < 35) fib(n - 1) + fib(n - 2) else {
- val (p, pp) = par(fib(n - 1), fib(n - 2))
- p() + pp()
- }
-
-}
diff --git a/test/files/specialized/td3651.check b/test/files/specialized/td3651.check
new file mode 100644
index 0000000000..9aea9e0ce5
--- /dev/null
+++ b/test/files/specialized/td3651.check
@@ -0,0 +1,2 @@
+0
+0 \ No newline at end of file
diff --git a/test/files/specialized/td3651.scala b/test/files/specialized/td3651.scala
new file mode 100644
index 0000000000..117710b6dc
--- /dev/null
+++ b/test/files/specialized/td3651.scala
@@ -0,0 +1,19 @@
+
+
+
+
+class Base[@specialized(Double) A](val a: A)
+
+class Derived(override val a: Double) extends Base[Double](a)
+
+object Test {
+ def main(args: Array[String]) {
+ val b: Base[Double] = new Derived(10)
+ b.a
+ println(runtime.BoxesRunTime.doubleBoxCount)
+
+ val der = new Derived(10)
+ der.a
+ println(runtime.BoxesRunTime.doubleBoxCount)
+ }
+}