Permalink
Browse files

Merge pull request #1764 from adriaanm/backport/sip14

SIP-14 backport to 2.9.x
  • Loading branch information...
adriaanm committed Dec 13, 2012
2 parents 8e3d23a + f0bc3f7 commit eda88c84daae182266565d21b31ad3c93d9b3be5
Showing with 4,925 additions and 15 deletions.
  1. +23 −10 build.xml
  2. +2 −0 src/compiler/scala/tools/nsc/ast/TreeGen.scala
  3. +1 −0 src/compiler/scala/tools/nsc/backend/icode/Members.scala
  4. +2 −2 src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
  5. +3 −0 src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
  6. +64 −0 src/library/scala/concurrent/Awaitable.scala
  7. +77 −0 src/library/scala/concurrent/BlockContext.scala
  8. +1 −3 src/library/scala/concurrent/DelayedLazyVal.scala
  9. +88 −0 src/library/scala/concurrent/ExecutionContext.scala
  10. +691 −0 src/library/scala/concurrent/Future.scala
  11. +152 −0 src/library/scala/concurrent/Promise.scala
  12. +81 −0 src/library/scala/concurrent/duration/Deadline.scala
  13. +697 −0 src/library/scala/concurrent/duration/Duration.scala
  14. +92 −0 src/library/scala/concurrent/duration/DurationConversions.scala
  15. +79 −0 src/library/scala/concurrent/duration/package.scala
  16. +40 −0 src/library/scala/concurrent/impl/AbstractPromise.java
  17. +21 −0 src/library/scala/concurrent/impl/AdaptedRunnableAction.java
  18. +135 −0 src/library/scala/concurrent/impl/ExecutionContextImpl.scala
  19. +34 −0 src/library/scala/concurrent/impl/Future.scala
  20. +174 −0 src/library/scala/concurrent/impl/Promise.scala
  21. +109 −0 src/library/scala/concurrent/package.scala
  22. +35 −0 src/library/scala/concurrent/util/Unsafe.java
  23. +216 −0 src/library/scala/util/Try.scala
  24. +45 −0 src/library/scala/util/control/NonFatal.scala
  25. +1 −0 test/files/jvm/future-spec.flags
  26. +524 −0 test/files/jvm/future-spec/FutureTests.scala
  27. +246 −0 test/files/jvm/future-spec/PromiseTests.scala
  28. +130 −0 test/files/jvm/future-spec/TryTests.scala
  29. +110 −0 test/files/jvm/future-spec/main.scala
  30. +1,036 −0 test/files/jvm/scala-concurrent-tck.scala
  31. +1 −0 test/files/pos/t5958.flags
  32. +15 −0 test/files/pos/t5958.scala
View
@@ -286,9 +286,9 @@ INITIALISATION
<property name="scalac.args.optimise" value=""/>
<!-- scalac.args.quickonly are added to quick.* targets but not others (particularly, locker.)
This is to facilitate testing new command line options which do not yet exist in starr. -->
- <property name="scalac.args.quickonly" value=""/>
+ <property name="scalac.args.quickonly" value="-Ydependent-method-types"/>
<property name="scalac.args.all" value="${scalac.args} ${scalac.args.optimise}"/>
- <property name="scalac.args.quick" value="${scalac.args.all} ${scalac.args.quickonly}"/>
+ <property name="scalac.args.quick" value="${scalac.args.all} ${scalac.args.quickonly}"/>
<!-- Setting-up Ant contrib tasks -->
<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${lib.dir}/ant/ant-contrib.jar"/>
<!-- This is the start time for the distribution -->
@@ -376,8 +376,9 @@ LOCAL REFERENCE BUILD (LOCKER)
<javac
srcdir="${src.dir}/library"
destdir="${build-locker.dir}/classes/library"
- classpath="${build-locker.dir}/classes/library"
+ classpathref="quick.compilation.path"
includes="**/*.java"
+ excludes="scala/concurrent/**/*.java"
target="1.5" source="1.5">
<compilerarg line="${javac.args}"/>
</javac>
@@ -392,6 +393,17 @@ LOCAL REFERENCE BUILD (LOCKER)
srcdir="${src.dir}/library"
jvmargs="${scalacfork.jvmargs}">
<include name="**/*.scala"/>
+ <!-- Exclude duration package and everything that depends on it -->
+ <exclude name="scala/concurrent/duration/**/*.scala"/>
+ <exclude name="scala/concurrent/package.scala"/>
+ <exclude name="scala/concurrent/Awaitable.scala"/>
+ <exclude name="scala/concurrent/Future.scala"/>
+ <exclude name="scala/concurrent/Promise.scala"/>
+ <exclude name="scala/concurrent/ExecutionContext.scala"/>
+ <exclude name="scala/concurrent/BlockContext.scala"/>
+ <exclude name="scala/concurrent/impl/Future.scala"/>
+ <exclude name="scala/concurrent/impl/Promise.scala"/>
+ <exclude name="scala/concurrent/impl/ExecutionContextImpl.scala"/>
<compilationpath>
<pathelement location="${build-locker.dir}/classes/library"/>
<pathelement location="${lib.dir}/forkjoin.jar"/>
@@ -546,7 +558,7 @@ QUICK BUILD (QUICK)
<javac
srcdir="${src.dir}/library"
destdir="${build-quick.dir}/classes/library"
- classpath="${build-quick.dir}/classes/library"
+ classpathref="quick.compilation.path"
includes="**/*.java"
target="1.5" source="1.5">
<compilerarg line="${javac.args}"/>
@@ -1083,7 +1095,7 @@ BOOTSTRAPPING BUILD (STRAP)
<javac
srcdir="${src.dir}/library"
destdir="${build-strap.dir}/classes/library"
- classpath="${build-strap.dir}/classes/library"
+ classpathref="strap.compilation.path"
includes="**/*.java"
target="1.5" source="1.5">
<compilerarg line="${javac.args}"/>
@@ -1100,7 +1112,7 @@ BOOTSTRAPPING BUILD (STRAP)
destdir="${build-strap.dir}/classes/library"
compilerpathref="pack.classpath"
srcpath="${src.dir}/library"
- params="${scalac.args.all}"
+ params="${scalac.args.quick}"
srcdir="${src.dir}/library"
jvmargs="${scalacfork.jvmargs}">
<include name="**/*.scala"/>
@@ -1109,7 +1121,7 @@ BOOTSTRAPPING BUILD (STRAP)
<scalacfork
destdir="${build-strap.dir}/classes/library"
compilerpathref="pack.classpath"
- params="${scalac.args.all}"
+ params="${scalac.args.quick}"
srcdir="${src.dir}/actors"
jvmargs="${scalacfork.jvmargs}">
<include name="**/*.scala"/>
@@ -1118,7 +1130,7 @@ BOOTSTRAPPING BUILD (STRAP)
<scalacfork
destdir="${build-strap.dir}/classes/library"
compilerpathref="pack.classpath"
- params="${scalac.args.all}"
+ params="${scalac.args.quick}"
srcdir="${src.dir}/dbc"
jvmargs="${scalacfork.jvmargs}">
<include name="**/*.scala"/>
@@ -1127,7 +1139,7 @@ BOOTSTRAPPING BUILD (STRAP)
<scalacfork
destdir="${build-strap.dir}/classes/library"
compilerpathref="pack.classpath"
- params="${scalac.args.all}"
+ params="${scalac.args.quick}"
srcdir="${src.dir}/swing"
jvmargs="${scalacfork.jvmargs}">
<include name="**/*.scala"/>
@@ -1163,7 +1175,7 @@ BOOTSTRAPPING BUILD (STRAP)
<scalacfork
destdir="${build-strap.dir}/classes/compiler"
compilerpathref="pack.classpath"
- params="${scalac.args.all}"
+ params="${scalac.args.quick}"
srcdir="${src.dir}/compiler"
jvmargs="${scalacfork.jvmargs}">
<include name="**/*.scala"/>
@@ -1531,6 +1543,7 @@ DOCUMENTATION
docUncompilable="${src.dir}/library-aux"
sourcepath="${src.dir}"
classpathref="pack.classpath"
+ addparams="-Ydependent-method-types"
docRootContent="${build-docs.dir}/library/lib/rootdoc.txt">
<src>
<files includes="${src.dir}/actors"/>
@@ -124,6 +124,8 @@ abstract class TreeGen {
/** Computes stable type for a tree if possible */
def stableTypeFor(tree: Tree): Option[Type] = tree match {
+ case This(_) if tree.symbol != null && !tree.symbol.isError =>
+ Some(ThisType(tree.symbol))
case Ident(_) if tree.symbol.isStable =>
Some(singleType(tree.symbol.owner.thisType, tree.symbol))
case Select(qual, _) if ((tree.symbol ne null) && (qual.tpe ne null)) && // turned assert into guard for #4064
@@ -154,6 +154,7 @@ trait Members { self: ICodes =>
var returnType: TypeKind = _
var recursive: Boolean = false
+ var bytecodeHasEHs = false // set by ICodeReader only, used by Inliner to prevent inlining (SI-6188)
/** local variables and method parameters */
var locals: List[Local] = Nil
@@ -311,7 +311,7 @@ abstract class Inliners extends SubComponent {
def isRecursive = m.recursive
def hasCode = m.code != null
def hasSourceFile = m.sourceFile != null
- def hasHandlers = handlers.nonEmpty
+ def hasHandlers = handlers.nonEmpty || m.bytecodeHasEHs
// the number of inlined calls in 'm', used by 'shouldInline'
var inlinedCalls = 0
@@ -495,7 +495,7 @@ abstract class Inliners extends SubComponent {
}
def isStampedForInlining(stack: TypeStack) =
- !sameSymbols && inc.hasCode && shouldInline && isSafeToInline(stack)
+ !sameSymbols && inc.hasCode && !inc.m.bytecodeHasEHs && shouldInline && isSafeToInline(stack)
def logFailure(stack: TypeStack) = log(
"""|inline failed for %s:
@@ -618,6 +618,7 @@ abstract class ICodeReader extends ClassfileParser {
while (pc < codeLength) parseInstruction
val exceptionEntries = in.nextChar.toInt
+ code.containsEHs = (exceptionEntries != 0)
var i = 0
while (i < exceptionEntries) {
// skip start end PC
@@ -669,6 +670,7 @@ abstract class ICodeReader extends ClassfileParser {
var containsDUPX = false
var containsNEW = false
+ var containsEHs = false
def emit(i: Instruction) {
instrs += ((pc, i))
@@ -686,6 +688,7 @@ abstract class ICodeReader extends ClassfileParser {
val code = new Code(method)
method.setCode(code)
+ method.bytecodeHasEHs = containsEHs
var bb = code.startBlock
def makeBasicBlocks: mutable.Map[Int, BasicBlock] =
@@ -0,0 +1,64 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.concurrent
+
+
+
+import scala.concurrent.duration.Duration
+
+
+
+/**
+ * An object that may eventually be completed with a result value of type `T` which may be
+ * awaited using blocking methods.
+ *
+ * The [[Await]] object provides methods that allow accessing the result of an `Awaitable`
+ * by blocking the current thread until the `Awaitable` has been completed or a timeout has
+ * occurred.
+ */
+trait Awaitable[+T] {
+
+ /**
+ * Await the "completed" state of this `Awaitable`.
+ *
+ * '''''This method should not be called directly; use [[Await.ready]] instead.'''''
+ *
+ * @param atMost
+ * maximum wait time, which may be negative (no waiting is done),
+ * [[scala.concurrent.duration.Duration.Inf Duration.Inf]] for unbounded waiting, or a finite positive
+ * duration
+ * @return this `Awaitable`
+ * @throws InterruptedException if the current thread is interrupted while waiting
+ * @throws TimeoutException if after waiting for the specified time this `Awaitable` is still not ready
+ * @throws IllegalArgumentException if `atMost` is [[scala.concurrent.duration.Duration.Undefined Duration.Undefined]]
+ */
+ @throws(classOf[TimeoutException])
+ @throws(classOf[InterruptedException])
+ def ready(atMost: Duration)(implicit permit: CanAwait): this.type
+
+ /**
+ * Await and return the result (of type `T`) of this `Awaitable`.
+ *
+ * '''''This method should not be called directly; use [[Await.result]] instead.'''''
+ *
+ * @param atMost
+ * maximum wait time, which may be negative (no waiting is done),
+ * [[scala.concurrent.duration.Duration.Inf Duration.Inf]] for unbounded waiting, or a finite positive
+ * duration
+ * @return the result value if the `Awaitable` is completed within the specific maximum wait time
+ * @throws InterruptedException if the current thread is interrupted while waiting
+ * @throws TimeoutException if after waiting for the specified time this `Awaitable` is still not ready
+ * @throws IllegalArgumentException if `atMost` is [[scala.concurrent.duration.Duration.Undefined Duration.Undefined]]
+ */
+ @throws(classOf[Exception])
+ def result(atMost: Duration)(implicit permit: CanAwait): T
+}
+
+
+
@@ -0,0 +1,77 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.concurrent
+
+/**
+ * A context to be notified by `scala.concurrent.blocking` when
+ * a thread is about to block. In effect this trait provides
+ * the implementation for `scala.concurrent.Await`.
+ * `scala.concurrent.Await.result()` and `scala.concurrent.Await.ready()`
+ * locates an instance of `BlockContext` by first looking for one
+ * provided through `BlockContext.withBlockContext()` and failing that,
+ * checking whether `Thread.currentThread` is an instance of `BlockContext`.
+ * So a thread pool can have its `java.lang.Thread` instances implement
+ * `BlockContext`. There's a default `BlockContext` used if the thread
+ * doesn't implement `BlockContext`.
+ *
+ * Typically, you'll want to chain to the previous `BlockContext`,
+ * like this:
+ * {{{
+ * val oldContext = BlockContext.current
+ * val myContext = new BlockContext {
+ * override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = {
+ * // you'd have code here doing whatever you need to do
+ * // when the thread is about to block.
+ * // Then you'd chain to the previous context:
+ * oldContext.blockOn(thunk)
+ * }
+ * }
+ * BlockContext.withBlockContext(myContext) {
+ * // then this block runs with myContext as the handler
+ * // for scala.concurrent.blocking
+ * }
+ * }}}
+ */
+trait BlockContext {
+
+ /** Used internally by the framework;
+ * Designates (and eventually executes) a thunk which potentially blocks the calling `Thread`.
+ *
+ * Clients must use `scala.concurrent.blocking` or `scala.concurrent.Await` instead.
+ */
+ def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T
+}
+
+object BlockContext {
+ private object DefaultBlockContext extends BlockContext {
+ override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = thunk
+ }
+
+ private val contextLocal = new ThreadLocal[BlockContext]()
+
+ /** Obtain the current thread's current `BlockContext`. */
+ def current: BlockContext = contextLocal.get match {
+ case null => Thread.currentThread match {
+ case ctx: BlockContext => ctx
+ case _ => DefaultBlockContext
+ }
+ case some => some
+ }
+
+ /** Pushes a current `BlockContext` while executing `body`. */
+ def withBlockContext[T](blockContext: BlockContext)(body: => T): T = {
+ val old = contextLocal.get // can be null
+ try {
+ contextLocal.set(blockContext)
+ body
+ } finally {
+ contextLocal.set(old)
+ }
+ }
+}
@@ -9,8 +9,6 @@
package scala.concurrent
-import ops.future
-
/** A <code>DelayedLazyVal</code> is a wrapper for lengthy
* computations which have a valid partially computed result.
* The first argument is a function for obtaining the result
@@ -41,7 +39,7 @@ class DelayedLazyVal[T](f: () => T, body: => Unit) {
*/
def apply(): T = if (isDone) complete else f()
- future {
+ ops.future {
body
_isDone = true
}
Oops, something went wrong.

0 comments on commit eda88c8

Please sign in to comment.