diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2014-12-11 21:30:35 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2014-12-15 12:55:30 +1000 |
commit | 1333b3837d405c31baaa44d1db89aab0f7d09349 (patch) | |
tree | bcceb74cff609645543c07c7114ef24a468360d5 /src/test | |
parent | 61b4c183fa2392522051305ec12ab5f433cc09a7 (diff) | |
download | scala-async-1333b3837d405c31baaa44d1db89aab0f7d09349.tar.gz scala-async-1333b3837d405c31baaa44d1db89aab0f7d09349.tar.bz2 scala-async-1333b3837d405c31baaa44d1db89aab0f7d09349.zip |
Avoid unbounded stack consumption for synchronous control flow
Previously, as sequence of state transitions that did not pass through
an asynchrous boundary incurred stack frames. The trivial loop in
the enclosed test case would then overflow the stack.
This commit merges the `resume` and `apply(tr: Try[Any])` methods into
a `apply`. It changes the body of this method to be an infinite loop
with returns at the terminal points in the state machine (or at a
terminal failure.)
To allow merging of these previously separate matches, states that
contain an await are now allocated two state ids: one for the setup
code that calls `onComplete`, and one for the code in the continuation
that records the result and advances the state machine.
Fixes #93
Diffstat (limited to 'src/test')
3 files changed, 37 insertions, 2 deletions
diff --git a/src/test/scala/scala/async/TreeInterrogation.scala b/src/test/scala/scala/async/TreeInterrogation.scala index 8261898..b7c403a 100644 --- a/src/test/scala/scala/async/TreeInterrogation.scala +++ b/src/test/scala/scala/async/TreeInterrogation.scala @@ -36,7 +36,7 @@ class TreeInterrogation { functions.size mustBe 1 val varDefs = tree1.collect { - case ValDef(mods, name, _, _) if mods.hasFlag(Flag.MUTABLE) => name + case vd @ ValDef(mods, name, _, _) if mods.hasFlag(Flag.MUTABLE) && vd.symbol.owner.isClass => name } varDefs.map(_.decoded.trim).toSet mustBe (Set("state", "await$1$1", "await$2$1")) @@ -49,7 +49,7 @@ class TreeInterrogation { && !dd.symbol.asTerm.isAccessor && !dd.symbol.asTerm.isSetter => dd.name } }.flatten - defDefs.map(_.decoded.trim).toSet mustBe (Set("foo$1", "apply", "resume", "<init>")) + defDefs.map(_.decoded.trim).toSet mustBe (Set("foo$1", "apply", "<init>")) } } diff --git a/src/test/scala/scala/async/run/futures/FutureSpec.scala b/src/test/scala/scala/async/run/futures/FutureSpec.scala index 1761db5..25be0b1 100644 --- a/src/test/scala/scala/async/run/futures/FutureSpec.scala +++ b/src/test/scala/scala/async/run/futures/FutureSpec.scala @@ -134,6 +134,13 @@ class FutureSpec { Await.result(future1, defaultTimeout) mustBe ("10-14") intercept[NoSuchElementException] { Await.result(future2, defaultTimeout) } } + + @Test def mini() { + val future4 = async { + await(Future.successful(0)).toString + } + Await.result(future4, defaultTimeout) + } @Test def `recover from exceptions`() { val future1 = Future(5) diff --git a/src/test/scala/scala/async/run/stackoverflow/StackOverflowSpec.scala b/src/test/scala/scala/async/run/stackoverflow/StackOverflowSpec.scala new file mode 100644 index 0000000..2dc9b92 --- /dev/null +++ b/src/test/scala/scala/async/run/stackoverflow/StackOverflowSpec.scala @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2012-2014 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.async +package run +package stackoverflow + +import org.junit.Test +import scala.async.internal.AsyncId + + +class StackOverflowSpec { + + @Test + def stackSafety() { + import AsyncId._ + async { + var i = 100000000 + while (i > 0) { + if (false) { + await(()) + } + i -= 1 + } + } + } +} |