Merge pull request #1357 from Kotlin/version-1.3.0-RC

Version 1.3.0-RC
diff --git a/CHANGES.md b/CHANGES.md
index a8f1106..cd920aa 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,28 @@
 # Change log for kotlinx.coroutines
 
+## Version 1.3.0-RC
+
+### Flow
+
+* Core `Flow` API is promoted to stable
+* New basic `Flow` operators: `withIndex`, `collectIndexed`, `distinctUntilChanged` overload
+* New core `Flow` operators: `onStart` and `onCompletion`
+* `ReceiveChannel.consumeAsFlow` and `emitAll` (#1340)
+
+### General changes
+
+* Kotlin updated to 1.3.41
+* Added `kotlinx-coroutines-bom` with Maven Bill of Materials (#1110)
+* Reactive integrations are seriously improved
+  * All builders now are top-level functions instead of extensions on `CoroutineScope` and prohibit `Job` instance in their context to simplify lifecycle management
+  * Fatal exceptions are handled consistently (#1297)
+  * Integration with Reactor Context added (#284)
+* Stacktrace recovery for `suspend fun main` (#1328)
+* `CoroutineScope.cancel` extension with message (#1338)
+* Protection against non-monotonic clocks in `delay` (#1312)
+* `Duration.ZERO` is handled properly in JDK 8 extensions (#1349)
+* Library code is adjusted to be more minification-friendly 
+
 ## Version 1.3.0-M2
 
  * Kotlin updated to 1.3.40.
diff --git a/README.md b/README.md
index f3c5558..84083a8 100644
--- a/README.md
+++ b/README.md
@@ -2,10 +2,10 @@
 
 [![official JetBrains project](https://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
 [![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0)
-[![Download](https://api.bintray.com/packages/kotlin/kotlinx/kotlinx.coroutines/images/download.svg?version=1.3.0-M2) ](https://bintray.com/kotlin/kotlinx/kotlinx.coroutines/1.3.0-M2)
+[![Download](https://api.bintray.com/packages/kotlin/kotlinx/kotlinx.coroutines/images/download.svg?version=1.3.0-RC) ](https://bintray.com/kotlin/kotlinx/kotlinx.coroutines/1.3.0-RC)
 
 Library support for Kotlin coroutines with [multiplatform](#multiplatform) support.
-This is a companion version for Kotlin `1.3.40` release.
+This is a companion version for Kotlin `1.3.41` release.
 
 ```kotlin
 suspend fun main() = coroutineScope {
@@ -81,7 +81,7 @@
 <dependency>
     <groupId>org.jetbrains.kotlinx</groupId>
     <artifactId>kotlinx-coroutines-core</artifactId>
-    <version>1.3.0-M2</version>
+    <version>1.3.0-RC</version>
 </dependency>
 ```
 
@@ -89,7 +89,7 @@
 
 ```xml
 <properties>
-    <kotlin.version>1.3.40</kotlin.version>
+    <kotlin.version>1.3.41</kotlin.version>
 </properties>
 ```
 
@@ -99,7 +99,7 @@
 
 ```groovy
 dependencies {
-    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0-M2'
+    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0-RC'
 }
 ```
 
@@ -107,7 +107,7 @@
 
 ```groovy
 buildscript {
-    ext.kotlin_version = '1.3.40'
+    ext.kotlin_version = '1.3.41'
 }
 ```
 
@@ -125,7 +125,7 @@
 
 ```groovy
 dependencies {
-    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0-M2")
+    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0-RC")
 }
 ```
 
@@ -133,7 +133,7 @@
 
 ```groovy
 plugins {
-    kotlin("jvm") version "1.3.40"
+    kotlin("jvm") version "1.3.41"
 }
 ```
 
@@ -144,7 +144,7 @@
 Core modules of `kotlinx.coroutines` are also available for 
 [Kotlin/JS](#js) and [Kotlin/Native](#native).
 In common code that should get compiled for different platforms, add dependency to  
-[`kotlinx-coroutines-core-common`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-common/1.3.0-M2/jar)
+[`kotlinx-coroutines-core-common`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-common/1.3.0-RC/jar)
 (follow the link to get the dependency declaration snippet).
 
 ### Android
@@ -153,7 +153,7 @@
 module as dependency when using `kotlinx.coroutines` on Android:
 
 ```groovy
-implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0-M2'
+implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0-RC'
 ```
 
 This gives you access to Android [Dispatchers.Main](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-android/kotlinx.coroutines.android/kotlinx.coroutines.-dispatchers/index.html)
@@ -172,7 +172,7 @@
 ### JS
 
 [Kotlin/JS](https://kotlinlang.org/docs/reference/js-overview.html) version of `kotlinx.coroutines` is published as 
-[`kotlinx-coroutines-core-js`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-js/1.3.0-M2/jar)
+[`kotlinx-coroutines-core-js`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-js/1.3.0-RC/jar)
 (follow the link to get the dependency declaration snippet).
  
 You can also use [`kotlinx-coroutines-core`](https://www.npmjs.com/package/kotlinx-coroutines-core) package via NPM. 
@@ -180,7 +180,7 @@
 ### Native
 
 [Kotlin/Native](https://kotlinlang.org/docs/reference/native-overview.html) version of `kotlinx.coroutines` is published as 
-[`kotlinx-coroutines-core-native`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-native/1.3.0-M2/jar)
+[`kotlinx-coroutines-core-native`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-native/1.3.0-RC/jar)
 (follow the link to get the dependency declaration snippet).
 
 Only single-threaded code (JS-style) on Kotlin/Native is currently supported. 
diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt
index 94df09a..3e20e88 100644
--- a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt
+++ b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt
@@ -202,7 +202,9 @@
 public final class kotlinx/coroutines/CoroutineScopeKt {
 	public static final fun CoroutineScope (Lkotlin/coroutines/CoroutineContext;)Lkotlinx/coroutines/CoroutineScope;
 	public static final fun MainScope ()Lkotlinx/coroutines/CoroutineScope;
+	public static final fun cancel (Lkotlinx/coroutines/CoroutineScope;Ljava/lang/String;Ljava/lang/Throwable;)V
 	public static final fun cancel (Lkotlinx/coroutines/CoroutineScope;Ljava/util/concurrent/CancellationException;)V
+	public static synthetic fun cancel$default (Lkotlinx/coroutines/CoroutineScope;Ljava/lang/String;Ljava/lang/Throwable;ILjava/lang/Object;)V
 	public static synthetic fun cancel$default (Lkotlinx/coroutines/CoroutineScope;Ljava/util/concurrent/CancellationException;ILjava/lang/Object;)V
 	public static final fun coroutineScope (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static final fun ensureActive (Lkotlinx/coroutines/CoroutineScope;)V
@@ -352,8 +354,10 @@
 	public static final synthetic fun cancel (Lkotlin/coroutines/CoroutineContext;)V
 	public static final synthetic fun cancel (Lkotlin/coroutines/CoroutineContext;Ljava/lang/Throwable;)Z
 	public static final fun cancel (Lkotlin/coroutines/CoroutineContext;Ljava/util/concurrent/CancellationException;)V
+	public static final fun cancel (Lkotlinx/coroutines/Job;Ljava/lang/String;Ljava/lang/Throwable;)V
 	public static synthetic fun cancel$default (Lkotlin/coroutines/CoroutineContext;Ljava/lang/Throwable;ILjava/lang/Object;)Z
 	public static synthetic fun cancel$default (Lkotlin/coroutines/CoroutineContext;Ljava/util/concurrent/CancellationException;ILjava/lang/Object;)V
+	public static synthetic fun cancel$default (Lkotlinx/coroutines/Job;Ljava/lang/String;Ljava/lang/Throwable;ILjava/lang/Object;)V
 	public static final fun cancelAndJoin (Lkotlinx/coroutines/Job;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static final synthetic fun cancelChildren (Lkotlin/coroutines/CoroutineContext;)V
 	public static final synthetic fun cancelChildren (Lkotlin/coroutines/CoroutineContext;Ljava/lang/Throwable;)V
@@ -437,6 +441,7 @@
 	public fun join (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public fun plus (Lkotlinx/coroutines/Job;)Lkotlinx/coroutines/Job;
 	public fun start ()Z
+	public fun toString ()Ljava/lang/String;
 }
 
 public final class kotlinx/coroutines/NonDisposableHandle : kotlinx/coroutines/ChildHandle, kotlinx/coroutines/DisposableHandle {
@@ -670,7 +675,9 @@
 	public static final fun minWith (Lkotlinx/coroutines/channels/ReceiveChannel;Ljava/util/Comparator;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static final fun none (Lkotlinx/coroutines/channels/ReceiveChannel;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static final fun none (Lkotlinx/coroutines/channels/ReceiveChannel;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+	public static final fun onReceiveOrNull (Lkotlinx/coroutines/channels/ReceiveChannel;)Lkotlinx/coroutines/selects/SelectClause1;
 	public static final fun partition (Lkotlinx/coroutines/channels/ReceiveChannel;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+	public static final fun receiveOrNull (Lkotlinx/coroutines/channels/ReceiveChannel;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static final fun reduce (Lkotlinx/coroutines/channels/ReceiveChannel;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static final fun reduceIndexed (Lkotlinx/coroutines/channels/ReceiveChannel;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static final fun requireNoNulls (Lkotlinx/coroutines/channels/ReceiveChannel;)Lkotlinx/coroutines/channels/ReceiveChannel;
@@ -743,12 +750,14 @@
 	public abstract synthetic fun cancel (Ljava/lang/Throwable;)Z
 	public abstract fun cancel (Ljava/util/concurrent/CancellationException;)V
 	public abstract fun getOnReceive ()Lkotlinx/coroutines/selects/SelectClause1;
+	public abstract fun getOnReceiveOrClosed ()Lkotlinx/coroutines/selects/SelectClause1;
 	public abstract fun getOnReceiveOrNull ()Lkotlinx/coroutines/selects/SelectClause1;
 	public abstract fun isClosedForReceive ()Z
 	public abstract fun isEmpty ()Z
 	public abstract fun iterator ()Lkotlinx/coroutines/channels/ChannelIterator;
 	public abstract fun poll ()Ljava/lang/Object;
 	public abstract fun receive (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+	public abstract fun receiveOrClosed (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public abstract fun receiveOrNull (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 }
 
@@ -784,6 +793,23 @@
 	public static fun values ()[Lkotlinx/coroutines/channels/TickerMode;
 }
 
+public final class kotlinx/coroutines/channels/ValueOrClosed {
+	public static final field Companion Lkotlinx/coroutines/channels/ValueOrClosed$Companion;
+	public static final synthetic fun box-impl (Ljava/lang/Object;)Lkotlinx/coroutines/channels/ValueOrClosed;
+	public fun equals (Ljava/lang/Object;)Z
+	public static fun equals-impl (Ljava/lang/Object;Ljava/lang/Object;)Z
+	public static final fun equals-impl0 (Ljava/lang/Object;Ljava/lang/Object;)Z
+	public static final fun getCloseCause-impl (Ljava/lang/Object;)Ljava/lang/Throwable;
+	public static final fun getValue-impl (Ljava/lang/Object;)Ljava/lang/Object;
+	public static final fun getValueOrNull-impl (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun hashCode ()I
+	public static fun hashCode-impl (Ljava/lang/Object;)I
+	public static final fun isClosed-impl (Ljava/lang/Object;)Z
+	public fun toString ()Ljava/lang/String;
+	public static fun toString-impl (Ljava/lang/Object;)Ljava/lang/String;
+	public final synthetic fun unbox-impl ()Ljava/lang/Object;
+}
+
 public abstract class kotlinx/coroutines/flow/AbstractFlow : kotlinx/coroutines/flow/Flow {
 	public fun <init> ()V
 	public final fun collect (Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
@@ -800,6 +826,9 @@
 
 public final class kotlinx/coroutines/flow/FlowKt {
 	public static final field DEFAULT_CONCURRENCY_PROPERTY_NAME Ljava/lang/String;
+	public static final fun BehaviourSubject ()Ljava/lang/Object;
+	public static final fun PublishSubject ()Ljava/lang/Object;
+	public static final fun ReplaySubject ()Ljava/lang/Object;
 	public static final fun asFlow (Ljava/lang/Iterable;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun asFlow (Ljava/util/Iterator;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun asFlow (Lkotlin/jvm/functions/Function0;)Lkotlinx/coroutines/flow/Flow;
@@ -820,22 +849,30 @@
 	public static final fun channelFlow (Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun collect (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static final fun collect (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+	public static final fun collectIndexed (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static final fun combineLatest (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun combineLatest (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function4;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun combineLatest (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function5;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun combineLatest (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function6;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun combineLatest (Lkotlinx/coroutines/flow/Flow;[Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
 	public static final synthetic fun combineLatest (Lkotlinx/coroutines/flow/Flow;[Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun compose (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun concatMap (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun concatWith (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun concatWith (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun conflate (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun consumeAsFlow (Lkotlinx/coroutines/channels/ReceiveChannel;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun count (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static final fun count (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static final fun debounce (Lkotlinx/coroutines/flow/Flow;J)Lkotlinx/coroutines/flow/Flow;
 	public static final fun delayEach (Lkotlinx/coroutines/flow/Flow;J)Lkotlinx/coroutines/flow/Flow;
 	public static final fun delayFlow (Lkotlinx/coroutines/flow/Flow;J)Lkotlinx/coroutines/flow/Flow;
 	public static final fun distinctUntilChanged (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun distinctUntilChanged (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun distinctUntilChangedBy (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun drop (Lkotlinx/coroutines/flow/Flow;I)Lkotlinx/coroutines/flow/Flow;
 	public static final fun dropWhile (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun emitAll (Lkotlinx/coroutines/flow/FlowCollector;Lkotlinx/coroutines/channels/ReceiveChannel;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static final fun emitAll (Lkotlinx/coroutines/flow/FlowCollector;Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static final fun emptyFlow ()Lkotlinx/coroutines/flow/Flow;
 	public static final fun filter (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
@@ -844,9 +881,11 @@
 	public static final fun filterNotNull (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun first (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static final fun first (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+	public static final fun flatMap (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun flatMapConcat (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun flatMapMerge (Lkotlinx/coroutines/flow/Flow;ILkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
 	public static synthetic fun flatMapMerge$default (Lkotlinx/coroutines/flow/Flow;ILkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun flatten (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun flattenConcat (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun flattenMerge (Lkotlinx/coroutines/flow/Flow;I)Lkotlinx/coroutines/flow/Flow;
 	public static synthetic fun flattenMerge$default (Lkotlinx/coroutines/flow/Flow;IILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
@@ -859,15 +898,26 @@
 	public static final fun flowWith (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/CoroutineContext;ILkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/flow/Flow;
 	public static synthetic fun flowWith$default (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/CoroutineContext;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun fold (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Object;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+	public static final fun forEach (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)V
 	public static final fun getDEFAULT_CONCURRENCY ()I
 	public static final fun launchIn (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/Job;
 	public static final fun map (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun mapNotNull (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
-	public static final fun onCompletion (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun merge (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun observeOn (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/CoroutineContext;)Lkotlinx/coroutines/flow/Flow;
+	public static final synthetic fun onCompletion (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun onCompletion (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun onEach (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun onErrorCollect (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/flow/Flow;
 	public static synthetic fun onErrorCollect$default (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun onErrorResume (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun onErrorResumeNext (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun onErrorReturn (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun onErrorReturn (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/flow/Flow;
+	public static synthetic fun onErrorReturn$default (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun onStart (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun produceIn (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/channels/ReceiveChannel;
+	public static final fun publishOn (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/CoroutineContext;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun reduce (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static final synthetic fun retry (Lkotlinx/coroutines/flow/Flow;ILkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun retry (Lkotlinx/coroutines/flow/Flow;JLkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
@@ -876,9 +926,17 @@
 	public static final fun retryWhen (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function4;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun sample (Lkotlinx/coroutines/flow/Flow;J)Lkotlinx/coroutines/flow/Flow;
 	public static final fun scan (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun scanFold (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun scanReduce (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun single (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static final fun singleOrNull (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+	public static final fun skip (Lkotlinx/coroutines/flow/Flow;I)Lkotlinx/coroutines/flow/Flow;
+	public static final fun startWith (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun startWith (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun subscribe (Lkotlinx/coroutines/flow/Flow;)V
+	public static final fun subscribe (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)V
+	public static final fun subscribe (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)V
+	public static final fun subscribeOn (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/CoroutineContext;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun switchMap (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun take (Lkotlinx/coroutines/flow/Flow;I)Lkotlinx/coroutines/flow/Flow;
 	public static final fun takeWhile (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
@@ -888,34 +946,10 @@
 	public static final fun toSet (Lkotlinx/coroutines/flow/Flow;Ljava/util/Set;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static synthetic fun toSet$default (Lkotlinx/coroutines/flow/Flow;Ljava/util/Set;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
 	public static final fun transform (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;
-	public static final fun unsafeFlow (Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
-	public static final fun zip (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;
-}
-
-public final class kotlinx/coroutines/flow/MigrationKt {
-	public static final fun BehaviourSubject ()Ljava/lang/Object;
-	public static final fun PublishSubject ()Ljava/lang/Object;
-	public static final fun ReplaySubject ()Ljava/lang/Object;
-	public static final fun compose (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/flow/Flow;
-	public static final fun concatMap (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/flow/Flow;
-	public static final fun flatMap (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
-	public static final fun flatten (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
-	public static final fun forEach (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)V
-	public static final fun merge (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
-	public static final fun observeOn (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/CoroutineContext;)Lkotlinx/coroutines/flow/Flow;
-	public static final fun onErrorResume (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
-	public static final fun onErrorResumeNext (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
-	public static final fun onErrorReturn (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
-	public static final fun onErrorReturn (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/flow/Flow;
-	public static synthetic fun onErrorReturn$default (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
-	public static final fun publishOn (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/CoroutineContext;)Lkotlinx/coroutines/flow/Flow;
-	public static final fun scanFold (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;
-	public static final fun skip (Lkotlinx/coroutines/flow/Flow;I)Lkotlinx/coroutines/flow/Flow;
-	public static final fun subscribe (Lkotlinx/coroutines/flow/Flow;)V
-	public static final fun subscribe (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)V
-	public static final fun subscribe (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)V
-	public static final fun subscribeOn (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/CoroutineContext;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun unsafeTransform (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;
 	public static final fun withContext (Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function1;)V
+	public static final fun withIndex (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
+	public static final fun zip (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;
 }
 
 public abstract class kotlinx/coroutines/flow/internal/ChannelFlow : kotlinx/coroutines/flow/Flow {
@@ -923,7 +957,7 @@
 	public final field context Lkotlin/coroutines/CoroutineContext;
 	public fun <init> (Lkotlin/coroutines/CoroutineContext;I)V
 	public fun additionalToStringProps ()Ljava/lang/String;
-	public final fun broadcastImpl (Lkotlinx/coroutines/CoroutineScope;Lkotlinx/coroutines/CoroutineStart;)Lkotlinx/coroutines/channels/BroadcastChannel;
+	public fun broadcastImpl (Lkotlinx/coroutines/CoroutineScope;Lkotlinx/coroutines/CoroutineStart;)Lkotlinx/coroutines/channels/BroadcastChannel;
 	public fun collect (Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	protected abstract fun collectTo (Lkotlinx/coroutines/channels/ProducerScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	protected abstract fun create (Lkotlin/coroutines/CoroutineContext;I)Lkotlinx/coroutines/flow/internal/ChannelFlow;
@@ -933,9 +967,12 @@
 	public static synthetic fun update$default (Lkotlinx/coroutines/flow/internal/ChannelFlow;Lkotlin/coroutines/CoroutineContext;IILjava/lang/Object;)Lkotlinx/coroutines/flow/internal/ChannelFlow;
 }
 
-public final class kotlinx/coroutines/flow/internal/SafeCollector : kotlinx/coroutines/flow/FlowCollector {
-	public fun <init> (Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/CoroutineContext;)V
-	public fun emit (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+public final class kotlinx/coroutines/flow/internal/FlowExceptions_commonKt {
+	public static final fun checkIndexOverflow (I)I
+}
+
+public final class kotlinx/coroutines/flow/internal/SafeCollectorKt {
+	public static final fun unsafeFlow (Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
 }
 
 public final class kotlinx/coroutines/flow/internal/SendingCollector : kotlinx/coroutines/flow/internal/ConcurrentFlowCollector {
diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-reactive.txt b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-reactive.txt
index 2afa313..643f641 100644
--- a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-reactive.txt
+++ b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-reactive.txt
@@ -20,8 +20,28 @@
 }
 
 public final class kotlinx/coroutines/reactive/PublishKt {
+	public static final fun publish (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lorg/reactivestreams/Publisher;
 	public static final fun publish (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lorg/reactivestreams/Publisher;
+	public static synthetic fun publish$default (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lorg/reactivestreams/Publisher;
 	public static synthetic fun publish$default (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lorg/reactivestreams/Publisher;
+	public static final fun publishInternal (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lorg/reactivestreams/Publisher;
+}
+
+public final class kotlinx/coroutines/reactive/PublisherCoroutine : kotlinx/coroutines/AbstractCoroutine, kotlinx/coroutines/channels/ProducerScope, kotlinx/coroutines/selects/SelectClause2, org/reactivestreams/Subscription {
+	public fun <init> (Lkotlin/coroutines/CoroutineContext;Lorg/reactivestreams/Subscriber;)V
+	public fun cancel ()V
+	public fun close (Ljava/lang/Throwable;)Z
+	public fun getChannel ()Lkotlinx/coroutines/channels/SendChannel;
+	public fun getOnSend ()Lkotlinx/coroutines/selects/SelectClause2;
+	public fun invokeOnClose (Lkotlin/jvm/functions/Function1;)Ljava/lang/Void;
+	public synthetic fun invokeOnClose (Lkotlin/jvm/functions/Function1;)V
+	public fun isClosedForSend ()Z
+	public fun isFull ()Z
+	public fun offer (Ljava/lang/Object;)Z
+	public synthetic fun onCompleted (Ljava/lang/Object;)V
+	public fun registerSelectClause2 (Lkotlinx/coroutines/selects/SelectInstance;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)V
+	public fun request (J)V
+	public fun send (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 }
 
 public final class kotlinx/coroutines/reactive/flow/FlowAsPublisherKt {
diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-reactor.txt b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-reactor.txt
index 8afd014..46b35ed 100644
--- a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-reactor.txt
+++ b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-reactor.txt
@@ -6,15 +6,32 @@
 }
 
 public final class kotlinx/coroutines/reactor/FluxKt {
+	public static final fun flux (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lreactor/core/publisher/Flux;
 	public static final fun flux (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lreactor/core/publisher/Flux;
+	public static synthetic fun flux$default (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lreactor/core/publisher/Flux;
 	public static synthetic fun flux$default (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lreactor/core/publisher/Flux;
 }
 
 public final class kotlinx/coroutines/reactor/MonoKt {
+	public static final fun mono (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lreactor/core/publisher/Mono;
 	public static final fun mono (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lreactor/core/publisher/Mono;
+	public static synthetic fun mono$default (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lreactor/core/publisher/Mono;
 	public static synthetic fun mono$default (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lreactor/core/publisher/Mono;
 }
 
+public final class kotlinx/coroutines/reactor/ReactorContext : kotlin/coroutines/AbstractCoroutineContextElement {
+	public static final field Key Lkotlinx/coroutines/reactor/ReactorContext$Key;
+	public fun <init> (Lreactor/util/context/Context;)V
+	public final fun getContext ()Lreactor/util/context/Context;
+}
+
+public final class kotlinx/coroutines/reactor/ReactorContext$Key : kotlin/coroutines/CoroutineContext$Key {
+}
+
+public final class kotlinx/coroutines/reactor/ReactorContextKt {
+	public static final fun asCoroutineContext (Lreactor/util/context/Context;)Lkotlinx/coroutines/reactor/ReactorContext;
+}
+
 public final class kotlinx/coroutines/reactor/SchedulerCoroutineDispatcher : kotlinx/coroutines/CoroutineDispatcher, kotlinx/coroutines/Delay {
 	public fun <init> (Lreactor/core/scheduler/Scheduler;)V
 	public fun delay (JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-rx2.txt b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-rx2.txt
index 67ef8a1..54a9663 100644
--- a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-rx2.txt
+++ b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-rx2.txt
@@ -21,7 +21,9 @@
 }
 
 public final class kotlinx/coroutines/rx2/RxCompletableKt {
+	public static final fun rxCompletable (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lio/reactivex/Completable;
 	public static final fun rxCompletable (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lio/reactivex/Completable;
+	public static synthetic fun rxCompletable$default (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/reactivex/Completable;
 	public static synthetic fun rxCompletable$default (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/reactivex/Completable;
 }
 
@@ -35,17 +37,23 @@
 }
 
 public final class kotlinx/coroutines/rx2/RxFlowableKt {
+	public static final fun rxFlowable (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lio/reactivex/Flowable;
 	public static final fun rxFlowable (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lio/reactivex/Flowable;
+	public static synthetic fun rxFlowable$default (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/reactivex/Flowable;
 	public static synthetic fun rxFlowable$default (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/reactivex/Flowable;
 }
 
 public final class kotlinx/coroutines/rx2/RxMaybeKt {
+	public static final fun rxMaybe (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lio/reactivex/Maybe;
 	public static final fun rxMaybe (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lio/reactivex/Maybe;
+	public static synthetic fun rxMaybe$default (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/reactivex/Maybe;
 	public static synthetic fun rxMaybe$default (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/reactivex/Maybe;
 }
 
 public final class kotlinx/coroutines/rx2/RxObservableKt {
+	public static final fun rxObservable (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lio/reactivex/Observable;
 	public static final fun rxObservable (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lio/reactivex/Observable;
+	public static synthetic fun rxObservable$default (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/reactivex/Observable;
 	public static synthetic fun rxObservable$default (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/reactivex/Observable;
 }
 
@@ -54,7 +62,9 @@
 }
 
 public final class kotlinx/coroutines/rx2/RxSingleKt {
+	public static final fun rxSingle (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lio/reactivex/Single;
 	public static final fun rxSingle (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lio/reactivex/Single;
+	public static synthetic fun rxSingle$default (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/reactivex/Single;
 	public static synthetic fun rxSingle$default (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/reactivex/Single;
 }
 
diff --git a/binary-compatibility-validator/resources/api.properties b/binary-compatibility-validator/resources/api.properties
index 690989a..9fa115b 100644
--- a/binary-compatibility-validator/resources/api.properties
+++ b/binary-compatibility-validator/resources/api.properties
@@ -4,6 +4,6 @@
 
 module.roots=/ integration reactive ui
 module.marker=build.gradle
-module.ignore=kotlinx-coroutines-rx-example stdlib-stubs benchmarks knit binary-compatibility-validator site publication-validator
+module.ignore=kotlinx-coroutines-rx-example stdlib-stubs benchmarks knit binary-compatibility-validator site publication-validator kotlinx-coroutines-bom
 
 packages.internal=kotlinx.coroutines.internal
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index a1813d1..4bccce7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -8,8 +8,8 @@
 def rootModule = "kotlinx.coroutines"
 def coreModule = "kotlinx-coroutines-core"
 // Not applicable for Kotlin plugin
-def sourceless = ['kotlinx.coroutines', 'site']
-def internal = sourceless + ['benchmarks', 'knit', 'js-stub', 'stdlib-stubs', 'binary-compatibility-validator']
+def sourceless = ['kotlinx.coroutines', 'site', 'kotlinx-coroutines-bom']
+def internal = ['kotlinx.coroutines', 'site', 'benchmarks', 'knit', 'js-stub', 'stdlib-stubs', 'binary-compatibility-validator']
 // Not published
 def unpublished = internal + ['kotlinx-coroutines-rx-example', 'example-frontend-js', 'android-unit-tests']
 
@@ -58,12 +58,12 @@
     }
 
     dependencies {
-        classpath "org.jfrog.buildinfo:build-info-extractor-gradle:$artifactory_plugin_version"
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
         classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version"
         classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version"
         classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$bintray_version"
         classpath "com.moowork.gradle:gradle-node-plugin:$gradle_node_version"
+        classpath "io.spring.gradle:dependency-management-plugin:$spring_dependency_management_version"
 
         // JMH plugins
         classpath "com.github.jengelman.gradle.plugins:shadow:4.0.2"
@@ -95,6 +95,8 @@
             maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
         }
     }
+
+    ext.unpublished = unpublished
 }
 
 allprojects {
@@ -123,7 +125,6 @@
     def platform = platformOf(it)
     apply from: rootProject.file("gradle/compile-${platform}.gradle")
 
-
     dependencies {
         // See comment below for rationale, it will be replaced with "project" dependency
         compile "org.jetbrains.kotlinx:kotlinx-coroutines-core:$version"
@@ -135,6 +136,7 @@
     tasks.withType(org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile).all {
         kotlinOptions.freeCompilerArgs += experimentalAnnotations.collect { "-Xuse-experimental=" + it }
         kotlinOptions.freeCompilerArgs += "-progressive"
+        kotlinOptions.freeCompilerArgs += "-XXLanguage:+InlineClasses"
         // Binary compatibility support
         kotlinOptions.freeCompilerArgs += ["-Xdump-declarations-to=${buildDir}/visibilities.json"]
     }
@@ -201,23 +203,27 @@
 def core_docs_file = "$projectDir/kotlinx-coroutines-core/build/dokka/kotlinx-coroutines-core/package-list"
 
 configure(subprojects.findAll { !unpublished.contains(it.name) }) {
-    apply from: rootProject.file('gradle/dokka.gradle')
+    if (it.name != 'kotlinx-coroutines-bom') {
+        apply from: rootProject.file('gradle/dokka.gradle')
+    }
     apply from: rootProject.file('gradle/publish-bintray.gradle')
 }
 
 configure(subprojects.findAll { !unpublished.contains(it.name) }) {
-    if (it.name != coreModule) {
-        dokka.dependsOn project(":$coreModule").dokka
-        tasks.withType(dokka.getClass()) {
-            externalDocumentationLink {
-                url = new URL(core_docs_url)
-                packageListUrl = new URL("file://$core_docs_file")
+    if (it.name != "kotlinx-coroutines-bom") {
+        if (it.name != coreModule) {
+            dokka.dependsOn project(":$coreModule").dokka
+            tasks.withType(dokka.getClass()) {
+                externalDocumentationLink {
+                    url = new URL(core_docs_url)
+                    packageListUrl = new URL("file://$core_docs_file")
+                }
             }
         }
-    }
 
-    if (platformOf(it) == "jvm") {
-        dokkaJavadoc.dependsOn project(":$coreModule").dokka
+        if (platformOf(it) == "jvm") {
+            dokkaJavadoc.dependsOn project(":$coreModule").dokka
+        }
     }
 }
 
diff --git a/common/kotlinx-coroutines-core-common/test/channels/ChannelReceiveOrClosedTest.kt b/common/kotlinx-coroutines-core-common/test/channels/ChannelReceiveOrClosedTest.kt
new file mode 100644
index 0000000..303e6d1
--- /dev/null
+++ b/common/kotlinx-coroutines-core-common/test/channels/ChannelReceiveOrClosedTest.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines.channels
+
+import kotlinx.coroutines.*
+import kotlin.test.*
+
+class ChannelReceiveOrClosedTest : TestBase() {
+    @Test
+    fun testChannelOfThrowables() = runTest {
+        val channel = Channel<Throwable>()
+        launch {
+            channel.send(TestException1())
+            channel.close(TestException2())
+        }
+
+        val element = channel.receiveOrClosed()
+        assertTrue(element.isValue)
+        assertTrue(element.value is TestException1)
+        assertTrue(element.valueOrNull is TestException1)
+
+        val closed = channel.receiveOrClosed()
+        assertTrue(closed.isClosed)
+        assertTrue(closed.closeCause is TestException2)
+    }
+
+    @Test
+    @Suppress("ReplaceAssertBooleanWithAssertEquality") // inline classes test
+    fun testNullableIntChanel() = runTest {
+        val channel = Channel<Int?>()
+        launch {
+            expect(2)
+            channel.send(1)
+            expect(3)
+            channel.send(null)
+
+            expect(6)
+            channel.close()
+        }
+
+        expect(1)
+        val element = channel.receiveOrClosed()
+        assertTrue(element.isValue)
+        assertEquals(1, element.value)
+        assertEquals(1, element.valueOrNull)
+        assertEquals("Value(1)", element.toString())
+        assertTrue(ValueOrClosed.value(1) == element) // Don't box
+
+        expect(4)
+        val nullElement = channel.receiveOrClosed()
+        assertTrue(nullElement.isValue)
+        assertNull(nullElement.value)
+        assertNull(nullElement.valueOrNull)
+        assertEquals("Value(null)", nullElement.toString())
+        assertTrue(ValueOrClosed.value(null) == nullElement) // Don't box
+
+        expect(5)
+        val closed = channel.receiveOrClosed()
+        assertTrue(closed.isClosed)
+
+        val closed2 = channel.receiveOrClosed()
+        assertTrue(closed2.isClosed)
+        assertTrue(closed2.closeCause is ClosedReceiveChannelException)
+        finish(7)
+    }
+
+    @Test
+    @ExperimentalUnsignedTypes
+    fun testUIntChannel() = runTest {
+        val channel = Channel<UInt>()
+        launch {
+            expect(2)
+            channel.send(1u)
+            yield()
+            expect(4)
+            channel.send((Long.MAX_VALUE - 1).toUInt())
+            expect(5)
+        }
+
+        expect(1)
+        val element = channel.receiveOrClosed()
+        assertEquals(1u, element.value)
+
+        expect(3)
+        val element2 = channel.receiveOrClosed()
+        assertEquals((Long.MAX_VALUE - 1).toUInt(), element2.value)
+        finish(6)
+    }
+
+    @Test
+    fun testCancelChannel() = runTest {
+        val channel = Channel<Boolean>()
+        launch {
+            expect(2)
+            channel.cancel()
+        }
+
+        expect(1)
+        val closed = channel.receiveOrClosed()
+        assertTrue(closed.isClosed)
+        assertTrue(closed.closeCause is ClosedReceiveChannelException)
+        finish(3)
+    }
+
+    @Test
+    @ExperimentalUnsignedTypes
+    fun testReceiveResultChannel() = runTest {
+        val channel = Channel<ValueOrClosed<UInt>>()
+        launch {
+            channel.send(ValueOrClosed.value(1u))
+            channel.send(ValueOrClosed.closed(TestException1()))
+            channel.close(TestException2())
+        }
+
+        val intResult = channel.receiveOrClosed()
+        assertTrue(intResult.isValue)
+        assertEquals(1u, intResult.value.value)
+
+        val closeCauseResult = channel.receiveOrClosed()
+        assertTrue(closeCauseResult.isValue)
+        assertTrue(closeCauseResult.value.closeCause is TestException1)
+
+        val closeCause = channel.receiveOrClosed()
+        assertTrue(closeCause.isClosed)
+        assertTrue(closeCause.closeCause is TestException2)
+        assertFailsWith<TestException2> { closeCause.valueOrThrow }
+    }
+
+    @Test
+    fun testToString() = runTest {
+        val channel = Channel<String>(1)
+        channel.send("message")
+        channel.close(TestException1())
+        assertEquals("Value(message)", channel.receiveOrClosed().toString())
+        // toString implementation for exception differs on every platform
+        val str = channel.receiveOrClosed().toString()
+        assertTrue(str.matches("Closed\\(.*TestException1\\)".toRegex()))
+    }
+}
diff --git a/docs/basics.md b/docs/basics.md
index 642ea48..a7321bb 100644
--- a/docs/basics.md
+++ b/docs/basics.md
@@ -1,6 +1,6 @@
 <!--- INCLUDE .*/example-([a-z]+)-([0-9a-z]+)\.kt 
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/docs/cancellation-and-timeouts.md b/docs/cancellation-and-timeouts.md
index 5f5fecd..afb8da9 100644
--- a/docs/cancellation-and-timeouts.md
+++ b/docs/cancellation-and-timeouts.md
@@ -1,6 +1,6 @@
 <!--- INCLUDE .*/example-([a-z]+)-([0-9a-z]+)\.kt 
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/docs/channels.md b/docs/channels.md
index 2acb242..5550759 100644
--- a/docs/channels.md
+++ b/docs/channels.md
@@ -1,6 +1,6 @@
 <!--- INCLUDE .*/example-([a-z]+)-([0-9a-z]+)\.kt 
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/docs/composing-suspending-functions.md b/docs/composing-suspending-functions.md
index 91cfeab..ed0d85c 100644
--- a/docs/composing-suspending-functions.md
+++ b/docs/composing-suspending-functions.md
@@ -1,6 +1,6 @@
 <!--- INCLUDE .*/example-([a-z]+)-([0-9a-z]+)\.kt 
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/docs/coroutine-context-and-dispatchers.md b/docs/coroutine-context-and-dispatchers.md
index 8590ed6..cf2a9e4 100644
--- a/docs/coroutine-context-and-dispatchers.md
+++ b/docs/coroutine-context-and-dispatchers.md
@@ -1,6 +1,6 @@
 <!--- INCLUDE .*/example-([a-z]+)-([0-9a-z]+)\.kt 
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/docs/exception-handling.md b/docs/exception-handling.md
index 5f15219..349b703 100644
--- a/docs/exception-handling.md
+++ b/docs/exception-handling.md
@@ -1,6 +1,6 @@
 <!--- INCLUDE .*/example-([a-z]+)-([0-9a-z]+)\.kt 
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/docs/select-expression.md b/docs/select-expression.md
index b085b93..35480ab 100644
--- a/docs/select-expression.md
+++ b/docs/select-expression.md
@@ -1,6 +1,6 @@
 <!--- INCLUDE .*/example-([a-z]+)-([0-9a-z]+)\.kt 
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
@@ -163,7 +163,7 @@
 ### Selecting on close
 
 The [onReceive][ReceiveChannel.onReceive] clause in `select` fails when the channel is closed causing the corresponding
-`select` to throw an exception. We can use [onReceiveOrNull][ReceiveChannel.onReceiveOrNull] clause to perform a
+`select` to throw an exception. We can use [onReceiveOrNull][onReceiveOrNull] clause to perform a
 specific action when the channel is closed. The following example also shows that `select` is an expression that returns 
 the result of its selected clause:
 
@@ -189,6 +189,10 @@
 
 </div>
 
+Note that [onReceiveOrNull][onReceiveOrNull] is an extension function defined only 
+for channels with non-nullable elements so that there is no accidental confusion between a closed channel
+and a null value. 
+
 Let's use it with channel `a` that produces "Hello" string four times and 
 channel `b` that produces "World" four times:
 
@@ -259,7 +263,7 @@
 being the first clause in select, wins. However, because we are using unbuffered channel, the `a` gets suspended from
 time to time on its [send][SendChannel.send] invocation and gives a chance for `b` to send, too.
 
-The second observation, is that [onReceiveOrNull][ReceiveChannel.onReceiveOrNull] gets immediately selected when the 
+The second observation, is that [onReceiveOrNull][onReceiveOrNull] gets immediately selected when the 
 channel is already closed.
 
 ### Selecting to send
@@ -433,7 +437,7 @@
 
 Let us write a channel producer function that consumes a channel of deferred string values, waits for each received
 deferred value, but only until the next deferred value comes over or the channel is closed. This example puts together 
-[onReceiveOrNull][ReceiveChannel.onReceiveOrNull] and [onAwait][Deferred.onAwait] clauses in the same `select`:
+[onReceiveOrNull][onReceiveOrNull] and [onAwait][Deferred.onAwait] clauses in the same `select`:
 
 <div class="sample" markdown="1" theme="idea" data-highlight-only>
 
@@ -556,7 +560,7 @@
 <!--- INDEX kotlinx.coroutines.channels -->
 [ReceiveChannel.receive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/receive.html
 [ReceiveChannel.onReceive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/on-receive.html
-[ReceiveChannel.onReceiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/on-receive-or-null.html
+[onReceiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/on-receive-or-null.html
 [SendChannel.send]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/send.html
 [SendChannel.onSend]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/on-send.html
 <!--- INDEX kotlinx.coroutines.selects -->
diff --git a/docs/shared-mutable-state-and-concurrency.md b/docs/shared-mutable-state-and-concurrency.md
index ed8f330..48d3d70 100644
--- a/docs/shared-mutable-state-and-concurrency.md
+++ b/docs/shared-mutable-state-and-concurrency.md
@@ -1,6 +1,6 @@
 <!--- INCLUDE .*/example-([a-z]+)-([0-9a-z]+)\.kt 
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/gradle.properties b/gradle.properties
index bf4a937..60c65a8 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,7 +1,7 @@
 # Kotlin
-version=1.3.0-M2-SNAPSHOT
+version=1.3.0-RC-SNAPSHOT
 group=org.jetbrains.kotlinx
-kotlin_version=1.3.40
+kotlin_version=1.3.41
 
 # Dependencies
 junit_version=4.12
@@ -14,7 +14,6 @@
 reactor_vesion=3.2.5.RELEASE
 reactive_streams_version=1.0.2
 rxjava2_version=2.2.8
-artifactory_plugin_version=4.7.3
 
 # JS
 gradle_node_version=1.2.0
@@ -24,5 +23,6 @@
 mocha_headless_chrome_version=1.8.2
 mocha_teamcity_reporter_version=2.2.2
 source_map_support_version=0.5.3
+spring_dependency_management_version=1.0.8.RELEASE
 
 kotlin.incremental.multiplatform=true
diff --git a/gradle/publish-bintray.gradle b/gradle/publish-bintray.gradle
index edf07ef..0e37c67 100644
--- a/gradle/publish-bintray.gradle
+++ b/gradle/publish-bintray.gradle
@@ -7,7 +7,6 @@
 apply plugin: 'maven'
 apply plugin: 'maven-publish'
 apply plugin: 'com.jfrog.bintray'
-apply plugin: 'com.jfrog.artifactory'
 apply plugin: "com.github.johnrengelman.shadow"
 
 apply from: project.rootProject.file('gradle/maven-central.gradle')
@@ -16,6 +15,8 @@
 
 def bUser = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER')
 def bKey = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY')
+def isMultiplatform = project.name == "kotlinx-coroutines-core"
+def isBom = project.name == "kotlinx-coroutines-bom"
 
 task stubSources(type: Jar) {
     classifier = 'sources'
@@ -32,7 +33,7 @@
     classifier = 'sources'
     if (project.name == "kotlinx-coroutines-core") {
         from kotlin.sourceSets.commonMain.kotlin
-    } else {
+    } else if (!isBom) {
         from sourceSets.main.allSource
     }
 }
@@ -61,24 +62,30 @@
     }
 }
 
-def isMultiplatform = project.name == "kotlinx-coroutines-core"
-
 publishing {
     repositories {
         maven { url = 'https://kotlin.bintray.com/kotlinx' }
     }
 
-    if (!isMultiplatform) {
+    if (isBom) {
+        publications {
+            mavenBom(MavenPublication) {
+                pom.withXml(configureMavenCentralMetadata)
+            }
+        }
+        return
+    } else if (!isMultiplatform) {
         publications {
             maven(MavenPublication) { publication ->
-                if (project.name == "kotlinx-coroutines-debug") {
-                    project.shadow.component(publication)
-                } else {
-                    publication.from components.java
-                }
                 publication.artifact javadocJar
                 publication.artifact sourcesJar
                 publication.pom.withXml(configureMavenCentralMetadata)
+                if (project.name == "kotlinx-coroutines-debug") {
+                    project.shadow.component(publication)
+                    publication.pom.withXml(configureMavenDependencies)
+                } else {
+                    publication.from components.java
+                }
             }
         }
 
@@ -144,27 +151,6 @@
     }
 }
 
-// snapshot publication is temporary disabled
-//artifactory {
-//    contextUrl = 'https://oss.jfrog.org/artifactory'
-//    publish {
-//        repository {
-//            repoKey = 'oss-snapshot-local'
-//            username = bUser
-//            password = bKey
-//        }
-//
-//        maven(MavenPublication) { publication ->
-//            preparePublication(publication)
-//        }
-//
-//        defaults {
-//            publications('maven')
-//        }
-//    }
-//}
-
-
 task publishDevelopSnapshot() {
     def branch = System.getenv('currentBranch')
     if (branch == "develop") {
diff --git a/integration/kotlinx-coroutines-jdk8/src/time/Time.kt b/integration/kotlinx-coroutines-jdk8/src/time/Time.kt
index f0d9415..031ac61 100644
--- a/integration/kotlinx-coroutines-jdk8/src/time/Time.kt
+++ b/integration/kotlinx-coroutines-jdk8/src/time/Time.kt
@@ -46,7 +46,7 @@
  *    - Non-suspending fast-paths (e.g. `withTimeout(1 nanosecond) { 42 }` should not throw)
  */
 private fun Duration.coerceToMillis(): Long {
-    if (isNegative) return 0
+    if (this <= Duration.ZERO) return 0
     if (this <= ChronoUnit.MILLIS.duration) return 1
 
     // Maximum scalar values of Duration.ofMillis(Long.MAX_VALUE)
diff --git a/integration/kotlinx-coroutines-jdk8/test/time/DurationOverflowTest.kt b/integration/kotlinx-coroutines-jdk8/test/time/DurationOverflowTest.kt
index a9b2752..9ab0ccf 100644
--- a/integration/kotlinx-coroutines-jdk8/test/time/DurationOverflowTest.kt
+++ b/integration/kotlinx-coroutines-jdk8/test/time/DurationOverflowTest.kt
@@ -65,4 +65,15 @@
         assertNull(result)
     }
 
+    @Test
+    fun testZeroDurationWithTimeout() = runTest {
+        assertFailsWith<TimeoutCancellationException> { withTimeout(0L) {} }
+        assertFailsWith<TimeoutCancellationException> { withTimeout(Duration.ZERO) {} }
+    }
+
+    @Test
+    fun testZeroDurationWithTimeoutOrNull() = runTest {
+        assertNull(withTimeoutOrNull(0L) {})
+        assertNull(withTimeoutOrNull(Duration.ZERO) {})
+    }
 }
diff --git a/knit/src/Knit.kt b/knit/src/Knit.kt
index c2e9fef..abb66df 100644
--- a/knit/src/Knit.kt
+++ b/knit/src/Knit.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 import java.io.*
@@ -228,7 +228,7 @@
                     }
                 }
                 for (code in codeLines) {
-                    outLines += code.replace("System.currentTimeMillis()", "timeSource.currentTimeMillis()")
+                    outLines += code.replace("System.currentTimeMillis()", "currentTimeMillis()")
                 }
                 codeLines.clear()
                 writeLinesIfNeeded(file, outLines)
diff --git a/kotlinx-coroutines-bom/build.gradle b/kotlinx-coroutines-bom/build.gradle
new file mode 100644
index 0000000..9ec43b2
--- /dev/null
+++ b/kotlinx-coroutines-bom/build.gradle
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+plugins {
+    id 'io.spring.dependency-management'
+}
+
+def name = project.name
+
+dependencyManagement {
+    dependencies {
+        rootProject.subprojects.each {
+            if (!ext.unpublished.contains(it.name) && it.name != name) {
+                dependency(group: it.group, name: it.name, version: it.version)
+            }
+        }
+    }
+}
diff --git a/kotlinx-coroutines-core/README.md b/kotlinx-coroutines-core/README.md
index 2dc751e..5fe3298 100644
--- a/kotlinx-coroutines-core/README.md
+++ b/kotlinx-coroutines-core/README.md
@@ -56,7 +56,7 @@
 | [Deferred]       | [await][Deferred.await]                       | [onAwait][Deferred.onAwait]                 | [isCompleted][Job.isCompleted]
 | [SendChannel][kotlinx.coroutines.channels.SendChannel]    | [send][kotlinx.coroutines.channels.SendChannel.send]                      | [onSend][kotlinx.coroutines.channels.SendChannel.onSend]                   | [offer][kotlinx.coroutines.channels.SendChannel.offer]
 | [ReceiveChannel][kotlinx.coroutines.channels.ReceiveChannel] | [receive][kotlinx.coroutines.channels.ReceiveChannel.receive]             | [onReceive][kotlinx.coroutines.channels.ReceiveChannel.onReceive]             | [poll][kotlinx.coroutines.channels.ReceiveChannel.poll]
-| [ReceiveChannel][kotlinx.coroutines.channels.ReceiveChannel] | [receiveOrNull][kotlinx.coroutines.channels.ReceiveChannel.receiveOrNull] | [onReceiveOrNull][kotlinx.coroutines.channels.ReceiveChannel.onReceiveOrNull] | [poll][kotlinx.coroutines.channels.ReceiveChannel.poll]
+| [ReceiveChannel][kotlinx.coroutines.channels.ReceiveChannel] | [receiveOrNull][kotlinx.coroutines.channels.receiveOrNull] | [onReceiveOrNull][kotlinx.coroutines.channels.onReceiveOrNull] | [poll][kotlinx.coroutines.channels.ReceiveChannel.poll]
 | [Mutex][kotlinx.coroutines.sync.Mutex]          | [lock][kotlinx.coroutines.sync.Mutex.lock]                            | [onLock][kotlinx.coroutines.sync.Mutex.onLock]                   | [tryLock][kotlinx.coroutines.sync.Mutex.tryLock]
 | none            | [delay]                                        | [onTimeout][kotlinx.coroutines.selects.SelectBuilder.onTimeout]                   | none
 
@@ -131,8 +131,8 @@
 [kotlinx.coroutines.channels.SendChannel.offer]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/offer.html
 [kotlinx.coroutines.channels.ReceiveChannel.onReceive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/on-receive.html
 [kotlinx.coroutines.channels.ReceiveChannel.poll]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/poll.html
-[kotlinx.coroutines.channels.ReceiveChannel.receiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/receive-or-null.html
-[kotlinx.coroutines.channels.ReceiveChannel.onReceiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/on-receive-or-null.html
+[kotlinx.coroutines.channels.receiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/receive-or-null.html
+[kotlinx.coroutines.channels.onReceiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/on-receive-or-null.html
 <!--- INDEX kotlinx.coroutines.selects -->
 [kotlinx.coroutines.selects.select]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/select.html
 [kotlinx.coroutines.selects.SelectBuilder.onTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/-select-builder/on-timeout.html
diff --git a/kotlinx-coroutines-core/common/README.md b/kotlinx-coroutines-core/common/README.md
index b84cedf..a0cc809 100644
--- a/kotlinx-coroutines-core/common/README.md
+++ b/kotlinx-coroutines-core/common/README.md
@@ -59,7 +59,7 @@
 | [Deferred]       | [await][Deferred.await]                       | [onAwait][Deferred.onAwait]                 | [isCompleted][Job.isCompleted]
 | [SendChannel][kotlinx.coroutines.channels.SendChannel]    | [send][kotlinx.coroutines.channels.SendChannel.send]                      | [onSend][kotlinx.coroutines.channels.SendChannel.onSend]                   | [offer][kotlinx.coroutines.channels.SendChannel.offer]
 | [ReceiveChannel][kotlinx.coroutines.channels.ReceiveChannel] | [receive][kotlinx.coroutines.channels.ReceiveChannel.receive]             | [onReceive][kotlinx.coroutines.channels.ReceiveChannel.onReceive]             | [poll][kotlinx.coroutines.channels.ReceiveChannel.poll]
-| [ReceiveChannel][kotlinx.coroutines.channels.ReceiveChannel] | [receiveOrNull][kotlinx.coroutines.channels.ReceiveChannel.receiveOrNull] | [onReceiveOrNull][kotlinx.coroutines.channels.ReceiveChannel.onReceiveOrNull] | [poll][kotlinx.coroutines.channels.ReceiveChannel.poll]
+| [ReceiveChannel][kotlinx.coroutines.channels.ReceiveChannel] | [receiveOrNull][kotlinx.coroutines.channels.receiveOrNull] | [onReceiveOrNull][kotlinx.coroutines.channels.onReceiveOrNull] | [poll][kotlinx.coroutines.channels.ReceiveChannel.poll]
 | [Mutex][kotlinx.coroutines.sync.Mutex]          | [lock][kotlinx.coroutines.sync.Mutex.lock]                            | [onLock][kotlinx.coroutines.sync.Mutex.onLock]                   | [tryLock][kotlinx.coroutines.sync.Mutex.tryLock]
 | none            | [delay]                                        | [onTimeout][kotlinx.coroutines.selects.SelectBuilder.onTimeout]                   | none
 
@@ -143,8 +143,8 @@
 [kotlinx.coroutines.channels.SendChannel.offer]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/offer.html
 [kotlinx.coroutines.channels.ReceiveChannel.onReceive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/on-receive.html
 [kotlinx.coroutines.channels.ReceiveChannel.poll]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/poll.html
-[kotlinx.coroutines.channels.ReceiveChannel.receiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/receive-or-null.html
-[kotlinx.coroutines.channels.ReceiveChannel.onReceiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/on-receive-or-null.html
+[kotlinx.coroutines.channels.receiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/receive-or-null.html
+[kotlinx.coroutines.channels.onReceiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/on-receive-or-null.html
 <!--- INDEX kotlinx.coroutines.selects -->
 [kotlinx.coroutines.selects.select]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/select.html
 [kotlinx.coroutines.selects.SelectBuilder.onTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/-select-builder/on-timeout.html
diff --git a/kotlinx-coroutines-core/common/src/Annotations.kt b/kotlinx-coroutines-core/common/src/Annotations.kt
index 5ee89b8..742a7d7 100644
--- a/kotlinx-coroutines-core/common/src/Annotations.kt
+++ b/kotlinx-coroutines-core/common/src/Annotations.kt
@@ -52,4 +52,5 @@
  */
 @Retention(value = AnnotationRetention.BINARY)
 @Experimental(level = Experimental.Level.ERROR)
+@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.TYPEALIAS, AnnotationTarget.PROPERTY)
 public annotation class InternalCoroutinesApi
diff --git a/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt b/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt
index a1a9097..40344c9 100644
--- a/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt
+++ b/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines
@@ -297,7 +297,7 @@
                 }
                 is CompletedIdempotentResult -> {
                     return if (state.idempotentResume === idempotent) {
-                        check(state.result === value) { "Non-idempotent resume" }
+                        assert { state.result === value } // "Non-idempotent resume"
                         state.token
                     } else {
                         null
diff --git a/kotlinx-coroutines-core/common/src/CoroutineScope.kt b/kotlinx-coroutines-core/common/src/CoroutineScope.kt
index 92977b1..a9c7fb3 100644
--- a/kotlinx-coroutines-core/common/src/CoroutineScope.kt
+++ b/kotlinx-coroutines-core/common/src/CoroutineScope.kt
@@ -203,6 +203,13 @@
 }
 
 /**
+ * Cancels this scope, including its job and all its children with a specified diagnostic error [message].
+ * A [cause] can be specified to provide additional details on a cancellation reason for debugging purposes.
+ * Throws [IllegalStateException] if the scope does not have a job in it.
+ */
+public fun CoroutineScope.cancel(message: String, cause: Throwable? = null): Unit = cancel(CancellationException(message, cause))
+
+/**
  * Ensures that current scope is [active][CoroutineScope.isActive].
  * Throws [IllegalStateException] if the context does not have a job in it.
  *
diff --git a/kotlinx-coroutines-core/common/src/Debug.common.kt b/kotlinx-coroutines-core/common/src/Debug.common.kt
index 92dd552..dd09a6a 100644
--- a/kotlinx-coroutines-core/common/src/Debug.common.kt
+++ b/kotlinx-coroutines-core/common/src/Debug.common.kt
@@ -1,8 +1,10 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines
 
+internal expect val DEBUG: Boolean
 internal expect val Any.hexAddress: String
 internal expect val Any.classSimpleName: String
+internal expect fun assert(value: () -> Boolean)
diff --git a/kotlinx-coroutines-core/common/src/Dispatched.kt b/kotlinx-coroutines-core/common/src/Dispatched.kt
index 450163c..a9624bd 100644
--- a/kotlinx-coroutines-core/common/src/Dispatched.kt
+++ b/kotlinx-coroutines-core/common/src/Dispatched.kt
@@ -87,7 +87,7 @@
 
     override fun takeState(): Any? {
         val state = _state
-        check(state !== UNDEFINED) // fail-fast if repeatedly invoked
+        assert { state !== UNDEFINED } // fail-fast if repeatedly invoked
         _state = UNDEFINED
         return state
     }
@@ -307,7 +307,14 @@
     val state = takeState()
     val exception = getExceptionalResult(state)
     if (exception != null) {
-        delegate.resumeWithExceptionMode(exception, useMode)
+        /*
+         * Recover stacktrace for non-dispatched tasks.
+         * We usually do not recover stacktrace in a `resume` as all resumes go through `DispatchedTask.run`
+         * and we recover stacktraces there, but this is not the case for a `suspend fun main()` that knows nothing about
+         * kotlinx.coroutines and DispatchedTask
+         */
+        val recovered = if (delegate is DispatchedTask<*>) exception else recoverStackTrace(exception, delegate)
+        delegate.resumeWithExceptionMode(recovered, useMode)
     } else {
         delegate.resumeMode(getSuccessfulResult(state), useMode)
     }
diff --git a/kotlinx-coroutines-core/common/src/EventLoop.common.kt b/kotlinx-coroutines-core/common/src/EventLoop.common.kt
index 3565292..7107059 100644
--- a/kotlinx-coroutines-core/common/src/EventLoop.common.kt
+++ b/kotlinx-coroutines-core/common/src/EventLoop.common.kt
@@ -1,10 +1,13 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines
 
+import kotlinx.atomicfu.*
 import kotlinx.coroutines.internal.*
+import kotlin.coroutines.*
+import kotlin.jvm.*
 
 /**
  * Extended by [CoroutineDispatcher] implementations that have event loop inside and can
@@ -12,18 +15,18 @@
  *
  * It may optionally implement [Delay] interface and support time-scheduled tasks.
  * It is created or pigged back onto (see [ThreadLocalEventLoop])
- * by [runBlocking] and by [Dispatchers.Unconfined].
+ * by `runBlocking` and by [Dispatchers.Unconfined].
  *
  * @suppress **This an internal API and should not be used from general code.**
  */
 internal abstract class EventLoop : CoroutineDispatcher() {
     /**
-     * Counts the number of nested [runBlocking] and [Dispatchers.Unconfined] that use this event loop.
+     * Counts the number of nested `runBlocking` and [Dispatchers.Unconfined] that use this event loop.
      */
     private var useCount = 0L
 
     /**
-     * Set to true on any use by [runBlocking], because it potentially leaks this loop to other threads, so
+     * Set to true on any use by `runBlocking`, because it potentially leaks this loop to other threads, so
      * this instance must be properly shutdown. We don't need to shutdown event loop that was used solely
      * by [Dispatchers.Unconfined] -- it can be left as [ThreadLocalEventLoop] and reused next time.
      */
@@ -104,7 +107,7 @@
     fun decrementUseCount(unconfined: Boolean = false) {
         useCount -= delta(unconfined)
         if (useCount > 0) return
-        check(useCount == 0L) { "Extra decrementUseCount" }
+        assert { useCount == 0L } // "Extra decrementUseCount"
         if (shared) {
             // shut it down and remove from ThreadLocalEventLoop
             shutdown()
@@ -133,5 +136,387 @@
     }
 }
 
+@SharedImmutable
+private val DISPOSED_TASK = Symbol("REMOVED_TASK")
+
+// results for scheduleImpl
+private const val SCHEDULE_OK = 0
+private const val SCHEDULE_COMPLETED = 1
+private const val SCHEDULE_DISPOSED = 2
+
+private const val MS_TO_NS = 1_000_000L
+private const val MAX_MS = Long.MAX_VALUE / MS_TO_NS
+
+/**
+ * First-line overflow protection -- limit maximal delay.
+ * Delays longer than this one (~146 years) are considered to be delayed "forever".
+ */
+private const val MAX_DELAY_NS = Long.MAX_VALUE / 2
+
+internal fun delayToNanos(timeMillis: Long): Long = when {
+    timeMillis <= 0 -> 0L
+    timeMillis >= MAX_MS -> Long.MAX_VALUE
+    else -> timeMillis * MS_TO_NS
+}
+
+internal fun delayNanosToMillis(timeNanos: Long): Long =
+    timeNanos / MS_TO_NS
+
+@SharedImmutable
+private val CLOSED_EMPTY = Symbol("CLOSED_EMPTY")
+
+private typealias Queue<T> = LockFreeTaskQueueCore<T>
+
+internal expect abstract class EventLoopImplPlatform() : EventLoop {
+    // Called to unpark this event loop's thread
+    protected fun unpark()
+
+    // Called to reschedule to DefaultExecutor when this event loop is complete
+    protected fun reschedule(now: Long, delayedTask: EventLoopImplBase.DelayedTask)
+}
+
+internal abstract class EventLoopImplBase: EventLoopImplPlatform(), Delay {
+    // null | CLOSED_EMPTY | task | Queue<Runnable>
+    private val _queue = atomic<Any?>(null)
+
+    // Allocated only only once
+    private val _delayed = atomic<DelayedTaskQueue?>(null)
+
+    @Volatile
+    private var isCompleted = false
+
+    override val isEmpty: Boolean get() {
+        if (!isUnconfinedQueueEmpty) return false
+        val delayed = _delayed.value
+        if (delayed != null && !delayed.isEmpty) return false
+        val queue = _queue.value
+        return when (queue) {
+            null -> true
+            is Queue<*> -> queue.isEmpty
+            else -> queue === CLOSED_EMPTY
+        }
+    }
+
+    protected override val nextTime: Long
+        get() {
+            if (super.nextTime == 0L) return 0L
+            val queue = _queue.value
+            when {
+                queue === null -> {} // empty queue -- proceed
+                queue is Queue<*> -> if (!queue.isEmpty) return 0 // non-empty queue
+                queue === CLOSED_EMPTY -> return Long.MAX_VALUE // no more events -- closed
+                else -> return 0 // non-empty queue
+            }
+            val nextDelayedTask = _delayed.value?.peek() ?: return Long.MAX_VALUE
+            return (nextDelayedTask.nanoTime - nanoTime()).coerceAtLeast(0)
+        }
+
+    override fun shutdown() {
+        // Clean up thread-local reference here -- this event loop is shutting down
+        ThreadLocalEventLoop.resetEventLoop()
+        // We should signal that this event loop should not accept any more tasks
+        // and process queued events (that could have been added after last processNextEvent)
+        isCompleted = true
+        closeQueue()
+        // complete processing of all queued tasks
+        while (processNextEvent() <= 0) { /* spin */ }
+        // reschedule the rest of delayed tasks
+        rescheduleAllDelayed()
+    }
+
+    public override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
+        val timeNanos = delayToNanos(timeMillis)
+        if (timeNanos < MAX_DELAY_NS) {
+            val now = nanoTime()
+            DelayedResumeTask(now + timeNanos, continuation).also { task ->
+                continuation.disposeOnCancellation(task)
+                schedule(now, task)
+            }
+        }
+    }
+
+    protected fun scheduleInvokeOnTimeout(timeMillis: Long, block: Runnable): DisposableHandle {
+        val timeNanos = delayToNanos(timeMillis)
+        return if (timeNanos < MAX_DELAY_NS) {
+            val now = nanoTime()
+            DelayedRunnableTask(now + timeNanos, block).also { task ->
+                schedule(now, task)
+            }
+        } else {
+            NonDisposableHandle
+        }
+    }
+
+    override fun processNextEvent(): Long {
+        // unconfined events take priority
+        if (processUnconfinedEvent()) return nextTime
+        // queue all delayed tasks that are due to be executed
+        val delayed = _delayed.value
+        if (delayed != null && !delayed.isEmpty) {
+            val now = nanoTime()
+            while (true) {
+                // make sure that moving from delayed to queue removes from delayed only after it is added to queue
+                // to make sure that 'isEmpty' and `nextTime` that check both of them
+                // do not transiently report that both delayed and queue are empty during move
+                delayed.removeFirstIf {
+                    if (it.timeToExecute(now)) {
+                        enqueueImpl(it)
+                    } else
+                        false
+                } ?: break // quit loop when nothing more to remove or enqueueImpl returns false on "isComplete"
+            }
+        }
+        // then process one event from queue
+        dequeue()?.run()
+        return nextTime
+    }
+
+    public final override fun dispatch(context: CoroutineContext, block: Runnable) = enqueue(block)
+
+    public fun enqueue(task: Runnable) {
+        if (enqueueImpl(task)) {
+            // todo: we should unpark only when this delayed task became first in the queue
+            unpark()
+        } else {
+            DefaultExecutor.enqueue(task)
+        }
+    }
+
+    @Suppress("UNCHECKED_CAST")
+    private fun enqueueImpl(task: Runnable): Boolean {
+        _queue.loop { queue ->
+            if (isCompleted) return false // fail fast if already completed, may still add, but queues will close
+            when (queue) {
+                null -> if (_queue.compareAndSet(null, task)) return true
+                is Queue<*> -> {
+                    when ((queue as Queue<Runnable>).addLast(task)) {
+                        Queue.ADD_SUCCESS -> return true
+                        Queue.ADD_CLOSED -> return false
+                        Queue.ADD_FROZEN -> _queue.compareAndSet(queue, queue.next())
+                    }
+                }
+                else -> when {
+                    queue === CLOSED_EMPTY -> return false
+                    else -> {
+                        // update to full-blown queue to add one more
+                        val newQueue = Queue<Runnable>(Queue.INITIAL_CAPACITY, singleConsumer = true)
+                        newQueue.addLast(queue as Runnable)
+                        newQueue.addLast(task)
+                        if (_queue.compareAndSet(queue, newQueue)) return true
+                    }
+                }
+            }
+        }
+    }
+
+    @Suppress("UNCHECKED_CAST")
+    private fun dequeue(): Runnable? {
+        _queue.loop { queue ->
+            when (queue) {
+                null -> return null
+                is Queue<*> -> {
+                    val result = (queue as Queue<Runnable>).removeFirstOrNull()
+                    if (result !== Queue.REMOVE_FROZEN) return result as Runnable?
+                    _queue.compareAndSet(queue, queue.next())
+                }
+                else -> when {
+                    queue === CLOSED_EMPTY -> return null
+                    else -> if (_queue.compareAndSet(queue, null)) return queue as Runnable
+                }
+            }
+        }
+    }
+
+    private fun closeQueue() {
+        assert { isCompleted }
+        _queue.loop { queue ->
+            when (queue) {
+                null -> if (_queue.compareAndSet(null, CLOSED_EMPTY)) return
+                is Queue<*> -> {
+                    queue.close()
+                    return
+                }
+                else -> when {
+                    queue === CLOSED_EMPTY -> return
+                    else -> {
+                        // update to full-blown queue to close
+                        val newQueue = Queue<Runnable>(Queue.INITIAL_CAPACITY, singleConsumer = true)
+                        newQueue.addLast(queue as Runnable)
+                        if (_queue.compareAndSet(queue, newQueue)) return
+                    }
+                }
+            }
+        }
+
+    }
+
+    public fun schedule(now: Long, delayedTask: DelayedTask) {
+        when (scheduleImpl(now, delayedTask)) {
+            SCHEDULE_OK -> if (shouldUnpark(delayedTask)) unpark()
+            SCHEDULE_COMPLETED -> reschedule(now, delayedTask)
+            SCHEDULE_DISPOSED -> {} // do nothing -- task was already disposed
+            else -> error("unexpected result")
+        }
+    }
+
+    private fun shouldUnpark(task: DelayedTask): Boolean = _delayed.value?.peek() === task
+
+    private fun scheduleImpl(now: Long, delayedTask: DelayedTask): Int {
+        if (isCompleted) return SCHEDULE_COMPLETED
+        val delayedQueue = _delayed.value ?: run {
+            _delayed.compareAndSet(null, DelayedTaskQueue(now))
+            _delayed.value!!
+        }
+        return delayedTask.scheduleTask(now, delayedQueue, this)
+    }
+
+    // It performs "hard" shutdown for test cleanup purposes
+    protected fun resetAll() {
+        _queue.value = null
+        _delayed.value = null
+    }
+
+    // This is a "soft" (normal) shutdown
+    private fun rescheduleAllDelayed() {
+        val now = nanoTime()
+        while (true) {
+            /*
+             * `removeFirstOrNull` below is the only operation on DelayedTask & ThreadSafeHeap that is not
+             * synchronized on DelayedTask itself. All other operation are synchronized both on
+             * DelayedTask & ThreadSafeHeap instances (in this order). It is still safe, because `dispose`
+             * first removes DelayedTask from the heap (under synchronization) then
+             * assign "_heap = DISPOSED_TASK", so there cannot be ever a race to _heap reference update.
+             */
+            val delayedTask = _delayed.value?.removeFirstOrNull() ?: break
+            reschedule(now, delayedTask)
+        }
+    }
+
+    internal abstract class DelayedTask(
+        /**
+         * This field can be only modified in [scheduleTask] before putting this DelayedTask
+         * into heap to avoid overflow and corruption of heap data structure.
+         */
+        @JvmField var nanoTime: Long
+    ) : Runnable, Comparable<DelayedTask>, DisposableHandle, ThreadSafeHeapNode {
+        private var _heap: Any? = null // null | ThreadSafeHeap | DISPOSED_TASK
+
+        override var heap: ThreadSafeHeap<*>?
+            get() = _heap as? ThreadSafeHeap<*>
+            set(value) {
+                require(_heap !== DISPOSED_TASK) // this can never happen, it is always checked before adding/removing
+                _heap = value
+            }
+
+        override var index: Int = -1
+
+        override fun compareTo(other: DelayedTask): Int {
+            val dTime = nanoTime - other.nanoTime
+            return when {
+                dTime > 0 -> 1
+                dTime < 0 -> -1
+                else -> 0
+            }
+        }
+
+        fun timeToExecute(now: Long): Boolean = now - nanoTime >= 0L
+
+        @Synchronized
+        fun scheduleTask(now: Long, delayed: DelayedTaskQueue, eventLoop: EventLoopImplBase): Int {
+            if (_heap === DISPOSED_TASK) return SCHEDULE_DISPOSED // don't add -- was already disposed
+            delayed.addLastIf(this) { firstTask ->
+                if (eventLoop.isCompleted) return SCHEDULE_COMPLETED // non-local return from scheduleTask
+                /**
+                 * We are about to add new task and we have to make sure that [DelayedTaskQueue]
+                 * invariant is maintained. The code in this lambda is additionally executed under
+                 * the lock of [DelayedTaskQueue] and working with [DelayedTaskQueue.timeNow] here is thread-safe.
+                 */
+                if (firstTask == null) {
+                    /**
+                     * When adding the first delayed task we simply update queue's [DelayedTaskQueue.timeNow] to
+                     * the current now time even if that means "going backwards in time". This makes the structure
+                     * self-correcting in spite of wild jumps in `nanoTime()` measurements once all delayed tasks
+                     * are removed from the delayed queue for execution.
+                     */
+                    delayed.timeNow = now
+                } else {
+                    /**
+                     * Carefully update [DelayedTaskQueue.timeNow] so that it does not sweep past first's tasks time
+                     * and only goes forward in time. We cannot let it go backwards in time or invariant can be
+                     * violated for tasks that were already scheduled.
+                     */
+                    val firstTime = firstTask.nanoTime
+                    // compute min(now, firstTime) using a wrap-safe check
+                    val minTime = if (firstTime - now >= 0) now else firstTime
+                    // update timeNow only when going forward in time
+                    if (minTime - delayed.timeNow > 0) delayed.timeNow = minTime
+                }
+                /**
+                 * Here [DelayedTaskQueue.timeNow] was already modified and we have to double-check that newly added
+                 * task does not violate [DelayedTaskQueue] invariant because of that. Note also that this scheduleTask
+                 * function can be called to reschedule from one queue to another and this might be another reason
+                 * where new task's time might now violate invariant.
+                 * We correct invariant violation (if any) by simply changing this task's time to now.
+                 */
+                if (nanoTime - delayed.timeNow < 0) nanoTime = delayed.timeNow
+                true
+            }
+            return SCHEDULE_OK
+        }
+
+        @Synchronized
+        final override fun dispose() {
+            val heap = _heap
+            if (heap === DISPOSED_TASK) return // already disposed
+            @Suppress("UNCHECKED_CAST")
+            (heap as? DelayedTaskQueue)?.remove(this) // remove if it is in heap (first)
+            _heap = DISPOSED_TASK // never add again to any heap
+        }
+
+        override fun toString(): String = "Delayed[nanos=$nanoTime]"
+    }
+
+    private inner class DelayedResumeTask(
+        nanoTime: Long,
+        private val cont: CancellableContinuation<Unit>
+    ) : DelayedTask(nanoTime) {
+        override fun run() { with(cont) { resumeUndispatched(Unit) } }
+        override fun toString(): String = super.toString() + cont.toString()
+    }
+
+    private class DelayedRunnableTask(
+        nanoTime: Long,
+        private val block: Runnable
+    ) : DelayedTask(nanoTime) {
+        override fun run() { block.run() }
+        override fun toString(): String = super.toString() + block.toString()
+    }
+
+    /**
+     * Delayed task queue maintains stable time-comparision invariant despite potential wraparounds in
+     * long nano time measurements by maintaining last observed [timeNow]. It protects the integrity of the
+     * heap data structure in spite of potential non-monotonicity of `nanoTime()` source.
+     * The invariant is that for every scheduled [DelayedTask]:
+     *
+     * ```
+     * delayedTask.nanoTime - timeNow >= 0
+     * ```
+     *
+     * So the comparison of scheduled tasks via [DelayedTask.compareTo] is always stable as
+     * scheduled [DelayedTask.nanoTime] can be at most [Long.MAX_VALUE] apart. This invariant is maintained when
+     * new tasks are added by [DelayedTask.scheduleTask] function and it cannot be violated when tasks are removed
+     * (so there is nothing special to do there).
+     */
+    internal class DelayedTaskQueue(
+        @JvmField var timeNow: Long
+    ) : ThreadSafeHeap<DelayedTask>()
+}
+
 internal expect fun createEventLoop(): EventLoop
 
+internal expect fun nanoTime(): Long
+
+internal expect object DefaultExecutor {
+    public fun enqueue(task: Runnable)
+}
+
diff --git a/kotlinx-coroutines-core/common/src/Job.kt b/kotlinx-coroutines-core/common/src/Job.kt
index 29232f7..c6716bc 100644
--- a/kotlinx-coroutines-core/common/src/Job.kt
+++ b/kotlinx-coroutines-core/common/src/Job.kt
@@ -577,6 +577,12 @@
 }
 
 /**
+ * Cancels current job, including all its children with a specified diagnostic error [message].
+ * A [cause] can be specified to provide additional details on a cancellation reason for debugging purposes.
+ */
+public fun Job.cancel(message: String, cause: Throwable? = null): Unit = cancel(CancellationException(message, cause))
+
+/**
  * @suppress This method has bad semantics when cause is not a [CancellationException]. Use [CoroutineContext.cancel].
  */
 @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
diff --git a/kotlinx-coroutines-core/common/src/JobSupport.kt b/kotlinx-coroutines-core/common/src/JobSupport.kt
index d8b6b92..63e34fd 100644
--- a/kotlinx-coroutines-core/common/src/JobSupport.kt
+++ b/kotlinx-coroutines-core/common/src/JobSupport.kt
@@ -136,10 +136,9 @@
     /**
      * Initializes parent job.
      * It shall be invoked at most once after construction after all other initialization.
-     * @suppress **This is unstable API and it is subject to change.**
      */
     internal fun initParentJobInternal(parent: Job?) {
-        check(parentHandle == null)
+        assert { parentHandle == null }
         if (parent == null) {
             parentHandle = NonDisposableHandle
             return
@@ -269,8 +268,8 @@
 
     // fast-path method to finalize normally completed coroutines without children
     private fun tryFinalizeSimpleState(state: Incomplete, update: Any?, mode: Int): Boolean {
-        check(state is Empty || state is JobNode<*>) // only simple state without lists where children can concurrently add
-        check(update !is CompletedExceptionally) // only for normal completion
+        assert { state is Empty || state is JobNode<*> } // only simple state without lists where children can concurrently add
+        assert { update !is CompletedExceptionally } // only for normal completion
         if (!_state.compareAndSet(state, update.boxIncomplete())) return false
         onCancelling(null) // simple state is not a failure
         onCompletionInternal(update)
@@ -397,16 +396,14 @@
      */
     internal open fun onStartInternal() {}
 
-    public final override fun getCancellationException(): CancellationException {
-        val state = this.state
-        return when (state) {
+    public final override fun getCancellationException(): CancellationException =
+        when (val state = this.state) {
             is Finishing -> state.rootCause?.toCancellationException("$classSimpleName is cancelling")
                 ?: error("Job is still new or active: $this")
             is Incomplete -> error("Job is still new or active: $this")
             is CompletedExceptionally -> state.cause.toCancellationException()
             else -> JobCancellationException("$classSimpleName has completed normally", null, this)
         }
-    }
 
     protected fun Throwable.toCancellationException(message: String? = null): CancellationException =
         this as? CancellationException ?:
@@ -747,8 +744,8 @@
 
     // try make new Cancelling state on the condition that we're still in the expected state
     private fun tryMakeCancelling(state: Incomplete, rootCause: Throwable): Boolean {
-        check(state !is Finishing) // only for non-finishing states
-        check(state.isActive) // only for active states
+        assert { state !is Finishing } // only for non-finishing states
+        assert { state.isActive } // only for active states
         // get state's list or else promote to list to correctly operate on child lists
         val list = getOrPromoteCancellingList(state) ?: return false
         // Create cancelling state (with rootCause!)
@@ -1037,8 +1034,7 @@
         // Seals current state and returns list of exceptions
         // guarded by `synchronized(this)`
         fun sealLocked(proposedException: Throwable?): List<Throwable> {
-            val eh = _exceptionsHolder // volatile read
-            val list = when(eh) {
+            val list = when(val eh = _exceptionsHolder) { // volatile read
                 null -> allocateList()
                 is Throwable -> allocateList().also { it.add(eh) }
                 is ArrayList<*> -> eh as ArrayList<Throwable>
@@ -1305,14 +1301,15 @@
         append("]")
     }
 
-    override fun toString(): String = getString("Active")
+    override fun toString(): String =
+        if (DEBUG) getString("Active") else super.toString()
 }
 
 internal class InactiveNodeList(
     override val list: NodeList
 ) : Incomplete {
     override val isActive: Boolean get() = false
-    override fun toString(): String = list.getString("New")
+    override fun toString(): String = if (DEBUG) list.getString("New") else super.toString()
 }
 
 private class InvokeOnCompletion(
@@ -1337,7 +1334,7 @@
 ) : JobNode<JobSupport>(job) {
     override fun invoke(cause: Throwable?) {
         val state = job.state
-        check(state !is Incomplete)
+        assert { state !is Incomplete }
         if (state is CompletedExceptionally) {
             // Resume with exception in atomic way to preserve exception
             continuation.resumeWithExceptionMode(state.cause, MODE_ATOMIC_DEFAULT)
diff --git a/kotlinx-coroutines-core/common/src/NonCancellable.kt b/kotlinx-coroutines-core/common/src/NonCancellable.kt
index 3a4faee..c48faea 100644
--- a/kotlinx-coroutines-core/common/src/NonCancellable.kt
+++ b/kotlinx-coroutines-core/common/src/NonCancellable.kt
@@ -115,4 +115,9 @@
      */
     @InternalCoroutinesApi
     override fun attachChild(child: ChildJob): ChildHandle = NonDisposableHandle
+
+    /** @suppress */
+    override fun toString(): String {
+        return "NonCancellable"
+    }
 }
diff --git a/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt b/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt
index 61bc090..bed4979 100644
--- a/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines.channels
@@ -14,7 +14,6 @@
 
 /**
  * Abstract send channel. It is a base class for all send channel implementations.
- *
  */
 internal abstract class AbstractSendChannel<E> : SendChannel<E> {
     /** @suppress **This is unstable API and it is subject to change.** */
@@ -449,7 +448,7 @@
             if (select.trySelect(idempotent)) SELECT_STARTED else null
 
         override fun completeResumeSend(token: Any) {
-            check(token === SELECT_STARTED)
+            assert { token === SELECT_STARTED }
             block.startCoroutine(receiver = channel, completion = select.completion)
         }
 
@@ -474,7 +473,7 @@
     ) : LockFreeLinkedListNode(), Send {
         override val pollResult: Any? get() = element
         override fun tryResumeSend(idempotent: Any?): Any? = SEND_RESUMED
-        override fun completeResumeSend(token: Any) { check(token === SEND_RESUMED) }
+        override fun completeResumeSend(token: Any) { assert { token === SEND_RESUMED } }
         override fun resumeSendClosed(closed: Closed<*>) {}
     }
 }
@@ -542,13 +541,12 @@
     public final override val isClosedForReceive: Boolean get() = closedForReceive != null && isBufferEmpty
     public final override val isEmpty: Boolean get() = queue.nextNode !is Send && isBufferEmpty
 
-    @Suppress("UNCHECKED_CAST")
     public final override suspend fun receive(): E {
         // fast path -- try poll non-blocking
         val result = pollInternal()
         if (result !== POLL_FAILED) return receiveResult(result)
         // slow-path does suspend
-        return receiveSuspend()
+        return receiveSuspend(RECEIVE_THROWS_ON_CLOSE)
     }
 
     @Suppress("UNCHECKED_CAST")
@@ -558,8 +556,8 @@
     }
 
     @Suppress("UNCHECKED_CAST")
-    private suspend fun receiveSuspend(): E = suspendAtomicCancellableCoroutine sc@ { cont ->
-        val receive = ReceiveElement(cont as CancellableContinuation<E?>, nullOnClose = false)
+    private suspend fun <R> receiveSuspend(onClose: Int): R = suspendAtomicCancellableCoroutine sc@ { cont ->
+        val receive = ReceiveElement<E>(cont as CancellableContinuation<Any?>, onClose)
         while (true) {
             if (enqueueReceive(receive)) {
                 removeReceiveOnCancel(cont, receive)
@@ -568,11 +566,11 @@
             // hm... something is not right. try to poll
             val result = pollInternal()
             if (result is Closed<*>) {
-                cont.resumeWithException(result.receiveException)
+                receive.resumeReceiveClosed(result)
                 return@sc
             }
             if (result !== POLL_FAILED) {
-                cont.resume(result as E)
+                cont.resume(receive.resumeValue(result as E))
                 return@sc
             }
         }
@@ -586,13 +584,12 @@
         return result
     }
 
-    @Suppress("UNCHECKED_CAST")
     public final override suspend fun receiveOrNull(): E? {
         // fast path -- try poll non-blocking
         val result = pollInternal()
         if (result !== POLL_FAILED) return receiveOrNullResult(result)
         // slow-path does suspend
-        return receiveOrNullSuspend()
+        return receiveSuspend(RECEIVE_NULL_ON_CLOSE)
     }
 
     @Suppress("UNCHECKED_CAST")
@@ -605,27 +602,12 @@
     }
 
     @Suppress("UNCHECKED_CAST")
-    private suspend fun receiveOrNullSuspend(): E? = suspendAtomicCancellableCoroutine sc@ { cont ->
-        val receive = ReceiveElement(cont, nullOnClose = true)
-        while (true) {
-            if (enqueueReceive(receive)) {
-                removeReceiveOnCancel(cont, receive)
-                return@sc
-            }
-            // hm... something is not right. try to poll
-            val result = pollInternal()
-            if (result is Closed<*>) {
-                if (result.closeCause == null)
-                    cont.resume(null)
-                else
-                    cont.resumeWithException(result.closeCause)
-                return@sc
-            }
-            if (result !== POLL_FAILED) {
-                cont.resume(result as E)
-                return@sc
-            }
-        }
+    public final override suspend fun receiveOrClosed(): ValueOrClosed<E> {
+        // fast path -- try poll non-blocking
+        val result = pollInternal()
+        if (result !== POLL_FAILED) return result.toResult()
+        // slow-path does suspend
+        return receiveSuspend(RECEIVE_RESULT)
     }
 
     @Suppress("UNCHECKED_CAST")
@@ -654,7 +636,7 @@
         while (true) {
             val send = takeFirstSendOrPeekClosed() ?: error("Cannot happen")
             if (send is Closed<*>) {
-                check(send === closed)
+                assert { send === closed }
                 return // cleaned
             }
             send.resumeSendClosed(closed)
@@ -694,9 +676,9 @@
 
     private inner class TryEnqueueReceiveDesc<E, R>(
         select: SelectInstance<R>,
-        block: suspend (E?) -> R,
-        nullOnClose: Boolean
-    ) : AddLastDesc<ReceiveSelect<R, E>>(queue, ReceiveSelect(select, block, nullOnClose)) {
+        block: suspend (Any?) -> R,
+        receiveMode: Int
+    ) : AddLastDesc<ReceiveSelect<R, E>>(queue, ReceiveSelect(select, block, receiveMode)) {
         override fun failure(affected: LockFreeLinkedListNode, next: Any): Any? {
             if (affected is Send) return ENQUEUE_FAILED
             return null
@@ -728,13 +710,7 @@
         while (true) {
             if (select.isSelected) return
             if (isEmpty) {
-                val enqueueOp = TryEnqueueReceiveDesc(select, block as (suspend (E?) -> R), nullOnClose = false)
-                val enqueueResult = select.performAtomicIfNotSelected(enqueueOp) ?: return
-                when {
-                    enqueueResult === ALREADY_SELECTED -> return
-                    enqueueResult === ENQUEUE_FAILED -> {} // retry
-                    else -> error("performAtomicIfNotSelected(TryEnqueueReceiveDesc) returned $enqueueResult")
-                }
+                if (registerEnqueueDesc(select, block, RECEIVE_THROWS_ON_CLOSE)) return
             } else {
                 val pollResult = pollSelectInternal(select)
                 when {
@@ -762,13 +738,7 @@
         while (true) {
             if (select.isSelected) return
             if (isEmpty) {
-                val enqueueOp = TryEnqueueReceiveDesc(select, block, nullOnClose = true)
-                val enqueueResult = select.performAtomicIfNotSelected(enqueueOp) ?: return
-                when {
-                    enqueueResult === ALREADY_SELECTED -> return
-                    enqueueResult === ENQUEUE_FAILED -> {} // retry
-                    else -> error("performAtomicIfNotSelected(TryEnqueueReceiveDesc) returned $enqueueResult")
-                }
+                if (registerEnqueueDesc(select, block, RECEIVE_NULL_ON_CLOSE)) return
             } else {
                 val pollResult = pollSelectInternal(select)
                 when {
@@ -793,6 +763,51 @@
         }
     }
 
+    override val onReceiveOrClosed: SelectClause1<ValueOrClosed<E>>
+        get() = object : SelectClause1<ValueOrClosed<E>> {
+            override fun <R> registerSelectClause1(select: SelectInstance<R>, block: suspend (ValueOrClosed<E>) -> R) {
+                registerSelectReceiveOrClosed(select, block)
+            }
+        }
+
+    @Suppress("UNCHECKED_CAST")
+    private fun <R> registerSelectReceiveOrClosed(select: SelectInstance<R>, block: suspend (ValueOrClosed<E>) -> R) {
+        while (true) {
+            if (select.isSelected) return
+            if (isEmpty) {
+                if (registerEnqueueDesc(select, block, RECEIVE_RESULT)) return
+            } else {
+                val pollResult = pollSelectInternal(select)
+                when {
+                    pollResult === ALREADY_SELECTED -> return
+                    pollResult === POLL_FAILED -> {} // retry
+                    pollResult is Closed<*> -> {
+                        block.startCoroutineUnintercepted(ValueOrClosed.closed(pollResult.closeCause), select.completion)
+                    }
+                    else -> {
+                        // selected successfully
+                        block.startCoroutineUnintercepted(ValueOrClosed.value(pollResult as E), select.completion)
+                        return
+                    }
+                }
+            }
+        }
+    }
+
+    private fun <R, E> registerEnqueueDesc(
+        select: SelectInstance<R>, block: suspend (E) -> R,
+        receiveMode: Int
+    ): Boolean {
+        @Suppress("UNCHECKED_CAST")
+        val enqueueOp = TryEnqueueReceiveDesc<E, R>(select, block as suspend (Any?) -> R, receiveMode)
+        val enqueueResult = select.performAtomicIfNotSelected(enqueueOp) ?: return true
+        return when {
+            enqueueResult === ALREADY_SELECTED -> true
+            enqueueResult === ENQUEUE_FAILED -> false // retry
+            else -> error("performAtomicIfNotSelected(TryEnqueueReceiveDesc) returned $enqueueResult")
+        }
+    }
+
     // ------ protected ------
 
     override fun takeFirstReceiveOrPeekClosed(): ReceiveOrClosed<E>? =
@@ -884,18 +899,25 @@
     }
 
     private class ReceiveElement<in E>(
-        @JvmField val cont: CancellableContinuation<E?>,
-        @JvmField val nullOnClose: Boolean
+        @JvmField val cont: CancellableContinuation<Any?>,
+        @JvmField val receiveMode: Int
     ) : Receive<E>() {
-        override fun tryResumeReceive(value: E, idempotent: Any?): Any? = cont.tryResume(value, idempotent)
+        fun resumeValue(value: E): Any? = when (receiveMode) {
+            RECEIVE_RESULT -> ValueOrClosed.value(value)
+            else -> value
+        }
+
+        @Suppress("IMPLICIT_CAST_TO_ANY")
+        override fun tryResumeReceive(value: E, idempotent: Any?): Any? = cont.tryResume(resumeValue(value), idempotent)
         override fun completeResumeReceive(token: Any) = cont.completeResume(token)
         override fun resumeReceiveClosed(closed: Closed<*>) {
-            if (closed.closeCause == null && nullOnClose)
-                cont.resume(null)
-            else
-                cont.resumeWithException(closed.receiveException)
+            when {
+                receiveMode == RECEIVE_NULL_ON_CLOSE && closed.closeCause == null -> cont.resume(null)
+                receiveMode == RECEIVE_RESULT -> cont.resume(closed.toResult<Any>())
+                else -> cont.resumeWithException(closed.receiveException)
+            }
         }
-        override fun toString(): String = "ReceiveElement[$cont,nullOnClose=$nullOnClose]"
+        override fun toString(): String = "ReceiveElement[$cont,receiveMode=$receiveMode]"
     }
 
     private class ReceiveHasNext<E>(
@@ -940,25 +962,26 @@
 
     private inner class ReceiveSelect<R, in E>(
         @JvmField val select: SelectInstance<R>,
-        @JvmField val block: suspend (E?) -> R,
-        @JvmField val nullOnClose: Boolean
+        @JvmField val block: suspend (Any?) -> R,
+        @JvmField val receiveMode: Int
     ) : Receive<E>(), DisposableHandle {
         override fun tryResumeReceive(value: E, idempotent: Any?): Any?  =
             if (select.trySelect(idempotent)) (value ?: NULL_VALUE) else null
 
         @Suppress("UNCHECKED_CAST")
         override fun completeResumeReceive(token: Any) {
-            block.startCoroutine(NULL_VALUE.unbox<E>(token), select.completion)
+            val value: E = NULL_VALUE.unbox<E>(token)
+            block.startCoroutine(if (receiveMode == RECEIVE_RESULT) ValueOrClosed.value(value) else value, select.completion)
         }
 
         override fun resumeReceiveClosed(closed: Closed<*>) {
-            if (select.trySelect(null)) {
-                if (closed.closeCause == null && nullOnClose) {
+            if (!select.trySelect(null)) return
+            when (receiveMode) {
+                RECEIVE_THROWS_ON_CLOSE -> select.resumeSelectCancellableWithException(closed.receiveException)
+                RECEIVE_RESULT -> block.startCoroutine(ValueOrClosed.closed<R>(closed.closeCause), select.completion)
+                RECEIVE_NULL_ON_CLOSE -> if (closed.closeCause == null) {
                     block.startCoroutine(null, select.completion)
                 } else {
-                    // even though we are dispatching coroutine to process channel close on receive,
-                    // which is an atomically cancellable suspending function,
-                    // close is a final state, so we can use a cancellable resume mode
                     select.resumeSelectCancellableWithException(closed.receiveException)
                 }
             }
@@ -973,7 +996,7 @@
                 onReceiveDequeued() // notify cancellation of receive
         }
 
-        override fun toString(): String = "ReceiveSelect[$select,nullOnClose=$nullOnClose]"
+        override fun toString(): String = "ReceiveSelect[$select,receiveMode=$receiveMode]"
     }
 
     private class IdempotentTokenValue<out E>(
@@ -982,6 +1005,11 @@
     )
 }
 
+// receiveMode values
+internal const val RECEIVE_THROWS_ON_CLOSE = 0
+internal const val RECEIVE_NULL_ON_CLOSE = 1
+internal const val RECEIVE_RESULT = 2
+
 @JvmField
 @SharedImmutable
 internal val OFFER_SUCCESS: Any = Symbol("OFFER_SUCCESS")
@@ -1065,10 +1093,10 @@
     override val offerResult get() = this
     override val pollResult get() = this
     override fun tryResumeSend(idempotent: Any?): Any? = CLOSE_RESUMED
-    override fun completeResumeSend(token: Any) { check(token === CLOSE_RESUMED) }
+    override fun completeResumeSend(token: Any) { assert { token === CLOSE_RESUMED } }
     override fun tryResumeReceive(value: E, idempotent: Any?): Any? = CLOSE_RESUMED
-    override fun completeResumeReceive(token: Any) { check(token === CLOSE_RESUMED) }
-    override fun resumeSendClosed(closed: Closed<*>) = error("Should be never invoked")
+    override fun completeResumeReceive(token: Any) { assert { token === CLOSE_RESUMED } }
+    override fun resumeSendClosed(closed: Closed<*>) = assert { false } // "Should be never invoked"
     override fun toString(): String = "Closed[$closeCause]"
 }
 
@@ -1076,3 +1104,10 @@
     override val offerResult get() = OFFER_SUCCESS
     abstract fun resumeReceiveClosed(closed: Closed<*>)
 }
+
+@Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST")
+private inline fun <E> Any?.toResult(): ValueOrClosed<E> =
+    if (this is Closed<*>) ValueOrClosed.closed(closeCause) else ValueOrClosed.value(this as E)
+
+@Suppress("NOTHING_TO_INLINE")
+private inline fun <E> Closed<*>.toResult(): ValueOrClosed<E> = ValueOrClosed.closed(closeCause)
diff --git a/kotlinx-coroutines-core/common/src/channels/ArrayChannel.kt b/kotlinx-coroutines-core/common/src/channels/ArrayChannel.kt
index 01afc21..688125d 100644
--- a/kotlinx-coroutines-core/common/src/channels/ArrayChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/ArrayChannel.kt
@@ -1,9 +1,10 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines.channels
 
+import kotlinx.coroutines.*
 import kotlinx.coroutines.internal.*
 import kotlinx.coroutines.selects.*
 import kotlin.jvm.*
@@ -94,7 +95,7 @@
                                 this.size = size // restore size
                                 receive = offerOp.result
                                 token = offerOp.resumeToken
-                                check(token != null)
+                                assert { token != null }
                                 return@withLock
                             }
                             failure === OFFER_FAILED -> break@loop // cannot offer -> Ok to queue to buffer
@@ -180,7 +181,7 @@
                         failure == null -> { // polled successfully
                             send = pollOp.result
                             token = pollOp.resumeToken
-                            check(token != null)
+                            assert { token != null }
                             replacement = send!!.pollResult
                             break@loop
                         }
diff --git a/kotlinx-coroutines-core/common/src/channels/Channel.kt b/kotlinx-coroutines-core/common/src/channels/Channel.kt
index 9fa3418..a2a6da2 100644
--- a/kotlinx-coroutines-core/common/src/channels/Channel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/Channel.kt
@@ -15,6 +15,7 @@
 import kotlinx.coroutines.internal.systemProp
 import kotlinx.coroutines.selects.*
 import kotlin.jvm.*
+import kotlin.internal.*
 
 /**
  * Sender's interface to [Channel].
@@ -91,7 +92,8 @@
      * on the side of [ReceiveChannel] starts returning `true` only after all previously sent elements
      * are received.
      *
-     * A channel that was closed without a [cause] throws [ClosedSendChannelException] on attempts to send or receive.
+     * A channel that was closed without a [cause] throws [ClosedSendChannelException] on attempts to send
+     * and [ClosedReceiveChannelException] on attempts to receive.
      * A channel that was closed with non-null [cause] is called a _failed_ channel. Attempts to send or
      * receive on a failed channel throw the specified [cause] exception.
      */
@@ -209,26 +211,74 @@
      * This function can be used in [select] invocation with [onReceiveOrNull] clause.
      * Use [poll] to try receiving from this channel without waiting.
      *
-     * **Note: This is an obsolete api.**
-     * This function will be replaced with `receiveOrClosed: ReceiveResult<E>` and
-     * extension `suspend fun <E: Any> ReceiveChannel<E>.receiveOrNull(): E?`
-     * It is obsolete because it does not distinguish closed channel and null elements.
+     * @suppress **Deprecated**: in favor of receiveOrClosed and receiveOrNull extension.
      */
     @ObsoleteCoroutinesApi
+    @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+    @LowPriorityInOverloadResolution
+    @Deprecated(
+        message = "Deprecated in favor of receiveOrClosed and receiveOrNull extension",
+        level = DeprecationLevel.WARNING,
+        replaceWith = ReplaceWith("receiveOrNull", "kotlinx.coroutines.channels.receiveOrNull")
+    )
     public suspend fun receiveOrNull(): E?
 
     /**
      * Clause for [select] expression of [receiveOrNull] suspending function that selects with the element that
-     * is received from the channel or selects with `null` if if the channel
+     * is received from the channel or selects with `null` if the channel
      * [isClosedForReceive] without cause. The [select] invocation fails with
      * the original [close][SendChannel.close] cause exception if the channel has _failed_.
      *
-     * **Note: This is an experimental api.** This function may be replaced with a better one in the future.
+     * @suppress **Deprecated**: in favor of onReceiveOrClosed and onReceiveOrNull extension.
      */
-    @ExperimentalCoroutinesApi
+    @ObsoleteCoroutinesApi
+    @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+    @LowPriorityInOverloadResolution
+    @Deprecated(
+        message = "Deprecated in favor of onReceiveOrClosed and onReceiveOrNull extension",
+        level = DeprecationLevel.WARNING,
+        replaceWith = ReplaceWith("onReceiveOrNull", "kotlinx.coroutines.channels.onReceiveOrNull")
+    )
     public val onReceiveOrNull: SelectClause1<E?>
 
     /**
+     * Retrieves and removes the element from this channel suspending the caller while this channel [isEmpty].
+     * This method returns [ValueOrClosed] with a value if element was successfully retrieved from the channel
+     * or [ValueOrClosed] with close cause if channel was closed.
+     *
+     * This suspending function is cancellable. If the [Job] of the current coroutine is cancelled or completed while this
+     * function is suspended, this function immediately resumes with [CancellationException].
+     *
+     * *Cancellation of suspended receive is atomic* -- when this function
+     * throws [CancellationException] it means that the element was not retrieved from this channel.
+     * As a side-effect of atomic cancellation, a thread-bound coroutine (to some UI thread, for example) may
+     * continue to execute even after it was cancelled from the same thread in the case when this receive operation
+     * was already resumed and the continuation was posted for execution to the thread's queue.
+     *
+     * Note, that this function does not check for cancellation when it is not suspended.
+     * Use [yield] or [CoroutineScope.isActive] to periodically check for cancellation in tight loops if needed.
+     *
+     * This function can be used in [select] invocation with [onReceiveOrClosed] clause.
+     * Use [poll] to try receiving from this channel without waiting.
+     *
+     * @suppress *This is an internal API, do not use*: Inline classes ABI is not stable yet and
+     *            [KT-27524](https://youtrack.jetbrains.com/issue/KT-27524) needs to be fixed.
+     */
+    @InternalCoroutinesApi // until https://youtrack.jetbrains.com/issue/KT-27524 is fixed
+    public suspend fun receiveOrClosed(): ValueOrClosed<E>
+
+    /**
+     * Clause for [select] expression of [receiveOrClosed] suspending function that selects with the [ValueOrClosed] with a value
+     * that is received from the channel or selects with [ValueOrClosed] with a close cause if the channel
+     * [isClosedForReceive].
+     *
+     * @suppress *This is an internal API, do not use*: Inline classes ABI is not stable yet and
+     *            [KT-27524](https://youtrack.jetbrains.com/issue/KT-27524) needs to be fixed.
+     */
+    @InternalCoroutinesApi // until https://youtrack.jetbrains.com/issue/KT-27524 is fixed
+    public val onReceiveOrClosed: SelectClause1<ValueOrClosed<E>>
+
+    /**
      * Retrieves and removes the element from this channel, or returns `null` if this channel is empty
      * or is [isClosedForReceive] without cause.
      * It throws the original [close][SendChannel.close] cause exception if the channel has _failed_.
@@ -272,6 +322,107 @@
 }
 
 /**
+ * A discriminated union of [ReceiveChannel.receiveOrClosed] result,
+ * that encapsulates either successfully received element of type [T] from the channel or a close cause.
+ *
+ * :todo: Do not make it public before resolving todos in the code of this class.
+ *
+ * @suppress *This is an internal API, do not use*: Inline classes ABI is not stable yet and
+ *            [KT-27524](https://youtrack.jetbrains.com/issue/KT-27524) needs to be fixed.
+ */
+@Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS")
+@InternalCoroutinesApi // until https://youtrack.jetbrains.com/issue/KT-27524 is fixed
+public inline class ValueOrClosed<out T>
+internal constructor(private val holder: Any?) {
+    /**
+     * Returns `true` if this instance represents received element.
+     * In this case [isClosed] returns `false`.
+     * todo: it is commented for now, because it is not used
+     */
+    //public val isValue: Boolean get() = holder !is Closed
+
+    /**
+     * Returns `true` if this instance represents close cause.
+     * In this case [isValue] returns `false`.
+     */
+    public val isClosed: Boolean get() = holder is Closed
+
+    /**
+     * Returns received value if this instance represents received value or throws [IllegalStateException] otherwise.
+     *
+     * :todo: Decide if it is needed how it shall be named with relation to [valueOrThrow]:
+     *
+     * So we have the following methods on ValueOrClosed: `value`, `valueOrNull`, `valueOrThrow`.
+     * On the other hand, the channel has the following receive variants:
+     *  * `receive` which corresponds to `receiveOrClosed().valueOrThrow`... huh?
+     *  * `receiveOrNull` which corresponds to `receiveOrClosed().valueOrNull`
+     *  * `receiveOrClosed`
+     * For the sake of consider dropping this version of `value` and rename [valueOrThrow] to simply `value`.
+     */
+    @Suppress("UNCHECKED_CAST")
+    public val value: T
+        get() = if (holder is Closed) error(DEFAULT_CLOSE_MESSAGE) else holder as T
+
+    /**
+     * Returns received value if this element represents received value or `null` otherwise.
+     * :todo: Decide if it shall be made into extension that is available only for non-null T.
+     * Note: it might become inconsistent with kotlin.Result
+     */
+    @Suppress("UNCHECKED_CAST")
+    public val valueOrNull: T?
+        get() = if (holder is Closed) null else holder as T
+
+    /**
+     * :todo: Decide if it is needed how it shall be named with relation to [value].
+     * Note, that valueOrThrow rethrows the cause adding no meaningful information about the callsite,
+     * so if one is sure that ValueOrClosed is always value, this very property should be used.
+     * Otherwise, it could be very hard to locate the source of the exception.
+     * todo: it is commented for now, because it is not used
+     */
+    //@Suppress("UNCHECKED_CAST")
+    //public val valueOrThrow: T
+    //    get() = if (holder is Closed) throw holder.exception else holder as T
+
+    /**
+     * Returns close cause of the channel if this instance represents close cause or throws
+     * [IllegalStateException] otherwise.
+     */
+    @Suppress("UNCHECKED_CAST")
+    public val closeCause: Throwable? get() =
+        if (holder is Closed) holder.cause else error("Channel was not closed")
+
+    /**
+     * @suppress
+     */
+    public override fun toString(): String =
+        when (holder) {
+            is Closed -> holder.toString()
+            else -> "Value($holder)"
+    }
+
+    internal class Closed(@JvmField val cause: Throwable?) {
+        // todo: it is commented for now, because it is not used
+        //val exception: Throwable get() = cause ?: ClosedReceiveChannelException(DEFAULT_CLOSE_MESSAGE)
+        override fun equals(other: Any?): Boolean = other is Closed && cause == other.cause
+        override fun hashCode(): Int = cause.hashCode()
+        override fun toString(): String = "Closed($cause)"
+    }
+
+    /**
+     * todo: consider making value/closed constructors public in the future.
+     */
+    internal companion object {
+        @Suppress("NOTHING_TO_INLINE")
+        internal inline fun <E> value(value: E): ValueOrClosed<E> =
+            ValueOrClosed(value)
+
+        @Suppress("NOTHING_TO_INLINE")
+        internal inline fun <E> closed(cause: Throwable?): ValueOrClosed<E> =
+            ValueOrClosed(Closed(cause))
+    }
+}
+
+/**
  * Iterator for [ReceiveChannel]. Instances of this interface are *not thread-safe* and shall not be used
  * from concurrent coroutines.
  */
diff --git a/kotlinx-coroutines-core/common/src/channels/Channels.common.kt b/kotlinx-coroutines-core/common/src/channels/Channels.common.kt
index 352c8c1..cd37bfb 100644
--- a/kotlinx-coroutines-core/common/src/channels/Channels.common.kt
+++ b/kotlinx-coroutines-core/common/src/channels/Channels.common.kt
@@ -8,6 +8,7 @@
 package kotlinx.coroutines.channels
 
 import kotlinx.coroutines.*
+import kotlinx.coroutines.selects.*
 import kotlin.coroutines.*
 import kotlin.jvm.*
 
@@ -34,6 +35,49 @@
 }
 
 /**
+ * Retrieves and removes the element from this channel suspending the caller while this channel [isEmpty]
+ * or returns `null` if the channel is [closed][Channel.isClosedForReceive].
+ *
+ * This suspending function is cancellable. If the [Job] of the current coroutine is cancelled or completed while this
+ * function is suspended, this function immediately resumes with [CancellationException].
+ *
+ * *Cancellation of suspended receive is atomic* -- when this function
+ * throws [CancellationException] it means that the element was not retrieved from this channel.
+ * As a side-effect of atomic cancellation, a thread-bound coroutine (to some UI thread, for example) may
+ * continue to execute even after it was cancelled from the same thread in the case when this receive operation
+ * was already resumed and the continuation was posted for execution to the thread's queue.
+ *
+ * Note, that this function does not check for cancellation when it is not suspended.
+ * Use [yield] or [CoroutineScope.isActive] to periodically check for cancellation in tight loops if needed.
+ *
+ * This extension is defined only for channels on non-null types, so that generic functions defined using
+ * these extensions do not accidentally confuse `null` value and a normally closed channel, leading to hard
+ * to find bugs.
+ */
+@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
+@ExperimentalCoroutinesApi // since 1.3.0, tentatively stable in 1.4.0
+public suspend fun <E : Any> ReceiveChannel<E>.receiveOrNull(): E? {
+    @Suppress("DEPRECATION", "UNCHECKED_CAST")
+    return (this as ReceiveChannel<E?>).receiveOrNull()
+}
+
+/**
+ * Clause for [select] expression of [receiveOrNull] suspending function that selects with the element that
+ * is received from the channel or selects with `null` if the channel
+ * [isClosedForReceive][ReceiveChannel.isClosedForReceive] without cause. The [select] invocation fails with
+ * the original [close][SendChannel.close] cause exception if the channel has _failed_.
+ *
+ * This extension is defined only for channels on non-null types, so that generic functions defined using
+ * these extensions do not accidentally confuse `null` value and a normally closed channel, leading to hard
+ * to find bugs.
+ **/
+@ExperimentalCoroutinesApi // since 1.3.0, tentatively stable in 1.4.0
+public fun <E : Any> ReceiveChannel<E>.onReceiveOrNull(): SelectClause1<E?> {
+    @Suppress("DEPRECATION", "UNCHECKED_CAST")
+    return (this as ReceiveChannel<E?>).onReceiveOrNull
+}
+
+/**
  * Subscribes to this [BroadcastChannel] and performs the specified action for each received element.
  *
  * **Note: This API will become obsolete in future updates with introduction of lazy asynchronous streams.**
diff --git a/kotlinx-coroutines-core/common/src/channels/ConflatedBroadcastChannel.kt b/kotlinx-coroutines-core/common/src/channels/ConflatedBroadcastChannel.kt
index 2d9858c..b242639 100644
--- a/kotlinx-coroutines-core/common/src/channels/ConflatedBroadcastChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/ConflatedBroadcastChannel.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines.channels
@@ -142,11 +142,18 @@
     private fun removeSubscriber(list: Array<Subscriber<E>>, subscriber: Subscriber<E>): Array<Subscriber<E>>? {
         val n = list.size
         val i = list.indexOf(subscriber)
-        check(i >= 0)
+        assert { i >= 0 }
         if (n == 1) return null
         val update = arrayOfNulls<Subscriber<E>>(n - 1)
-        arraycopy(list, 0, update, 0, i)
-        arraycopy(list, i + 1, update, i, n - i - 1)
+        list.copyInto(
+            destination = update,
+            endIndex = i
+        )
+        list.copyInto(
+            destination = update,
+            destinationOffset = i,
+            startIndex = i + 1
+        )
         return update as Array<Subscriber<E>>
     }
 
diff --git a/kotlinx-coroutines-core/common/src/channels/Produce.kt b/kotlinx-coroutines-core/common/src/channels/Produce.kt
index 9e34773..a579d7a 100644
--- a/kotlinx-coroutines-core/common/src/channels/Produce.kt
+++ b/kotlinx-coroutines-core/common/src/channels/Produce.kt
@@ -42,7 +42,7 @@
  * ```
  */
 @ExperimentalCoroutinesApi
-public suspend fun <T> ProducerScope<T>.awaitClose(block: () -> Unit = {}) {
+public suspend fun ProducerScope<*>.awaitClose(block: () -> Unit = {}) {
     check(kotlin.coroutines.coroutineContext[Job] === this) { "awaitClose() can be invoke only from the producer context" }
     try {
         suspendCancellableCoroutine<Unit> { cont ->
diff --git a/kotlinx-coroutines-core/common/src/flow/Builders.kt b/kotlinx-coroutines-core/common/src/flow/Builders.kt
index f1a5c0b..41f13aa 100644
--- a/kotlinx-coroutines-core/common/src/flow/Builders.kt
+++ b/kotlinx-coroutines-core/common/src/flow/Builders.kt
@@ -11,6 +11,7 @@
 import kotlinx.coroutines.channels.*
 import kotlinx.coroutines.channels.Channel.Factory.BUFFERED
 import kotlinx.coroutines.flow.internal.*
+import kotlinx.coroutines.flow.internal.unsafeFlow as flow
 import kotlin.coroutines.*
 import kotlin.jvm.*
 
@@ -44,25 +45,12 @@
  * ```
  * If you want to switch the context of execution of a flow, use the [flowOn] operator.
  */
-@ExperimentalCoroutinesApi
-public fun <T> flow(@BuilderInference block: suspend FlowCollector<T>.() -> Unit): Flow<T> {
-    return object : Flow<T> {
-        override suspend fun collect(collector: FlowCollector<T>) {
-            SafeCollector(collector, coroutineContext).block()
-        }
-    }
-}
+public fun <T> flow(@BuilderInference block: suspend FlowCollector<T>.() -> Unit): Flow<T> = SafeFlow(block)
 
-/**
- * An analogue of the [flow] builder that does not check the context of execution of the resulting flow.
- * Used in our own operators where we trust the context of invocations.
- */
-@PublishedApi
-internal inline fun <T> unsafeFlow(@BuilderInference crossinline block: suspend FlowCollector<T>.() -> Unit): Flow<T> {
-    return object : Flow<T> {
-        override suspend fun collect(collector: FlowCollector<T>) {
-            collector.block()
-        }
+// Named anonymous object
+private class SafeFlow<T>(private val block: suspend FlowCollector<T>.() -> Unit) : Flow<T> {
+    override suspend fun collect(collector: FlowCollector<T>) {
+        SafeCollector(collector, coroutineContext).block()
     }
 }
 
@@ -70,7 +58,7 @@
  * Creates a flow that produces a single value from the given functional type.
  */
 @FlowPreview
-public fun <T> (() -> T).asFlow(): Flow<T> = unsafeFlow {
+public fun <T> (() -> T).asFlow(): Flow<T> = flow {
     emit(invoke())
 }
 
@@ -83,15 +71,14 @@
  * ```
  */
 @FlowPreview
-public fun <T> (suspend () -> T).asFlow(): Flow<T> = unsafeFlow {
+public fun <T> (suspend () -> T).asFlow(): Flow<T> = flow {
     emit(invoke())
 }
 
 /**
  * Creates a flow that produces values from the given iterable.
  */
-@ExperimentalCoroutinesApi
-public fun <T> Iterable<T>.asFlow(): Flow<T> = unsafeFlow {
+public fun <T> Iterable<T>.asFlow(): Flow<T> = flow {
     forEach { value ->
         emit(value)
     }
@@ -100,8 +87,7 @@
 /**
  * Creates a flow that produces values from the given iterable.
  */
-@ExperimentalCoroutinesApi
-public fun <T> Iterator<T>.asFlow(): Flow<T> = unsafeFlow {
+public fun <T> Iterator<T>.asFlow(): Flow<T> = flow {
     forEach { value ->
         emit(value)
     }
@@ -110,8 +96,7 @@
 /**
  * Creates a flow that produces values from the given sequence.
  */
-@ExperimentalCoroutinesApi
-public fun <T> Sequence<T>.asFlow(): Flow<T> = unsafeFlow {
+public fun <T> Sequence<T>.asFlow(): Flow<T> = flow {
     forEach { value ->
         emit(value)
     }
@@ -120,8 +105,7 @@
 /**
  * Creates a flow that produces values from the given array of elements.
  */
-@ExperimentalCoroutinesApi
-public fun <T> flowOf(vararg elements: T): Flow<T> = unsafeFlow {
+public fun <T> flowOf(vararg elements: T): Flow<T> = flow {
     for (element in elements) {
         emit(element)
     }
@@ -130,8 +114,7 @@
 /**
  * Creates flow that produces a given [value].
  */
-@ExperimentalCoroutinesApi
-public fun <T> flowOf(value: T): Flow<T> = unsafeFlow {
+public fun <T> flowOf(value: T): Flow<T> = flow {
     /*
      * Implementation note: this is just an "optimized" overload of flowOf(vararg)
      * which significantly reduce the footprint of widespread single-value flows.
@@ -142,7 +125,6 @@
 /**
  * Returns an empty flow.
  */
-@ExperimentalCoroutinesApi
 public fun <T> emptyFlow(): Flow<T> = EmptyFlow
 
 private object EmptyFlow : Flow<Nothing> {
@@ -152,8 +134,7 @@
 /**
  * Creates a flow that produces values from the given array.
  */
-@ExperimentalCoroutinesApi
-public fun <T> Array<T>.asFlow(): Flow<T> = unsafeFlow {
+public fun <T> Array<T>.asFlow(): Flow<T> = flow {
     forEach { value ->
         emit(value)
     }
@@ -162,8 +143,7 @@
 /**
  * Creates flow that produces values from the given array.
  */
-@ExperimentalCoroutinesApi
-public fun IntArray.asFlow(): Flow<Int> = unsafeFlow {
+public fun IntArray.asFlow(): Flow<Int> = flow {
     forEach { value ->
         emit(value)
     }
@@ -172,8 +152,7 @@
 /**
  * Creates flow that produces values from the given array.
  */
-@ExperimentalCoroutinesApi
-public fun LongArray.asFlow(): Flow<Long> = unsafeFlow {
+public fun LongArray.asFlow(): Flow<Long> = flow {
     forEach { value ->
         emit(value)
     }
@@ -182,8 +161,7 @@
 /**
  * Creates flow that produces values from the given range.
  */
-@ExperimentalCoroutinesApi
-public fun IntRange.asFlow(): Flow<Int> = unsafeFlow {
+public fun IntRange.asFlow(): Flow<Int> = flow {
     forEach { value ->
         emit(value)
     }
@@ -192,7 +170,6 @@
 /**
  * Creates flow that produces values from the given range.
  */
-@ExperimentalCoroutinesApi
 public fun LongRange.asFlow(): Flow<Long> = flow {
     forEach { value ->
         emit(value)
diff --git a/kotlinx-coroutines-core/common/src/flow/Channels.kt b/kotlinx-coroutines-core/common/src/flow/Channels.kt
index d0d2243..a554a4a 100644
--- a/kotlinx-coroutines-core/common/src/flow/Channels.kt
+++ b/kotlinx-coroutines-core/common/src/flow/Channels.kt
@@ -7,14 +7,128 @@
 
 package kotlinx.coroutines.flow
 
+import kotlinx.atomicfu.*
 import kotlinx.coroutines.*
 import kotlinx.coroutines.channels.*
-import kotlinx.coroutines.channels.Channel.Factory.CONFLATED
-import kotlinx.coroutines.channels.Channel.Factory.BUFFERED
-import kotlinx.coroutines.channels.Channel.Factory.OPTIONAL_CHANNEL
 import kotlinx.coroutines.flow.internal.*
 import kotlin.coroutines.*
 import kotlin.jvm.*
+import kotlinx.coroutines.flow.internal.unsafeFlow as flow
+
+/**
+ * Emits all elements from the given [channel] to this flow collector and [cancels][cancel] (consumes)
+ * the channel afterwards. If you need to iterate over the channel without consuming it,
+ * a regular `for` loop should be used instead.
+ *
+ * This function provides a more efficient shorthand for `channel.consumeEach { value -> emit(value) }`.
+ * See [consumeEach][ReceiveChannel.consumeEach].
+ */
+@ExperimentalCoroutinesApi
+public suspend fun <T> FlowCollector<T>.emitAll(channel: ReceiveChannel<T>) {
+    // Manually inlined "consumeEach" implementation that does not use iterator but works via "receiveOrClosed".
+    // It has smaller and more efficient spilled state which also allows to implement a manual kludge to
+    // fix retention of the last emitted value.
+    // See https://youtrack.jetbrains.com/issue/KT-16222
+    // See https://github.com/Kotlin/kotlinx.coroutines/issues/1333
+    var cause: Throwable? = null
+    try {
+        while (true) {
+            // :KLUDGE: This "run" call is resolved to an extension function "run" and forces the size of
+            // spilled state to increase by an additional slot, so there are 4 object local variables spilled here
+            // which makes the size of spill state equal to the 4 slots that are spilled around subsequent "emit"
+            // call, ensuring that the previously emitted value is not retained in the state while receiving
+            // the next one.
+            //     L$0 <- this
+            //     L$1 <- channel
+            //     L$2 <- cause
+            //     L$3 <- this$run (actually equal to this)
+            val result = run { channel.receiveOrClosed() }
+            if (result.isClosed) {
+                result.closeCause?.let { throw it }
+                break // returns normally when result.closeCause == null
+            }
+            // result is spilled here to the coroutine state and retained after the call, even though
+            // it is not actually needed in the next loop iteration.
+            //     L$0 <- this
+            //     L$1 <- channel
+            //     L$2 <- cause
+            //     L$3 <- result
+            emit(result.value)
+        }
+    } catch (e: Throwable) {
+        cause = e
+        throw e
+    } finally {
+        channel.cancelConsumed(cause)
+    }
+}
+
+/**
+ * Represents the given receive channel as a hot flow and [consumes][ReceiveChannel.consume] the channel
+ * on the first collection from this flow. The resulting flow can be collected just once and throws
+ * [IllegalStateException] when trying to collect it more than once.
+ *
+ * ### Cancellation semantics
+ *
+ * 1) Flow consumer is cancelled when the original channel is cancelled.
+ * 2) Flow consumer completes normally when the original channel completes (~is closed) normally.
+ * 3) If the flow consumer fails with an exception, channel is cancelled.
+ *
+ * ### Operator fusion
+ *
+ * Adjacent applications of [flowOn], [buffer], [conflate], and [produceIn] to the result of `consumeAsFlow` are fused.
+ * In particular, [produceIn] returns the original channel (but throws [IllegalStateException] on repeated calls).
+ * Calls to [flowOn] have generally no effect, unless [buffer] is used to explicitly request buffering.
+ */
+@FlowPreview
+public fun <T> ReceiveChannel<T>.consumeAsFlow(): Flow<T> = ConsumeAsFlow(this)
+
+/**
+ * Represents an existing [channel] as [ChannelFlow] implementation.
+ * It fuses with subsequent [flowOn] operators, but for the most part ignores the specified context.
+ * However, additional [buffer] calls cause a separate buffering channel to be created and that is where
+ * the context might play a role, because it is used by the producing coroutine.
+ */
+private class ConsumeAsFlow<T>(
+    private val channel: ReceiveChannel<T>,
+    context: CoroutineContext = EmptyCoroutineContext,
+    capacity: Int = Channel.OPTIONAL_CHANNEL
+) : ChannelFlow<T>(context, capacity) {
+    private val consumed = atomic(false)
+
+    private fun markConsumed() =
+        check(!consumed.getAndSet(true)) { "ReceiveChannel.consumeAsFlow can be collected just once" }
+    
+    override fun create(context: CoroutineContext, capacity: Int): ChannelFlow<T> =
+        ConsumeAsFlow(channel, context, capacity)
+
+    override suspend fun collectTo(scope: ProducerScope<T>) =
+        SendingCollector(scope).emitAll(channel) // use efficient channel receiving code from emitAll
+
+    override fun broadcastImpl(scope: CoroutineScope, start: CoroutineStart): BroadcastChannel<T> {
+        markConsumed() // fail fast on repeated attempt to collect it
+        return super.broadcastImpl(scope, start)
+    }
+
+    override fun produceImpl(scope: CoroutineScope): ReceiveChannel<T> {
+        markConsumed() // fail fast on repeated attempt to collect it
+        return if (capacity == Channel.OPTIONAL_CHANNEL) {
+            channel // direct
+        } else
+            super.produceImpl(scope) // extra buffering channel
+    }
+
+    override suspend fun collect(collector: FlowCollector<T>) {
+        if (capacity == Channel.OPTIONAL_CHANNEL) {
+            markConsumed()
+            collector.emitAll(channel) // direct
+        } else {
+            super.collect(collector) // extra buffering channel, produceImpl will mark it as consumed
+        }
+    }
+
+    override fun additionalToStringProps(): String = "channel=$channel, "
+}
 
 /**
  * Represents the given broadcast channel as a hot flow.
@@ -27,10 +141,7 @@
  */
 @FlowPreview
 public fun <T> BroadcastChannel<T>.asFlow(): Flow<T> = flow {
-    val subscription = openSubscription()
-    subscription.consumeEach { value ->
-        emit(value)
-    }
+    emitAll(openSubscription())
 }
 
 /**
diff --git a/kotlinx-coroutines-core/common/src/flow/Flow.kt b/kotlinx-coroutines-core/common/src/flow/Flow.kt
index b810305..bda326f 100644
--- a/kotlinx-coroutines-core/common/src/flow/Flow.kt
+++ b/kotlinx-coroutines-core/common/src/flow/Flow.kt
@@ -157,7 +157,6 @@
  * Flow is [Reactive Streams](http://www.reactive-streams.org/) compliant, you can safely interop it with
  * reactive streams using [Flow.asPublisher] and [Publisher.asFlow] from `kotlinx-coroutines-reactive` module.
  */
-@ExperimentalCoroutinesApi
 public interface Flow<out T> {
     /**
      * Accepts the given [collector] and [emits][FlowCollector.emit] values into it.
diff --git a/kotlinx-coroutines-core/common/src/flow/FlowCollector.kt b/kotlinx-coroutines-core/common/src/flow/FlowCollector.kt
index bb0d5b5..7254c6d 100644
--- a/kotlinx-coroutines-core/common/src/flow/FlowCollector.kt
+++ b/kotlinx-coroutines-core/common/src/flow/FlowCollector.kt
@@ -4,8 +4,6 @@
 
 package kotlinx.coroutines.flow
 
-import kotlinx.coroutines.*
-
 /**
  * [FlowCollector] is used as an intermediate or a terminal collector of the flow and represents
  * an entity that accepts values emitted by the [Flow].
@@ -13,7 +11,6 @@
  * This interface should usually not be implemented directly, but rather used as a receiver in a [flow] builder when implementing a custom operator.
  * Implementations of this interface are not thread-safe.
  */
-@ExperimentalCoroutinesApi
 public interface FlowCollector<in T> {
 
     /**
diff --git a/kotlinx-coroutines-core/common/src/flow/Migration.kt b/kotlinx-coroutines-core/common/src/flow/Migration.kt
index bc45b01..b7e91f5 100644
--- a/kotlinx-coroutines-core/common/src/flow/Migration.kt
+++ b/kotlinx-coroutines-core/common/src/flow/Migration.kt
@@ -1,15 +1,26 @@
 /*
  * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
+
+@file:JvmMultifileClass
+@file:JvmName("FlowKt")
 @file:Suppress("unused", "DeprecatedCallableAddReplaceWith", "UNUSED_PARAMETER")
+
 package kotlinx.coroutines.flow
 
 import kotlin.coroutines.*
+import kotlin.jvm.*
 
 /**
+ * **GENERAL NOTE**
+ *
  * These deprecations are added to improve user experience when they will start to
  * search for their favourite operators and/or patterns that are missing or renamed in Flow.
+ * Deprecated functions also are moved here when they renamed. The difference is that they have
+ * a body with their implementation while pure stubs have [noImpl].
  */
+private fun noImpl(): Nothing =
+    throw UnsupportedOperationException("Not implemented, should not be called")
 
 /**
  * `observeOn` has no direct match in [Flow] API because all terminal flow operators are suspending and
@@ -33,7 +44,7 @@
  * @suppress
  */
 @Deprecated(message = "Collect flow in the desired context instead", level = DeprecationLevel.ERROR)
-public fun <T> Flow<T>.observeOn(context: CoroutineContext): Flow<T> = error("Should not be called")
+public fun <T> Flow<T>.observeOn(context: CoroutineContext): Flow<T> = noImpl()
 
 /**
  * `publishOn` has no direct match in [Flow] API because all terminal flow operators are suspending and
@@ -57,7 +68,7 @@
  * @suppress
  */
 @Deprecated(message = "Collect flow in the desired context instead", level = DeprecationLevel.ERROR)
-public fun <T> Flow<T>.publishOn(context: CoroutineContext): Flow<T> = error("Should not be called")
+public fun <T> Flow<T>.publishOn(context: CoroutineContext): Flow<T> = noImpl()
 
 /**
  * `subscribeOn` has no direct match in [Flow] API because [Flow] preserves its context and does not leak it.
@@ -86,36 +97,54 @@
  * @suppress
  */
 @Deprecated(message = "Use flowOn instead", level = DeprecationLevel.ERROR)
-public fun <T> Flow<T>.subscribeOn(context: CoroutineContext): Flow<T> = error("Should not be called")
+public fun <T> Flow<T>.subscribeOn(context: CoroutineContext): Flow<T> = noImpl()
 
-/** @suppress **/
+/**
+ * Use [BroadcastChannel][kotlinx.coroutines.channels.BroadcastChannel].asFlow().
+ * @suppress
+ */
 @Deprecated(message = "Use BroadcastChannel.asFlow()", level = DeprecationLevel.ERROR)
-public fun BehaviourSubject(): Any = error("Should not be called")
+public fun BehaviourSubject(): Any = noImpl()
 
-/** @suppress **/
+/**
+ * `ReplaySubject` is not supported. The closest analogue is buffered [BroadcastChannel][kotlinx.coroutines.channels.BroadcastChannel].
+ * @suppress
+ */
 @Deprecated(
     message = "ReplaySubject is not supported. The closest analogue is buffered broadcast channel",
     level = DeprecationLevel.ERROR)
-public fun ReplaySubject(): Any = error("Should not be called")
+public fun ReplaySubject(): Any = noImpl()
 
-/** @suppress **/
+/**
+ * `PublishSubject` is not supported.
+ * @suppress
+ */
 @Deprecated(message = "PublishSubject is not supported", level = DeprecationLevel.ERROR)
-public fun PublishSubject(): Any = error("Should not be called")
+public fun PublishSubject(): Any = noImpl()
 
-/** @suppress **/
+/**
+ * Flow analogue of `onErrorXxx` is [catch].
+ * Use `catch { emitAll(fallback) }`.
+ * @suppress
+ */
 @Deprecated(
     level = DeprecationLevel.ERROR,
     message = "Flow analogue of 'onErrorXxx' is 'catch'. Use 'catch { emitAll(fallback) }'",
     replaceWith = ReplaceWith("catch { emitAll(fallback) }")
 )
-public fun <T> Flow<T>.onErrorResume(fallback: Flow<T>): Flow<T> = error("Should not be called")
+public fun <T> Flow<T>.onErrorResume(fallback: Flow<T>): Flow<T> = noImpl()
 
+/**
+ * Flow analogue of `onErrorXxx` is [catch].
+ * Use `catch { emitAll(fallback) }`.
+ * @suppress
+ */
 @Deprecated(
     level = DeprecationLevel.ERROR,
     message = "Flow analogue of 'onErrorXxx' is 'catch'. Use 'catch { emitAll(fallback) }'",
     replaceWith = ReplaceWith("catch { emitAll(fallback) }")
 )
-public fun <T> Flow<T>.onErrorResumeNext(fallback: Flow<T>): Flow<T> = error("Should not be called")
+public fun <T> Flow<T>.onErrorResumeNext(fallback: Flow<T>): Flow<T> = noImpl()
 
 /**
  * Self-explanatory, the reason of deprecation is "context preservation" property (you can read more in [Flow] documentation)
@@ -123,7 +152,7 @@
  **/
 @Suppress("UNUSED_PARAMETER", "UNUSED", "DeprecatedCallableAddReplaceWith")
 @Deprecated(message = "withContext in flow body is deprecated, use flowOn instead", level = DeprecationLevel.ERROR)
-public fun <T, R> FlowCollector<T>.withContext(context: CoroutineContext, block: suspend () -> R): Unit = error("Should not be called")
+public fun <T, R> FlowCollector<T>.withContext(context: CoroutineContext, block: suspend () -> R): Unit = noImpl()
 
 /**
  * `subscribe` is Rx-specific API that has no direct match in flows.
@@ -153,19 +182,25 @@
     message = "Use launchIn with onEach, onCompletion and catch operators instead",
     level = DeprecationLevel.ERROR
 )
-public fun <T> Flow<T>.subscribe(): Unit = error("Should not be called")
+public fun <T> Flow<T>.subscribe(): Unit = noImpl()
 
-/** @suppress **/
+/**
+ * Use [launchIn] with [onEach], [onCompletion] and [catch] operators instead.
+ * @suppress
+ */
 @Deprecated(
     message = "Use launchIn with onEach, onCompletion and catch operators instead",
     level = DeprecationLevel.ERROR
-)public fun <T> Flow<T>.subscribe(onEach: suspend (T) -> Unit): Unit = error("Should not be called")
+)public fun <T> Flow<T>.subscribe(onEach: suspend (T) -> Unit): Unit = noImpl()
 
-/** @suppress **/
+/**
+ * Use [launchIn] with [onEach], [onCompletion] and [catch] operators instead.
+ * @suppress
+ */
 @Deprecated(
     message = "Use launchIn with onEach, onCompletion and catch operators instead",
     level = DeprecationLevel.ERROR
-)public fun <T> Flow<T>.subscribe(onEach: suspend (T) -> Unit, onError: suspend (Throwable) -> Unit): Unit = error("Should not be called")
+)public fun <T> Flow<T>.subscribe(onEach: suspend (T) -> Unit, onError: suspend (Throwable) -> Unit): Unit = noImpl()
 
 /**
  * Note that this replacement is sequential (`concat`) by default.
@@ -177,15 +212,18 @@
     message = "Flow analogue is named flatMapConcat",
     replaceWith = ReplaceWith("flatMapConcat(mapper)")
 )
-public fun <T, R> Flow<T>.flatMap(mapper: suspend (T) -> Flow<R>): Flow<R> = error("Should not be called")
+public fun <T, R> Flow<T>.flatMap(mapper: suspend (T) -> Flow<R>): Flow<R> = noImpl()
 
-/** @suppress **/
+/**
+ * Flow analogue of `concatMap` is [flatMapConcat].
+ * @suppress
+ */
 @Deprecated(
     level = DeprecationLevel.ERROR,
-    message = "Flow analogue is named flatMapConcat",
+    message = "Flow analogue of 'concatMap' is 'flatMapConcat'",
     replaceWith = ReplaceWith("flatMapConcat(mapper)")
 )
-public fun <T, R> Flow<T>.concatMap(mapper: (T) -> Flow<R>): Flow<R> = error("Should not be called")
+public fun <T, R> Flow<T>.concatMap(mapper: (T) -> Flow<R>): Flow<R> = noImpl()
 
 /**
  * Note that this replacement is sequential (`concat`) by default.
@@ -197,15 +235,18 @@
     message = "Flow analogue of 'merge' is 'flattenConcat'",
     replaceWith = ReplaceWith("flattenConcat()")
 )
-public fun <T> Flow<Flow<T>>.merge(): Flow<T> = error("Should not be called")
+public fun <T> Flow<Flow<T>>.merge(): Flow<T> = noImpl()
 
-/** @suppress **/
+/**
+ * Flow analogue of `flatten` is [flattenConcat].
+ * @suppress
+ */
 @Deprecated(
     level = DeprecationLevel.ERROR,
     message = "Flow analogue of 'flatten' is 'flattenConcat'",
     replaceWith = ReplaceWith("flattenConcat()")
 )
-public fun <T> Flow<Flow<T>>.flatten(): Flow<T> = error("Should not be called")
+public fun <T> Flow<Flow<T>>.flatten(): Flow<T> = noImpl()
 
 /**
  * Kotlin has a built-in generic mechanism for making chained calls.
@@ -218,7 +259,6 @@
  * ```
  * myFlow.let(MyFlowExtensions.ignoreErrors()).collect { ... }
  * ```
- *
  * @suppress
  */
 @Deprecated(
@@ -226,9 +266,10 @@
     message = "Flow analogue of 'compose' is 'let'",
     replaceWith = ReplaceWith("let(transformer)")
 )
-public fun <T, R> Flow<T>.compose(transformer: Flow<T>.() -> Flow<R>): Flow<R> = error("Should not be called")
+public fun <T, R> Flow<T>.compose(transformer: Flow<T>.() -> Flow<R>): Flow<R> = noImpl()
 
 /**
+ * Flow analogue of `skip` is [drop].
  * @suppress
  */
 @Deprecated(
@@ -236,7 +277,7 @@
     message = "Flow analogue of 'skip' is 'drop'",
     replaceWith = ReplaceWith("drop(count)")
 )
-public fun <T> Flow<T>.skip(count: Int): Flow<T> = error("Should not be called")
+public fun <T> Flow<T>.skip(count: Int): Flow<T> = noImpl()
 
 /**
  * Flow extension to iterate over elements is [collect].
@@ -251,23 +292,38 @@
     message = "Flow analogue of 'forEach' is 'collect'",
     replaceWith = ReplaceWith("collect(block)")
 )
-public fun <T> Flow<T>.forEach(action: suspend (value: T) -> Unit): Unit = error("Should not be called")
+public fun <T> Flow<T>.forEach(action: suspend (value: T) -> Unit): Unit = noImpl()
 
+/**
+ * Flow has less verbose [scan] shortcut.
+ * @suppress
+ */
 @Deprecated(
     level = DeprecationLevel.ERROR,
     message = "Flow has less verbose 'scan' shortcut",
     replaceWith = ReplaceWith("scan(initial, operation)")
 )
-public fun <T, R> Flow<T>.scanFold(initial: R, @BuilderInference operation: suspend (accumulator: R, value: T) -> R): Flow<R> = error("Should not be called")
+public fun <T, R> Flow<T>.scanFold(initial: R, @BuilderInference operation: suspend (accumulator: R, value: T) -> R): Flow<R> =
+    noImpl()
 
+/**
+ * Flow analogue of `onErrorXxx` is [catch].
+ * Use `catch { emit(fallback) }`.
+ * @suppress
+ */
 @Deprecated(
     level = DeprecationLevel.ERROR,
     message = "Flow analogue of 'onErrorXxx' is 'catch'. Use 'catch { emit(fallback) }'",
     replaceWith = ReplaceWith("catch { emit(fallback) }")
 )
 // Note: this version without predicate gives better "replaceWith" action
-public fun <T> Flow<T>.onErrorReturn(fallback: T): Flow<T> = error("Should not be called")
+public fun <T> Flow<T>.onErrorReturn(fallback: T): Flow<T> = noImpl()
 
+/**
+ * Flow analogue of `onErrorXxx` is [catch].
+ * Use `catch { e -> if (predicate(e)) emit(fallback) else throw e }`.
+ * @suppress
+ */
 @Deprecated(
     level = DeprecationLevel.ERROR,
     message = "Flow analogue of 'onErrorXxx' is 'catch'. Use 'catch { e -> if (predicate(e)) emit(fallback) else throw e }'",
@@ -279,3 +335,52 @@
         if (!predicate(e)) throw e
         emit(fallback)
     }
+
+/**
+ * Flow analogue of `startWith` is [onStart].
+ * Use `onStart { emit(value) }`.
+ * @suppress
+ */
+@Deprecated(
+    level = DeprecationLevel.ERROR,
+    message = "Flow analogue of 'startWith' is 'onStart'. Use 'onStart { emit(value) }'",
+    replaceWith = ReplaceWith("onStart { emit(value) }")
+)
+public fun <T> Flow<T>.startWith(value: T): Flow<T> = noImpl()
+
+/**
+ * Flow analogue of `startWith` is [onStart].
+ * Use `onStart { emitAll(other) }`.
+ * @suppress
+ */
+@Deprecated(
+    level = DeprecationLevel.ERROR,
+    message = "Flow analogue of 'startWith' is 'onStart'. Use 'onStart { emitAll(other) }'",
+    replaceWith = ReplaceWith("onStart { emitAll(other) }")
+)
+public fun <T> Flow<T>.startWith(other: Flow<T>): Flow<T> = noImpl()
+
+/**
+ * Flow analogue of `concatWith` is [onCompletion].
+ * Use `onCompletion { emit(value) }`.
+ * @suppress
+ */
+@Deprecated(
+    level = DeprecationLevel.ERROR,
+    message = "Flow analogue of 'concatWith' is 'onCompletion'. Use 'onCompletion { emit(value) }'",
+    replaceWith = ReplaceWith("onCompletion { emit(value) }")
+)
+public fun <T> Flow<T>.concatWith(value: T): Flow<T> = noImpl()
+
+/**
+ * Flow analogue of `concatWith` is [onCompletion].
+ * Use `onCompletion { emitAll(other) }`.
+ * @suppress
+ */
+@Deprecated(
+    level = DeprecationLevel.ERROR,
+    message = "Flow analogue of 'concatWith' is 'onCompletion'. Use 'onCompletion { emitAll(other) }'",
+    replaceWith = ReplaceWith("onCompletion { emitAkk(other) }")
+)
+public fun <T> Flow<T>.concatWith(other: Flow<T>): Flow<T> = noImpl()
+
diff --git a/kotlinx-coroutines-core/common/src/flow/internal/ChannelFlow.kt b/kotlinx-coroutines-core/common/src/flow/internal/ChannelFlow.kt
index e676869..99a3bdc 100644
--- a/kotlinx-coroutines-core/common/src/flow/internal/ChannelFlow.kt
+++ b/kotlinx-coroutines-core/common/src/flow/internal/ChannelFlow.kt
@@ -42,8 +42,8 @@
             capacity == Channel.CONFLATED -> Channel.CONFLATED
             else -> {
                 // sanity checks
-                check(this.capacity >= 0) { "Unexpected capacity ${this.capacity}" }
-                check(capacity >= 0) { "Unexpected capacity $capacity" }
+                assert { this.capacity >= 0 }
+                assert { capacity >= 0 }
                 // combine capacities clamping to UNLIMITED on overflow
                 val sum = this.capacity + capacity
                 if (sum >= 0) sum else Channel.UNLIMITED // unlimited on int overflow
@@ -64,7 +64,7 @@
     private val produceCapacity: Int
         get() = if (capacity == Channel.OPTIONAL_CHANNEL) Channel.BUFFERED else capacity
 
-    fun broadcastImpl(scope: CoroutineScope, start: CoroutineStart): BroadcastChannel<T> =
+    open fun broadcastImpl(scope: CoroutineScope, start: CoroutineStart): BroadcastChannel<T> =
         scope.broadcast(context, produceCapacity, start, block = collectToFun)
 
     open fun produceImpl(scope: CoroutineScope): ReceiveChannel<T> =
@@ -72,8 +72,7 @@
 
     override suspend fun collect(collector: FlowCollector<T>) =
         coroutineScope {
-            val channel = produceImpl(this)
-            channel.consumeEach { collector.emit(it) }
+            collector.emitAll(produceImpl(this))
         }
 
     // debug toString
diff --git a/kotlinx-coroutines-core/common/src/flow/internal/FlowCoroutine.kt b/kotlinx-coroutines-core/common/src/flow/internal/FlowCoroutine.kt
index 258869f..f0b5b39 100644
--- a/kotlinx-coroutines-core/common/src/flow/internal/FlowCoroutine.kt
+++ b/kotlinx-coroutines-core/common/src/flow/internal/FlowCoroutine.kt
@@ -11,7 +11,7 @@
 import kotlinx.coroutines.intrinsics.*
 import kotlin.coroutines.*
 import kotlin.coroutines.intrinsics.*
-import kotlinx.coroutines.flow.unsafeFlow as flow
+import kotlinx.coroutines.flow.internal.unsafeFlow as flow
 
 /**
  * Creates a [CoroutineScope] and calls the specified suspend block with this scope.
diff --git a/kotlinx-coroutines-core/common/src/flow/internal/FlowExceptions.common.kt b/kotlinx-coroutines-core/common/src/flow/internal/FlowExceptions.common.kt
index 6c675b3..c3a85a3 100644
--- a/kotlinx-coroutines-core/common/src/flow/internal/FlowExceptions.common.kt
+++ b/kotlinx-coroutines-core/common/src/flow/internal/FlowExceptions.common.kt
@@ -16,3 +16,12 @@
  * Exception used to cancel child of [scopedFlow] without cancelling the whole scope.
  */
 internal expect class ChildCancelledException() : CancellationException
+
+@Suppress("NOTHING_TO_INLINE")
+@PublishedApi
+internal inline fun checkIndexOverflow(index: Int): Int {
+    if (index < 0) {
+        throw ArithmeticException("Index overflow has happened")
+    }
+    return index
+}
diff --git a/kotlinx-coroutines-core/common/src/flow/internal/NopCollector.kt b/kotlinx-coroutines-core/common/src/flow/internal/NopCollector.kt
index 297d4d1..f83f313 100644
--- a/kotlinx-coroutines-core/common/src/flow/internal/NopCollector.kt
+++ b/kotlinx-coroutines-core/common/src/flow/internal/NopCollector.kt
@@ -4,8 +4,6 @@
 
 package kotlinx.coroutines.flow.internal
 
-import kotlinx.coroutines.flow.*
-
 internal object NopCollector : ConcurrentFlowCollector<Any?> {
     override suspend fun emit(value: Any?) {
         // does nothing
diff --git a/kotlinx-coroutines-core/common/src/flow/internal/SafeCollector.kt b/kotlinx-coroutines-core/common/src/flow/internal/SafeCollector.kt
index 5604dc5..09a6378 100644
--- a/kotlinx-coroutines-core/common/src/flow/internal/SafeCollector.kt
+++ b/kotlinx-coroutines-core/common/src/flow/internal/SafeCollector.kt
@@ -9,7 +9,6 @@
 import kotlinx.coroutines.internal.*
 import kotlin.coroutines.*
 
-@PublishedApi
 internal class SafeCollector<T>(
     private val collector: FlowCollector<T>,
     private val collectContext: CoroutineContext
@@ -99,3 +98,16 @@
         return parent.transitiveCoroutineParent(collectJob)
     }
 }
+
+/**
+ * An analogue of the [flow] builder that does not check the context of execution of the resulting flow.
+ * Used in our own operators where we trust the context of invocations.
+ */
+@PublishedApi
+internal inline fun <T> unsafeFlow(@BuilderInference crossinline block: suspend FlowCollector<T>.() -> Unit): Flow<T> {
+    return object : Flow<T> {
+        override suspend fun collect(collector: FlowCollector<T>) {
+            collector.block()
+        }
+    }
+}
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Context.kt b/kotlinx-coroutines-core/common/src/flow/operators/Context.kt
index c9aa555..8f3325c 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Context.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Context.kt
@@ -265,4 +265,3 @@
         "Flow context cannot contain job in it. Had $context"
     }
 }
-
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Delay.kt b/kotlinx-coroutines-core/common/src/flow/operators/Delay.kt
index 2f01061..8d74be5 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Delay.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Delay.kt
@@ -12,7 +12,7 @@
 import kotlinx.coroutines.flow.internal.*
 import kotlinx.coroutines.selects.*
 import kotlin.jvm.*
-import kotlinx.coroutines.flow.unsafeFlow as flow
+import kotlinx.coroutines.flow.internal.unsafeFlow as flow
 
 /**
  * Delays the emission of values from this flow for the given [timeMillis].
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Distinct.kt b/kotlinx-coroutines-core/common/src/flow/operators/Distinct.kt
index 45e971e..89491f4 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Distinct.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Distinct.kt
@@ -10,7 +10,7 @@
 import kotlinx.coroutines.*
 import kotlinx.coroutines.flow.internal.*
 import kotlin.jvm.*
-import kotlinx.coroutines.flow.unsafeFlow as flow
+import kotlinx.coroutines.flow.internal.unsafeFlow as flow
 
 /**
  * Returns flow where all subsequent repetitions of the same value are filtered out.
@@ -19,16 +19,36 @@
 public fun <T> Flow<T>.distinctUntilChanged(): Flow<T> = distinctUntilChangedBy { it }
 
 /**
+ * Returns flow where all subsequent repetitions of the same value are filtered out, when compared
+ * with each other via the provided [areEquivalent] function.
+ */
+@FlowPreview
+public fun <T> Flow<T>.distinctUntilChanged(areEquivalent: (old: T, new: T) -> Boolean): Flow<T> =
+    distinctUntilChangedBy(keySelector = { it }, areEquivalent = areEquivalent)
+
+/**
  * Returns flow where all subsequent repetitions of the same key are filtered out, where
  * key is extracted with [keySelector] function.
  */
 @FlowPreview
 public fun <T, K> Flow<T>.distinctUntilChangedBy(keySelector: (T) -> K): Flow<T> =
+    distinctUntilChangedBy(keySelector = keySelector, areEquivalent = { old, new -> old == new })
+
+/**
+ * Returns flow where all subsequent repetitions of the same key are filtered out, where
+ * keys are extracted with [keySelector] function and compared with each other via the
+ * provided [areEquivalent] function.
+ */
+private inline fun <T, K> Flow<T>.distinctUntilChangedBy(
+    crossinline keySelector: (T) -> K,
+    crossinline areEquivalent: (old: K, new: K) -> Boolean
+): Flow<T> =
     flow {
         var previousKey: Any? = NULL
         collect { value ->
             val key = keySelector(value)
-            if (previousKey != key) {
+            @Suppress("UNCHECKED_CAST")
+            if (previousKey === NULL || !areEquivalent(previousKey as K, key)) {
                 previousKey = key
                 emit(value)
             }
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Emitters.kt b/kotlinx-coroutines-core/common/src/flow/operators/Emitters.kt
new file mode 100644
index 0000000..f3a1126
--- /dev/null
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Emitters.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:JvmMultifileClass
+@file:JvmName("FlowKt")
+@file:Suppress("UNCHECKED_CAST")
+
+package kotlinx.coroutines.flow
+
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.internal.*
+import kotlin.coroutines.*
+import kotlin.jvm.*
+
+// ------------------ WARNING ------------------
+//   These emitting operators must use safe flow builder, because their allow
+//   user code to directly emit to the underlying FlowCollector.
+
+/**
+ * Applies [transform] function to each value of the given flow.
+ *
+ * The receiver of the [transform] is [FlowCollector] and thus `transform` is a
+ * generic function that may transform emitted element, skip it or emit it multiple times.
+ *
+ * This operator can be used as a building block for other operators, for example:
+ *
+ * ```
+ * fun Flow<Int>.skipOddAndDuplicateEven(): Flow<Int> = transform { value ->
+ *     if (value % 2 == 0) { // Emit only even values, but twice
+ *         emit(value)
+ *         emit(value)
+ *     } // Do nothing if odd
+ * }
+ * ```
+ */
+@ExperimentalCoroutinesApi
+public inline fun <T, R> Flow<T>.transform(
+    @BuilderInference crossinline transform: suspend FlowCollector<R>.(value: T) -> Unit
+): Flow<R> = flow { // Note: safe flow is used here, because collector is exposed to transform on each operation
+    collect { value ->
+        // kludge, without it Unit will be returned and TCE won't kick in, KT-28938
+        return@collect transform(value)
+    }
+}
+
+// For internal operator implementation
+@PublishedApi
+internal inline fun <T, R> Flow<T>.unsafeTransform(
+    @BuilderInference crossinline transform: suspend FlowCollector<R>.(value: T) -> Unit
+): Flow<R> = unsafeFlow { // Note: unsafe flow is used here, because unsafeTransform is only for internal use
+    collect { value ->
+        // kludge, without it Unit will be returned and TCE won't kick in, KT-28938
+        return@collect transform(value)
+    }
+}
+
+/**
+ * Invokes the given [action] when the this flow starts to be collected.
+ *
+ * The receiver of the [action] is [FlowCollector] and thus `onStart` can emit additional elements.
+ * For example:
+ *
+ * ```
+ * flowOf("a", "b", "c")
+ *     .onStart { emit("Begin") }
+ *     .collect { println(it) } // prints Begin, a, b, c
+ * ```
+ */
+@ExperimentalCoroutinesApi // tentatively stable in 1.3.0
+public fun <T> Flow<T>.onStart(
+    action: suspend FlowCollector<T>.() -> Unit
+): Flow<T> = unsafeFlow { // Note: unsafe flow is used here, but safe collector is used to invoke start action
+    SafeCollector<T>(this, coroutineContext).action()
+    collect(this) // directly delegate
+}
+
+/**
+ * Invokes the given [action] when the given flow is completed or cancelled, using
+ * the exception from the upstream (if any) as cause parameter of [action].
+ *
+ * Conceptually, `onCompletion` is similar to wrapping the flow collection into a `finally` block,
+ * for example the following imperative snippet:
+ *
+ * ```
+ * try {
+ *     myFlow.collect { value ->
+ *         println(value)
+ *     }
+ * } finally {
+ *     println("Done")
+ * }
+ * ```
+ *
+ * can be replaced with a declarative one using `onCompletion`:
+ *
+ * ```
+ * myFlow
+ *     .onEach { println(it) }
+ *     .onCompletion { println("Done") }
+ *     .collect()
+ * ```
+ *
+ * This operator is *transparent* to exceptions that occur in downstream flow
+ * and does not observe exceptions that are thrown to cancel the flow,
+ * while any exception from the [action] will be thrown downstream.
+ * This behaviour can be demonstrated by the following example:
+ *
+ * ```
+ * flow { emitData() }
+ *     .map { computeOne(it) }
+ *     .onCompletion { println(it) } // Can print exceptions from emitData and computeOne
+ *     .map { computeTwo(it) }
+ *     .onCompletion { println(it) } // Can print exceptions from emitData, computeOne, onCompletion and computeTwo
+ *     .collect()
+ * ```
+ *
+ * The receiver of the [action] is [FlowCollector] and this operator can be used to emit additional
+ * elements at the end of the collection. For example:
+ *
+ * ```
+ * flowOf("a", "b", "c")
+ *     .onCompletion { emit("Done") }
+ *     .collect { println(it) } // prints a, b, c, Done
+ * ```
+ */
+@ExperimentalCoroutinesApi // tentatively stable in 1.3.0
+public fun <T> Flow<T>.onCompletion(
+    action: suspend FlowCollector<T>.(cause: Throwable?) -> Unit
+): Flow<T> = unsafeFlow { // Note: unsafe flow is used here, but safe collector is used to invoke completion action
+    var exception: Throwable? = null
+    try {
+        exception = catchImpl(this)
+    } finally {
+        // Separate method because of KT-32220
+        SafeCollector<T>(this, coroutineContext).invokeSafely(action, exception)
+        exception?.let { throw it }
+    }
+}
+
+// It was only released in 1.3.0-M2, remove in 1.4.0
+/** @suppress */
+@Deprecated(level = DeprecationLevel.HIDDEN, message = "binary compatibility with a version w/o FlowCollector receiver")
+public fun <T> Flow<T>.onCompletion(action: suspend (cause: Throwable?) -> Unit) =
+    onCompletion { action(it) }
+
+private suspend fun <T> FlowCollector<T>.invokeSafely(
+    action: suspend FlowCollector<T>.(cause: Throwable?) -> Unit,
+    cause: Throwable?
+) {
+    try {
+        action(cause)
+    } catch (e: Throwable) {
+        if (cause !== null) e.addSuppressedThrowable(cause)
+        throw e
+    }
+}
+
+
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Errors.kt b/kotlinx-coroutines-core/common/src/flow/operators/Errors.kt
index c744842..9b7a91f 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Errors.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Errors.kt
@@ -11,7 +11,7 @@
 import kotlinx.coroutines.internal.*
 import kotlin.coroutines.*
 import kotlin.jvm.*
-import kotlinx.coroutines.flow.unsafeFlow as flow
+import kotlinx.coroutines.flow.internal.unsafeFlow as flow
 
 /**
  * Catches exceptions in the flow completion and calls a specified [action] with
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Limit.kt b/kotlinx-coroutines-core/common/src/flow/operators/Limit.kt
index f633612..7f638f9 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Limit.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Limit.kt
@@ -2,7 +2,6 @@
  * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
-
 @file:JvmMultifileClass
 @file:JvmName("FlowKt")
 
@@ -11,7 +10,7 @@
 import kotlinx.coroutines.*
 import kotlinx.coroutines.flow.internal.*
 import kotlin.jvm.*
-import kotlinx.coroutines.flow.unsafeFlow as flow
+import kotlinx.coroutines.flow.internal.unsafeFlow as flow
 
 /**
  * Returns a flow that ignores first [count] elements.
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Merge.kt b/kotlinx-coroutines-core/common/src/flow/operators/Merge.kt
index 3ed2c0b..e593d03 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Merge.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Merge.kt
@@ -16,7 +16,7 @@
 import kotlinx.coroutines.sync.*
 import kotlin.coroutines.*
 import kotlin.jvm.*
-import kotlinx.coroutines.flow.unsafeFlow as flow
+import kotlinx.coroutines.flow.internal.unsafeFlow as flow
 
 /**
  * Name of the property that defines the value of [DEFAULT_CONCURRENCY].
@@ -125,7 +125,7 @@
  * ```
  * produces `aa bb b_last`
  */
-@ExperimentalCoroutinesApi
+@FlowPreview
 public fun <T, R> Flow<T>.switchMap(transform: suspend (value: T) -> Flow<R>): Flow<R> = scopedFlow { downstream ->
     var previousFlow: Job? = null
     collect { value ->
@@ -167,7 +167,7 @@
     // Fast path in ChannelFlowOperator calls this function (channel was not created yet)
     override suspend fun flowCollect(collector: FlowCollector<T>) {
         // this function should not have been invoked when channel was explicitly requested
-        check(capacity == OPTIONAL_CHANNEL)
+        assert { capacity == OPTIONAL_CHANNEL }
         flowScope {
             mergeImpl(this, collector.asConcurrentFlowCollector())
         }
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Transform.kt b/kotlinx-coroutines-core/common/src/flow/operators/Transform.kt
index f6b32b3..37ba0d3 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Transform.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Transform.kt
@@ -10,73 +10,40 @@
 
 import kotlinx.coroutines.*
 import kotlinx.coroutines.flow.internal.*
-import kotlin.coroutines.*
 import kotlin.jvm.*
-import kotlinx.coroutines.flow.unsafeFlow as flow
-
-/**
- * Applies [transform] function to each value of the given flow.
- * [transform] is a generic function that may transform emitted element, skip it or emit it multiple times.
- *
- * This operator is useless by itself, but can be used as a building block of user-specific operators:
- * ```
- * fun Flow<Int>.skipOddAndDuplicateEven(): Flow<Int> = transform { value ->
- *     if (value % 2 == 0) { // Emit only even values, but twice
- *         emit(value)
- *         emit(value)
- *     } // Do nothing if odd
- * }
- * ```
- */
-@ExperimentalCoroutinesApi
-public inline fun <T, R> Flow<T>.transform(@BuilderInference crossinline transform: suspend FlowCollector<R>.(value: T) -> Unit): Flow<R> {
-    return flow {
-        collect { value ->
-            // kludge, without it Unit will be returned and TCE won't kick in, KT-28938
-            return@collect transform(value)
-        }
-    }
-}
+import kotlinx.coroutines.flow.internal.unsafeFlow as flow
+import kotlinx.coroutines.flow.unsafeTransform as transform
 
 /**
  * Returns a flow containing only values of the original flow that matches the given [predicate].
  */
-@ExperimentalCoroutinesApi
-public inline fun <T> Flow<T>.filter(crossinline predicate: suspend (T) -> Boolean): Flow<T> = flow {
-    collect { value ->
-        if (predicate(value)) return@collect emit(value)
-    }
+public inline fun <T> Flow<T>.filter(crossinline predicate: suspend (T) -> Boolean): Flow<T> = transform { value ->
+    if (predicate(value)) return@transform emit(value)
 }
 
 /**
  * Returns a flow containing only values of the original flow that do not match the given [predicate].
  */
-@ExperimentalCoroutinesApi
-public inline fun <T> Flow<T>.filterNot(crossinline predicate: suspend (T) -> Boolean): Flow<T> = flow {
-    collect { value ->
-        if (!predicate(value)) return@collect emit(value)
-    }
+public inline fun <T> Flow<T>.filterNot(crossinline predicate: suspend (T) -> Boolean): Flow<T> = transform { value ->
+    if (!predicate(value)) return@transform emit(value)
 }
 
 /**
  * Returns a flow containing only values that are instances of specified type [R].
  */
-@ExperimentalCoroutinesApi
 @Suppress("UNCHECKED_CAST")
 public inline fun <reified R> Flow<*>.filterIsInstance(): Flow<R> = filter { it is R } as Flow<R>
 
 /**
  * Returns a flow containing only values of the original flow that are not null.
  */
-@ExperimentalCoroutinesApi
-public fun <T: Any> Flow<T?>.filterNotNull(): Flow<T> = flow<T> {
-    collect { value -> if (value != null) return@collect  emit(value) }
+public fun <T: Any> Flow<T?>.filterNotNull(): Flow<T> = transform<T?, T> { value ->
+    if (value != null) return@transform emit(value)
 }
 
 /**
  * Returns a flow containing the results of applying the given [transform] function to each value of the original flow.
  */
-@ExperimentalCoroutinesApi
 public inline fun <T, R> Flow<T>.map(crossinline transform: suspend (value: T) -> R): Flow<R> = transform { value ->
    return@transform emit(transform(value))
 }
@@ -84,79 +51,28 @@
 /**
  * Returns a flow that contains only non-null results of applying the given [transform] function to each value of the original flow.
  */
-@ExperimentalCoroutinesApi
 public inline fun <T, R: Any> Flow<T>.mapNotNull(crossinline transform: suspend (value: T) -> R?): Flow<R> = transform { value ->
     val transformed = transform(value) ?: return@transform
     return@transform emit(transformed)
 }
 
 /**
- * Returns a flow which performs the given [action] on each value of the original flow.
+ * Returns a flow that wraps each element into [IndexedValue], containing value and its index (starting from zero).
  */
 @ExperimentalCoroutinesApi
-public fun <T> Flow<T>.onEach(action: suspend (T) -> Unit): Flow<T> = flow {
+public fun <T> Flow<T>.withIndex(): Flow<IndexedValue<T>> = flow {
+    var index = 0
     collect { value ->
-        action(value)
-        emit(value)
+        emit(IndexedValue(checkIndexOverflow(index++), value))
     }
 }
 
 /**
- * Invokes the given [action] when the given flow is completed or cancelled, using
- * the exception from the upstream (if any) as cause parameter of [action].
- *
- * Conceptually, [onCompletion] is similar to wrapping the flow collection into a `finally` block,
- * for example the following imperative snippet:
- * ```
- * try {
- *     myFlow.collect { value ->
- *         println(value)
- *     }
- * } finally {
- *     println("Done")
- * }
- * ```
- *
- * can be replaced with a declarative one using [onCompletion]:
- * ```
- * myFlow
- *     .onEach { println(it) }
- *     .onCompletion { println("Done") }
- *     .collect()
- * ```
- *
- * This operator is *transparent* to exceptions that occur in downstream flow
- * and does not observe exceptions that are thrown to cancel the flow,
- * while any exception from the [action] will be thrown downstream.
- * This behaviour can be demonstrated by the following example:
- * ```
- * flow { emitData() }
- *     .map { computeOne(it) }
- *     .onCompletion { println(it) } // Can print exceptions from emitData and computeOne
- *     .map { computeTwo(it) }
- *     .onCompletion { println(it) } // Can print exceptions from emitData, computeOne, onCompletion and computeTwo
- *     .collect()
- * ```
+ * Returns a flow which performs the given [action] on each value of the original flow.
  */
-@ExperimentalCoroutinesApi // tentatively stable in 1.3.0
-public fun <T> Flow<T>.onCompletion(action: suspend (cause: Throwable?) -> Unit): Flow<T> = flow {
-    var exception: Throwable? = null
-    try {
-        exception = catchImpl(this)
-    } finally {
-        // Separate method because of KT-32220
-        invokeSafely(action, exception)
-        exception?.let { throw it }
-    }
-}
-
-private suspend fun invokeSafely(action: suspend (cause: Throwable?) -> Unit, cause: Throwable?) {
-    try {
-        action(cause)
-    } catch (e: Throwable) {
-        if (cause !== null) e.addSuppressedThrowable(cause)
-        throw e
-    }
+public fun <T> Flow<T>.onEach(action: suspend (T) -> Unit): Flow<T> = transform { value ->
+    action(value)
+    return@transform emit(value)
 }
 
 /**
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Zip.kt b/kotlinx-coroutines-core/common/src/flow/operators/Zip.kt
index e9d99d3..72822bb 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Zip.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Zip.kt
@@ -13,7 +13,7 @@
 import kotlinx.coroutines.flow.internal.*
 import kotlinx.coroutines.selects.*
 import kotlin.jvm.*
-import kotlinx.coroutines.flow.unsafeFlow as flow
+import kotlinx.coroutines.flow.internal.unsafeFlow as flow
 
 /**
  * Returns a [Flow] whose values are generated with [transform] function by combining
@@ -28,7 +28,7 @@
  * }
  * ```
  */
-@ExperimentalCoroutinesApi
+@FlowPreview
 public fun <T1, T2, R> Flow<T1>.combineLatest(other: Flow<T2>, transform: suspend (T1, T2) -> R): Flow<R> = flow {
     coroutineScope {
         val firstChannel = asFairChannel(this@combineLatest)
@@ -80,7 +80,7 @@
  * Returns a [Flow] whose values are generated with [transform] function by combining
  * the most recently emitted values by each flow.
  */
-@ExperimentalCoroutinesApi
+@FlowPreview
 public inline fun <T1, T2, T3, R> Flow<T1>.combineLatest(
     other: Flow<T2>,
     other2: Flow<T3>,
@@ -97,7 +97,7 @@
  * Returns a [Flow] whose values are generated with [transform] function by combining
  * the most recently emitted values by each flow.
  */
-@ExperimentalCoroutinesApi
+@FlowPreview
 public inline fun <T1, T2, T3, T4, R> Flow<T1>.combineLatest(
     other: Flow<T2>,
     other2: Flow<T3>,
@@ -116,7 +116,7 @@
  * Returns a [Flow] whose values are generated with [transform] function by combining
  * the most recently emitted values by each flow.
  */
-@ExperimentalCoroutinesApi
+@FlowPreview
 public inline fun <T1, T2, T3, T4, T5, R> Flow<T1>.combineLatest(
     other: Flow<T2>,
     other2: Flow<T3>,
@@ -137,7 +137,7 @@
  * Returns a [Flow] whose values are generated with [transform] function by combining
  * the most recently emitted values by each flow.
  */
-@ExperimentalCoroutinesApi
+@FlowPreview
 public inline fun <reified T, R> Flow<T>.combineLatest(vararg others: Flow<T>, crossinline transform: suspend (Array<T>) -> R): Flow<R> =
     combineLatest(*others, arrayFactory = { arrayOfNulls(others.size + 1) }, transform = { transform(it) })
 
diff --git a/kotlinx-coroutines-core/common/src/flow/terminal/Collect.kt b/kotlinx-coroutines-core/common/src/flow/terminal/Collect.kt
index a98b7f3..42ac800 100644
--- a/kotlinx-coroutines-core/common/src/flow/terminal/Collect.kt
+++ b/kotlinx-coroutines-core/common/src/flow/terminal/Collect.kt
@@ -27,7 +27,6 @@
  *     .collect() // trigger collection of the flow
  * ```
  */
-@ExperimentalCoroutinesApi // tentatively stable in 1.3.0
 public suspend fun Flow<*>.collect() = collect(NopCollector)
 
 /**
@@ -69,13 +68,25 @@
  * }
  * ```
  */
-@ExperimentalCoroutinesApi
 public suspend inline fun <T> Flow<T>.collect(crossinline action: suspend (value: T) -> Unit): Unit =
     collect(object : FlowCollector<T> {
         override suspend fun emit(value: T) = action(value)
     })
 
 /**
+ * Terminal flow operator that collects the given flow with a provided [action] that takes the index of an element (zero-based) and the element.
+ * If any exception occurs during collect or in the provided flow, this exception is rethrown from this method.
+ *
+ * See also [collect] and [withIndex].
+ */
+@ExperimentalCoroutinesApi
+public suspend inline fun <T> Flow<T>.collectIndexed(crossinline action: suspend (index: Int, value: T) -> Unit): Unit =
+    collect(object : FlowCollector<T> {
+        private var index = 0
+        override suspend fun emit(value: T) = action(checkIndexOverflow(index++), value)
+    })
+
+/**
  * Collects all the values from the given [flow] and emits them to the collector.
  * 
  * It is a shorthand for `flow.collect { value -> emit(value) }`.
diff --git a/kotlinx-coroutines-core/common/src/flow/terminal/Collection.kt b/kotlinx-coroutines-core/common/src/flow/terminal/Collection.kt
index 836ea7e..e07be61 100644
--- a/kotlinx-coroutines-core/common/src/flow/terminal/Collection.kt
+++ b/kotlinx-coroutines-core/common/src/flow/terminal/Collection.kt
@@ -7,25 +7,21 @@
 
 package kotlinx.coroutines.flow
 
-import kotlinx.coroutines.*
 import kotlin.jvm.*
 
 /**
  * Collects given flow into a [destination]
  */
-@ExperimentalCoroutinesApi
 public suspend fun <T> Flow<T>.toList(destination: MutableList<T> = ArrayList()): List<T> = toCollection(destination)
 
 /**
  * Collects given flow into a [destination]
  */
-@ExperimentalCoroutinesApi
 public suspend fun <T> Flow<T>.toSet(destination: MutableSet<T> = LinkedHashSet()): Set<T> = toCollection(destination)
 
 /**
  * Collects given flow into a [destination]
  */
-@ExperimentalCoroutinesApi
 public suspend fun <T, C : MutableCollection<in T>> Flow<T>.toCollection(destination: C): C {
     collect { value ->
         destination.add(value)
diff --git a/kotlinx-coroutines-core/common/src/flow/terminal/Count.kt b/kotlinx-coroutines-core/common/src/flow/terminal/Count.kt
index 1d73700..d57dfde 100644
--- a/kotlinx-coroutines-core/common/src/flow/terminal/Count.kt
+++ b/kotlinx-coroutines-core/common/src/flow/terminal/Count.kt
@@ -27,7 +27,7 @@
  * Returns the number of elements matching the given predicate.
  */
 @ExperimentalCoroutinesApi
-public suspend fun <T> Flow<T>.count(predicate: suspend (T) -> Boolean): Int  {
+public suspend fun <T> Flow<T>.count(predicate: suspend (T) -> Boolean): Int {
     var i = 0
     collect { value ->
         if (predicate(value)) {
diff --git a/kotlinx-coroutines-core/common/src/flow/terminal/Reduce.kt b/kotlinx-coroutines-core/common/src/flow/terminal/Reduce.kt
index 8db762e..875e6b6 100644
--- a/kotlinx-coroutines-core/common/src/flow/terminal/Reduce.kt
+++ b/kotlinx-coroutines-core/common/src/flow/terminal/Reduce.kt
@@ -10,7 +10,7 @@
 
 import kotlinx.coroutines.*
 import kotlinx.coroutines.flow.internal.*
-import kotlinx.coroutines.flow.unsafeFlow as flow
+import kotlinx.coroutines.flow.internal.unsafeFlow as flow
 import kotlin.jvm.*
 
 /**
@@ -55,7 +55,6 @@
  * Throws [NoSuchElementException] for empty flow and [IllegalStateException] for flow
  * that contains more than one element.
  */
-@ExperimentalCoroutinesApi
 public suspend fun <T> Flow<T>.single(): T {
     var result: Any? = NULL
     collect { value ->
@@ -72,7 +71,6 @@
  * The terminal operator, that awaits for one and only one value to be published.
  * Throws [IllegalStateException] for flow that contains more than one element.
  */
-@ExperimentalCoroutinesApi
 public suspend fun <T: Any> Flow<T>.singleOrNull(): T? {
     var result: T? = null
     collect { value ->
@@ -87,7 +85,6 @@
  * The terminal operator that returns the first element emitted by the flow and then cancels flow's collection.
  * Throws [NoSuchElementException] if the flow was empty.
  */
-@ExperimentalCoroutinesApi
 public suspend fun <T> Flow<T>.first(): T {
     var result: Any? = NULL
     try {
@@ -107,7 +104,6 @@
  * The terminal operator that returns the first element emitted by the flow matching the given [predicate] and then cancels flow's collection.
  * Throws [NoSuchElementException] if the flow has not contained elements matching the [predicate].
  */
-@ExperimentalCoroutinesApi
 public suspend fun <T> Flow<T>.first(predicate: suspend (T) -> Boolean): T {
     var result: Any? = NULL
     try {
diff --git a/kotlinx-coroutines-core/common/src/internal/ArrayCopy.common.kt b/kotlinx-coroutines-core/common/src/internal/ArrayCopy.common.kt
deleted file mode 100644
index ac620ba..0000000
--- a/kotlinx-coroutines-core/common/src/internal/ArrayCopy.common.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.coroutines.internal
-
-/**
- * Cross-platform array copy. Overlaps of source and destination are not supported
- */
-internal expect fun <E> arraycopy(source: Array<E>, srcPos: Int, destination: Array<E?>, destinationStart: Int, length: Int)
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/common/src/internal/ArrayQueue.kt b/kotlinx-coroutines-core/common/src/internal/ArrayQueue.kt
index 759c0db..61a3233 100644
--- a/kotlinx-coroutines-core/common/src/internal/ArrayQueue.kt
+++ b/kotlinx-coroutines-core/common/src/internal/ArrayQueue.kt
@@ -36,9 +36,15 @@
         val currentSize = elements.size
         val newCapacity = currentSize shl 1
         val newElements = arrayOfNulls<Any>(newCapacity)
-        val remaining = elements.size - head
-        arraycopy(elements, head, newElements, 0, remaining)
-        arraycopy(elements, 0, newElements, remaining, head)
+        elements.copyInto(
+            destination = newElements,
+            startIndex = head
+        )
+        elements.copyInto(
+            destination = newElements,
+            destinationOffset = elements.size - head,
+            endIndex = head
+        )
         elements = newElements
         head = 0
         tail = currentSize
diff --git a/kotlinx-coroutines-core/common/src/internal/Atomic.kt b/kotlinx-coroutines-core/common/src/internal/Atomic.kt
index b589db2..bc52815 100644
--- a/kotlinx-coroutines-core/common/src/internal/Atomic.kt
+++ b/kotlinx-coroutines-core/common/src/internal/Atomic.kt
@@ -5,6 +5,7 @@
 package kotlinx.coroutines.internal
 
 import kotlinx.atomicfu.atomic
+import kotlinx.coroutines.*
 
 /**
  * The most abstract operation that can be in process. Other threads observing an instance of this
@@ -40,7 +41,7 @@
     val isDecided: Boolean get() = _consensus.value !== NO_DECISION
 
     fun tryDecide(decision: Any?): Boolean {
-        check(decision !== NO_DECISION)
+        assert { decision !== NO_DECISION }
         return _consensus.compareAndSet(NO_DECISION, decision)
     }
 
diff --git a/kotlinx-coroutines-core/jvm/src/internal/LockFreeTaskQueue.kt b/kotlinx-coroutines-core/common/src/internal/LockFreeTaskQueue.kt
similarity index 92%
rename from kotlinx-coroutines-core/jvm/src/internal/LockFreeTaskQueue.kt
rename to kotlinx-coroutines-core/common/src/internal/LockFreeTaskQueue.kt
index 5855dbb..6872310 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/LockFreeTaskQueue.kt
+++ b/kotlinx-coroutines-core/common/src/internal/LockFreeTaskQueue.kt
@@ -1,12 +1,12 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines.internal
 
 import kotlinx.atomicfu.*
-import java.util.*
-import java.util.concurrent.atomic.*
+import kotlinx.coroutines.*
+import kotlin.jvm.*
 
 private typealias Core<E> = LockFreeTaskQueueCore<E>
 
@@ -83,7 +83,7 @@
     private val mask = capacity - 1
     private val _next = atomic<Core<E>?>(null)
     private val _state = atomic(0L)
-    private val array = AtomicReferenceArray<Any?>(capacity)
+    private val array = atomicArrayOfNulls<Any?>(capacity)
 
     init {
         check(mask <= MAX_CAPACITY_MASK)
@@ -114,7 +114,7 @@
                 if ((tail + 2) and mask == head and mask) return ADD_FROZEN // overfull, so do freeze & copy
                 // If queue is Multi-Consumer then the consumer could still have not cleared element
                 // despite the above check for one free slot.
-                if (!singleConsumer && array[tail and mask] != null) {
+                if (!singleConsumer && array[tail and mask].value != null) {
                     // There are two options in this situation
                     // 1. Spin-wait until consumer clears the slot
                     // 2. Freeze & resize to avoid spinning
@@ -129,7 +129,7 @@
                 val newTail = (tail + 1) and MAX_CAPACITY_MASK
                 if (_state.compareAndSet(state, state.updateTail(newTail))) {
                     // successfully added
-                    array[tail and mask] = element
+                    array[tail and mask].value = element
                     // could have been frozen & copied before this item was set -- correct it by filling placeholder
                     var cur = this
                     while(true) {
@@ -143,7 +143,7 @@
     }
 
     private fun fillPlaceholder(index: Int, element: E): Core<E>? {
-        val old = array.get(index and mask)
+        val old = array[index and mask].value
         /*
          * addLast actions:
          * 1) Commit tail slot
@@ -155,7 +155,7 @@
          * perform *unique* check that current placeholder is our to avoid overwriting another producer placeholder
          */
         if (old is Placeholder && old.index == index) {
-            array.set(index and mask, element)
+            array[index and mask].value = element
             // we've corrected missing element, should check if that propagated to further copies, just in case
             return this
         }
@@ -172,7 +172,7 @@
             if (state and FROZEN_MASK != 0L) return REMOVE_FROZEN // frozen -- cannot modify
             state.withState { head, tail ->
                 if ((tail and mask) == (head and mask)) return null // empty
-                val element = array[head and mask]
+                val element = array[head and mask].value
                 if (element == null) {
                     // If queue is Single-Consumer, then element == null only when add has not finished yet
                     if (singleConsumer) return null // consider it not added yet
@@ -189,7 +189,7 @@
                 if (_state.compareAndSet(state, state.updateHead(newHead))) {
                     // Array could have been copied by another thread and it is perfectly fine, since only elements
                     // between head and tail were copied and there are no extra steps we should take here
-                    array[head and mask] = null // now can safely put null (state was updated)
+                    array[head and mask].value = null // now can safely put null (state was updated)
                     return element // successfully removed in fast-path
                 }
                 // Multi-Consumer queue must retry this loop on CAS failure (another consumer might have removed element)
@@ -207,13 +207,13 @@
     private fun removeSlowPath(oldHead: Int, newHead: Int): Core<E>? {
         _state.loop { state ->
             state.withState { head, _ ->
-                check(head == oldHead) { "This queue can have only one consumer" }
+                assert { head == oldHead } // "This queue can have only one consumer"
                 if (state and FROZEN_MASK != 0L) {
                     // state was already frozen, so removed element was copied to next
                     return next() // continue to correct head in next
                 }
                 if (_state.compareAndSet(state, state.updateHead(newHead))) {
-                    array[head and mask] = null // now can safely put null (state was updated)
+                    array[head and mask].value = null // now can safely put null (state was updated)
                     return null
                 }
             }
@@ -241,7 +241,8 @@
             var index = head
             while (index and mask != tail and mask) {
                 // replace nulls with placeholders on copy
-                next.array[index and next.mask] = array[index and mask] ?: Placeholder(index)
+                val value = array[index and mask].value ?: Placeholder(index)
+                next.array[index and next.mask].value = value
                 index++
             }
             next._state.value = state wo FROZEN_MASK
@@ -251,12 +252,12 @@
 
     // Used for validation in tests only
     fun <R> map(transform: (E) -> R): List<R> {
-        val res = ArrayList<R>(array.length())
+        val res = ArrayList<R>(capacity)
         _state.value.withState { head, tail ->
             var index = head
             while (index and mask != tail and mask) {
                 // replace nulls with placeholders on copy
-                val element = array[index and mask]
+                val element = array[index and mask].value
                 @Suppress("UNCHECKED_CAST")
                 if (element != null && element !is Placeholder) res.add(transform(element as E))
                 index++
diff --git a/kotlinx-coroutines-core/common/src/internal/SegmentQueue.kt b/kotlinx-coroutines-core/common/src/internal/SegmentQueue.kt
index 4ad554f..370fcfc 100644
--- a/kotlinx-coroutines-core/common/src/internal/SegmentQueue.kt
+++ b/kotlinx-coroutines-core/common/src/internal/SegmentQueue.kt
@@ -1,8 +1,11 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
 package kotlinx.coroutines.internal
 
-import kotlinx.atomicfu.AtomicRef
-import kotlinx.atomicfu.atomic
-import kotlinx.atomicfu.loop
+import kotlinx.atomicfu.*
+import kotlinx.coroutines.*
 
 /**
  * Essentially, this segment queue is an infinite array of segments, which is represented as
@@ -133,7 +136,7 @@
      * logically removed (so [removed] returns `true`) at the point of invocation.
      */
     fun remove() {
-        check(removed) { " The segment should be logically removed at first "}
+        assert { removed } // The segment should be logically removed at first
         // Read `next` and `prev` pointers.
         var next = this._next.value ?: return // tail cannot be removed
         var prev = prev.value ?: return // head cannot be removed
diff --git a/kotlinx-coroutines-core/common/src/internal/Synchronized.common.kt b/kotlinx-coroutines-core/common/src/internal/Synchronized.common.kt
index 6b05202..8bcc8f0 100644
--- a/kotlinx-coroutines-core/common/src/internal/Synchronized.common.kt
+++ b/kotlinx-coroutines-core/common/src/internal/Synchronized.common.kt
@@ -4,7 +4,16 @@
 
 package kotlinx.coroutines.internal
 
-internal expect open class SynchronizedObject() // marker abstract class
+import kotlinx.coroutines.*
 
-@PublishedApi
-internal expect inline fun <T> synchronized(lock: SynchronizedObject, block: () -> T): T
\ No newline at end of file
+/**
+ * @suppress **This an internal API and should not be used from general code.**
+ */
+@InternalCoroutinesApi
+public expect open class SynchronizedObject() // marker abstract class
+
+/**
+ * @suppress **This an internal API and should not be used from general code.**
+ */
+@InternalCoroutinesApi
+public expect inline fun <T> synchronized(lock: SynchronizedObject, block: () -> T): T
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/common/src/internal/ThreadSafeHeap.common.kt b/kotlinx-coroutines-core/common/src/internal/ThreadSafeHeap.common.kt
new file mode 100644
index 0000000..fa8e051
--- /dev/null
+++ b/kotlinx-coroutines-core/common/src/internal/ThreadSafeHeap.common.kt
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines.internal
+
+import kotlinx.atomicfu.*
+import kotlinx.coroutines.*
+
+/**
+ * @suppress **This an internal API and should not be used from general code.**
+ */
+@InternalCoroutinesApi
+public interface ThreadSafeHeapNode {
+    public var heap: ThreadSafeHeap<*>?
+    public var index: Int
+}
+
+/**
+ * Synchronized binary heap.
+ * @suppress **This an internal API and should not be used from general code.**
+ */
+@InternalCoroutinesApi
+public open class ThreadSafeHeap<T> : SynchronizedObject() where T: ThreadSafeHeapNode, T: Comparable<T> {
+    private var a: Array<T?>? = null
+
+    private val _size = atomic(0)
+
+    public var size: Int
+        get() = _size.value
+        private set(value) { _size.value = value }
+
+    public val isEmpty: Boolean get() = size == 0
+
+    public fun clear() = synchronized(this) {
+        a?.let { clear(it) }
+        _size.value = 0
+    }
+
+    public fun peek(): T? = synchronized(this) { firstImpl() }
+
+    public fun removeFirstOrNull(): T? = synchronized(this) {
+        if (size > 0) {
+            removeAtImpl(0)
+        } else {
+            null
+        }
+    }
+
+    // @Synchronized // NOTE! NOTE! NOTE! inline fun cannot be @Synchronized
+    public inline fun removeFirstIf(predicate: (T) -> Boolean): T? = synchronized(this) {
+        val first = firstImpl() ?: return null
+        if (predicate(first)) {
+            removeAtImpl(0)
+        } else {
+            null
+        }
+    }
+
+    public fun addLast(node: T) = synchronized(this) { addImpl(node) }
+
+    // @Synchronized // NOTE! NOTE! NOTE! inline fun cannot be @Synchronized
+    // Condition also receives current first node in the heap
+    public inline fun addLastIf(node: T, cond: (T?) -> Boolean): Boolean = synchronized(this) {
+        if (cond(firstImpl())) {
+            addImpl(node)
+            true
+        } else {
+            false
+        }
+    }
+
+    public fun remove(node: T): Boolean = synchronized(this) {
+        return if (node.heap == null) {
+            false
+        } else {
+            val index = node.index
+            assert { index >= 0 }
+            removeAtImpl(index)
+            true
+        }
+    }
+
+    @PublishedApi
+    internal fun firstImpl(): T? = a?.get(0)
+
+    @PublishedApi
+    internal fun removeAtImpl(index: Int): T {
+        assert { size > 0 }
+        val a = this.a!!
+        size--
+        if (index < size) {
+            swap(index, size)
+            val j = (index - 1) / 2
+            if (index > 0 && a[index]!! < a[j]!!) {
+                swap(index, j)
+                siftUpFrom(j)
+            } else {
+                siftDownFrom(index)
+            }
+        }
+        val result = a[size]!!
+        assert { result.heap === this }
+        result.heap = null
+        result.index = -1
+        a[size] = null
+        return result
+    }
+
+    @PublishedApi
+    internal fun addImpl(node: T) {
+        assert { node.heap == null }
+        node.heap = this
+        val a = realloc()
+        val i = size++
+        a[i] = node
+        node.index = i
+        siftUpFrom(i)
+    }
+
+    private tailrec fun siftUpFrom(i: Int) {
+        if (i <= 0) return
+        val a = a!!
+        val j = (i - 1) / 2
+        if (a[j]!! <= a[i]!!) return
+        swap(i, j)
+        siftUpFrom(j)
+    }
+
+    private tailrec fun siftDownFrom(i: Int) {
+        var j = 2 * i + 1
+        if (j >= size) return
+        val a = a!!
+        if (j + 1 < size && a[j + 1]!! < a[j]!!) j++
+        if (a[i]!! <= a[j]!!) return
+        swap(i, j)
+        siftDownFrom(j)
+    }
+
+    @Suppress("UNCHECKED_CAST")
+    private fun realloc(): Array<T?> {
+        val a = this.a
+        return when {
+            a == null -> (arrayOfNulls<ThreadSafeHeapNode>(4) as Array<T?>).also { this.a = it }
+            size >= a.size -> a.copyOf(size * 2).also { this.a = it }
+            else -> a
+        }
+    }
+
+    private fun swap(i: Int, j: Int) {
+        val a = a!!
+        val ni = a[j]!!
+        val nj = a[i]!!
+        a[i] = ni
+        a[j] = nj
+        ni.index = i
+        nj.index = j
+    }
+}
+
+internal expect fun <T> clear(a: Array<T?>)
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/common/src/selects/Select.kt b/kotlinx-coroutines-core/common/src/selects/Select.kt
index 9d71b7a..b42fde3 100644
--- a/kotlinx-coroutines-core/common/src/selects/Select.kt
+++ b/kotlinx-coroutines-core/common/src/selects/Select.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines.selects
@@ -234,7 +234,7 @@
     override val completion: Continuation<R> get() = this
 
     private inline fun doResume(value: () -> Any?, block: () -> Unit) {
-        check(isSelected) { "Must be selected first" }
+        assert { isSelected } // "Must be selected first"
         _result.loop { result ->
             when {
                 result === UNDECIDED -> if (_result.compareAndSet(UNDECIDED, value())) return
@@ -343,7 +343,7 @@
 
     // it is just like start(), but support idempotent start
     override fun trySelect(idempotent: Any?): Boolean {
-        check(idempotent !is OpDescriptor) { "cannot use OpDescriptor as idempotent marker"}
+        assert { idempotent !is OpDescriptor } // "cannot use OpDescriptor as idempotent marker"
         while (true) { // lock-free loop on state
             val state = this.state
             when {
diff --git a/kotlinx-coroutines-core/common/src/sync/Mutex.kt b/kotlinx-coroutines-core/common/src/sync/Mutex.kt
index b58885c..fa198e1 100644
--- a/kotlinx-coroutines-core/common/src/sync/Mutex.kt
+++ b/kotlinx-coroutines-core/common/src/sync/Mutex.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines.sync
@@ -206,7 +206,7 @@
                 is LockedQueue -> {
                     val curOwner = state.owner
                     check(curOwner !== owner) { "Already locked by $owner" }
-                    if (state.addLastIf(waiter, { _state.value === state })) {
+                    if (state.addLastIf(waiter) { _state.value === state }) {
                         // added to waiter list!
                         cont.removeOnCancellation(waiter)
                         return@sc
@@ -226,8 +226,7 @@
     override fun <R> registerSelectClause2(select: SelectInstance<R>, owner: Any?, block: suspend (Mutex) -> R) {
         while (true) { // lock-free loop on state
             if (select.isSelected) return
-            val state = _state.value
-            when (state) {
+            when (val state = _state.value) {
                 is Empty -> {
                     if (state.locked !== UNLOCKED) { // try upgrade to queue & retry
                         _state.compareAndSet(state, LockedQueue(state.locked))
@@ -388,7 +387,7 @@
     ) : LockWaiter(owner) {
         override fun tryResumeLockWaiter(): Any? = if (select.trySelect(null)) SELECT_SUCCESS else null
         override fun completeResumeLockWaiter(token: Any) {
-            check(token === SELECT_SUCCESS)
+            assert { token === SELECT_SUCCESS }
             block.startCoroutine(receiver = mutex, completion = select.completion)
         }
         override fun toString(): String = "LockSelect[$owner, $mutex, $select]"
diff --git a/kotlinx-coroutines-core/common/src/sync/Semaphore.kt b/kotlinx-coroutines-core/common/src/sync/Semaphore.kt
index 0ffb990..6e0552d 100644
--- a/kotlinx-coroutines-core/common/src/sync/Semaphore.kt
+++ b/kotlinx-coroutines-core/common/src/sync/Semaphore.kt
@@ -121,14 +121,16 @@
     }
 
     override fun release() {
-        val p = _availablePermits.getAndUpdate { cur ->
-            check(cur < permits) { "The number of acquired permits cannot be greater than `permits`" }
-            cur + 1
-        }
+        val p = incPermits()
         if (p >= 0) return // no waiters
         resumeNextFromQueue()
     }
 
+    internal fun incPermits() = _availablePermits.getAndUpdate { cur ->
+        check(cur < permits) { "The number of acquired permits cannot be greater than `permits`" }
+        cur + 1
+    }
+
     private suspend fun addToQueueAndSuspend() = suspendAtomicCancellableCoroutine<Unit> sc@ { cont ->
         val last = this.tail
         val enqIdx = enqIdx.getAndIncrement()
@@ -143,37 +145,37 @@
     }
 
     @Suppress("UNCHECKED_CAST")
-    private fun resumeNextFromQueue() {
-        val first = this.head
-        val deqIdx = deqIdx.getAndIncrement()
-        val segment = getSegmentAndMoveHead(first, deqIdx / SEGMENT_SIZE) ?: return
-        val i = (deqIdx % SEGMENT_SIZE).toInt()
-        val cont = segment.getAndUpdate(i) {
-            // Cancelled continuation invokes `release`
-            // and resumes next suspended acquirer if needed.
-            if (it === CANCELLED) return
-            RESUMED
+    internal fun resumeNextFromQueue() {
+        try_again@while (true) {
+            val first = this.head
+            val deqIdx = deqIdx.getAndIncrement()
+            val segment = getSegmentAndMoveHead(first, deqIdx / SEGMENT_SIZE) ?: continue@try_again
+            val i = (deqIdx % SEGMENT_SIZE).toInt()
+            val cont = segment.getAndSet(i, RESUMED)
+            if (cont === null) return // just resumed
+            if (cont === CANCELLED) continue@try_again
+            (cont as CancellableContinuation<Unit>).resume(Unit)
+            return
         }
-        if (cont === null) return // just resumed
-        (cont as CancellableContinuation<Unit>).resume(Unit)
     }
 }
 
 private class CancelSemaphoreAcquisitionHandler(
-    private val semaphore: Semaphore,
+    private val semaphore: SemaphoreImpl,
     private val segment: SemaphoreSegment,
     private val index: Int
 ) : CancelHandler() {
     override fun invoke(cause: Throwable?) {
-        segment.cancel(index)
-        semaphore.release()
+        semaphore.incPermits()
+        if (segment.cancel(index)) return
+        semaphore.resumeNextFromQueue()
     }
 
     override fun toString() = "CancelSemaphoreAcquisitionHandler[$semaphore, $segment, $index]"
 }
 
 private class SemaphoreSegment(id: Long, prev: SemaphoreSegment?): Segment<SemaphoreSegment>(id, prev) {
-    private val acquirers = atomicArrayOfNulls<Any?>(SEGMENT_SIZE)
+    val acquirers = atomicArrayOfNulls<Any?>(SEGMENT_SIZE)
 
     @Suppress("NOTHING_TO_INLINE")
     inline fun get(index: Int): Any? = acquirers[index].value
@@ -181,25 +183,21 @@
     @Suppress("NOTHING_TO_INLINE")
     inline fun cas(index: Int, expected: Any?, value: Any?): Boolean = acquirers[index].compareAndSet(expected, value)
 
-    inline fun getAndUpdate(index: Int, function: (Any?) -> Any?): Any? {
-        while (true) {
-            val cur = acquirers[index].value
-            val upd = function(cur)
-            if (cas(index, cur, upd)) return cur
-        }
-    }
+    @Suppress("NOTHING_TO_INLINE")
+    inline fun getAndSet(index: Int, value: Any?) = acquirers[index].getAndSet(value)
 
     private val cancelledSlots = atomic(0)
     override val removed get() = cancelledSlots.value == SEGMENT_SIZE
 
     // Cleans the acquirer slot located by the specified index
     // and removes this segment physically if all slots are cleaned.
-    fun cancel(index: Int) {
-        // Clean the specified waiter
-        acquirers[index].value = CANCELLED
+    fun cancel(index: Int): Boolean {
+        // Try to cancel the slot
+        val cancelled = getAndSet(index, CANCELLED) !== RESUMED
         // Remove this segment if needed
         if (cancelledSlots.incrementAndGet() == SEGMENT_SIZE)
             remove()
+        return cancelled
     }
 
     override fun toString() = "SemaphoreSegment[id=$id, hashCode=${hashCode()}]"
diff --git a/kotlinx-coroutines-core/common/test/channels/BasicOperationsTest.kt b/kotlinx-coroutines-core/common/test/channels/BasicOperationsTest.kt
index 167edba..a6ddd81 100644
--- a/kotlinx-coroutines-core/common/test/channels/BasicOperationsTest.kt
+++ b/kotlinx-coroutines-core/common/test/channels/BasicOperationsTest.kt
@@ -35,6 +35,11 @@
     }
 
     @Test
+    fun testReceiveOrClosed() = runTest {
+        TestChannelKind.values().forEach { kind -> testReceiveOrClosed(kind) }
+    }
+
+    @Test
     fun testInvokeOnClose() = TestChannelKind.values().forEach { kind ->
         reset()
         val channel = kind.create()
@@ -124,6 +129,34 @@
         assertTrue(d.getCancellationException().cause is TestException)
     }
 
+    @Suppress("ReplaceAssertBooleanWithAssertEquality")
+    private suspend fun testReceiveOrClosed(kind: TestChannelKind) = coroutineScope {
+        reset()
+        val channel = kind.create()
+        launch {
+            expect(2)
+            channel.send(1)
+        }
+
+        expect(1)
+        val result = channel.receiveOrClosed()
+        assertEquals(1, result.value)
+        assertEquals(1, result.valueOrNull)
+        assertTrue(ValueOrClosed.value(1) == result)
+
+        expect(3)
+        launch {
+            expect(4)
+            channel.close()
+        }
+        val closed = channel.receiveOrClosed()
+        expect(5)
+        assertNull(closed.valueOrNull)
+        assertTrue(closed.isClosed)
+        assertNull(closed.closeCause)
+        assertTrue(ValueOrClosed.closed<Int>(closed.closeCause) == closed)
+        finish(6)
+    }
 
     private suspend fun testOffer(kind: TestChannelKind) = coroutineScope {
         val channel = kind.create()
diff --git a/kotlinx-coroutines-core/common/test/channels/ProduceTest.kt b/kotlinx-coroutines-core/common/test/channels/ProduceTest.kt
index cbaf708..bf85c74 100644
--- a/kotlinx-coroutines-core/common/test/channels/ProduceTest.kt
+++ b/kotlinx-coroutines-core/common/test/channels/ProduceTest.kt
@@ -145,7 +145,7 @@
     fun testAwaitIllegalState() = runTest {
         val channel = produce<Int> {  }
         @Suppress("RemoveExplicitTypeArguments") // KT-31525
-        assertFailsWith<IllegalStateException> { (channel as ProducerScope<*>).awaitClose<Nothing>() }
+        assertFailsWith<IllegalStateException> { (channel as ProducerScope<*>).awaitClose() }
     }
 
     private suspend fun cancelOnCompletion(coroutineContext: CoroutineContext) = CoroutineScope(coroutineContext).apply {
diff --git a/kotlinx-coroutines-core/common/test/channels/TestChannelKind.kt b/kotlinx-coroutines-core/common/test/channels/TestChannelKind.kt
index 465699e..27c5816 100644
--- a/kotlinx-coroutines-core/common/test/channels/TestChannelKind.kt
+++ b/kotlinx-coroutines-core/common/test/channels/TestChannelKind.kt
@@ -58,6 +58,7 @@
 
     override suspend fun receive(): E = sub.receive()
     override suspend fun receiveOrNull(): E? = sub.receiveOrNull()
+    override suspend fun receiveOrClosed(): ValueOrClosed<E> = sub.receiveOrClosed()
     override fun poll(): E? = sub.poll()
     override fun iterator(): ChannelIterator<E> = sub.iterator()
     
@@ -71,4 +72,6 @@
         get() = sub.onReceive
     override val onReceiveOrNull: SelectClause1<E?>
         get() = sub.onReceiveOrNull
+    override val onReceiveOrClosed: SelectClause1<ValueOrClosed<E>>
+        get() = sub.onReceiveOrClosed
 }
diff --git a/kotlinx-coroutines-core/common/test/flow/NamedDispatchers.kt b/kotlinx-coroutines-core/common/test/flow/NamedDispatchers.kt
index 5e48bb6..67bcbdc 100644
--- a/kotlinx-coroutines-core/common/test/flow/NamedDispatchers.kt
+++ b/kotlinx-coroutines-core/common/test/flow/NamedDispatchers.kt
@@ -4,7 +4,6 @@
 
 package kotlinx.coroutines
 
-import kotlinx.coroutines.internal.*
 import kotlin.coroutines.*
 import kotlin.native.concurrent.*
 
@@ -55,9 +54,15 @@
         val currentSize = elements.size
         val newCapacity = currentSize shl 1
         val newElements = arrayOfNulls<String>(newCapacity)
-        val remaining = elements.size - head
-        arraycopy(elements, head, newElements, 0, remaining)
-        arraycopy(elements, 0, newElements, remaining, head)
+        elements.copyInto(
+            destination = newElements,
+            startIndex = head
+        )
+        elements.copyInto(
+            destination = newElements,
+            destinationOffset = elements.size - head,
+            endIndex = head
+        )
         elements = newElements
     }
 }
diff --git a/kotlinx-coroutines-core/common/test/flow/channels/ChannelBuildersFlowTest.kt b/kotlinx-coroutines-core/common/test/flow/channels/ChannelBuildersFlowTest.kt
index 3c74b0f..de5c220 100644
--- a/kotlinx-coroutines-core/common/test/flow/channels/ChannelBuildersFlowTest.kt
+++ b/kotlinx-coroutines-core/common/test/flow/channels/ChannelBuildersFlowTest.kt
@@ -10,6 +10,76 @@
 
 class ChannelBuildersFlowTest : TestBase() {
     @Test
+    fun testChannelConsumeAsFlow() = runTest {
+        val channel = produce {
+           repeat(10) {
+               send(it + 1)
+           }
+        }
+        val flow = channel.consumeAsFlow()
+        assertEquals(55, flow.sum())
+        assertFailsWith<IllegalStateException> { flow.collect() }
+    }
+
+    @Test
+    fun testConsumeAsFlowCancellation() = runTest {
+        val channel = produce(NonCancellable) { // otherwise failure will cancel scope as well
+            repeat(10) {
+                send(it + 1)
+            }
+            throw TestException()
+        }
+        val flow = channel.consumeAsFlow()
+        assertEquals(15, flow.take(5).sum())
+        // the channel should have been canceled, even though took only 5 elements
+        assertTrue(channel.isClosedForReceive)
+        assertFailsWith<IllegalStateException> { flow.collect() }
+    }
+
+    @Test
+    fun testConsumeAsFlowException() = runTest {
+        val channel = produce(NonCancellable) { // otherwise failure will cancel scope as well
+            repeat(10) {
+                send(it + 1)
+            }
+            throw TestException()
+        }
+        val flow = channel.consumeAsFlow()
+        assertFailsWith<TestException> { flow.sum() }
+        assertFailsWith<IllegalStateException> { flow.collect() }
+    }
+
+    @Test
+    fun testConsumeAsFlowProduceFusing() = runTest {
+        val channel = produce { send("OK") }
+        val flow = channel.consumeAsFlow()
+        assertSame(channel, flow.produceIn(this))
+        assertFailsWith<IllegalStateException> { flow.produceIn(this) }
+        channel.cancel()
+    }
+
+    @Test
+    fun testConsumeAsFlowProduceBuffered() = runTest {
+        expect(1)
+        val channel = produce {
+            expect(3)
+            (1..10).forEach { send(it) }
+            expect(4) // produces everything because of buffering
+        }
+        val flow = channel.consumeAsFlow().buffer() // request buffering
+        expect(2) // producer is not running yet
+        val result = flow.produceIn(this)
+        // run the flow pipeline until it consumes everything into buffer
+        while (!channel.isClosedForReceive) yield()
+        expect(5) // produced had done running (buffered stuff)
+        assertNotSame(channel, result)
+        assertFailsWith<IllegalStateException> { flow.produceIn(this) }
+        // check that we received everything
+        assertEquals((1..10).toList(), result.toList())
+        finish(6)
+    }
+
+    @Test
     fun testBroadcastChannelAsFlow() = runTest {
         val channel = broadcast {
            repeat(10) {
diff --git a/kotlinx-coroutines-core/common/test/flow/operators/DistinctUntilChangedTest.kt b/kotlinx-coroutines-core/common/test/flow/operators/DistinctUntilChangedTest.kt
index cb4fb83..fc03d36 100644
--- a/kotlinx-coroutines-core/common/test/flow/operators/DistinctUntilChangedTest.kt
+++ b/kotlinx-coroutines-core/common/test/flow/operators/DistinctUntilChangedTest.kt
@@ -33,6 +33,28 @@
     }
 
     @Test
+    fun testDistinctUntilChangedAreEquivalent() = runTest {
+        val flow = flow {
+            emit(Box(1))
+            emit(Box(1))
+            emit(Box(2))
+            emit(Box(1))
+        }
+
+        val sum1 = flow.distinctUntilChanged().map { it.i }.sum()
+        val sum2 = flow.distinctUntilChanged { old, new -> old.i == new.i }.map { it.i }.sum()
+        assertEquals(5, sum1)
+        assertEquals(4, sum2)
+    }
+
+    @Test
+    fun testDistinctUntilChangedAreEquivalentSingleValue() = runTest {
+        val flow = flowOf(1)
+        val values = flow.distinctUntilChanged { _, _ -> fail("Expected not to compare single value.") }.toList()
+        assertEquals(listOf(1), values)
+    }
+
+    @Test
     fun testThrowingKeySelector() = runTest {
         val flow = flow {
             coroutineScope {
@@ -50,8 +72,26 @@
     }
 
     @Test
-    fun testDistinctUntilChangedNull() = runTest{
-        val flow = flowOf(null, 1, null).distinctUntilChanged()
+    fun testThrowingAreEquivalent() = runTest {
+        val flow = flow {
+            coroutineScope {
+                launch(start = CoroutineStart.ATOMIC) {
+                    hang { expect(3) }
+                }
+                expect(2)
+                emit(1)
+                emit(2)
+            }
+        }.distinctUntilChanged { _, _ -> throw TestException() }
+
+        expect(1)
+        assertFailsWith<TestException>(flow)
+        finish(4)
+    }
+
+    @Test
+    fun testDistinctUntilChangedNull() = runTest {
+        val flow = flowOf(null, 1, null, null).distinctUntilChanged()
         assertEquals(listOf(null, 1, null), flow.toList())
     }
 }
diff --git a/kotlinx-coroutines-core/common/test/flow/operators/IndexedTest.kt b/kotlinx-coroutines-core/common/test/flow/operators/IndexedTest.kt
new file mode 100644
index 0000000..53db88d
--- /dev/null
+++ b/kotlinx-coroutines-core/common/test/flow/operators/IndexedTest.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines.flow
+
+import kotlinx.coroutines.*
+import kotlin.test.*
+
+class IndexedTest : TestBase() {
+
+    @Test
+    fun testWithIndex() = runTest {
+        val flow = flowOf(3, 2, 1).withIndex()
+        assertEquals(listOf(IndexedValue(0, 3), IndexedValue(1, 2), IndexedValue(2, 1)), flow.toList())
+    }
+
+    @Test
+    fun testWithIndexEmpty() = runTest {
+        val flow = emptyFlow<Int>().withIndex()
+        assertEquals(emptyList(), flow.toList())
+    }
+
+    @Test
+    fun testCollectIndexed() = runTest {
+        val result = ArrayList<IndexedValue<Long>>()
+        flowOf(3L, 2L, 1L).collectIndexed { index, value ->
+            result.add(IndexedValue(index, value))
+        }
+        assertEquals(listOf(IndexedValue(0, 3L), IndexedValue(1, 2L), IndexedValue(2, 1L)), result)
+    }
+
+    @Test
+    fun testCollectIndexedEmptyFlow() = runTest {
+        val flow = flow<Int> {
+            expect(1)
+        }
+
+        flow.collectIndexed { _, _ ->
+            expectUnreached()
+        }
+
+        finish(2)
+    }
+}
diff --git a/kotlinx-coroutines-core/common/test/flow/operators/OnCompletionTest.kt b/kotlinx-coroutines-core/common/test/flow/operators/OnCompletionTest.kt
index ff29481..af50608 100644
--- a/kotlinx-coroutines-core/common/test/flow/operators/OnCompletionTest.kt
+++ b/kotlinx-coroutines-core/common/test/flow/operators/OnCompletionTest.kt
@@ -112,4 +112,73 @@
             }.collect()
         finish(4)
     }
+
+    @Test
+    fun testEmitExample() = runTest {
+        val flow = flowOf("a", "b", "c")
+            .onCompletion() { emit("Done") }
+        assertEquals(listOf("a", "b", "c", "Done"), flow.toList())
+    }
+
+    sealed class TestData {
+        data class Value(val i: Int) : TestData()
+        data class Done(val e: Throwable?) : TestData() {
+            override fun equals(other: Any?): Boolean =
+                other is Done && other.e?.message == e?.message
+        }
+    }
+
+    @Test
+    fun testCrashedEmit() = runTest {
+        expect(1)
+        val collected = ArrayList<TestData>()
+        assertFailsWith<TestException> {
+            (1..10).asFlow()
+                .map<Int, TestData> { TestData.Value(it) }
+                .onEach { value ->
+                    value as TestData.Value
+                    expect(value.i + 1)
+                    if (value.i == 6) throw TestException("OK")
+                    yield()
+                }
+                .onCompletion { e ->
+                    expect(8)
+                    assertTrue(e is TestException)
+                    emit(TestData.Done(e))
+                }.collect {
+                    collected += it
+                }
+        }
+        val expected = (1..5).map { TestData.Value(it) } + TestData.Done(TestException("OK"))
+        assertEquals(expected, collected)
+        finish(9)
+    }
+
+    @Test
+    fun testCancelledEmit() = runTest {
+        expect(1)
+        val collected = ArrayList<TestData>()
+        assertFailsWith<JobCancellationException> {
+            coroutineScope {
+                (1..10).asFlow()
+                    .map<Int, TestData> { TestData.Value(it) }
+                    .onEach { value ->
+                        value as TestData.Value
+                        expect(value.i + 1)
+                        if (value.i == 6) coroutineContext.cancel()
+                        yield()
+                    }
+                    .onCompletion { e ->
+                        expect(8)
+                        assertNull(e)
+                        emit(TestData.Done(e))
+                    }.collect {
+                        collected += it
+                    }
+            }
+        }
+        val expected = (1..5).map { TestData.Value(it) } + TestData.Done(null)
+        assertEquals(expected, collected)
+        finish(9)
+    }
 }
diff --git a/kotlinx-coroutines-core/common/test/flow/operators/OnStartTest.kt b/kotlinx-coroutines-core/common/test/flow/operators/OnStartTest.kt
new file mode 100644
index 0000000..a0981ab
--- /dev/null
+++ b/kotlinx-coroutines-core/common/test/flow/operators/OnStartTest.kt
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines.flow
+
+import kotlinx.coroutines.*
+import kotlin.test.*
+
+class OnStartTest : TestBase() {
+    @Test
+    fun testEmitExample() = runTest {
+        val flow = flowOf("a", "b", "c")
+            .onStart { emit("Begin") }
+        assertEquals(listOf("Begin", "a", "b", "c"), flow.toList())
+    }
+}
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/common/test/flow/operators/TransformTest.kt b/kotlinx-coroutines-core/common/test/flow/operators/TransformTest.kt
new file mode 100644
index 0000000..feb3596
--- /dev/null
+++ b/kotlinx-coroutines-core/common/test/flow/operators/TransformTest.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines.flow
+
+import kotlinx.coroutines.*
+import kotlin.test.*
+
+class TransformTest : TestBase() {
+    @Test
+    fun testDoubleEmit() = runTest {
+         val flow = flowOf(1, 2, 3)
+             .transform {
+                 emit(it)
+                 emit(it)
+             }
+        assertEquals(listOf(1, 1, 2, 2, 3, 3), flow.toList())
+    }
+}
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/common/test/flow/terminal/SingleTest.kt b/kotlinx-coroutines-core/common/test/flow/terminal/SingleTest.kt
index 5ce6d47..f720595 100644
--- a/kotlinx-coroutines-core/common/test/flow/terminal/SingleTest.kt
+++ b/kotlinx-coroutines-core/common/test/flow/terminal/SingleTest.kt
@@ -7,7 +7,7 @@
 import kotlinx.coroutines.*
 import kotlin.test.*
 
-class SingleTest : TestBase() {
+class SingleTest : TestBase() { 
 
     @Test
     fun testSingle() = runTest {
diff --git a/kotlinx-coroutines-core/common/test/selects/SelectArrayChannelTest.kt b/kotlinx-coroutines-core/common/test/selects/SelectArrayChannelTest.kt
index f8c3439..ece95db 100644
--- a/kotlinx-coroutines-core/common/test/selects/SelectArrayChannelTest.kt
+++ b/kotlinx-coroutines-core/common/test/selects/SelectArrayChannelTest.kt
@@ -284,6 +284,104 @@
         finish(10)
     }
 
+    @Test
+    fun testSelectReceiveOrClosedWaitClosed() = runTest {
+        expect(1)
+        val channel = Channel<String>(1)
+        launch {
+            expect(3)
+            channel.close()
+            expect(4)
+        }
+        expect(2)
+        select<Unit> {
+            channel.onReceiveOrClosed {
+                expect(5)
+                assertTrue(it.isClosed)
+                assertNull(it.closeCause)
+            }
+        }
+
+        finish(6)
+    }
+
+    @Test
+    fun testSelectReceiveOrClosedWaitClosedWithCause() = runTest {
+        expect(1)
+        val channel = Channel<String>(1)
+        launch {
+            expect(3)
+            channel.close(TestException())
+            expect(4)
+        }
+        expect(2)
+        select<Unit> {
+            channel.onReceiveOrClosed {
+                expect(5)
+                assertTrue(it.isClosed)
+                assertTrue(it.closeCause is TestException)
+            }
+        }
+
+        finish(6)
+    }
+
+    @Test
+    fun testSelectReceiveOrClosed() = runTest {
+        val c = Channel<Int>(1)
+        val iterations = 10
+        expect(1)
+        val job = launch {
+            repeat(iterations) {
+                select<Unit> {
+                    c.onReceiveOrClosed { v ->
+                        expect(4 + it * 2)
+                        assertEquals(it, v.value)
+                    }
+                }
+            }
+        }
+
+        expect(2)
+        repeat(iterations) {
+            expect(3 + it * 2)
+            c.send(it)
+            yield()
+        }
+
+        job.join()
+        finish(3 + iterations * 2)
+    }
+
+    @Test
+    fun testSelectReceiveOrClosedDispatch() = runTest {
+        val c = Channel<Int>(1)
+        expect(1)
+        launch {
+            expect(3)
+            val res = select<String> {
+                c.onReceiveOrClosed { v ->
+                    expect(6)
+                    assertEquals(42, v.value)
+                    yield() // back to main
+                    expect(8)
+                    "OK"
+                }
+            }
+            expect(9)
+            assertEquals("OK", res)
+        }
+        expect(2)
+        yield() // to launch
+        expect(4)
+        c.send(42) // do not suspend
+        expect(5)
+        yield() // to receive
+        expect(7)
+        yield() // again
+        finish(10)
+    }
+
     // only for debugging
     internal fun <R> SelectBuilder<R>.default(block: suspend () -> R) {
         this as SelectBuilderImpl // type assertion
diff --git a/kotlinx-coroutines-core/common/test/selects/SelectRendezvousChannelTest.kt b/kotlinx-coroutines-core/common/test/selects/SelectRendezvousChannelTest.kt
index 0c1f9f6..ed8b8d3 100644
--- a/kotlinx-coroutines-core/common/test/selects/SelectRendezvousChannelTest.kt
+++ b/kotlinx-coroutines-core/common/test/selects/SelectRendezvousChannelTest.kt
@@ -305,6 +305,104 @@
         finish(10)
     }
 
+    @Test
+    fun testSelectReceiveOrClosedWaitClosed() = runTest {
+        expect(1)
+        val channel = Channel<String>(Channel.RENDEZVOUS)
+        launch {
+            expect(3)
+            channel.close()
+            expect(4)
+        }
+        expect(2)
+        select<Unit> {
+            channel.onReceiveOrClosed {
+                expect(5)
+                assertTrue(it.isClosed)
+                assertNull(it.closeCause)
+            }
+        }
+
+        finish(6)
+    }
+
+    @Test
+    fun testSelectReceiveOrClosedWaitClosedWithCause() = runTest {
+        expect(1)
+        val channel = Channel<String>(Channel.RENDEZVOUS)
+        launch {
+            expect(3)
+            channel.close(TestException())
+            expect(4)
+        }
+        expect(2)
+        select<Unit> {
+            channel.onReceiveOrClosed {
+                expect(5)
+                assertTrue(it.isClosed)
+                assertTrue(it.closeCause is TestException)
+            }
+        }
+
+        finish(6)
+    }
+
+    @Test
+    fun testSelectReceiveOrClosed() = runTest {
+        val channel = Channel<Int>(Channel.RENDEZVOUS)
+        val iterations = 10
+        expect(1)
+        val job = launch {
+            repeat(iterations) {
+                select<Unit> {
+                    channel.onReceiveOrClosed { v ->
+                        expect(4 + it * 2)
+                        assertEquals(it, v.value)
+                    }
+                }
+            }
+        }
+
+        expect(2)
+        repeat(iterations) {
+            expect(3 + it * 2)
+            channel.send(it)
+            yield()
+        }
+
+        job.join()
+        finish(3 + iterations * 2)
+    }
+
+    @Test
+    fun testSelectReceiveOrClosedDispatch() = runTest {
+        val c = Channel<Int>(Channel.RENDEZVOUS)
+        expect(1)
+        launch {
+            expect(3)
+            val res = select<String> {
+                c.onReceiveOrClosed { v ->
+                    expect(6)
+                    assertEquals(42, v.value)
+                    yield() // back to main
+                    expect(8)
+                    "OK"
+                }
+            }
+            expect(9)
+            assertEquals("OK", res)
+        }
+        expect(2)
+        yield() // to launch
+        expect(4)
+        c.send(42) // do not suspend
+        expect(5)
+        yield() // to receive
+        expect(7)
+        yield() // again
+        finish(10)
+    }
+
     // only for debugging
     internal fun <R> SelectBuilder<R>.default(block: suspend () -> R) {
         this as SelectBuilderImpl // type assertion
diff --git a/kotlinx-coroutines-core/common/test/sync/SemaphoreTest.kt b/kotlinx-coroutines-core/common/test/sync/SemaphoreTest.kt
index a6aaf24..dc14a12 100644
--- a/kotlinx-coroutines-core/common/test/sync/SemaphoreTest.kt
+++ b/kotlinx-coroutines-core/common/test/sync/SemaphoreTest.kt
@@ -102,7 +102,7 @@
     }
 
     @Test
-    fun testCancellationReleasesSemaphore() = runTest {
+    fun testCancellationReturnsPermitBack() = runTest {
         val semaphore = Semaphore(1)
         semaphore.acquire()
         assertEquals(0, semaphore.availablePermits)
@@ -116,4 +116,28 @@
         semaphore.release()
         assertEquals(1, semaphore.availablePermits)
     }
+
+    @Test
+    fun testCancellationDoesNotResumeWaitingAcquirers() = runTest {
+        val semaphore = Semaphore(1)
+        semaphore.acquire()
+        val job1 = launch { // 1st job in the waiting queue
+            expect(2)
+            semaphore.acquire()
+            expectUnreached()
+        }
+        val job2 = launch { // 2nd job in the waiting queue
+            expect(3)
+            semaphore.acquire()
+            expectUnreached()
+        }
+        expect(1)
+        yield()
+        expect(4)
+        job2.cancel()
+        yield()
+        expect(5)
+        job1.cancel()
+        finish(6)
+    }
 }
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/js/src/Debug.kt b/kotlinx-coroutines-core/js/src/Debug.kt
index 143cbb6..57a94d4 100644
--- a/kotlinx-coroutines-core/js/src/Debug.kt
+++ b/kotlinx-coroutines-core/js/src/Debug.kt
@@ -1,11 +1,13 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines
 
 private var counter = 0
 
+internal actual val DEBUG: Boolean = false
+
 internal actual val Any.hexAddress: String
     get() {
         var result = this.asDynamic().__debug_counter
@@ -18,3 +20,5 @@
     }
 
 internal actual val Any.classSimpleName: String get() = this::class.simpleName ?: "Unknown"
+
+internal actual inline fun assert(value: () -> Boolean) {}
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/js/src/EventLoop.kt b/kotlinx-coroutines-core/js/src/EventLoop.kt
index 7a27fe6..19d75c0 100644
--- a/kotlinx-coroutines-core/js/src/EventLoop.kt
+++ b/kotlinx-coroutines-core/js/src/EventLoop.kt
@@ -8,8 +8,20 @@
 
 internal actual fun createEventLoop(): EventLoop = UnconfinedEventLoop()
 
+internal actual fun nanoTime(): Long = unsupported()
+
 internal class UnconfinedEventLoop : EventLoop() {
-    override fun dispatch(context: CoroutineContext, block: Runnable) {
-        throw UnsupportedOperationException("runBlocking event loop is not supported")
-    }
+    override fun dispatch(context: CoroutineContext, block: Runnable): Unit = unsupported()
 }
+
+internal actual abstract class EventLoopImplPlatform : EventLoop() {
+    protected actual fun unpark(): Unit = unsupported()
+    protected actual fun reschedule(now: Long, delayedTask: EventLoopImplBase.DelayedTask): Unit = unsupported()
+}
+
+internal actual object DefaultExecutor {
+    public actual fun enqueue(task: Runnable): Unit = unsupported()
+}
+
+private fun unsupported(): Nothing =
+    throw UnsupportedOperationException("runBlocking event loop is not supported")
diff --git a/kotlinx-coroutines-core/js/src/internal/ArrayCopy.kt b/kotlinx-coroutines-core/js/src/internal/ArrayCopy.kt
deleted file mode 100644
index c6bd1aa..0000000
--- a/kotlinx-coroutines-core/js/src/internal/ArrayCopy.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.coroutines.internal
-
-internal actual fun <E> arraycopy(source: Array<E>, srcPos: Int, destination: Array<E?>, destinationStart: Int, length: Int) {
-    var destinationIndex = destinationStart
-    for (sourceIndex in srcPos until srcPos + length) {
-        destination[destinationIndex++] = source[sourceIndex]
-    }
-}
diff --git a/kotlinx-coroutines-core/js/src/internal/Synchronized.kt b/kotlinx-coroutines-core/js/src/internal/Synchronized.kt
index 1c12140..fbed546 100644
--- a/kotlinx-coroutines-core/js/src/internal/Synchronized.kt
+++ b/kotlinx-coroutines-core/js/src/internal/Synchronized.kt
@@ -4,9 +4,17 @@
 
 package kotlinx.coroutines.internal
 
-@Suppress("ACTUAL_WITHOUT_EXPECT") // visibility
-internal actual typealias SynchronizedObject = Any
+import kotlinx.coroutines.*
 
-@PublishedApi
-internal actual inline fun <T> synchronized(lock: SynchronizedObject, block: () -> T): T =
+/**
+ * @suppress **This an internal API and should not be used from general code.**
+ */
+@InternalCoroutinesApi
+public actual typealias SynchronizedObject = Any
+
+/**
+ * @suppress **This an internal API and should not be used from general code.**
+ */
+@InternalCoroutinesApi
+public actual inline fun <T> synchronized(lock: SynchronizedObject, block: () -> T): T =
     block()
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/js/src/internal/ThreadSafeHeap.kt b/kotlinx-coroutines-core/js/src/internal/ThreadSafeHeap.kt
new file mode 100644
index 0000000..f966c999
--- /dev/null
+++ b/kotlinx-coroutines-core/js/src/internal/ThreadSafeHeap.kt
@@ -0,0 +1,10 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines.internal
+
+@Suppress("NOTHING_TO_INLINE")
+internal actual inline fun <T> clear(a: Array<T?>) {
+    for (i in a.indices) a[i] = null
+}
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/js/test/internal/ArrayCopyKtTest.kt b/kotlinx-coroutines-core/js/test/internal/ArrayCopyKtTest.kt
deleted file mode 100644
index 42bc5ae..0000000
--- a/kotlinx-coroutines-core/js/test/internal/ArrayCopyKtTest.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.coroutines.internal
-
-import kotlin.test.*
-
-class ArrayCopyTest {
-
-    @Test
-    fun testArrayCopy() {
-        val source = Array(10, { it })
-        val destination = arrayOfNulls<Int>(7)
-        arraycopy(source, 2, destination, 1, 5)
-        assertEquals(listOf(null, 2, 3, 4, 5, 6, null), destination.toList())
-    }
-}
diff --git a/kotlinx-coroutines-core/jvm/src/Builders.kt b/kotlinx-coroutines-core/jvm/src/Builders.kt
index 52841cd..ac3cade 100644
--- a/kotlinx-coroutines-core/jvm/src/Builders.kt
+++ b/kotlinx-coroutines-core/jvm/src/Builders.kt
@@ -69,7 +69,7 @@
 
     @Suppress("UNCHECKED_CAST")
     fun joinBlocking(): T {
-        timeSource.registerTimeLoopThread()
+        registerTimeLoopThread()
         try {
             eventLoop?.incrementUseCount()
             try {
@@ -79,13 +79,13 @@
                     val parkNanos = eventLoop?.processNextEvent() ?: Long.MAX_VALUE
                     // note: process next even may loose unpark flag, so check if completed before parking
                     if (isCompleted) break
-                    timeSource.parkNanos(this, parkNanos)
+                    parkNanos(this, parkNanos)
                 }
             } finally { // paranoia
                 eventLoop?.decrementUseCount()
             }
         } finally { // paranoia
-            timeSource.unregisterTimeLoopThread()
+            unregisterTimeLoopThread()
         }
         // now return result
         val state = this.state.unboxState()
diff --git a/kotlinx-coroutines-core/jvm/src/CommonPool.kt b/kotlinx-coroutines-core/jvm/src/CommonPool.kt
index 7c8ac7c..1b5aae9 100644
--- a/kotlinx-coroutines-core/jvm/src/CommonPool.kt
+++ b/kotlinx-coroutines-core/jvm/src/CommonPool.kt
@@ -100,9 +100,9 @@
 
     override fun dispatch(context: CoroutineContext, block: Runnable) {
         try {
-            (pool ?: getOrCreatePoolSync()).execute(timeSource.wrapTask(block))
+            (pool ?: getOrCreatePoolSync()).execute(wrapTask(block))
         } catch (e: RejectedExecutionException) {
-            timeSource.unTrackTask()
+            unTrackTask()
             DefaultExecutor.enqueue(block)
         }
     }
diff --git a/kotlinx-coroutines-core/jvm/src/CoroutineContext.kt b/kotlinx-coroutines-core/jvm/src/CoroutineContext.kt
index bd586d6..1d0c4d6 100644
--- a/kotlinx-coroutines-core/jvm/src/CoroutineContext.kt
+++ b/kotlinx-coroutines-core/jvm/src/CoroutineContext.kt
@@ -9,13 +9,6 @@
 import java.util.concurrent.atomic.*
 import kotlin.coroutines.*
 
-private val COROUTINE_ID = AtomicLong()
-
-// for tests only
-internal fun resetCoroutineId() {
-    COROUTINE_ID.set(0)
-}
-
 internal const val COROUTINES_SCHEDULER_PROPERTY_NAME = "kotlinx.coroutines.scheduler"
 
 internal val useCoroutinesScheduler = systemProp(COROUTINES_SCHEDULER_PROPERTY_NAME).let { value ->
diff --git a/kotlinx-coroutines-core/jvm/src/Debug.kt b/kotlinx-coroutines-core/jvm/src/Debug.kt
index 3c750da..40de02a 100644
--- a/kotlinx-coroutines-core/jvm/src/Debug.kt
+++ b/kotlinx-coroutines-core/jvm/src/Debug.kt
@@ -1,11 +1,15 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
+// Need InlineOnly for efficient bytecode on Android
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+
 package kotlinx.coroutines
 
 import kotlinx.coroutines.internal.*
-import kotlin.coroutines.*
+import java.util.concurrent.atomic.*
+import kotlin.internal.InlineOnly
 
 /**
  * Name of the property that controls coroutine debugging. See [newCoroutineContext][CoroutineScope.newCoroutineContext].
@@ -68,10 +72,13 @@
  */
 public const val DEBUG_PROPERTY_VALUE_OFF = "off"
 
-@JvmField
-internal val DEBUG = systemProp(DEBUG_PROPERTY_NAME).let { value ->
+// @JvmField: Don't use JvmField here to enable R8 optimizations via "assumenosideeffects"
+internal val ASSERTIONS_ENABLED = CoroutineId::class.java.desiredAssertionStatus()
+
+// @JvmField: Don't use JvmField here to enable R8 optimizations via "assumenosideeffects"
+internal actual val DEBUG = systemProp(DEBUG_PROPERTY_NAME).let { value ->
     when (value) {
-        DEBUG_PROPERTY_VALUE_AUTO, null -> CoroutineId::class.java.desiredAssertionStatus()
+        DEBUG_PROPERTY_VALUE_AUTO, null -> ASSERTIONS_ENABLED
         DEBUG_PROPERTY_VALUE_ON, "" -> true
         DEBUG_PROPERTY_VALUE_OFF -> false
         else -> error("System property '$DEBUG_PROPERTY_NAME' has unrecognized value '$value'")
@@ -79,18 +86,19 @@
 }
 
 // Note: stack-trace recovery is enabled only in debug mode
-@JvmField
-internal actual val RECOVER_STACK_TRACES = DEBUG && systemProp(STACKTRACE_RECOVERY_PROPERTY_NAME, true)
+// @JvmField: Don't use JvmField here to enable R8 optimizations via "assumenosideeffects"
+internal actual val RECOVER_STACK_TRACES =
+    DEBUG && systemProp(STACKTRACE_RECOVERY_PROPERTY_NAME, true)
 
-// internal debugging tools
+// It is used only in debug mode
+internal val COROUTINE_ID = AtomicLong(0)
 
-internal actual val Any.hexAddress: String
-    get() = Integer.toHexString(System.identityHashCode(this))
-
-internal actual fun Continuation<*>.toDebugString(): String = when (this) {
-    is DispatchedContinuation -> toString()
-    // Workaround for #858
-    else -> kotlin.runCatching { "$this@$hexAddress" }.getOrElse { "${this::class.java.name}@$hexAddress" }
+// for tests only
+internal fun resetCoroutineId() {
+    COROUTINE_ID.set(0)
 }
 
-internal actual val Any.classSimpleName: String get() = this::class.java.simpleName
+@InlineOnly
+internal actual inline fun assert(value: () -> Boolean) {
+    if (ASSERTIONS_ENABLED && !value()) throw AssertionError()
+}
diff --git a/kotlinx-coroutines-core/jvm/src/DebugStrings.kt b/kotlinx-coroutines-core/jvm/src/DebugStrings.kt
new file mode 100644
index 0000000..78ad418
--- /dev/null
+++ b/kotlinx-coroutines-core/jvm/src/DebugStrings.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines
+
+import kotlin.coroutines.*
+
+// internal debugging tools for string representation
+
+internal actual val Any.hexAddress: String
+    get() = Integer.toHexString(System.identityHashCode(this))
+
+internal actual fun Continuation<*>.toDebugString(): String = when (this) {
+    is DispatchedContinuation -> toString()
+    // Workaround for #858
+    else -> runCatching { "$this@$hexAddress" }.getOrElse { "${this::class.java.name}@$hexAddress" }
+}
+
+internal actual val Any.classSimpleName: String get() = this::class.java.simpleName
diff --git a/kotlinx-coroutines-core/jvm/src/DefaultExecutor.kt b/kotlinx-coroutines-core/jvm/src/DefaultExecutor.kt
index 8358dcc..19adcef 100644
--- a/kotlinx-coroutines-core/jvm/src/DefaultExecutor.kt
+++ b/kotlinx-coroutines-core/jvm/src/DefaultExecutor.kt
@@ -9,7 +9,7 @@
 internal actual val DefaultDelay: Delay = DefaultExecutor
 
 @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
-internal object DefaultExecutor : EventLoopImplBase(), Runnable {
+internal actual object DefaultExecutor : EventLoopImplBase(), Runnable {
     const val THREAD_NAME = "kotlinx.coroutines.DefaultExecutor"
 
     init {
@@ -55,11 +55,11 @@
      * but it's not exposed as public API.
      */
     override fun invokeOnTimeout(timeMillis: Long, block: Runnable): DisposableHandle =
-        DelayedRunnableTask(timeMillis, block).also { schedule(it) }
+        scheduleInvokeOnTimeout(timeMillis, block)
 
     override fun run() {
         ThreadLocalEventLoop.setEventLoop(this)
-        timeSource.registerTimeLoopThread()
+        registerTimeLoopThread()
         try {
             var shutdownNanos = Long.MAX_VALUE
             if (!notifyStartup()) return
@@ -69,7 +69,7 @@
                 if (parkNanos == Long.MAX_VALUE) {
                     // nothing to do, initialize shutdown timeout
                     if (shutdownNanos == Long.MAX_VALUE) {
-                        val now = timeSource.nanoTime()
+                        val now = nanoTime()
                         if (shutdownNanos == Long.MAX_VALUE) shutdownNanos = now + KEEP_ALIVE_NANOS
                         val tillShutdown = shutdownNanos - now
                         if (tillShutdown <= 0) return // shut thread down
@@ -80,13 +80,13 @@
                 if (parkNanos > 0) {
                     // check if shutdown was requested and bail out in this case
                     if (isShutdownRequested) return
-                    timeSource.parkNanos(this, parkNanos)
+                    parkNanos(this, parkNanos)
                 }
             }
         } finally {
             _thread = null // this thread is dead
             acknowledgeShutdownIfNeeded()
-            timeSource.unregisterTimeLoopThread()
+            unregisterTimeLoopThread()
             // recheck if queues are empty after _thread reference was set to null (!!!)
             if (!isEmpty) thread // recreate thread if it is needed
         }
@@ -104,8 +104,8 @@
     // used for tests
     @Synchronized
     internal fun ensureStarted() {
-        assert(_thread == null) // ensure we are at a clean state
-        assert(debugStatus == FRESH || debugStatus == SHUTDOWN_ACK)
+        assert { _thread == null } // ensure we are at a clean state
+        assert { debugStatus == FRESH || debugStatus == SHUTDOWN_ACK }
         debugStatus = FRESH
         createThreadSync() // create fresh thread
         while (debugStatus == FRESH) (this as Object).wait()
@@ -126,7 +126,7 @@
         if (!isShutdownRequested) debugStatus = SHUTDOWN_REQ
         // loop while there is anything to do immediately or deadline passes
         while (debugStatus != SHUTDOWN_ACK && _thread != null) {
-            _thread?.let { timeSource.unpark(it) } // wake up thread if present
+            _thread?.let { unpark(it) } // wake up thread if present
             val remaining = deadline - System.currentTimeMillis()
             if (remaining <= 0) break
             (this as Object).wait(timeout)
diff --git a/kotlinx-coroutines-core/jvm/src/EventLoop.kt b/kotlinx-coroutines-core/jvm/src/EventLoop.kt
index 5d214d1..598f424 100644
--- a/kotlinx-coroutines-core/jvm/src/EventLoop.kt
+++ b/kotlinx-coroutines-core/jvm/src/EventLoop.kt
@@ -1,311 +1,21 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines
 
-import kotlinx.atomicfu.*
-import kotlinx.coroutines.internal.*
-import kotlin.coroutines.*
-
-private val DISPOSED_TASK = Symbol("REMOVED_TASK")
-
-// results for scheduleImpl
-private const val SCHEDULE_OK = 0
-private const val SCHEDULE_COMPLETED = 1
-private const val SCHEDULE_DISPOSED = 2
-
-private const val MS_TO_NS = 1_000_000L
-private const val MAX_MS = Long.MAX_VALUE / MS_TO_NS
-
-internal fun delayToNanos(timeMillis: Long): Long = when {
-    timeMillis <= 0 -> 0L
-    timeMillis >= MAX_MS -> Long.MAX_VALUE
-    else -> timeMillis * MS_TO_NS
-}
-
-internal fun delayNanosToMillis(timeNanos: Long): Long =
-    timeNanos / MS_TO_NS
-
-@Suppress("PrivatePropertyName")
-private val CLOSED_EMPTY = Symbol("CLOSED_EMPTY")
-
-private typealias Queue<T> = LockFreeTaskQueueCore<T>
-
-internal abstract class EventLoopImplBase: EventLoop(), Delay {
-    // null | CLOSED_EMPTY | task | Queue<Runnable>
-    private val _queue = atomic<Any?>(null)
-
-    // Allocated only only once
-    private val _delayed = atomic<ThreadSafeHeap<DelayedTask>?>(null)
-
+internal actual abstract class EventLoopImplPlatform: EventLoop() {
     protected abstract val thread: Thread
 
-    @Volatile
-    private var isCompleted = false
-
-    override val isEmpty: Boolean get() {
-        if (!isUnconfinedQueueEmpty) return false
-        val delayed = _delayed.value
-        if (delayed != null && !delayed.isEmpty) return false
-        val queue = _queue.value
-        return when (queue) {
-            null -> true
-            is Queue<*> -> queue.isEmpty
-            else -> queue === CLOSED_EMPTY
-        }
-    }
-
-    protected override val nextTime: Long
-        get() {
-            if (super.nextTime == 0L) return 0L 
-            val queue = _queue.value
-            when {
-                queue === null -> {} // empty queue -- proceed
-                queue is Queue<*> -> if (!queue.isEmpty) return 0 // non-empty queue
-                queue === CLOSED_EMPTY -> return Long.MAX_VALUE // no more events -- closed
-                else -> return 0 // non-empty queue
-            }
-            val delayed = _delayed.value ?: return Long.MAX_VALUE
-            val nextDelayedTask = delayed.peek() ?: return Long.MAX_VALUE
-            return (nextDelayedTask.nanoTime - timeSource.nanoTime()).coerceAtLeast(0)
-        }
-
-    private fun unpark() {
-        val thread = thread
+    protected actual fun unpark() {
+        val thread = thread // atomic read
         if (Thread.currentThread() !== thread)
-            timeSource.unpark(thread)
+            unpark(thread)
     }
 
-    override fun shutdown() {
-        // Clean up thread-local reference here -- this event loop is shutting down
-        ThreadLocalEventLoop.resetEventLoop()
-        // We should signal that this event loop should not accept any more tasks
-        // and process queued events (that could have been added after last processNextEvent)
-        isCompleted = true
-        closeQueue()
-        // complete processing of all queued tasks
-        while (processNextEvent() <= 0) { /* spin */ }
-        // reschedule the rest of delayed tasks
-        rescheduleAllDelayed()
-    }
-
-    override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) =
-        schedule(DelayedResumeTask(timeMillis, continuation))
-
-    override fun processNextEvent(): Long {
-        // unconfined events take priority
-        if (processUnconfinedEvent()) return nextTime
-        // queue all delayed tasks that are due to be executed
-        val delayed = _delayed.value
-        if (delayed != null && !delayed.isEmpty) {
-            val now = timeSource.nanoTime()
-            while (true) {
-                // make sure that moving from delayed to queue removes from delayed only after it is added to queue
-                // to make sure that 'isEmpty' and `nextTime` that check both of them
-                // do not transiently report that both delayed and queue are empty during move
-                delayed.removeFirstIf {
-                    if (it.timeToExecute(now)) {
-                        enqueueImpl(it)
-                    } else
-                        false
-                } ?: break // quit loop when nothing more to remove or enqueueImpl returns false on "isComplete"
-            }
-        }
-        // then process one event from queue
-        dequeue()?.run()
-        return nextTime
-    }
-
-    public final override fun dispatch(context: CoroutineContext, block: Runnable) = enqueue(block)
-
-    public fun enqueue(task: Runnable) {
-        if (enqueueImpl(task)) {
-            // todo: we should unpark only when this delayed task became first in the queue
-            unpark()
-        } else {
-            DefaultExecutor.enqueue(task)
-        }
-    }
-
-    @Suppress("UNCHECKED_CAST")
-    private fun enqueueImpl(task: Runnable): Boolean {
-        _queue.loop { queue ->
-            if (isCompleted) return false // fail fast if already completed, may still add, but queues will close
-            when (queue) {
-                null -> if (_queue.compareAndSet(null, task)) return true
-                is Queue<*> -> {
-                    when ((queue as Queue<Runnable>).addLast(task)) {
-                        Queue.ADD_SUCCESS -> return true
-                        Queue.ADD_CLOSED -> return false
-                        Queue.ADD_FROZEN -> _queue.compareAndSet(queue, queue.next())
-                    }
-                }
-                else -> when {
-                    queue === CLOSED_EMPTY -> return false
-                    else -> {
-                        // update to full-blown queue to add one more
-                        val newQueue = Queue<Runnable>(Queue.INITIAL_CAPACITY, singleConsumer = true)
-                        newQueue.addLast(queue as Runnable)
-                        newQueue.addLast(task)
-                        if (_queue.compareAndSet(queue, newQueue)) return true
-                    }
-                }
-            }
-        }
-    }
-
-    @Suppress("UNCHECKED_CAST")
-    private fun dequeue(): Runnable? {
-        _queue.loop { queue ->
-            when (queue) {
-                null -> return null
-                is Queue<*> -> {
-                    val result = (queue as Queue<Runnable>).removeFirstOrNull()
-                    if (result !== Queue.REMOVE_FROZEN) return result as Runnable?
-                    _queue.compareAndSet(queue, queue.next())
-                }
-                else -> when {
-                    queue === CLOSED_EMPTY -> return null
-                    else -> if (_queue.compareAndSet(queue, null)) return queue as Runnable
-                }
-            }
-        }
-    }
-
-    private fun closeQueue() {
-        assert(isCompleted)
-        _queue.loop { queue ->
-            when (queue) {
-                null -> if (_queue.compareAndSet(null, CLOSED_EMPTY)) return
-                is Queue<*> -> {
-                    queue.close()
-                    return
-                }
-                else -> when {
-                    queue === CLOSED_EMPTY -> return
-                    else -> {
-                        // update to full-blown queue to close
-                        val newQueue = Queue<Runnable>(Queue.INITIAL_CAPACITY, singleConsumer = true)
-                        newQueue.addLast(queue as Runnable)
-                        if (_queue.compareAndSet(queue, newQueue)) return
-                    }
-                }
-            }
-        }
-
-    }
-
-    internal fun schedule(delayedTask: DelayedTask) {
-        when (scheduleImpl(delayedTask)) {
-            SCHEDULE_OK -> if (shouldUnpark(delayedTask)) unpark()
-            SCHEDULE_COMPLETED -> DefaultExecutor.schedule(delayedTask)
-            SCHEDULE_DISPOSED -> {} // do nothing -- task was already disposed
-            else -> error("unexpected result")
-        }
-    }
-
-    private fun shouldUnpark(task: DelayedTask): Boolean = _delayed.value?.peek() === task
-
-    private fun scheduleImpl(delayedTask: DelayedTask): Int {
-        if (isCompleted) return SCHEDULE_COMPLETED
-        val delayed = _delayed.value ?: run {
-            _delayed.compareAndSet(null, ThreadSafeHeap())
-            _delayed.value!!
-        }
-        return delayedTask.schedule(delayed, this)
-    }
-
-    // It performs "hard" shutdown for test cleanup purposes
-    protected fun resetAll() {
-        _queue.value = null
-        _delayed.value = null
-    }
-
-    // This is a "soft" (normal) shutdown
-    private fun rescheduleAllDelayed() {
-        while (true) {
-            /*
-             * `removeFirstOrNull` below is the only operation on DelayedTask & ThreadSafeHeap that is not
-             * synchronized on DelayedTask itself. All other operation are synchronized both on
-             * DelayedTask & ThreadSafeHeap instances (in this order). It is still safe, because `dispose`
-             * first removes DelayedTask from the heap (under synchronization) then
-             * assign "_heap = DISPOSED_TASK", so there cannot be ever a race to _heap reference update.
-             */
-            val delayedTask = _delayed.value?.removeFirstOrNull() ?: break
-            delayedTask.rescheduleOnShutdown()
-        }
-    }
-
-    internal abstract class DelayedTask(
-        timeMillis: Long
-    ) : Runnable, Comparable<DelayedTask>, DisposableHandle, ThreadSafeHeapNode {
-        private var _heap: Any? = null // null | ThreadSafeHeap | DISPOSED_TASK
-        
-        override var heap: ThreadSafeHeap<*>?
-            get() = _heap as? ThreadSafeHeap<*>
-            set(value) {
-                require(_heap !== DISPOSED_TASK) // this can never happen, it is always checked before adding/removing
-                _heap = value
-            }
-        
-        override var index: Int = -1
-        
-        @JvmField val nanoTime: Long = timeSource.nanoTime() + delayToNanos(timeMillis)
-
-        override fun compareTo(other: DelayedTask): Int {
-            val dTime = nanoTime - other.nanoTime
-            return when {
-                dTime > 0 -> 1
-                dTime < 0 -> -1
-                else -> 0
-            }
-        }
-
-        fun timeToExecute(now: Long): Boolean = now - nanoTime >= 0L
-
-        @Synchronized
-        fun schedule(delayed: ThreadSafeHeap<DelayedTask>, eventLoop: EventLoopImplBase): Int {
-            if (_heap === DISPOSED_TASK) return SCHEDULE_DISPOSED // don't add -- was already disposed
-            return if (delayed.addLastIf(this) { !eventLoop.isCompleted }) SCHEDULE_OK else SCHEDULE_COMPLETED
-        }
-
-        // note: DefaultExecutor.schedule performs `schedule` (above) which does sync & checks for DISPOSED_TASK
-        fun rescheduleOnShutdown() = DefaultExecutor.schedule(this)
-
-        @Synchronized
-        final override fun dispose() {
-            val heap = _heap
-            if (heap === DISPOSED_TASK) return // already disposed
-            @Suppress("UNCHECKED_CAST")
-            (heap as? ThreadSafeHeap<DelayedTask>)?.remove(this) // remove if it is in heap (first)
-            _heap = DISPOSED_TASK // never add again to any heap
-        }
-
-        override fun toString(): String = "Delayed[nanos=$nanoTime]"
-    }
-
-    private inner class DelayedResumeTask(
-        timeMillis: Long,
-        private val cont: CancellableContinuation<Unit>
-    ) : DelayedTask(timeMillis) {
-        init {
-            // Note that this operation isn't lock-free, but very short
-            cont.disposeOnCancellation(this)
-        }
-
-        override fun run() {
-            with(cont) { resumeUndispatched(Unit) }
-        }
-    }
-
-    // Cannot be moved to DefaultExecutor due to BE bug
-    internal class DelayedRunnableTask(
-        time: Long,
-        private val block: Runnable
-    ) : DelayedTask(time) {
-        override fun run() { block.run() }
-        override fun toString(): String = super.toString() + block.toString()
+    protected actual fun reschedule(now: Long, delayedTask: EventLoopImplBase.DelayedTask) {
+        assert { this !== DefaultExecutor } // otherwise default execution was shutdown with tasks in it (cannot be)
+        DefaultExecutor.schedule(now, delayedTask)
     }
 }
 
@@ -336,4 +46,4 @@
  */
 @InternalCoroutinesApi
 public fun processNextEventInCurrentThread(): Long =
-    ThreadLocalEventLoop.currentOrNull()?.processNextEvent() ?: Long.MAX_VALUE
+    ThreadLocalEventLoop.currentOrNull()?.processNextEvent() ?: Long.MAX_VALUE
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/jvm/src/Executors.kt b/kotlinx-coroutines-core/jvm/src/Executors.kt
index 876b44a..c5ce537 100644
--- a/kotlinx-coroutines-core/jvm/src/Executors.kt
+++ b/kotlinx-coroutines-core/jvm/src/Executors.kt
@@ -61,9 +61,9 @@
 
     override fun dispatch(context: CoroutineContext, block: Runnable) {
         try {
-            executor.execute(timeSource.wrapTask(block))
+            executor.execute(wrapTask(block))
         } catch (e: RejectedExecutionException) {
-            timeSource.unTrackTask()
+            unTrackTask()
             DefaultExecutor.enqueue(block)
         }
     }
diff --git a/kotlinx-coroutines-core/jvm/src/TimeSource.kt b/kotlinx-coroutines-core/jvm/src/TimeSource.kt
index fec1a82..99a0ca4 100644
--- a/kotlinx-coroutines-core/jvm/src/TimeSource.kt
+++ b/kotlinx-coroutines-core/jvm/src/TimeSource.kt
@@ -1,10 +1,14 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
+// Need InlineOnly for efficient bytecode on Android
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "NOTHING_TO_INLINE")
+
 package kotlinx.coroutines
 
-import java.util.concurrent.locks.LockSupport
+import java.util.concurrent.locks.*
+import kotlin.internal.InlineOnly
 
 internal interface TimeSource {
     fun currentTimeMillis(): Long
@@ -18,22 +22,48 @@
     fun unpark(thread: Thread)
 }
 
-internal object DefaultTimeSource : TimeSource {
-    override fun currentTimeMillis(): Long = System.currentTimeMillis()
-    override fun nanoTime(): Long = System.nanoTime()
-    override fun wrapTask(block: Runnable): Runnable = block
-    override fun trackTask() {}
-    override fun unTrackTask() {}
-    override fun registerTimeLoopThread() {}
-    override fun unregisterTimeLoopThread() {}
+// For tests only
+// @JvmField: Don't use JvmField here to enable R8 optimizations via "assumenosideeffects"
+internal var timeSource: TimeSource? = null
 
-    override fun parkNanos(blocker: Any, nanos: Long) {
-        LockSupport.parkNanos(blocker, nanos)
-    }
+@InlineOnly
+internal inline fun currentTimeMillis(): Long =
+    timeSource?.currentTimeMillis() ?: System.currentTimeMillis()
 
-    override fun unpark(thread: Thread) {
-        LockSupport.unpark(thread)
-    }
+@InlineOnly
+internal actual inline fun nanoTime(): Long =
+    timeSource?.nanoTime() ?: System.nanoTime()
+
+@InlineOnly
+internal inline fun wrapTask(block: Runnable): Runnable =
+    timeSource?.wrapTask(block) ?: block
+
+@InlineOnly
+internal inline fun trackTask() {
+    timeSource?.trackTask()
 }
 
-internal var timeSource: TimeSource = DefaultTimeSource
+@InlineOnly
+internal inline fun unTrackTask() {
+    timeSource?.unTrackTask()
+}
+
+@InlineOnly
+internal inline fun registerTimeLoopThread() {
+    timeSource?.registerTimeLoopThread()
+}
+
+@InlineOnly
+internal inline fun unregisterTimeLoopThread() {
+    timeSource?.unregisterTimeLoopThread()
+}
+
+@InlineOnly
+internal inline fun parkNanos(blocker: Any, nanos: Long) {
+    timeSource?.parkNanos(blocker, nanos) ?: LockSupport.parkNanos(blocker, nanos)
+}
+
+@InlineOnly
+internal inline fun unpark(thread: Thread) {
+    timeSource?.unpark(thread) ?: LockSupport.unpark(thread)
+}
diff --git a/kotlinx-coroutines-core/jvm/src/channels/TickerChannels.kt b/kotlinx-coroutines-core/jvm/src/channels/TickerChannels.kt
index 9d49ead..4bbf77d 100644
--- a/kotlinx-coroutines-core/jvm/src/channels/TickerChannels.kt
+++ b/kotlinx-coroutines-core/jvm/src/channels/TickerChannels.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines.channels
@@ -80,13 +80,13 @@
     initialDelayMillis: Long,
     channel: SendChannel<Unit>
 ) {
-    var deadline = timeSource.nanoTime() + delayToNanos(initialDelayMillis)
+    var deadline = nanoTime() + delayToNanos(initialDelayMillis)
     delay(initialDelayMillis)
     val delayNs = delayToNanos(delayMillis)
     while (true) {
         deadline += delayNs
         channel.send(Unit)
-        val now = timeSource.nanoTime()
+        val now = nanoTime()
         val nextDelay = (deadline - now).coerceAtLeast(0)
         if (nextDelay == 0L && delayNs != 0L) {
             val adjustedDelay = delayNs - (now - deadline) % delayNs
diff --git a/kotlinx-coroutines-core/jvm/src/internal/ArrayCopy.kt b/kotlinx-coroutines-core/jvm/src/internal/ArrayCopy.kt
deleted file mode 100644
index f9196f3..0000000
--- a/kotlinx-coroutines-core/jvm/src/internal/ArrayCopy.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.coroutines.internal
-
-internal actual fun <E> arraycopy(
-    source: Array<E>,
-    srcPos: Int,
-    destination: Array<E?>,
-    destinationStart: Int,
-    length: Int
-) {
-    System.arraycopy(source, srcPos, destination, destinationStart, length)
-}
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/jvm/src/internal/LockFreeLinkedList.kt b/kotlinx-coroutines-core/jvm/src/internal/LockFreeLinkedList.kt
index 7d765b9..7d28de2 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/LockFreeLinkedList.kt
+++ b/kotlinx-coroutines-core/jvm/src/internal/LockFreeLinkedList.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines.internal
@@ -315,7 +315,7 @@
     ) : AbstractAtomicDesc() {
         init {
             // require freshly allocated node here
-            check(node._next.value === node && node._prev.value === node)
+            assert { node._next.value === node && node._prev.value === node }
         }
 
         final override fun takeAffectedNode(op: OpDescriptor): Node {
@@ -390,7 +390,7 @@
 
         @Suppress("UNCHECKED_CAST")
         final override fun onPrepare(affected: Node, next: Node): Any? {
-            check(affected !is LockFreeLinkedListHead)
+            assert { affected !is LockFreeLinkedListHead }
             if (!validatePrepared(affected as T)) return REMOVE_PREPARED
             // Note: onPrepare must use CAS to make sure the stale invocation is not
             // going to overwrite the previous decision on successful preparation.
@@ -475,8 +475,8 @@
 
         final override fun complete(op: AtomicOp<*>, failure: Any?) {
             val success = failure == null
-            val affectedNode = affectedNode ?: run { check(!success); return }
-            val originalNext = originalNext ?: run { check(!success); return }
+            val affectedNode = affectedNode ?: run { assert { !success }; return }
+            val originalNext = originalNext ?: run { assert { !success }; return }
             val update = if (success) updatedNext(affectedNode, originalNext) else originalNext
             if (affectedNode._next.compareAndSet(op, update)) {
                 if (success) finishOnSuccess(affectedNode, originalNext)
@@ -564,7 +564,7 @@
         while (true) {
             if (cur is LockFreeLinkedListHead) return cur
             cur = cur.nextNode
-            check(cur !== this) { "Cannot loop to this while looking for list head" }
+            assert { cur !== this } // "Cannot loop to this while looking for list head"
         }
     }
 
@@ -648,8 +648,8 @@
     }
 
     internal fun validateNode(prev: Node, next: Node) {
-        check(prev === this._prev.value)
-        check(next === this._next.value)
+        assert { prev === this._prev.value }
+        assert { next === this._next.value }
     }
 
     override fun toString(): String = "${this::class.java.simpleName}@${Integer.toHexString(System.identityHashCode(this))}"
diff --git a/kotlinx-coroutines-core/jvm/src/internal/Synchronized.kt b/kotlinx-coroutines-core/jvm/src/internal/Synchronized.kt
index 5407ade..51dcee4 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/Synchronized.kt
+++ b/kotlinx-coroutines-core/jvm/src/internal/Synchronized.kt
@@ -4,9 +4,17 @@
 
 package kotlinx.coroutines.internal
 
-@Suppress("ACTUAL_WITHOUT_EXPECT") // visibility
-internal actual typealias SynchronizedObject = Any
+import kotlinx.coroutines.*
 
-@PublishedApi
-internal actual inline fun <T> synchronized(lock: SynchronizedObject, block: () -> T): T =
+/**
+ * @suppress **This an internal API and should not be used from general code.**
+ */
+@InternalCoroutinesApi
+public actual typealias SynchronizedObject = Any
+
+/**
+ * @suppress **This an internal API and should not be used from general code.**
+ */
+@InternalCoroutinesApi
+public actual inline fun <T> synchronized(lock: SynchronizedObject, block: () -> T): T =
     kotlin.synchronized(lock, block)
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/jvm/src/internal/ThreadSafeHeap.kt b/kotlinx-coroutines-core/jvm/src/internal/ThreadSafeHeap.kt
index b164084..661a6bc 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/ThreadSafeHeap.kt
+++ b/kotlinx-coroutines-core/jvm/src/internal/ThreadSafeHeap.kt
@@ -1,159 +1,8 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines.internal
 
-import kotlinx.coroutines.*
-import java.util.*
-
-/**
- * @suppress **This an internal API and should not be used from general code.**
- */
-@InternalCoroutinesApi
-public interface ThreadSafeHeapNode {
-    public var heap: ThreadSafeHeap<*>?
-    public var index: Int
-}
-
-/**
- * Synchronized binary heap.
- * @suppress **This an internal API and should not be used from general code.**
- */
-@InternalCoroutinesApi
-public class ThreadSafeHeap<T> : SynchronizedObject() where T: ThreadSafeHeapNode, T: Comparable<T> {
-    private var a: Array<T?>? = null
-
-    @JvmField @Volatile
-    public var size = 0
-
-    public val isEmpty: Boolean get() = size == 0
-
-    @Synchronized
-    public fun clear() {
-        Arrays.fill(a, 0, size, null)
-        size = 0
-    }
-
-    @Synchronized
-    public fun peek(): T? = firstImpl()
-
-    @Synchronized
-    public fun removeFirstOrNull(): T? =
-        if (size > 0) {
-            removeAtImpl(0)
-        } else {
-            null
-        }
-
-    // @Synchronized // NOTE! NOTE! NOTE! inline fun cannot be @Synchronized
-    public inline fun removeFirstIf(predicate: (T) -> Boolean): T? = synchronized(this) {
-        val first = firstImpl() ?: return null
-        if (predicate(first)) {
-            removeAtImpl(0)
-        } else {
-            null
-        }
-    }
-
-    @Synchronized
-    public fun addLast(node: T) = addImpl(node)
-
-    // @Synchronized // NOTE! NOTE! NOTE! inline fun cannot be @Synchronized
-    public inline fun addLastIf(node: T, cond: () -> Boolean): Boolean = synchronized(this) {
-        if (cond()) {
-            addImpl(node)
-            true
-        } else {
-            false
-        }
-    }
-
-    @Synchronized
-    public fun remove(node: T): Boolean {
-        return if (node.heap == null) {
-            false
-        } else {
-            val index = node.index
-            check(index >= 0)
-            removeAtImpl(index)
-            true
-        }
-    }
-
-    @PublishedApi
-    internal fun firstImpl(): T? = a?.get(0)
-
-    @PublishedApi
-    internal fun removeAtImpl(index: Int): T {
-        check(size > 0)
-        val a = this.a!!
-        size--
-        if (index < size) {
-            swap(index, size)
-            val j = (index - 1) / 2
-            if (index > 0 && a[index]!! < a[j]!!) {
-                swap(index, j)
-                siftUpFrom(j)
-            } else {
-                siftDownFrom(index)
-            }
-        }
-        val result = a[size]!!
-        check(result.heap === this)
-        result.heap = null
-        result.index = -1
-        a[size] = null
-        return result
-    }
-
-    @PublishedApi
-    internal fun addImpl(node: T) {
-        check(node.heap == null)
-        node.heap = this
-        val a = realloc()
-        val i = size++
-        a[i] = node
-        node.index = i
-        siftUpFrom(i)
-    }
-
-    private tailrec fun siftUpFrom(i: Int) {
-        if (i <= 0) return
-        val a = a!!
-        val j = (i - 1) / 2
-        if (a[j]!! <= a[i]!!) return
-        swap(i, j)
-        siftUpFrom(j)
-    }
-
-    private tailrec fun siftDownFrom(i: Int) {
-        var j = 2 * i + 1
-        if (j >= size) return
-        val a = a!!
-        if (j + 1 < size && a[j + 1]!! < a[j]!!) j++
-        if (a[i]!! <= a[j]!!) return
-        swap(i, j)
-        siftDownFrom(j)
-    }
-
-    @Suppress("UNCHECKED_CAST")
-    private fun realloc(): Array<T?> {
-        val a = this.a
-        return when {
-            a == null -> (arrayOfNulls<ThreadSafeHeapNode>(4) as Array<T?>).also { this.a = it }
-            size >= a.size -> a.copyOf(size * 2).also { this.a = it }
-            else -> a
-        }
-    }
-
-    private fun swap(i: Int, j: Int) {
-        val a = a!!
-        val ni = a[j]!!
-        val nj = a[i]!!
-        a[i] = ni
-        a[j] = nj
-        ni.index = i
-        nj.index = j
-    }
-}
+@Suppress("NOTHING_TO_INLINE")
+internal actual inline fun <T> clear(a: Array<T?>) = a.fill(null)
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/jvm/src/scheduling/CoroutineScheduler.kt b/kotlinx-coroutines-core/jvm/src/scheduling/CoroutineScheduler.kt
index e488905..4089710 100644
--- a/kotlinx-coroutines-core/jvm/src/scheduling/CoroutineScheduler.kt
+++ b/kotlinx-coroutines-core/jvm/src/scheduling/CoroutineScheduler.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines.scheduling
@@ -7,7 +7,7 @@
 import kotlinx.atomicfu.*
 import kotlinx.coroutines.*
 import kotlinx.coroutines.internal.*
-import java.io.Closeable
+import java.io.*
 import java.util.*
 import java.util.concurrent.*
 import java.util.concurrent.locks.*
@@ -146,7 +146,7 @@
             val index = (top and PARKED_INDEX_MASK).toInt()
             val updVersion = (top + PARKED_VERSION_INC) and PARKED_VERSION_MASK
             val updIndex = worker.indexInArray
-            assert(updIndex != 0) // only this worker can push itself, cannot be terminated
+            assert { updIndex != 0 } // only this worker can push itself, cannot be terminated
             worker.nextParkedWorker = workers[index]
             /*
              * Other thread can be changing this worker's index at this point, but it
@@ -311,7 +311,7 @@
                     worker.join(timeout)
                 }
                 val state = worker.state
-                check(state === WorkerState.TERMINATED) { "Expected TERMINATED state, but found $state"}
+                assert { state === WorkerState.TERMINATED } // Expected TERMINATED state
                 worker.localQueue.offloadAllWork(globalQueue)
             }
         }
@@ -325,7 +325,7 @@
         // Shutdown current thread
         currentWorker?.tryReleaseCpu(WorkerState.TERMINATED)
         // check & cleanup state
-        assert(cpuPermits.availablePermits() == corePoolSize)
+        assert { cpuPermits.availablePermits() == corePoolSize }
         parkedWorkersStack.value = 0L
         controlState.value = 0L
     }
@@ -339,7 +339,7 @@
      * @param fair whether the task should be dispatched fairly (strict FIFO) or not (semi-FIFO)
      */
     fun dispatch(block: Runnable, taskContext: TaskContext = NonBlockingContext, fair: Boolean = false) {
-        timeSource.trackTask() // this is needed for virtual time support
+        trackTask() // this is needed for virtual time support
         val task = createTask(block, taskContext)
         // try to submit the task to the local queue and act depending on the result
         when (submitToLocalQueue(task, fair)) {
@@ -596,7 +596,7 @@
             val thread = Thread.currentThread()
             thread.uncaughtExceptionHandler.uncaughtException(thread, e)
         } finally {
-            timeSource.unTrackTask()
+            unTrackTask()
         }
     }
 
@@ -664,9 +664,8 @@
          * This attempt may fail either because worker terminated itself or because someone else
          * claimed this worker (though this case is rare, because require very bad timings)
          */
-        fun tryForbidTermination(): Boolean {
-            val state = terminationState.value
-            return when (state) {
+        fun tryForbidTermination(): Boolean =
+            when (val state = terminationState.value) {
                 TERMINATED -> false // already terminated
                 FORBIDDEN -> false // already forbidden, someone else claimed this worker
                 ALLOWED -> terminationState.compareAndSet(
@@ -675,7 +674,6 @@
                 )
                 else -> error("Invalid terminationState = $state")
             }
-        }
 
         /**
          * Tries to acquire CPU token if worker doesn't have one
@@ -780,7 +778,7 @@
                 val currentState = state
                 // Shutdown sequence of blocking dispatcher
                 if (currentState !== WorkerState.TERMINATED) {
-                    assert(currentState == WorkerState.BLOCKING) { "Expected BLOCKING state, but has $currentState" }
+                    assert { currentState == WorkerState.BLOCKING } // "Expected BLOCKING state, but has $currentState"
                     state = WorkerState.RETIRING
                 }
             }
@@ -927,7 +925,7 @@
             terminationDeadline = 0L // reset deadline for termination
             lastStealIndex = 0 // reset steal index (next time try random)
             if (state == WorkerState.PARKING) {
-                assert(mode == TaskMode.PROBABLY_BLOCKING)
+                assert { mode == TaskMode.PROBABLY_BLOCKING }
                 state = WorkerState.BLOCKING
                 parkTimeNs = MIN_PARK_TIME_NS
             }
diff --git a/kotlinx-coroutines-core/jvm/src/scheduling/WorkQueue.kt b/kotlinx-coroutines-core/jvm/src/scheduling/WorkQueue.kt
index a0f209b..a9aa86d 100644
--- a/kotlinx-coroutines-core/jvm/src/scheduling/WorkQueue.kt
+++ b/kotlinx-coroutines-core/jvm/src/scheduling/WorkQueue.kt
@@ -5,6 +5,7 @@
 package kotlinx.coroutines.scheduling
 
 import kotlinx.atomicfu.*
+import kotlinx.coroutines.*
 import java.util.concurrent.atomic.*
 
 internal const val BUFFER_CAPACITY_BASE = 7
diff --git a/kotlinx-coroutines-core/jvm/test/TestBase.kt b/kotlinx-coroutines-core/jvm/test/TestBase.kt
index 0a10913..073c7a5 100644
--- a/kotlinx-coroutines-core/jvm/test/TestBase.kt
+++ b/kotlinx-coroutines-core/jvm/test/TestBase.kt
@@ -9,6 +9,7 @@
 import org.junit.*
 import java.util.*
 import java.util.concurrent.atomic.*
+import kotlin.coroutines.*
 import kotlin.test.*
 
 private val VERBOSE = systemProp("test.verbose", false)
@@ -213,4 +214,6 @@
         assertTrue(result.exceptionOrNull() is T, "Expected ${T::class}, but had $result")
         return result.exceptionOrNull()!! as T
     }
+
+    protected suspend fun currentDispatcher() = coroutineContext[ContinuationInterceptor]!!
 }
diff --git a/kotlinx-coroutines-core/jvm/test/VirtualTimeSource.kt b/kotlinx-coroutines-core/jvm/test/VirtualTimeSource.kt
index 009ae00..ca399f5 100644
--- a/kotlinx-coroutines-core/jvm/test/VirtualTimeSource.kt
+++ b/kotlinx-coroutines-core/jvm/test/VirtualTimeSource.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines
@@ -20,7 +20,7 @@
     } finally {
         DefaultExecutor.shutdown(SHUTDOWN_TIMEOUT)
         testTimeSource.shutdown()
-        timeSource = DefaultTimeSource // restore time source
+        timeSource = null // restore time source
     }
 }
 
diff --git a/kotlinx-coroutines-core/jvm/test/channels/TickerChannelCommonTest.kt b/kotlinx-coroutines-core/jvm/test/channels/TickerChannelCommonTest.kt
index cffe6c0..5178907 100644
--- a/kotlinx-coroutines-core/jvm/test/channels/TickerChannelCommonTest.kt
+++ b/kotlinx-coroutines-core/jvm/test/channels/TickerChannelCommonTest.kt
@@ -112,18 +112,15 @@
         var sum = 0
         var n = 0
         whileSelect {
-            this@averageInTimeWindow.onReceiveOrNull {
-                when (it) {
-                    null -> {
-                        // Send leftovers and bail out
-                        if (n != 0) send(sum / n.toDouble())
-                        false
-                    }
-                    else -> {
-                        sum += it
-                        ++n
-                        true
-                    }
+            this@averageInTimeWindow.onReceiveOrClosed {
+                if (it.isClosed) {
+                    // Send leftovers and bail out
+                    if (n != 0) send(sum / n.toDouble())
+                    false
+                } else {
+                    sum += it.value
+                    ++n
+                    true
                 }
             }
 
diff --git a/kotlinx-coroutines-core/jvm/test/exceptions/StackTraceRecoveryTest.kt b/kotlinx-coroutines-core/jvm/test/exceptions/StackTraceRecoveryTest.kt
index 3b5e173..db5fabc 100644
--- a/kotlinx-coroutines-core/jvm/test/exceptions/StackTraceRecoveryTest.kt
+++ b/kotlinx-coroutines-core/jvm/test/exceptions/StackTraceRecoveryTest.kt
@@ -6,9 +6,11 @@
 
 import kotlinx.coroutines.*
 import kotlinx.coroutines.channels.*
+import kotlinx.coroutines.intrinsics.*
 import kotlinx.coroutines.selects.*
 import org.junit.Test
 import java.util.concurrent.*
+import kotlin.coroutines.*
 import kotlin.test.*
 
 /*
@@ -271,4 +273,40 @@
             checkCycles(e)
         }
     }
+
+
+    private suspend fun throws() {
+        yield() // TCE
+        throw RecoverableTestException()
+    }
+
+    private suspend fun awaiter() {
+        val task = GlobalScope.async(Dispatchers.Default, start = CoroutineStart.LAZY) { throws() }
+        task.await()
+        yield() // TCE
+    }
+
+    @Test
+    fun testNonDispatchedRecovery() {
+        val await = suspend { awaiter() }
+
+        val barrier = CyclicBarrier(2)
+        var exception: Throwable? = null
+        await.startCoroutineUnintercepted(Continuation(EmptyCoroutineContext) {
+            exception = it.exceptionOrNull()
+            barrier.await()
+        })
+
+        barrier.await()
+        val e = exception
+        assertNotNull(e)
+        verifyStackTrace(e, "kotlinx.coroutines.RecoverableTestException\n" +
+                "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryTest.throws(StackTraceRecoveryTest.kt:280)\n" +
+                "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryTest\$throws\$1.invokeSuspend(StackTraceRecoveryTest.kt)\n" +
+                "\t(Coroutine boundary)\n" +
+                "\tat kotlinx.coroutines.DeferredCoroutine.await\$suspendImpl(Builders.common.kt:99)\n" +
+                "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryTest.awaiter(StackTraceRecoveryTest.kt:285)\n" +
+                "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryTest\$testNonDispatchedRecovery\$await\$1.invokeSuspend(StackTraceRecoveryTest.kt:291)\n" +
+                "Caused by: kotlinx.coroutines.RecoverableTestException")
+    }
 }
diff --git a/kotlinx-coroutines-core/jvm/test/flow/FlatMapStressTest.kt b/kotlinx-coroutines-core/jvm/test/flow/FlatMapStressTest.kt
index 9092a18..699d9c6 100644
--- a/kotlinx-coroutines-core/jvm/test/flow/FlatMapStressTest.kt
+++ b/kotlinx-coroutines-core/jvm/test/flow/FlatMapStressTest.kt
@@ -5,6 +5,7 @@
 package kotlinx.coroutines.flow
 
 import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.internal.*
 import kotlinx.coroutines.scheduling.*
 import org.junit.Assume.*
 import org.junit.Test
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt
index 89a9370..dcb36af 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt
index 6aa62d2..4f1277d 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-02b.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-02b.kt
index 67d6f67..a78840d 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-02b.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-02b.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-03.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-03.kt
index b7c36f1..e6a299e 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-03.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-03.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-03s.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-03s.kt
index 253d691..13cf679 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-03s.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-03s.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-04.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-04.kt
index 98abe6b..3afa0fe 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-04.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-04.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-05.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-05.kt
index 7a4340e..e6a9112 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-05.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-05.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-06.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-06.kt
index ff6db92..60de941 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-06.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-06.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-07.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-07.kt
index 58eadd6..a348ef4 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-07.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-07.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-cancel-01.kt b/kotlinx-coroutines-core/jvm/test/guide/example-cancel-01.kt
index ab699f2..e44b703 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-cancel-01.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-cancel-01.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-cancel-02.kt b/kotlinx-coroutines-core/jvm/test/guide/example-cancel-02.kt
index cbb3d62..518c0be 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-cancel-02.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-cancel-02.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
@@ -9,13 +9,13 @@
 
 fun main() = runBlocking {
 //sampleStart
-    val startTime = timeSource.currentTimeMillis()
+    val startTime = currentTimeMillis()
     val job = launch(Dispatchers.Default) {
         var nextPrintTime = startTime
         var i = 0
         while (i < 5) { // computation loop, just wastes CPU
             // print a message twice a second
-            if (timeSource.currentTimeMillis() >= nextPrintTime) {
+            if (currentTimeMillis() >= nextPrintTime) {
                 println("job: I'm sleeping ${i++} ...")
                 nextPrintTime += 500L
             }
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-cancel-03.kt b/kotlinx-coroutines-core/jvm/test/guide/example-cancel-03.kt
index bebb94b..8c1e3f8 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-cancel-03.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-cancel-03.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
@@ -9,13 +9,13 @@
 
 fun main() = runBlocking {
 //sampleStart
-    val startTime = timeSource.currentTimeMillis()
+    val startTime = currentTimeMillis()
     val job = launch(Dispatchers.Default) {
         var nextPrintTime = startTime
         var i = 0
         while (isActive) { // cancellable computation loop
             // print a message twice a second
-            if (timeSource.currentTimeMillis() >= nextPrintTime) {
+            if (currentTimeMillis() >= nextPrintTime) {
                 println("job: I'm sleeping ${i++} ...")
                 nextPrintTime += 500L
             }
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-cancel-04.kt b/kotlinx-coroutines-core/jvm/test/guide/example-cancel-04.kt
index fcad730..002521e 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-cancel-04.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-cancel-04.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-cancel-05.kt b/kotlinx-coroutines-core/jvm/test/guide/example-cancel-05.kt
index 08bb1e2..5c7debb 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-cancel-05.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-cancel-05.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-cancel-06.kt b/kotlinx-coroutines-core/jvm/test/guide/example-cancel-06.kt
index da8ecbd..299ceb2 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-cancel-06.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-cancel-06.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-cancel-07.kt b/kotlinx-coroutines-core/jvm/test/guide/example-cancel-07.kt
index 3fbbd09..1116f91 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-cancel-07.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-cancel-07.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-channel-01.kt b/kotlinx-coroutines-core/jvm/test/guide/example-channel-01.kt
index ab437ed..d3ab53b 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-channel-01.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-channel-01.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-channel-02.kt b/kotlinx-coroutines-core/jvm/test/guide/example-channel-02.kt
index d65f0f2..9ab469f 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-channel-02.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-channel-02.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-channel-03.kt b/kotlinx-coroutines-core/jvm/test/guide/example-channel-03.kt
index 84419aa..c6550b4 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-channel-03.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-channel-03.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-channel-04.kt b/kotlinx-coroutines-core/jvm/test/guide/example-channel-04.kt
index 87fd355..02ac7bb 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-channel-04.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-channel-04.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-channel-05.kt b/kotlinx-coroutines-core/jvm/test/guide/example-channel-05.kt
index 5f9d247..625b52c 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-channel-05.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-channel-05.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-channel-06.kt b/kotlinx-coroutines-core/jvm/test/guide/example-channel-06.kt
index 7224ffa..b88a1b0 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-channel-06.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-channel-06.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-channel-07.kt b/kotlinx-coroutines-core/jvm/test/guide/example-channel-07.kt
index 64df2ec..0487296 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-channel-07.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-channel-07.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-channel-08.kt b/kotlinx-coroutines-core/jvm/test/guide/example-channel-08.kt
index f1e9d9b..6c55980 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-channel-08.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-channel-08.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-channel-09.kt b/kotlinx-coroutines-core/jvm/test/guide/example-channel-09.kt
index ee7afab..ae9d95c 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-channel-09.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-channel-09.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-channel-10.kt b/kotlinx-coroutines-core/jvm/test/guide/example-channel-10.kt
index 4615e30..43ceea5 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-channel-10.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-channel-10.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-compose-01.kt b/kotlinx-coroutines-core/jvm/test/guide/example-compose-01.kt
index 6c027e4..5dfb770 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-compose-01.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-compose-01.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-compose-02.kt b/kotlinx-coroutines-core/jvm/test/guide/example-compose-02.kt
index 1cb75d9..d78e514 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-compose-02.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-compose-02.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-compose-03.kt b/kotlinx-coroutines-core/jvm/test/guide/example-compose-03.kt
index 4a919fb..aa6dd6f 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-compose-03.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-compose-03.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-compose-04.kt b/kotlinx-coroutines-core/jvm/test/guide/example-compose-04.kt
index d840f70..ea6860e 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-compose-04.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-compose-04.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-compose-05.kt b/kotlinx-coroutines-core/jvm/test/guide/example-compose-05.kt
index 81e75a8..e3c5403 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-compose-05.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-compose-05.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-compose-06.kt b/kotlinx-coroutines-core/jvm/test/guide/example-compose-06.kt
index 6346842..1df506e 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-compose-06.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-compose-06.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-context-01.kt b/kotlinx-coroutines-core/jvm/test/guide/example-context-01.kt
index 1471f72..13534c7 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-context-01.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-context-01.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-context-02.kt b/kotlinx-coroutines-core/jvm/test/guide/example-context-02.kt
index 7a29aed..d7be586 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-context-02.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-context-02.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-context-03.kt b/kotlinx-coroutines-core/jvm/test/guide/example-context-03.kt
index 5740495..a26d3a0 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-context-03.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-context-03.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-context-04.kt b/kotlinx-coroutines-core/jvm/test/guide/example-context-04.kt
index 6624252..55cfecc 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-context-04.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-context-04.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-context-05.kt b/kotlinx-coroutines-core/jvm/test/guide/example-context-05.kt
index f39ffd9..d014f56 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-context-05.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-context-05.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-context-06.kt b/kotlinx-coroutines-core/jvm/test/guide/example-context-06.kt
index ba0b04c..563d418 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-context-06.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-context-06.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-context-07.kt b/kotlinx-coroutines-core/jvm/test/guide/example-context-07.kt
index 992e672..27bff49 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-context-07.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-context-07.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-context-08.kt b/kotlinx-coroutines-core/jvm/test/guide/example-context-08.kt
index bcc754a..2a278d2 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-context-08.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-context-08.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-context-09.kt b/kotlinx-coroutines-core/jvm/test/guide/example-context-09.kt
index 58b1dd0..b72041b 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-context-09.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-context-09.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-context-10.kt b/kotlinx-coroutines-core/jvm/test/guide/example-context-10.kt
index 5a7b3d5..bce5f14 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-context-10.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-context-10.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-context-11.kt b/kotlinx-coroutines-core/jvm/test/guide/example-context-11.kt
index 1945495..a26d8c6 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-context-11.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-context-11.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-01.kt b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-01.kt
index c931409..4bec14f 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-01.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-01.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-02.kt b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-02.kt
index 46f6dab..80da1df 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-02.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-02.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-03.kt b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-03.kt
index 1166519..eadbb9b 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-03.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-03.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-04.kt b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-04.kt
index a55be12..e741d39 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-04.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-04.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-05.kt b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-05.kt
index 5271873..e90606f 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-05.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-05.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-06.kt b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-06.kt
index 076a097..0faf8d4 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-06.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-06.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-select-01.kt b/kotlinx-coroutines-core/jvm/test/guide/example-select-01.kt
index f49cab6..24beb56 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-select-01.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-select-01.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-select-02.kt b/kotlinx-coroutines-core/jvm/test/guide/example-select-02.kt
index 02bd98c..c763f81 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-select-02.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-select-02.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-select-03.kt b/kotlinx-coroutines-core/jvm/test/guide/example-select-03.kt
index 7b79bbe..1837aae 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-select-03.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-select-03.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-select-04.kt b/kotlinx-coroutines-core/jvm/test/guide/example-select-04.kt
index 3da88f1..1c7818d 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-select-04.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-select-04.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-select-05.kt b/kotlinx-coroutines-core/jvm/test/guide/example-select-05.kt
index fbbad49..6cda382 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-select-05.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-select-05.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-supervision-01.kt b/kotlinx-coroutines-core/jvm/test/guide/example-supervision-01.kt
index eac450a..d70b6c9 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-supervision-01.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-supervision-01.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-supervision-02.kt b/kotlinx-coroutines-core/jvm/test/guide/example-supervision-02.kt
index 47a3525..facc2e0 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-supervision-02.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-supervision-02.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-supervision-03.kt b/kotlinx-coroutines-core/jvm/test/guide/example-supervision-03.kt
index c50b263..47c31b9 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-supervision-03.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-supervision-03.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-sync-01.kt b/kotlinx-coroutines-core/jvm/test/guide/example-sync-01.kt
index 66c7be3..e0aeeb3 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-sync-01.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-sync-01.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-sync-02.kt b/kotlinx-coroutines-core/jvm/test/guide/example-sync-02.kt
index d624c18..84376f7 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-sync-02.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-sync-02.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-sync-03.kt b/kotlinx-coroutines-core/jvm/test/guide/example-sync-03.kt
index ebb7144..a2e503f 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-sync-03.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-sync-03.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-sync-04.kt b/kotlinx-coroutines-core/jvm/test/guide/example-sync-04.kt
index c55ba44..cdf1f3c 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-sync-04.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-sync-04.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-sync-05.kt b/kotlinx-coroutines-core/jvm/test/guide/example-sync-05.kt
index 8bec253..72dd1f7 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-sync-05.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-sync-05.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-sync-06.kt b/kotlinx-coroutines-core/jvm/test/guide/example-sync-06.kt
index 5cf09eb..7a401e9 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-sync-06.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-sync-06.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-sync-07.kt b/kotlinx-coroutines-core/jvm/test/guide/example-sync-07.kt
index 9990200..0ef8a2a 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-sync-07.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-sync-07.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
diff --git a/kotlinx-coroutines-core/jvm/test/guide/test/TestUtil.kt b/kotlinx-coroutines-core/jvm/test/guide/test/TestUtil.kt
index 786338c..83150e1 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/test/TestUtil.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/test/TestUtil.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines.guide.test
@@ -11,7 +11,7 @@
 import java.io.*
 import java.util.concurrent.*
 
-fun wrapTask(block: Runnable) = timeSource.wrapTask(block)
+fun wrapTask(block: Runnable) = kotlinx.coroutines.wrapTask(block)
 
 // helper function to dump exception to stdout for ease of debugging failed tests
 private inline fun <T> outputException(name: String, block: () -> T): T =
diff --git a/kotlinx-coroutines-core/native/src/CoroutineContext.kt b/kotlinx-coroutines-core/native/src/CoroutineContext.kt
index 017a01c..41d2c88 100644
--- a/kotlinx-coroutines-core/native/src/CoroutineContext.kt
+++ b/kotlinx-coroutines-core/native/src/CoroutineContext.kt
@@ -5,33 +5,24 @@
 package kotlinx.coroutines
 
 import kotlin.coroutines.*
-import kotlinx.coroutines.internal.*
 
 private fun takeEventLoop(): EventLoopImpl =
     ThreadLocalEventLoop.currentOrNull() as? EventLoopImpl ?:
         error("There is no event loop. Use runBlocking { ... } to start one.")
 
-internal object DefaultExecutor : CoroutineDispatcher(), Delay {
+internal actual object DefaultExecutor : CoroutineDispatcher(), Delay {
     override fun dispatch(context: CoroutineContext, block: Runnable) =
         takeEventLoop().dispatch(context, block)
-    override fun scheduleResumeAfterDelay(time: Long, continuation: CancellableContinuation<Unit>) =
-        takeEventLoop().scheduleResumeAfterDelay(time, continuation)
-    override fun invokeOnTimeout(time: Long, block: Runnable): DisposableHandle =
-        takeEventLoop().invokeOnTimeout(time, block)
+    override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) =
+        takeEventLoop().scheduleResumeAfterDelay(timeMillis, continuation)
+    override fun invokeOnTimeout(timeMillis: Long, block: Runnable): DisposableHandle =
+        takeEventLoop().invokeOnTimeout(timeMillis, block)
 
-    fun enqueue(task: Runnable): Boolean {
-        error("Cannot execute task because event loop was shut down")
-    }
-
-    fun schedule(delayedTask: EventLoopImpl.DelayedTask) {
-        error("Cannot schedule task because event loop was shut down")
-    }
-
-    fun removeDelayedImpl(delayedTask: EventLoopImpl.DelayedTask) {
-        error("Cannot happen")
-    }
+    actual fun enqueue(task: Runnable): Unit = loopWasShutDown()
 }
 
+internal fun loopWasShutDown(): Nothing = error("Cannot execute task because event loop was shut down")
+
 internal actual fun createDefaultDispatcher(): CoroutineDispatcher =
     DefaultExecutor
 
@@ -39,8 +30,8 @@
 
 public actual fun CoroutineScope.newCoroutineContext(context: CoroutineContext): CoroutineContext {
     val combined = coroutineContext + context
-    return if (combined !== kotlinx.coroutines.DefaultExecutor && combined[ContinuationInterceptor] == null)
-        combined + kotlinx.coroutines.DefaultExecutor else combined
+    return if (combined !== DefaultExecutor && combined[ContinuationInterceptor] == null)
+        combined + DefaultExecutor else combined
 }
 
 // No debugging facilities on native
diff --git a/kotlinx-coroutines-core/native/src/Debug.kt b/kotlinx-coroutines-core/native/src/Debug.kt
index e81e89a..653cb06 100644
--- a/kotlinx-coroutines-core/native/src/Debug.kt
+++ b/kotlinx-coroutines-core/native/src/Debug.kt
@@ -1,15 +1,18 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines
 
 import kotlin.math.*
 
+internal actual val DEBUG: Boolean = false
+
 internal actual val Any.hexAddress: String get() = abs(id().let { if (it == Int.MIN_VALUE) 0 else it }).toString(16)
 
 internal actual val Any.classSimpleName: String get() = this::class.simpleName ?: "Unknown"
 
-
 @SymbolName("Kotlin_Any_hashCode")
 external fun Any.id(): Int // Note: can return negative value on K/N
+
+internal actual inline fun assert(value: () -> Boolean) {}
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/native/src/EventLoop.kt b/kotlinx-coroutines-core/native/src/EventLoop.kt
index 37f5442..8f2dfeb 100644
--- a/kotlinx-coroutines-core/native/src/EventLoop.kt
+++ b/kotlinx-coroutines-core/native/src/EventLoop.kt
@@ -4,286 +4,19 @@
 
 package kotlinx.coroutines
 
-import kotlinx.atomicfu.*
-import kotlinx.cinterop.*
-import kotlinx.coroutines.internal.*
-import platform.posix.*
-import kotlin.coroutines.*
 import kotlin.system.*
 
-private const val DELAYED = 0
-private const val REMOVED = 1
-private const val RESCHEDULED = 2
-
-private const val MS_TO_NS = 1_000_000L
-private const val MAX_MS = Long.MAX_VALUE / MS_TO_NS
-
-private fun delayToNanos(timeMillis: Long): Long = when {
-    timeMillis <= 0 -> 0L
-    timeMillis >= MAX_MS -> Long.MAX_VALUE
-    else -> timeMillis * MS_TO_NS
+internal actual abstract class EventLoopImplPlatform: EventLoop() {
+    protected actual fun unpark() { /* does nothing */ }
+    protected actual fun reschedule(now: Long, delayedTask: EventLoopImplBase.DelayedTask): Unit =
+        loopWasShutDown()
 }
 
-@Suppress("PrivatePropertyName")
-@SharedImmutable
-private val CLOSED_EMPTY = Symbol("CLOSED_EMPTY")
-
-private typealias Queue<T> = LockFreeMPSCQueueCore<T>
-
-internal class EventLoopImpl: EventLoop(), Delay {
-    // null | CLOSED_EMPTY | task | Queue<Runnable>
-    private val _queue = atomic<Any?>(null)
-
-    // Allocated only once
-    private val _delayed = atomic<ThreadSafeHeap<DelayedTask>?>(null)
-
-    private var isCompleted = false
-
-    override val isEmpty: Boolean get() {
-        if (!isUnconfinedQueueEmpty) return false
-        val delayed = _delayed.value
-        if (delayed != null && !delayed.isEmpty) return false
-        val queue = _queue.value
-        return when (queue) {
-            null -> true
-            is Queue<*> -> queue.isEmpty
-            else -> queue === CLOSED_EMPTY
-        }
-    }
-
-    protected override val nextTime: Long
-        get() {
-            if (super.nextTime == 0L) return 0L
-            val queue = _queue.value
-            when {
-                queue === null -> {} // empty queue -- proceed
-                queue is Queue<*> -> if (!queue.isEmpty) return 0 // non-empty queue
-                queue === CLOSED_EMPTY -> return Long.MAX_VALUE // no more events -- closed
-                else -> return 0 // non-empty queue
-            }
-            val delayed = _delayed.value ?: return Long.MAX_VALUE
-            val nextDelayedTask = delayed.peek() ?: return Long.MAX_VALUE
-            return (nextDelayedTask.nanoTime - nanoTime()).coerceAtLeast(0)
-        }
-
-    override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) =
-        schedule(DelayedResumeTask(timeMillis, continuation))
-
+internal class EventLoopImpl: EventLoopImplBase() {
     override fun invokeOnTimeout(timeMillis: Long, block: Runnable): DisposableHandle =
-        DelayedRunnableTask(timeMillis, block).also { schedule(it) }
-
-    override fun processNextEvent(): Long {
-        // unconfined events take priority
-        if (processUnconfinedEvent()) return nextTime
-        // queue all delayed tasks that are due to be executed
-        val delayed = _delayed.value
-        if (delayed != null && !delayed.isEmpty) {
-            val now = nanoTime()
-            while (true) {
-                // make sure that moving from delayed to queue removes from delayed only after it is added to queue
-                // to make sure that 'isEmpty' and `nextTime` that check both of them
-                // do not transiently report that both delayed and queue are empty during move
-                delayed.removeFirstIf {
-                    if (it.timeToExecute(now)) {
-                        enqueueImpl(it)
-                    } else
-                        false
-                } ?: break // quit loop when nothing more to remove or enqueueImpl returns false on "isComplete"
-            }
-        }
-        // then process one event from queue
-        dequeue()?.run()
-        return nextTime
-    }
-
-    public final override fun dispatch(context: CoroutineContext, block: Runnable) = enqueue(block)
-
-    public fun enqueue(task: Runnable) {
-        if (enqueueImpl(task)) {
-            // todo: we should unpark only when this delayed task became first in the queue
-            unpark()
-        } else {
-            DefaultExecutor.enqueue(task)
-        }
-    }
-
-    @Suppress("UNCHECKED_CAST")
-    private fun enqueueImpl(task: Runnable): Boolean {
-        _queue.loop { queue ->
-            if (isCompleted) return false // fail fast if already completed, may still add, but queues will close
-            when (queue) {
-                null -> if (_queue.compareAndSet(null, task)) return true
-                is Queue<*> -> {
-                    when ((queue as Queue<Runnable>).addLast(task)) {
-                        Queue.ADD_SUCCESS -> return true
-                        Queue.ADD_CLOSED -> return false
-                        Queue.ADD_FROZEN -> _queue.compareAndSet(queue, queue.next())
-                    }
-                }
-                else -> when {
-                    queue === CLOSED_EMPTY -> return false
-                    else -> {
-                        // update to full-blown queue to add one more
-                        val newQueue = Queue<Runnable>(Queue.INITIAL_CAPACITY)
-                        newQueue.addLast(queue as Runnable)
-                        newQueue.addLast(task)
-                        if (_queue.compareAndSet(queue, newQueue)) return true
-                    }
-                }
-            }
-        }
-    }
-
-    @Suppress("UNCHECKED_CAST")
-    private fun dequeue(): Runnable? {
-        _queue.loop { queue ->
-            when (queue) {
-                null -> return null
-                is Queue<*> -> {
-                    val result = (queue as Queue<Runnable>).removeFirstOrNull()
-                    if (result !== Queue.REMOVE_FROZEN) return result as Runnable?
-                    _queue.compareAndSet(queue, queue.next())
-                }
-                else -> when {
-                    queue === CLOSED_EMPTY -> return null
-                    else -> if (_queue.compareAndSet(queue, null)) return queue as Runnable
-                }
-            }
-        }
-    }
-
-    protected fun closeQueue() {
-        assert(isCompleted)
-        _queue.loop { queue ->
-            when (queue) {
-                null -> if (_queue.compareAndSet(null, CLOSED_EMPTY)) return
-                is Queue<*> -> {
-                    queue.close()
-                    return
-                }
-                else -> when {
-                    queue === CLOSED_EMPTY -> return
-                    else -> {
-                        // update to full-blown queue to close
-                        val newQueue = Queue<Runnable>(Queue.INITIAL_CAPACITY)
-                        newQueue.addLast(queue as Runnable)
-                        if (_queue.compareAndSet(queue, newQueue)) return
-                    }
-                }
-            }
-        }
-
-    }
-
-    internal fun schedule(delayedTask: DelayedTask) {
-        if (scheduleImpl(delayedTask)) {
-            // todo: we should unpark only when this delayed task became first in the queue
-            unpark()
-        } else
-            DefaultExecutor.schedule(delayedTask)
-    }
-
-    private fun scheduleImpl(delayedTask: DelayedTask): Boolean {
-        if (isCompleted) return false
-        val delayed = _delayed.value ?: run {
-            _delayed.compareAndSet(null, ThreadSafeHeap())
-            _delayed.value!!
-        }
-        return delayed.addLastIf(delayedTask) { !isCompleted }
-    }
-
-    internal fun removeDelayedImpl(delayedTask: DelayedTask) {
-        _delayed.value?.remove(delayedTask)
-    }
-
-    // It performs "hard" shutdown for test cleanup purposes
-    protected fun resetAll() {
-        _queue.value = null
-        _delayed.value = null
-    }
-
-    // This is a "soft" (normal) shutdown
-    protected fun rescheduleAllDelayed() {
-        while (true) {
-            val delayedTask = _delayed.value?.removeFirstOrNull() ?: break
-            delayedTask.rescheduleOnShutdown()
-        }
-    }
-
-    override fun shutdown() {
-        // Clean up thread-local reference here -- this event loop is shutting down
-        ThreadLocalEventLoop.resetEventLoop()
-        // We should signal that ThreadEventLoop should not accept any more tasks
-        // and process queued events (that could have been added after last processNextEvent)
-        isCompleted = true
-        closeQueue()
-        // complete processing of all queued tasks
-        while (processNextEvent() <= 0) { /* spin */ }
-        // reschedule the rest of delayed tasks
-        rescheduleAllDelayed()
-    }
-
-    internal abstract inner class DelayedTask(
-        timeMillis: Long
-    ) : Runnable, Comparable<DelayedTask>, DisposableHandle, ThreadSafeHeapNode {
-        override var index: Int = -1
-        var state = DELAYED // Guarded by by lock on this task for reschedule/dispose purposes
-        val nanoTime: Long = nanoTime() + delayToNanos(timeMillis)
-
-        override fun compareTo(other: DelayedTask): Int {
-            val dTime = nanoTime - other.nanoTime
-            return when {
-                dTime > 0 -> 1
-                dTime < 0 -> -1
-                else -> 0
-            }
-        }
-
-        fun timeToExecute(now: Long): Boolean = now - nanoTime >= 0L
-
-        fun rescheduleOnShutdown() {
-            if (state != DELAYED) return
-            if (_delayed.value!!.remove(this)) {
-                state = RESCHEDULED
-                DefaultExecutor.schedule(this)
-            } else
-                state = REMOVED
-        }
-
-        final override fun dispose() {
-            when (state) {
-                DELAYED -> _delayed.value?.remove(this)
-                RESCHEDULED -> DefaultExecutor.removeDelayedImpl(this)
-                else -> return
-            }
-            state = REMOVED
-        }
-
-        override fun toString(): String = "Delayed[nanos=$nanoTime]"
-    }
-
-    private inner class DelayedResumeTask(
-        timeMillis: Long,
-        private val cont: CancellableContinuation<Unit>
-    ) : DelayedTask(timeMillis) {
-        override fun run() {
-            with(cont) { resumeUndispatched(Unit) }
-        }
-    }
-
-    private inner class DelayedRunnableTask(
-        timeMillis: Long,
-        private val block: Runnable
-    ) : DelayedTask(timeMillis) {
-        override fun run() { block.run() }
-        override fun toString(): String = super.toString() + block.toString()
-    }
+        scheduleInvokeOnTimeout(timeMillis, block)
 }
 
 internal actual fun createEventLoop(): EventLoop = EventLoopImpl()
 
-private fun nanoTime(): Long {
-    return getTimeNanos()
-}
-
-private fun unpark(): Unit { /* does nothing */ }
+internal actual fun nanoTime(): Long = getTimeNanos()
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/native/src/internal/ArrayCopy.kt b/kotlinx-coroutines-core/native/src/internal/ArrayCopy.kt
deleted file mode 100644
index f4f2831..0000000
--- a/kotlinx-coroutines-core/native/src/internal/ArrayCopy.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.coroutines.internal
-
-internal actual fun <E> arraycopy(
-    source: Array<E>,
-    srcPos: Int,
-    destination: Array<E?>,
-    destinationStart: Int,
-    length: Int
-) {
-    var destinationIndex = destinationStart
-    for (sourceIndex in srcPos until srcPos + length) {
-        destination[destinationIndex++] = source[sourceIndex]
-    }
-}
diff --git a/kotlinx-coroutines-core/native/src/internal/CopyOnWriteList.kt b/kotlinx-coroutines-core/native/src/internal/CopyOnWriteList.kt
index 252f938..c81f653 100644
--- a/kotlinx-coroutines-core/native/src/internal/CopyOnWriteList.kt
+++ b/kotlinx-coroutines-core/native/src/internal/CopyOnWriteList.kt
@@ -21,9 +21,18 @@
     override fun add(index: Int, element: E) {
         rangeCheck(index)
         val update = arrayOfNulls<Any?>(if (array.size == _size) array.size * 2 else array.size)
-        arraycopy(array, 0, update, 0, index)
+        array.copyInto(
+            destination = update,
+            endIndex = index
+        )
         update[index] = element
-        arraycopy(array, index, update, index + 1, _size - index + 1)
+        array.copyInto(
+            destination = update,
+            destinationOffset = index + 1,
+            startIndex = index,
+            endIndex = _size + 1
+        )
+        ++_size
         array = update
     }
 
@@ -43,8 +52,16 @@
         val n = array.size
         val element = array[index]
         val update = arrayOfNulls<Any>(n)
-        arraycopy(array, 0, update, 0, index)
-        arraycopy(array, index + 1, update, index, n - index - 1)
+        array.copyInto(
+            destination = update,
+            endIndex = index
+        )
+        array.copyInto(
+            destination = update,
+            destinationOffset = index,
+            startIndex = index + 1,
+            endIndex = n
+        )
         array = update
         --_size
         return element as E
diff --git a/kotlinx-coroutines-core/native/src/internal/LockFreeMPSCQueue.kt b/kotlinx-coroutines-core/native/src/internal/LockFreeMPSCQueue.kt
deleted file mode 100644
index ae2c017..0000000
--- a/kotlinx-coroutines-core/native/src/internal/LockFreeMPSCQueue.kt
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.coroutines.internal
-
-import kotlinx.atomicfu.*
-
-private typealias Core<E> = LockFreeMPSCQueueCore<E>
-
-/**
- * Lock-free Multiply-Producer Single-Consumer Queue.
- * *Note: This queue is NOT linearizable. It provides only quiescent consistency for its operations.*
- *
- * In particular, the following execution is permitted for this queue, but is not permitted for a linearizable queue:
- *
- * ```
- * Thread 1: addLast(1) = true, removeFirstOrNull() = null
- * Thread 2: addLast(2) = 2 // this operation is concurrent with both operations in the first thread
- * ```
- *
- * @suppress **This is unstable API and it is subject to change.**
- */
-class LockFreeMPSCQueue<E : Any> {
-    private val _cur = atomic(Core<E>(Core.INITIAL_CAPACITY))
-
-    // Note: it is not atomic w.r.t. remove operation (remove can transiently fail when isEmpty is false)
-    val isEmpty: Boolean get() = _cur.value.isEmpty
-
-    fun close() {
-        _cur.loop { cur ->
-            if (cur.close()) return // closed this copy
-            _cur.compareAndSet(cur, cur.next()) // move to next
-        }
-    }
-
-    fun addLast(element: E): Boolean {
-        _cur.loop { cur ->
-            when (cur.addLast(element)) {
-                Core.ADD_SUCCESS -> return true
-                Core.ADD_CLOSED -> return false
-                Core.ADD_FROZEN -> _cur.compareAndSet(cur, cur.next()) // move to next
-            }
-        }
-    }
-
-    @Suppress("UNCHECKED_CAST")
-    fun removeFirstOrNull(): E? {
-        _cur.loop { cur ->
-            val result = cur.removeFirstOrNull()
-            if (result !== Core.REMOVE_FROZEN) return result as E?
-            _cur.compareAndSet(cur, cur.next())
-        }
-    }
-}
-
-/**
- * Lock-free Multiply-Producer Single-Consumer Queue core.
- * *Note: This queue is NOT linearizable. It provides only quiescent consistency for its operations.*
- *
- * @see LockFreeMPSCQueue
- * @suppress **This is unstable API and it is subject to change.**
- */
-internal class LockFreeMPSCQueueCore<E : Any>(private val capacity: Int) {
-    private val mask = capacity - 1
-    private val _next = atomic<Core<E>?>(null)
-    private val _state = atomic(0L)
-    private val array = arrayOfNulls<Any?>(capacity);
-
-    init {
-        check(mask <= MAX_CAPACITY_MASK)
-        check(capacity and mask == 0)
-    }
-
-    // Note: it is not atomic w.r.t. remove operation (remove can transiently fail when isEmpty is false)
-    val isEmpty: Boolean get() = _state.value.withState { head, tail -> head == tail }
-
-    fun close(): Boolean {
-        _state.update { state ->
-            if (state and CLOSED_MASK != 0L) return true // ok - already closed
-            if (state and FROZEN_MASK != 0L) return false // frozen -- try next
-            state or CLOSED_MASK // try set closed bit
-        }
-        return true
-    }
-
-    // ADD_CLOSED | ADD_FROZEN | ADD_SUCCESS
-    fun addLast(element: E): Int {
-        _state.loop { state ->
-            if (state and (FROZEN_MASK or CLOSED_MASK) != 0L) return state.addFailReason() // cannot add
-            state.withState { head, tail ->
-                // there could be one REMOVE element beyond head that we cannot stump up,
-                // so we check for full queue with an extra margin of one element
-                if ((tail + 2) and mask == head and mask) return ADD_FROZEN // overfull, so do freeze & copy
-                val newTail = (tail + 1) and MAX_CAPACITY_MASK
-                if (_state.compareAndSet(state, state.updateTail(newTail))) {
-                    // successfully added
-                    array[tail and mask] = element
-                    // could have been frozen & copied before this item was set -- correct it by filling placeholder
-                    var cur = this
-                    while(true) {
-                        if (cur._state.value and FROZEN_MASK == 0L) break // all fine -- not frozen yet
-                        cur = cur.next().fillPlaceholder(tail, element) ?: break
-                    }
-                    return ADD_SUCCESS // added successfully
-                }
-            }
-        }
-    }
-
-    private fun fillPlaceholder(index: Int, element: E): Core<E>? {
-//        if (array.compareAndSet(index and mask, PLACEHOLDER, element)) {
-//            // we've corrected missing element, should check if that propagated to further copies, just in case
-//            return this
-//        }
-//        // it is Ok, no need for further action
-//        return null
-        if (array[index and mask] != PLACEHOLDER) return null
-        array[index and mask] = element
-        return this
-    }
-
-    // SINGLE CONSUMER
-    // REMOVE_FROZEN | null (EMPTY) | E (SUCCESS)
-    fun removeFirstOrNull(): Any? {
-        _state.loop { state ->
-            if (state and FROZEN_MASK != 0L) return REMOVE_FROZEN // frozen -- cannot modify
-            state.withState { head, tail ->
-                if ((tail and mask) == (head and mask)) return null // empty
-                // because queue is Single Consumer, then element == null|PLACEHOLDER can only be when add has not finished yet
-                val element = array[head and mask] ?: return null
-                if (element === PLACEHOLDER) return null // same story -- consider it not added yet
-                check(element !== REMOVED) { "This queue can have only one consumer" }
-                // tentatively remove element to let GC work
-                // we cannot put null into array, because copying thread could replace it with PLACEHOLDER
-                // and that is a disaster, so a separate REMOVED token is used here.
-                // Note: at most one REMOVED in the array, because single consumer.
-                array[head and mask] = REMOVED
-                val newHead = (head + 1) and MAX_CAPACITY_MASK
-                if (_state.compareAndSet(state, state.updateHead(newHead))) {
-                    array[head and mask] = null // now can safely put null (state was updated)
-                    return element // successfully removed in fast-path
-                }
-                // Slow-path for remove in case of interference
-                var cur = this
-                while (true) {
-                    cur = cur.removeSlowPath(head, newHead) ?: return element
-                }
-            }
-        }
-    }
-
-    private fun removeSlowPath(oldHead: Int, newHead: Int): Core<E>? {
-        _state.loop { state ->
-            state.withState { head, _ ->
-                check(head == oldHead) { "This queue can have only one consumer" }
-                if (state and FROZEN_MASK != 0L) {
-                    // state was already frozen, so either old or REMOVED item could have been copied to next
-                    val next = next()
-                    next.array[head and next.mask] = REMOVED // make sure it is removed in new array regardless
-                    return next // continue to correct head in next
-                }
-                if (_state.compareAndSet(state, state.updateHead(newHead))) {
-                    array[head and mask] = null // now can safely put null (state was updated)
-                    return null
-                }
-            }
-        }
-    }
-
-    fun next(): LockFreeMPSCQueueCore<E> = allocateOrGetNextCopy(markFrozen())
-
-    private fun markFrozen(): Long =
-        _state.updateAndGet { state ->
-            if (state and FROZEN_MASK != 0L) return state // already marked
-            state or FROZEN_MASK
-        }
-
-    private fun allocateOrGetNextCopy(state: Long): Core<E> {
-        _next.loop { next ->
-            if (next != null) return next // already allocated & copied
-            _next.compareAndSet(null, allocateNextCopy(state))
-        }
-    }
-
-    private fun allocateNextCopy(state: Long): Core<E> {
-        val next = LockFreeMPSCQueueCore<E>(capacity * 2)
-        state.withState { head, tail ->
-            var index = head
-            while (index and mask != tail and mask) {
-                // replace nulls with placeholders on copy
-                next.array[index and next.mask] = array[index and mask] ?: PLACEHOLDER
-                index++
-            }
-            next._state.value = state wo FROZEN_MASK
-        }
-        return next
-    }
-
-    @Suppress("PrivatePropertyName")
-    internal companion object {
-        internal const val INITIAL_CAPACITY = 8
-
-        private const val CAPACITY_BITS = 30
-        private const val MAX_CAPACITY_MASK = (1 shl CAPACITY_BITS) - 1
-        private const val HEAD_SHIFT = 0
-        private const val HEAD_MASK = MAX_CAPACITY_MASK.toLong() shl HEAD_SHIFT
-        private const val TAIL_SHIFT = HEAD_SHIFT + CAPACITY_BITS
-        private const val TAIL_MASK = MAX_CAPACITY_MASK.toLong() shl TAIL_SHIFT
-
-        private const val FROZEN_SHIFT = TAIL_SHIFT + CAPACITY_BITS
-        private const val FROZEN_MASK = 1L shl FROZEN_SHIFT
-        private const val CLOSED_SHIFT = FROZEN_SHIFT + 1
-        private const val CLOSED_MASK = 1L shl CLOSED_SHIFT
-        @SharedImmutable
-        internal val REMOVE_FROZEN = Symbol("REMOVE_FROZEN")
-
-        internal const val ADD_SUCCESS = 0
-        internal const val ADD_FROZEN = 1
-        internal const val ADD_CLOSED = 2
-        @SharedImmutable
-        private val PLACEHOLDER = Symbol("PLACEHOLDER")
-        @SharedImmutable
-        private val REMOVED = Symbol("PLACEHOLDER")
-
-        private infix fun Long.wo(other: Long) = this and other.inv()
-        private fun Long.updateHead(newHead: Int) = (this wo HEAD_MASK) or (newHead.toLong() shl HEAD_SHIFT)
-        private fun Long.updateTail(newTail: Int) = (this wo TAIL_MASK) or (newTail.toLong() shl TAIL_SHIFT)
-
-        private inline fun <T> Long.withState(block: (head: Int, tail: Int) -> T): T {
-            val head = ((this and HEAD_MASK) shr HEAD_SHIFT).toInt()
-            val tail = ((this and TAIL_MASK) shr TAIL_SHIFT).toInt()
-            return block(head, tail)
-        }
-
-        // FROZEN | CLOSED
-        private fun Long.addFailReason(): Int = if (this and CLOSED_MASK != 0L) ADD_CLOSED else ADD_FROZEN
-    }
-}
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/native/src/internal/Synchronized.kt b/kotlinx-coroutines-core/native/src/internal/Synchronized.kt
index 1c12140..fbed546 100644
--- a/kotlinx-coroutines-core/native/src/internal/Synchronized.kt
+++ b/kotlinx-coroutines-core/native/src/internal/Synchronized.kt
@@ -4,9 +4,17 @@
 
 package kotlinx.coroutines.internal
 
-@Suppress("ACTUAL_WITHOUT_EXPECT") // visibility
-internal actual typealias SynchronizedObject = Any
+import kotlinx.coroutines.*
 
-@PublishedApi
-internal actual inline fun <T> synchronized(lock: SynchronizedObject, block: () -> T): T =
+/**
+ * @suppress **This an internal API and should not be used from general code.**
+ */
+@InternalCoroutinesApi
+public actual typealias SynchronizedObject = Any
+
+/**
+ * @suppress **This an internal API and should not be used from general code.**
+ */
+@InternalCoroutinesApi
+public actual inline fun <T> synchronized(lock: SynchronizedObject, block: () -> T): T =
     block()
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/native/src/internal/ThreadSafeHeap.kt b/kotlinx-coroutines-core/native/src/internal/ThreadSafeHeap.kt
index 7787a1d..f966c999 100644
--- a/kotlinx-coroutines-core/native/src/internal/ThreadSafeHeap.kt
+++ b/kotlinx-coroutines-core/native/src/internal/ThreadSafeHeap.kt
@@ -1,134 +1,10 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines.internal
 
-import kotlinx.coroutines.*
-
-/**
- * @suppress **This is unstable API and it is subject to change.**
- */
-public interface ThreadSafeHeapNode {
-    public var index: Int
-}
-
-/**
- * Binary heap.
- *
- * @suppress **This is unstable API and it is subject to change.**
- */
-public class ThreadSafeHeap<T> where T: ThreadSafeHeapNode, T: Comparable<T> {
-    private var a: Array<T?>? = null
-
-    internal var size = 0
-
-    public val isEmpty: Boolean get() = size == 0
-
-    public fun peek(): T? = firstImpl()
-
-    public fun removeFirstOrNull(): T? =
-        if (size > 0) {
-            removeAtImpl(0)
-        } else
-            null
-
-    public inline fun removeFirstIf(predicate: (T) -> Boolean): T? {
-        val first = firstImpl() ?: return null
-        return if (predicate(first)) {
-            removeAtImpl(0)
-        } else
-            null
-    }
-
-    public fun addLast(node: T) {
-        addImpl(node)
-    }
-
-    public fun addLastIf(node: T, cond: () -> Boolean): Boolean =
-        if (cond()) {
-            addImpl(node)
-            true
-        } else
-            false
-
-    public fun remove(node: T): Boolean =
-        if (node.index < 0) {
-            false
-        } else {
-            removeAtImpl(node.index)
-            true
-        }
-
-    @PublishedApi
-    internal fun firstImpl(): T? = a?.get(0)
-
-    @PublishedApi
-    internal fun removeAtImpl(index: Int): T {
-        check(size > 0)
-        val a = this.a!!
-        size--
-        if (index < size) {
-            swap(index, size)
-            val j = (index - 1) / 2
-            if (index > 0 && a[index]!! < a[j]!!) {
-                swap(index, j)
-                siftUpFrom(j)
-            } else {
-                siftDownFrom(index)
-            }
-        }
-        val result = a[size]!!
-        result.index = -1
-        a[size] = null
-        return result
-    }
-
-    @PublishedApi
-    internal fun addImpl(node: T) {
-        val a = realloc()
-        var i = size++
-        a[i] = node
-        node.index = i
-        siftUpFrom(i)
-    }
-
-    private tailrec fun siftUpFrom(i: Int) {
-        if (i <= 0) return
-        val a = a!!
-        val j = (i - 1) / 2
-        if (a[j]!! <= a[i]!!) return
-        swap(i, j)
-        siftUpFrom(j)
-    }
-
-    private tailrec fun siftDownFrom(i: Int) {
-        var j = 2 * i + 1
-        if (j >= size) return
-        val a = a!!
-        if (j + 1 < size && a[j + 1]!! < a[j]!!) j++
-        if (a[i]!! <= a[j]!!) return
-        swap(i, j)
-        siftDownFrom(j)
-    }
-
-    @Suppress("UNCHECKED_CAST")
-    private fun realloc(): Array<T?> {
-        val a = this.a
-        return when {
-            a == null -> (arrayOfNulls<ThreadSafeHeapNode>(4) as Array<T?>).also { this.a = it }
-            size >= a.size -> a.copyOf(size * 2).also { this.a = it }
-            else -> a
-        }
-    }
-
-    private fun swap(i: Int, j: Int) {
-        val a = a!!
-        val ni = a[j]!!
-        val nj = a[i]!!
-        a[i] = ni
-        a[j] = nj
-        ni.index = i
-        nj.index = j
-    }
+@Suppress("NOTHING_TO_INLINE")
+internal actual inline fun <T> clear(a: Array<T?>) {
+    for (i in a.indices) a[i] = null
 }
\ No newline at end of file
diff --git a/kotlinx-coroutines-debug/README.md b/kotlinx-coroutines-debug/README.md
index 6e4d6d5..2286927 100644
--- a/kotlinx-coroutines-debug/README.md
+++ b/kotlinx-coroutines-debug/README.md
@@ -18,7 +18,7 @@
 Add `kotlinx-coroutines-debug` to your project test dependencies:
 ```
 dependencies {
-    testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-debug:1.3.0-M2'
+    testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-debug:1.3.0-RC'
 }
 ```
 
@@ -57,7 +57,7 @@
 ### Using as JVM agent
 
 It is possible to use this module as a standalone JVM agent to enable debug probes on the application startup.
-You can run your application with an additional argument: `-javaagent:kotlinx-coroutines-debug-1.3.0-M2.jar`.
+You can run your application with an additional argument: `-javaagent:kotlinx-coroutines-debug-1.3.0-RC.jar`.
 Additionally, on Linux and Mac OS X you can use `kill -5 $pid` command in order to force your application to print all alive coroutines.
 
 
diff --git a/kotlinx-coroutines-debug/build.gradle b/kotlinx-coroutines-debug/build.gradle
index e96cc6c..296566b 100644
--- a/kotlinx-coroutines-debug/build.gradle
+++ b/kotlinx-coroutines-debug/build.gradle
@@ -1,3 +1,5 @@
+import org.w3c.dom.Element
+
 /*
  * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
@@ -16,6 +18,35 @@
         attributes "Can-Redefine-Classes": "true"
     }
 }
+/*
+ * It is possible to extend a particular configuration with shadow,
+ * but in that case it changes dependency type to "runtime" and resolves it
+ * (so it cannot be further modified). Otherwise, shadow just ignores all dependencies.
+ */
+configurations.shadow.extendsFrom(configurations.compile)
+
+/*
+ * Thus we are rewriting the POM. I am really question my existence at this point.
+ */
+project.ext.configureMavenDependencies = {
+    def root = it.asElement() as Element
+    def dependencies = root.getChildNodes().find { it.nodeName == "dependencies" }.childNodes
+    def childrenToRemove = []
+    for (i in 0..dependencies.length - 1) {
+        def dependency = dependencies.item(i) as Element
+        def scope = dependency.getChildNodes().find { it.nodeName == "scope" } as Element
+        def groupId = dependency.getChildNodes().find { it.nodeName == "groupId" } as Element
+        if (groupId != null && groupId.firstChild.nodeValue == "net.bytebuddy") {
+            childrenToRemove.add(dependency)
+        } else if (scope != null) {
+            scope.firstChild.setNodeValue("compile")
+        }
+    }
+
+    childrenToRemove.each {
+        root.getChildNodes().find { it.nodeName == "dependencies" }.removeChild(it)
+    }
+}
 
 shadowJar {
     classifier null
diff --git a/kotlinx-coroutines-debug/test/RunningThreadStackMergeTest.kt b/kotlinx-coroutines-debug/test/RunningThreadStackMergeTest.kt
index 7208294..3ccbe0a 100644
--- a/kotlinx-coroutines-debug/test/RunningThreadStackMergeTest.kt
+++ b/kotlinx-coroutines-debug/test/RunningThreadStackMergeTest.kt
@@ -70,6 +70,7 @@
     fun testStackMergeEscapeSuspendMethod() = runTest {
         launchEscapingCoroutine()
         awaitCoroutineStarted()
+        Thread.sleep(10)
         verifyDump(
             "Coroutine \"coroutine#1\":BlockingCoroutine{Active}@62230679", // <- this one is ignored
             "Coroutine \"coroutine#2\":StandaloneCoroutine{Active}@3aea3c67, state: RUNNING\n" +
diff --git a/kotlinx-coroutines-test/README.md b/kotlinx-coroutines-test/README.md
index a8bbafc..1838bbf 100644
--- a/kotlinx-coroutines-test/README.md
+++ b/kotlinx-coroutines-test/README.md
@@ -9,7 +9,7 @@
 Add `kotlinx-coroutines-test` to your project test dependencies:
 ```
 dependencies {
-    testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.0-M2'
+    testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.0-RC'
 }
 ```
 
diff --git a/reactive/coroutines-guide-reactive.md b/reactive/coroutines-guide-reactive.md
index 5942326..0eff27b 100644
--- a/reactive/coroutines-guide-reactive.md
+++ b/reactive/coroutines-guide-reactive.md
@@ -1,6 +1,6 @@
 <!--- INCLUDE .*/example-reactive-([a-z]+)-([0-9]+)\.kt 
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
@@ -617,7 +617,7 @@
     context: CoroutineContext,   // the context to execute this coroutine in
     predicate: (T) -> Boolean,   // the filter predicate
     mapper: (T) -> R             // the mapper function
-) = GlobalScope.publish<R>(context) {
+) = publish<R>(context) {
     collect {                    // collect the source stream 
         if (predicate(it))       // filter part
             send(mapper(it))     // map part
@@ -638,7 +638,7 @@
 ```kotlin
 fun main() = runBlocking<Unit> {
    range(1, 5)
-       .fusedFilterMap(coroutineContext, { it % 2 == 0}, { "$it is even" })
+       .fusedFilterMap(Dispatchers.Unconfined, { it % 2 == 0}, { "$it is even" })
        .collect { println(it) } // print all the resulting strings
 }
 ```
@@ -673,7 +673,7 @@
 -->
 
 ```kotlin
-fun <T, U> Publisher<T>.takeUntil(context: CoroutineContext, other: Publisher<U>) = GlobalScope.publish<T>(context) {
+fun <T, U> Publisher<T>.takeUntil(context: CoroutineContext, other: Publisher<U>) = publish<T>(context) {
     this@takeUntil.openSubscription().consume { // explicitly open channel to Publisher<T>
         val current = this
         other.openSubscription().consume { // explicitly open channel to Publisher<U>
@@ -711,7 +711,7 @@
 fun main() = runBlocking<Unit> {
     val slowNums = rangeWithInterval(200, 1, 10)         // numbers with 200ms interval
     val stop = rangeWithInterval(500, 1, 10)             // the first one after 500ms
-    slowNums.takeUntil(coroutineContext, stop).collect { println(it) } // let's test it
+    slowNums.takeUntil(Dispatchers.Unconfined, stop).collect { println(it) } // let's test it
 }
 ```
 
@@ -742,7 +742,7 @@
 -->
 
 ```kotlin
-fun <T> Publisher<Publisher<T>>.merge(context: CoroutineContext) = GlobalScope.publish<T>(context) {
+fun <T> Publisher<Publisher<T>>.merge(context: CoroutineContext) = publish<T>(context) {
   collect { pub -> // for each publisher collected
       launch {  // launch a child coroutine
           pub.collect { send(it) } // resend all element from this publisher
@@ -783,7 +783,7 @@
 
 ```kotlin
 fun main() = runBlocking<Unit> {
-    testPub().merge(coroutineContext).collect { println(it) } // print the whole stream
+    testPub().merge(Dispatchers.Unconfined).collect { println(it) } // print the whole stream
 }
 ```
 
@@ -865,7 +865,7 @@
 -->
 
 ```kotlin
-fun rangeWithInterval(context: CoroutineContext, time: Long, start: Int, count: Int) = GlobalScope.publish<Int>(context) {
+fun rangeWithInterval(context: CoroutineContext, time: Long, start: Int, count: Int) = publish<Int>(context) {
     for (x in start until start + count) { 
         delay(time) // wait before sending each number
         send(x)
@@ -915,7 +915,7 @@
 -->
 
 ```kotlin
-fun rangeWithInterval(context: CoroutineContext, time: Long, start: Int, count: Int) = GlobalScope.publish<Int>(context) {
+fun rangeWithInterval(context: CoroutineContext, time: Long, start: Int, count: Int) = publish<Int>(context) {
     for (x in start until start + count) { 
         delay(time) // wait before sending each number
         send(x)
@@ -1067,12 +1067,12 @@
 [whileSelect]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/while-select.html
 <!--- MODULE kotlinx-coroutines-reactive -->
 <!--- INDEX kotlinx.coroutines.reactive -->
-[publish]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/kotlinx.coroutines.-coroutine-scope/publish.html
+[publish]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/publish.html
 [org.reactivestreams.Publisher.collect]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/org.reactivestreams.-publisher/collect.html
 [org.reactivestreams.Publisher.openSubscription]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/org.reactivestreams.-publisher/open-subscription.html
 <!--- MODULE kotlinx-coroutines-rx2 -->
 <!--- INDEX kotlinx.coroutines.rx2 -->
-[rxFlowable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/kotlinx.coroutines.-coroutine-scope/rx-flowable.html
+[rxFlowable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/rx-flowable.html
 <!--- END -->
 
 
diff --git a/reactive/kotlinx-coroutines-reactive/README.md b/reactive/kotlinx-coroutines-reactive/README.md
index d7746e1..69691e8 100644
--- a/reactive/kotlinx-coroutines-reactive/README.md
+++ b/reactive/kotlinx-coroutines-reactive/README.md
@@ -33,7 +33,7 @@
 [ReceiveChannel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/index.html
 <!--- MODULE kotlinx-coroutines-reactive -->
 <!--- INDEX kotlinx.coroutines.reactive -->
-[publish]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/kotlinx.coroutines.-coroutine-scope/publish.html
+[publish]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/publish.html
 [org.reactivestreams.Publisher.awaitFirst]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/org.reactivestreams.-publisher/await-first.html
 [org.reactivestreams.Publisher.awaitFirstOrDefault]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/org.reactivestreams.-publisher/await-first-or-default.html
 [org.reactivestreams.Publisher.awaitFirstOrElse]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/org.reactivestreams.-publisher/await-first-or-else.html
diff --git a/reactive/kotlinx-coroutines-reactive/src/Convert.kt b/reactive/kotlinx-coroutines-reactive/src/Convert.kt
index 2be24af..a7ae128 100644
--- a/reactive/kotlinx-coroutines-reactive/src/Convert.kt
+++ b/reactive/kotlinx-coroutines-reactive/src/Convert.kt
@@ -21,7 +21,7 @@
  * @param context -- the coroutine context from which the resulting observable is going to be signalled
  */
 @ObsoleteCoroutinesApi
-public fun <T> ReceiveChannel<T>.asPublisher(context: CoroutineContext = EmptyCoroutineContext): Publisher<T> = GlobalScope.publish(context) {
+public fun <T> ReceiveChannel<T>.asPublisher(context: CoroutineContext = EmptyCoroutineContext): Publisher<T> = publish(context) {
     for (t in this@asPublisher)
         send(t)
 }
diff --git a/reactive/kotlinx-coroutines-reactive/src/Publish.kt b/reactive/kotlinx-coroutines-reactive/src/Publish.kt
index f5ea01e..a7d5387 100644
--- a/reactive/kotlinx-coroutines-reactive/src/Publish.kt
+++ b/reactive/kotlinx-coroutines-reactive/src/Publish.kt
@@ -1,7 +1,9 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+
 package kotlinx.coroutines.reactive
 
 import kotlinx.atomicfu.*
@@ -11,6 +13,7 @@
 import kotlinx.coroutines.sync.*
 import org.reactivestreams.*
 import kotlin.coroutines.*
+import kotlin.internal.LowPriorityInOverloadResolution
 
 /**
  * Creates cold reactive [Publisher] that runs a given [block] in a coroutine.
@@ -26,25 +29,44 @@
  * | Normal completion or `close` without cause   | `onComplete`
  * | Failure with exception or `close` with cause | `onError`
  *
- * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument.
+ * Coroutine context can be specified with [context] argument.
  * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used.
- * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden
- * with corresponding [coroutineContext] element.
+ * Method throws [IllegalArgumentException] if provided [context] contains a [Job] instance.
  *
  * **Note: This is an experimental api.** Behaviour of publishers that work as children in a parent scope with respect
  *        to cancellation and error handling may change in the future.
- *
- * @param context context of the coroutine.
- * @param block the coroutine code.
  */
 @ExperimentalCoroutinesApi
+public fun <T> publish(
+    context: CoroutineContext = EmptyCoroutineContext,
+    @BuilderInference block: suspend ProducerScope<T>.() -> Unit
+): Publisher<T> {
+    require(context[Job] === null) { "Publisher context cannot contain job in it." +
+            "Its lifecycle should be managed via subscription. Had $context" }
+    return publishInternal(GlobalScope, context, block)
+}
+
+@Deprecated(
+    message = "CoroutineScope.publish is deprecated in favour of top-level publish",
+    level = DeprecationLevel.WARNING,
+    replaceWith = ReplaceWith("publish(context, block)")
+) // Since 1.3.0, will be error in 1.3.1 and hidden in 1.4.0. Binary compatibility with Spring
+@LowPriorityInOverloadResolution
 public fun <T> CoroutineScope.publish(
     context: CoroutineContext = EmptyCoroutineContext,
     @BuilderInference block: suspend ProducerScope<T>.() -> Unit
+): Publisher<T> = publishInternal(this, context, block)
+
+/** @suppress For internal use from other reactive integration modules only */
+@InternalCoroutinesApi
+public fun <T> publishInternal(
+    scope: CoroutineScope, // support for legacy publish in scope
+    context: CoroutineContext,
+    block: suspend ProducerScope<T>.() -> Unit
 ): Publisher<T> = Publisher { subscriber ->
     // specification requires NPE on null subscriber
     if (subscriber == null) throw NullPointerException("Subscriber cannot be null")
-    val newContext = newCoroutineContext(context)
+    val newContext = scope.newCoroutineContext(context)
     val coroutine = PublisherCoroutine(newContext, subscriber)
     subscriber.onSubscribe(coroutine) // do it first (before starting coroutine), to avoid unnecessary suspensions
     coroutine.start(CoroutineStart.DEFAULT, coroutine, block)
@@ -54,7 +76,8 @@
 private const val SIGNALLED = -2L  // already signalled subscriber onCompleted/onError
 
 @Suppress("CONFLICTING_JVM_DECLARATIONS", "RETURN_TYPE_MISMATCH_ON_INHERITANCE")
-private class PublisherCoroutine<in T>(
+@InternalCoroutinesApi
+public class PublisherCoroutine<in T>(
     parentContext: CoroutineContext,
     private val subscriber: Subscriber<T>
 ) : AbstractCoroutine<Unit>(parentContext, true), ProducerScope<T>, Subscription, SelectClause2<T, SendChannel<T>> {
@@ -138,16 +161,16 @@
         }
         // now update nRequested
         while (true) { // lock-free loop on nRequested
-            val cur = _nRequested.value
-            if (cur < 0) break // closed from inside onNext => unlock
-            if (cur == Long.MAX_VALUE) break // no back-pressure => unlock
-            val upd = cur - 1
-            if (_nRequested.compareAndSet(cur, upd)) {
-                if (upd == 0L) {
+            val current = _nRequested.value
+            if (current < 0) break // closed from inside onNext => unlock
+            if (current == Long.MAX_VALUE) break // no back-pressure => unlock
+            val updated = current - 1
+            if (_nRequested.compareAndSet(current, updated)) {
+                if (updated == 0L) {
                     // return to keep locked due to back-pressure
                     return
                 }
-                break // unlock if upd > 0
+                break // unlock if updated > 0
             }
         }
         unlockAndCheckCompleted()
@@ -176,17 +199,31 @@
                 if (cancelled) {
                     // If the parent had failed to handle our exception, then we must not lose this exception
                     if (cause != null && !handled) handleCoroutineException(context, cause)
-                } else {
-                    try {
-                        if (cause != null && cause !is CancellationException) {
-                            subscriber.onError(cause)
+                    return
+                }
+
+                try {
+                    if (cause != null && cause !is CancellationException) {
+                        /*
+                         * Reactive frameworks have two types of exceptions: regular and fatal.
+                         * Regular are passed to onError.
+                         * Fatal can be passed to onError, but even the standard implementations **can just swallow it** (e.g. see #1297).
+                         * Such behaviour is inconsistent, leads to silent failures and we can't possibly know whether
+                         * the cause will be handled by onError (and moreover, it depends on whether a fatal exception was
+                         * thrown by subscriber or upstream).
+                         * To make behaviour consistent and least surprising, we always handle fatal exceptions
+                         * by coroutines machinery, anyway, they should not be present in regular program flow,
+                         * thus our goal here is just to expose it as soon as possible.
+                         */
+                        subscriber.onError(cause)
+                        if (!handled && cause.isFatal()) {
+                            handleCoroutineException(context, cause)
                         }
-                        else {
-                            subscriber.onComplete()
-                        }
-                    } catch (e: Throwable) {
-                        handleCoroutineException(context, e)
+                    } else {
+                        subscriber.onComplete()
                     }
+                } catch (e: Throwable) {
+                    handleCoroutineException(context, e)
                 }
             }
         } finally {
@@ -220,12 +257,12 @@
     // assert: isCompleted
     private fun signalCompleted(cause: Throwable?, handled: Boolean) {
         while (true) { // lock-free loop for nRequested
-            val cur = _nRequested.value
-            if (cur == SIGNALLED) return // some other thread holding lock already signalled cancellation/completion
-            check(cur >= 0) // no other thread could have marked it as CLOSED, because onCompleted[Exceptionally] is invoked once
-            if (!_nRequested.compareAndSet(cur, CLOSED)) continue // retry on failed CAS
+            val current = _nRequested.value
+            if (current == SIGNALLED) return // some other thread holding lock already signalled cancellation/completion
+            check(current >= 0) // no other thread could have marked it as CLOSED, because onCompleted[Exceptionally] is invoked once
+            if (!_nRequested.compareAndSet(current, CLOSED)) continue // retry on failed CAS
             // Ok -- marked as CLOSED, now can unlock the mutex if it was locked due to backpressure
-            if (cur == 0L) {
+            if (current == 0L) {
                 doLockedSignalCompleted(cause, handled)
             } else {
                 // otherwise mutex was either not locked or locked in concurrent onNext... try lock it to signal completion
@@ -250,4 +287,6 @@
         cancelled = true
         super.cancel(null)
     }
+
+    private fun Throwable.isFatal() = this is VirtualMachineError || this is ThreadDeath || this is LinkageError
 }
diff --git a/reactive/kotlinx-coroutines-reactive/test/IntegrationTest.kt b/reactive/kotlinx-coroutines-reactive/test/IntegrationTest.kt
index ca18349..aaeaa00 100644
--- a/reactive/kotlinx-coroutines-reactive/test/IntegrationTest.kt
+++ b/reactive/kotlinx-coroutines-reactive/test/IntegrationTest.kt
@@ -20,7 +20,7 @@
 ) : TestBase() {
 
     enum class Ctx {
-        MAIN        { override fun invoke(context: CoroutineContext): CoroutineContext = context },
+        MAIN        { override fun invoke(context: CoroutineContext): CoroutineContext = context.minusKey(Job) },
         DEFAULT     { override fun invoke(context: CoroutineContext): CoroutineContext = Dispatchers.Default },
         UNCONFINED  { override fun invoke(context: CoroutineContext): CoroutineContext = Dispatchers.Unconfined };
 
@@ -39,7 +39,7 @@
 
     @Test
     fun testEmpty(): Unit = runBlocking {
-        val pub = CoroutineScope(ctx(coroutineContext)).publish<String> {
+        val pub = publish<String>(ctx(coroutineContext)) {
             if (delay) delay(1)
             // does not send anything
         }
@@ -77,7 +77,7 @@
     @Test
     fun testNumbers() = runBlocking<Unit> {
         val n = 100 * stressTestMultiplier
-        val pub = CoroutineScope(ctx(coroutineContext)).publish {
+        val pub = publish(ctx(coroutineContext)) {
             for (i in 1..n) {
                 send(i)
                 if (delay) delay(1)
@@ -99,8 +99,7 @@
     fun testCancelWithoutValue() = runTest {
         val job = launch(Job(), start = CoroutineStart.UNDISPATCHED) {
             publish<String> {
-                yield()
-                expectUnreached()
+                hang {}
             }.awaitFirst()
         }
 
diff --git a/reactive/kotlinx-coroutines-reactive/test/PublishParentCancelStressTest.kt b/reactive/kotlinx-coroutines-reactive/test/PublishParentCancelStressTest.kt
deleted file mode 100644
index 5936712..0000000
--- a/reactive/kotlinx-coroutines-reactive/test/PublishParentCancelStressTest.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.coroutines.reactive
-
-import kotlinx.coroutines.*
-import org.junit.*
-import org.junit.Test
-import org.reactivestreams.*
-import java.util.concurrent.*
-import kotlin.test.*
-
-public class PublishParentCancelStressTest : TestBase() {
-    private val dispatcher = newFixedThreadPoolContext(3, "PublishParentCancelStressTest")
-    private val N_TIMES = 5000 * stressTestMultiplier
-
-    @After
-    fun tearDown() {
-        dispatcher.close()
-    }
-
-    @Test
-    fun testStress() = runTest {
-        var unhandled: Throwable? = null
-        val handler = CoroutineExceptionHandler { _, ex -> unhandled = ex }
-        repeat(N_TIMES) {
-            val barrier = CyclicBarrier(4)
-            // launch parent job for publisher
-            val parent = GlobalScope.async<Unit>(dispatcher + handler) {
-                val publisher = publish<Unit> {
-                    // BARRIER #1 - child publisher crashes
-                    barrier.await()
-                    throw TestException()
-                }
-                var sub: Subscription? = null
-                publisher.subscribe(object : Subscriber<Unit> {
-                    override fun onComplete() { error("Cannot be reached") }
-                    override fun onSubscribe(s: Subscription?) { sub = s }
-                    override fun onNext(t: Unit?) { error("Cannot be reached" ) }
-                    override fun onError(t: Throwable?) {
-                        assertTrue(t is TestException)
-                    }
-                })
-                launch {
-                    // BARRIER #3 -- cancel subscription
-                    barrier.await()
-                    sub!!.cancel()
-                }
-                // BARRIER #2 -- parent completes
-                barrier.await()
-                Unit
-            }
-            // BARRIE #4 - go 1-3 together
-            barrier.await()
-            // Make sure exception is not lost, but incorporated into parent
-            val result = kotlin.runCatching { parent.await() }
-            assertTrue(result.exceptionOrNull() is TestException)
-            // Make sure unhandled exception handler was not invoked
-            assertNull(unhandled)
-        }
-    }
-
-    private class TestException : Exception()
-}
\ No newline at end of file
diff --git a/reactive/kotlinx-coroutines-reactive/test/PublishTest.kt b/reactive/kotlinx-coroutines-reactive/test/PublishTest.kt
index e022ff1..4ffa074 100644
--- a/reactive/kotlinx-coroutines-reactive/test/PublishTest.kt
+++ b/reactive/kotlinx-coroutines-reactive/test/PublishTest.kt
@@ -14,7 +14,7 @@
     @Test
     fun testBasicEmpty() = runTest {
         expect(1)
-        val publisher = publish<Int> {
+        val publisher = publish<Int>(currentDispatcher()) {
             expect(5)
         }
         expect(2)
@@ -32,7 +32,7 @@
     @Test
     fun testBasicSingle() = runTest {
         expect(1)
-        val publisher = publish {
+        val publisher = publish(currentDispatcher()) {
             expect(5)
             send(42)
             expect(7)
@@ -58,7 +58,7 @@
     @Test
     fun testBasicError() = runTest {
         expect(1)
-        val publisher = publish<Int>(NonCancellable) {
+        val publisher = publish<Int>(currentDispatcher()) {
             expect(5)
             throw RuntimeException("OK")
         }
@@ -82,23 +82,14 @@
     }
 
     @Test
-    fun testCancelsParentOnFailure() = runTest(
-        expected = { it is RuntimeException && it.message == "OK" }
-    ) {
-        // has parent, so should cancel it on failure
-        publish<Unit> {
-            throw RuntimeException("OK")
-        }.openSubscription()
-    }
-
-    @Test
-    fun testHandleFailureAfterCancel() = runTest(
-        unhandled = listOf({ it -> it is RuntimeException && it.message == "FAILED" })
-    ){
+    fun testHandleFailureAfterCancel() = runTest {
         expect(1)
-        // Exception should be delivered to CoroutineExceptionHandler, because we create publisher
-        // with the NonCancellable parent
-        val publisher = publish<Unit>(NonCancellable + Dispatchers.Unconfined) {
+
+        val eh = CoroutineExceptionHandler { _, t ->
+            assertTrue(t is RuntimeException)
+            expect(6)
+        }
+        val publisher = publish<Unit>(Dispatchers.Unconfined + eh) {
             try {
                 expect(3)
                 delay(10000)
@@ -128,95 +119,13 @@
         })
         expect(4)
         sub!!.cancel()
-        finish(6)
-    }
-
-    @Test
-    fun testParentHandlesFailure() = runTest {
-        expect(1)
-        val deferred = CompletableDeferred<Unit>()
-        val publisher = publish<Unit>(deferred + Dispatchers.Unconfined) {
-            try {
-                expect(3)
-                delay(10000)
-            } finally {
-                expect(5)
-                throw TestException("FAILED")
-            }
-        }
-        var sub: Subscription? = null
-        publisher.subscribe(object : Subscriber<Unit> {
-            override fun onComplete() {
-                expectUnreached()
-            }
-
-            override fun onSubscribe(s: Subscription) {
-                expect(2)
-                sub = s
-            }
-
-            override fun onNext(t: Unit?) {
-                expectUnreached()
-            }
-
-            override fun onError(t: Throwable?) {
-                expectUnreached()
-            }
-        })
-        expect(4)
-        sub!!.cancel()
-
-        try {
-            deferred.await()
-            expectUnreached()
-        } catch (e: TestException) {
-            expect(6)
-        }
-
         finish(7)
     }
 
     @Test
-    fun testPublishFailureCancelsParent() = runTest(
-        expected = { it is TestException }
-    ) {
-        expect(1)
-        val publisher = publish<Unit> {
-            expect(5)
-            throw TestException()
-        }
-        expect(2)
-        publisher.subscribe(object : Subscriber<Unit> {
-            override fun onComplete() {
-                expectUnreached()
-            }
-
-            override fun onSubscribe(s: Subscription) {
-                expect(3)
-            }
-
-            override fun onNext(t: Unit?) {
-                expectUnreached()
-            }
-
-            override fun onError(t: Throwable?) {
-                assertTrue(t is TestException)
-                expect(6)
-            }
-        })
-        expect(4)
-        try {
-            yield() // to coroutine, will crash because it is a cancelled parent coroutine
-        } finally {
-            finish(7)
-        }
-        expectUnreached()
-    }
-
-    @Test
     fun testOnNextError() = runTest {
         expect(1)
-        val publisher = publish<String>(NonCancellable) {
+        val publisher = publish(currentDispatcher()) {
             expect(4)
             try {
                 send("OK")
@@ -255,7 +164,7 @@
 
     @Test
     fun testFailingConsumer() = runTest {
-        val pub = publish {
+        val pub = publish(currentDispatcher()) {
             repeat(3) {
                 expect(it + 1) // expect(1), expect(2) *should* be invoked
                 send(it)
@@ -269,4 +178,9 @@
             finish(3)
         }
     }
+
+    @Test
+    fun testIllegalArgumentException() {
+        assertFailsWith<IllegalArgumentException> { publish<Int>(Job()) { } }
+    }
 }
\ No newline at end of file
diff --git a/reactive/kotlinx-coroutines-reactive/test/PublisherBackpressureTest.kt b/reactive/kotlinx-coroutines-reactive/test/PublisherBackpressureTest.kt
index 503a015..258632b 100644
--- a/reactive/kotlinx-coroutines-reactive/test/PublisherBackpressureTest.kt
+++ b/reactive/kotlinx-coroutines-reactive/test/PublisherBackpressureTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines.reactive
@@ -12,7 +12,7 @@
     @Test
     fun testCancelWhileBPSuspended() = runBlocking {
         expect(1)
-        val observable = publish {
+        val observable = publish(currentDispatcher()) {
             expect(5)
             send("A") // will not suspend, because an item was requested
             expect(7)
diff --git a/reactive/kotlinx-coroutines-reactive/test/PublisherMultiTest.kt b/reactive/kotlinx-coroutines-reactive/test/PublisherMultiTest.kt
index cac2f55..e238d39 100644
--- a/reactive/kotlinx-coroutines-reactive/test/PublisherMultiTest.kt
+++ b/reactive/kotlinx-coroutines-reactive/test/PublisherMultiTest.kt
@@ -13,7 +13,7 @@
     @Test
     fun testConcurrentStress() = runBlocking {
         val n = 10_000 * stressTestMultiplier
-        val observable = GlobalScope.publish {
+        val observable = publish {
             // concurrent emitters (many coroutines)
             val jobs = List(n) {
                 // launch
diff --git a/reactive/kotlinx-coroutines-reactive/test/ReactiveStreamTckTest.kt b/reactive/kotlinx-coroutines-reactive/test/ReactiveStreamTckTest.kt
index 2e55b8a..6816a98 100644
--- a/reactive/kotlinx-coroutines-reactive/test/ReactiveStreamTckTest.kt
+++ b/reactive/kotlinx-coroutines-reactive/test/ReactiveStreamTckTest.kt
@@ -26,29 +26,17 @@
         private val dispatcher: Dispatcher
     ) : PublisherVerification<Long>(TestEnvironment(500, 500)) {
 
-        private val scope = CoroutineScope(dispatcher.dispatcher + NonCancellable)
-
         override fun createPublisher(elements: Long): Publisher<Long> =
-            scope.publish {
+            publish(dispatcher.dispatcher) {
                 for (i in 1..elements) send(i)
             }
 
         override fun createFailedPublisher(): Publisher<Long> =
-            scope.publish {
+            publish(dispatcher.dispatcher) {
                 throw TestException()
             }
 
         @Test
-        public override fun required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber() {
-            // This test fails on default dispatcher because it retains a reference to the last task
-            // in the structure of  its GlobalQueue
-            // So we skip it with the default dispatcher.
-            // todo: remove it when CoroutinesScheduler is improved
-            if (dispatcher == Dispatcher.DEFAULT) return
-            super.required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber()
-        }
-
-        @Test
         public override fun optional_spec105_emptyStreamMustTerminateBySignallingOnComplete() {
             throw SkipException("Skipped")
         }
diff --git a/reactive/kotlinx-coroutines-reactive/test/flow/PublisherAsFlowTest.kt b/reactive/kotlinx-coroutines-reactive/test/flow/PublisherAsFlowTest.kt
index 74f5914..3f33b33 100644
--- a/reactive/kotlinx-coroutines-reactive/test/flow/PublisherAsFlowTest.kt
+++ b/reactive/kotlinx-coroutines-reactive/test/flow/PublisherAsFlowTest.kt
@@ -17,7 +17,7 @@
         var onCancelled = 0
         var onError = 0
 
-        val publisher = publish {
+        val publisher = publish(currentDispatcher()) {
             coroutineContext[Job]?.invokeOnCompletion {
                 if (it is CancellationException) ++onCancelled
             }
@@ -45,7 +45,7 @@
 
     @Test
     fun testBufferSize1() = runTest {
-        val publisher = publish {
+        val publisher = publish(currentDispatcher()) {
             expect(1)
             send(3)
 
@@ -66,7 +66,7 @@
 
     @Test
     fun testBufferSize10() = runTest {
-        val publisher = publish {
+        val publisher = publish(currentDispatcher()) {
             expect(1)
             send(5)
 
@@ -87,7 +87,7 @@
 
     @Test
     fun testConflated() = runTest {
-        val publisher = publish {
+        val publisher = publish(currentDispatcher()) {
             for (i in 1..5) send(i)
         }
         val list = publisher.asFlow().conflate().toList()
@@ -96,7 +96,7 @@
 
     @Test
     fun testProduce() = runTest {
-        val flow = publish { repeat(10) { send(it) } }.asFlow()
+        val flow = publish(currentDispatcher()) { repeat(10) { send(it) } }.asFlow()
         check((0..9).toList(), flow.produceIn(this))
         check((0..9).toList(), flow.buffer(2).produceIn(this))
         check((0..9).toList(), flow.buffer(Channel.UNLIMITED).produceIn(this))
@@ -113,7 +113,7 @@
     fun testProduceCancellation() = runTest {
         expect(1)
         // publisher is an async coroutine, so it overproduces to the channel, but still gets cancelled
-        val flow = publish {
+        val flow = publish(currentDispatcher()) {
             expect(3)
             repeat(10) { value ->
                 when (value) {
diff --git a/reactive/kotlinx-coroutines-reactor/README.md b/reactive/kotlinx-coroutines-reactor/README.md
index 1a08834..1531488 100644
--- a/reactive/kotlinx-coroutines-reactor/README.md
+++ b/reactive/kotlinx-coroutines-reactor/README.md
@@ -29,8 +29,8 @@
 <!--- INDEX kotlinx.coroutines.channels -->
 <!--- MODULE kotlinx-coroutines-reactor -->
 <!--- INDEX kotlinx.coroutines.reactor -->
-[mono]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactor/kotlinx.coroutines.reactor/kotlinx.coroutines.-coroutine-scope/mono.html
-[flux]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactor/kotlinx.coroutines.reactor/kotlinx.coroutines.-coroutine-scope/flux.html
+[mono]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactor/kotlinx.coroutines.reactor/mono.html
+[flux]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactor/kotlinx.coroutines.reactor/flux.html
 [kotlinx.coroutines.Job.asMono]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactor/kotlinx.coroutines.reactor/kotlinx.coroutines.-job/as-mono.html
 [kotlinx.coroutines.Deferred.asMono]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactor/kotlinx.coroutines.reactor/kotlinx.coroutines.-deferred/as-mono.html
 [kotlinx.coroutines.channels.ReceiveChannel.asFlux]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactor/kotlinx.coroutines.reactor/kotlinx.coroutines.channels.-receive-channel/as-flux.html
diff --git a/reactive/kotlinx-coroutines-reactor/build.gradle b/reactive/kotlinx-coroutines-reactor/build.gradle
index 72ef6e5..c73716d 100644
--- a/reactive/kotlinx-coroutines-reactor/build.gradle
+++ b/reactive/kotlinx-coroutines-reactor/build.gradle
@@ -12,4 +12,12 @@
         url = new URL("https://projectreactor.io/docs/core/$reactor_vesion/api/")
         packageListUrl = projectDir.toPath().resolve("package.list").toUri().toURL()
     }
+}
+
+compileTestKotlin {
+    kotlinOptions.jvmTarget = "1.8"
+}
+
+compileKotlin {
+    kotlinOptions.jvmTarget = "1.8"
 }
\ No newline at end of file
diff --git a/reactive/kotlinx-coroutines-reactor/src/Convert.kt b/reactive/kotlinx-coroutines-reactor/src/Convert.kt
index ea9f882..cf6b65d 100644
--- a/reactive/kotlinx-coroutines-reactor/src/Convert.kt
+++ b/reactive/kotlinx-coroutines-reactor/src/Convert.kt
@@ -22,7 +22,7 @@
  * @param context -- the coroutine context from which the resulting mono is going to be signalled
  */
 @ExperimentalCoroutinesApi
-public fun Job.asMono(context: CoroutineContext): Mono<Unit> = GlobalScope.mono(context) { this@asMono.join() }
+public fun Job.asMono(context: CoroutineContext): Mono<Unit> = mono(context) { this@asMono.join() }
 /**
  * Converts this deferred value to the hot reactive mono that signals
  * [success][MonoSink.success] or [error][MonoSink.error].
@@ -36,7 +36,7 @@
  * @param context -- the coroutine context from which the resulting mono is going to be signalled
  */
 @ExperimentalCoroutinesApi
-public fun <T> Deferred<T?>.asMono(context: CoroutineContext): Mono<T> = GlobalScope.mono(context) { this@asMono.await() }
+public fun <T> Deferred<T?>.asMono(context: CoroutineContext): Mono<T> = mono(context) { this@asMono.await() }
 
 /**
  * Converts a stream of elements received from the channel to the hot reactive flux.
@@ -50,7 +50,7 @@
  * @param context -- the coroutine context from which the resulting flux is going to be signalled
  */
 @ObsoleteCoroutinesApi
-public fun <T> ReceiveChannel<T>.asFlux(context: CoroutineContext = EmptyCoroutineContext): Flux<T> = GlobalScope.flux(context) {
+public fun <T> ReceiveChannel<T>.asFlux(context: CoroutineContext = EmptyCoroutineContext): Flux<T> = flux(context) {
     for (t in this@asFlux)
         send(t)
 }
\ No newline at end of file
diff --git a/reactive/kotlinx-coroutines-reactor/src/Flux.kt b/reactive/kotlinx-coroutines-reactor/src/Flux.kt
index 3495501..316146b 100644
--- a/reactive/kotlinx-coroutines-reactor/src/Flux.kt
+++ b/reactive/kotlinx-coroutines-reactor/src/Flux.kt
@@ -1,24 +1,28 @@
+
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+
 package kotlinx.coroutines.reactor
 
 import kotlinx.coroutines.*
 import kotlinx.coroutines.channels.*
 import kotlinx.coroutines.reactive.*
+import org.reactivestreams.Publisher
+import reactor.core.CoreSubscriber
 import reactor.core.publisher.*
 import kotlin.coroutines.*
+import kotlin.internal.LowPriorityInOverloadResolution
 
 /**
  * Creates cold reactive [Flux] that runs a given [block] in a coroutine.
  * Every time the returned flux is subscribed, it starts a new coroutine in the specified [context].
  * Coroutine emits items with `send`. Unsubscribing cancels running coroutine.
  *
- * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument.
+ * Coroutine context can be specified with [context] argument.
  * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used.
- * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden
- * with corresponding [coroutineContext] element.
  *
  * Invocations of `send` are suspended appropriately when subscribers apply back-pressure and to ensure that
  * `onNext` is not invoked concurrently.
@@ -29,12 +33,45 @@
  * | Normal completion or `close` without cause   | `onComplete`
  * | Failure with exception or `close` with cause | `onError`
  *
+ * Method throws [IllegalArgumentException] if provided [context] contains a [Job] instance.
+ *
  * **Note: This is an experimental api.** Behaviour of publishers that work as children in a parent scope with respect
  *        to cancellation and error handling may change in the future.
  */
 @ExperimentalCoroutinesApi
-fun <T> CoroutineScope.flux(
+public fun <T> flux(
+    context: CoroutineContext = EmptyCoroutineContext,
+    @BuilderInference block: suspend ProducerScope<T>.() -> Unit
+): Flux<T> {
+    require(context[Job] === null) { "Flux context cannot contain job in it." +
+        "Its lifecycle should be managed via Disposable handle. Had $context" }
+    return Flux.from(reactorPublish(GlobalScope, context, block))
+}
+
+@Deprecated(
+    message = "CoroutineScope.flux is deprecated in favour of top-level flux",
+    level = DeprecationLevel.WARNING,
+    replaceWith = ReplaceWith("flux(context, block)")
+) // Since 1.3.0, will be error in 1.3.1 and hidden in 1.4.0. Binary compatibility with Spring
+@LowPriorityInOverloadResolution
+public fun <T> CoroutineScope.flux(
     context: CoroutineContext = EmptyCoroutineContext,
     @BuilderInference block: suspend ProducerScope<T>.() -> Unit
 ): Flux<T> =
-    Flux.from(publish(newCoroutineContext(context), block = block))
+    Flux.from(reactorPublish(this, context, block))
+
+private fun <T> reactorPublish(
+    scope: CoroutineScope,
+    context: CoroutineContext = EmptyCoroutineContext,
+    @BuilderInference block: suspend ProducerScope<T>.() -> Unit
+): Publisher<T> = Publisher { subscriber ->
+    // specification requires NPE on null subscriber
+    if (subscriber == null) throw NullPointerException("Subscriber cannot be null")
+    require(subscriber is CoreSubscriber) { "Subscriber is not an instance of CoreSubscriber, context can not be extracted." }
+    val currentContext = subscriber.currentContext()
+    val reactorContext = (context[ReactorContext]?.context?.putAll(currentContext) ?: currentContext).asCoroutineContext()
+    val newContext = scope.newCoroutineContext(context + reactorContext)
+    val coroutine = PublisherCoroutine(newContext, subscriber)
+    subscriber.onSubscribe(coroutine) // do it first (before starting coroutine), to avoid unnecessary suspensions
+    coroutine.start(CoroutineStart.DEFAULT, coroutine, block)
+}
diff --git a/reactive/kotlinx-coroutines-reactor/src/Mono.kt b/reactive/kotlinx-coroutines-reactor/src/Mono.kt
index 7174fb6..b218f6d 100644
--- a/reactive/kotlinx-coroutines-reactor/src/Mono.kt
+++ b/reactive/kotlinx-coroutines-reactor/src/Mono.kt
@@ -1,13 +1,16 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+
 package kotlinx.coroutines.reactor
 
 import kotlinx.coroutines.*
 import reactor.core.*
 import reactor.core.publisher.*
 import kotlin.coroutines.*
+import kotlin.internal.*
 
 /**
  * Creates cold [mono][Mono] that will run a given [block] in a coroutine.
@@ -20,19 +23,38 @@
  * | Returns a null                        | `success`
  * | Failure with exception or unsubscribe | `error`
  *
- * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument.
+ * Coroutine context can be specified with [context] argument.
  * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used.
- * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden
- * with corresponding [coroutineContext] element.
  *
- * @param context context of the coroutine.
- * @param block the coroutine code.
+ * Method throws [IllegalArgumentException] if provided [context] contains a [Job] instance.
  */
-fun <T> CoroutineScope.mono(
+public fun <T> mono(
     context: CoroutineContext = EmptyCoroutineContext,
     block: suspend CoroutineScope.() -> T?
+): Mono<T> {
+    require(context[Job] === null) { "Mono context cannot contain job in it." +
+            "Its lifecycle should be managed via Disposable handle. Had $context" }
+    return monoInternal(GlobalScope, context, block)
+}
+
+@Deprecated(
+    message = "CoroutineScope.mono is deprecated in favour of top-level mono",
+    level = DeprecationLevel.WARNING,
+    replaceWith = ReplaceWith("mono(context, block)")
+) // Since 1.3.0, will be error in 1.3.1 and hidden in 1.4.0
+@LowPriorityInOverloadResolution
+public fun <T> CoroutineScope.mono(
+    context: CoroutineContext = EmptyCoroutineContext,
+    block: suspend CoroutineScope.() -> T?
+): Mono<T> = monoInternal(this, context, block)
+
+private fun <T> monoInternal(
+    scope: CoroutineScope, // support for legacy mono in scope
+    context: CoroutineContext,
+    block: suspend CoroutineScope.() -> T?
 ): Mono<T> = Mono.create { sink ->
-    val newContext = newCoroutineContext(context)
+    val reactorContext = (context[ReactorContext]?.context?.putAll(sink.currentContext()) ?: sink.currentContext()).asCoroutineContext()
+    val newContext = scope.newCoroutineContext(context + reactorContext)
     val coroutine = MonoCoroutine(newContext, sink)
     sink.onDispose(coroutine)
     coroutine.start(CoroutineStart.DEFAULT, coroutine, block)
@@ -57,7 +79,7 @@
             handleCoroutineException(context, cause)
         }
     }
-    
+
     override fun dispose() {
         disposed = true
         cancel()
@@ -65,4 +87,3 @@
 
     override fun isDisposed(): Boolean = disposed
 }
-
diff --git a/reactive/kotlinx-coroutines-reactor/src/ReactorContext.kt b/reactive/kotlinx-coroutines-reactor/src/ReactorContext.kt
new file mode 100644
index 0000000..5a4ccd0
--- /dev/null
+++ b/reactive/kotlinx-coroutines-reactor/src/ReactorContext.kt
@@ -0,0 +1,44 @@
+package kotlinx.coroutines.reactor
+
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import reactor.util.context.Context
+import kotlin.coroutines.*
+
+/**
+ * Wraps Reactor's [Context] into [CoroutineContext] element for seamless integration Reactor and kotlinx.coroutines.
+ *
+ * [Context.asCoroutineContext] is defined to add Reactor's [Context] elements as part of [CoroutineContext].
+ *
+ * Reactor builders [mono] and [flux] use this context element to enhance the resulting `subscriberContext`.
+ *
+ * ### Usages
+ * Passing reactor context from coroutine builder to reactor entity:
+ * ```
+ * launch(Context.of("key", "value").asCoroutineContext()) {
+ *     mono {
+ *         println(coroutineContext[ReactorContext]) // Prints { "key": "value" }
+ *     }.subscribe()
+ * }
+ * ```
+ *
+ * Accessing modified reactor context enriched from the downstream:
+ * ```
+ * launch {
+ *     mono {
+ *         println(coroutineContext[ReactorContext]) // Prints { "key": "value" }
+ *     }.subscriberContext(Context.of("key", "value"))
+ *    .subscribe()
+ * }
+ * ```
+ */
+@ExperimentalCoroutinesApi
+public class ReactorContext(val context: Context) : AbstractCoroutineContextElement(ReactorContext) {
+    companion object Key : CoroutineContext.Key<ReactorContext>
+}
+
+/**
+ * Wraps the given [Context] into [ReactorContext], so it can be added to coroutine's context
+ * and later used via `coroutineContext[ReactorContext]`.
+ */
+@ExperimentalCoroutinesApi
+public fun Context.asCoroutineContext(): ReactorContext = ReactorContext(this)
\ No newline at end of file
diff --git a/reactive/kotlinx-coroutines-reactor/test/ConvertTest.kt b/reactive/kotlinx-coroutines-reactor/test/ConvertTest.kt
index 9bd55cd..10e05b7 100644
--- a/reactive/kotlinx-coroutines-reactor/test/ConvertTest.kt
+++ b/reactive/kotlinx-coroutines-reactor/test/ConvertTest.kt
@@ -17,7 +17,7 @@
         val job = launch {
             expect(3)
         }
-        val mono = job.asMono(coroutineContext)
+        val mono = job.asMono(coroutineContext.minusKey(Job))
         mono.subscribe {
             expect(4)
         }
@@ -29,11 +29,11 @@
     @Test
     fun testJobToMonoFail() = runBlocking {
         expect(1)
-        val job = async(NonCancellable) { // don't kill parent on exception
+        val job = async(NonCancellable) {
             expect(3)
             throw RuntimeException("OK")
         }
-        val mono = job.asMono(coroutineContext + NonCancellable)
+        val mono = job.asMono(coroutineContext.minusKey(Job))
         mono.subscribe(
                 { fail("no item should be emitted") },
                 { expect(4) }
@@ -110,10 +110,10 @@
             throw TestException("K")
         }
         val flux = c.asFlux(Dispatchers.Unconfined)
-        val mono = GlobalScope.mono(Dispatchers.Unconfined) {
+        val mono = mono(Dispatchers.Unconfined) {
             var result = ""
             try {
-                flux.consumeEach { result += it }
+                flux.collect { result += it }
             } catch(e: Throwable) {
                 check(e is TestException)
                 result += e.message
diff --git a/reactive/kotlinx-coroutines-reactor/test/FluxMultiTest.kt b/reactive/kotlinx-coroutines-reactor/test/FluxMultiTest.kt
index c4c0dbc..ae23d3c 100644
--- a/reactive/kotlinx-coroutines-reactor/test/FluxMultiTest.kt
+++ b/reactive/kotlinx-coroutines-reactor/test/FluxMultiTest.kt
@@ -15,7 +15,7 @@
     @Test
     fun testNumbers() {
         val n = 100 * stressTestMultiplier
-        val flux = GlobalScope.flux {
+        val flux = flux {
             repeat(n) { send(it) }
         }
         checkMonoValue(flux.collectList()) { list ->
@@ -26,7 +26,7 @@
     @Test
     fun testConcurrentStress() {
         val n = 10_000 * stressTestMultiplier
-        val flux = GlobalScope.flux {
+        val flux = flux {
             // concurrent emitters (many coroutines)
             val jobs = List(n) {
                 // launch
@@ -45,7 +45,7 @@
     @Test
     fun testIteratorResendUnconfined() {
         val n = 10_000 * stressTestMultiplier
-        val flux = GlobalScope.flux(Dispatchers.Unconfined) {
+        val flux = flux(Dispatchers.Unconfined) {
             Flux.range(0, n).collect { send(it) }
         }
         checkMonoValue(flux.collectList()) { list ->
@@ -56,7 +56,7 @@
     @Test
     fun testIteratorResendPool() {
         val n = 10_000 * stressTestMultiplier
-        val flux = GlobalScope.flux {
+        val flux = flux {
             Flux.range(0, n).collect { send(it) }
         }
         checkMonoValue(flux.collectList()) { list ->
@@ -66,11 +66,11 @@
 
     @Test
     fun testSendAndCrash() {
-        val flux = GlobalScope.flux {
+        val flux = flux {
             send("O")
             throw IOException("K")
         }
-        val mono = GlobalScope.mono {
+        val mono = mono {
             var result = ""
             try {
                 flux.consumeEach { result += it }
diff --git a/reactive/kotlinx-coroutines-reactor/test/FluxSingleTest.kt b/reactive/kotlinx-coroutines-reactor/test/FluxSingleTest.kt
index 241cc6a..7d8d469 100644
--- a/reactive/kotlinx-coroutines-reactor/test/FluxSingleTest.kt
+++ b/reactive/kotlinx-coroutines-reactor/test/FluxSingleTest.kt
@@ -14,7 +14,7 @@
 class FluxSingleTest {
     @Test
     fun testSingleNoWait() {
-        val flux = GlobalScope.flux {
+        val flux = flux {
             send("OK")
         }
 
@@ -30,7 +30,7 @@
 
     @Test
     fun testSingleEmitAndAwait() {
-        val flux = GlobalScope.flux {
+        val flux = flux {
             send(Flux.just("O").awaitSingle() + "K")
         }
 
@@ -41,7 +41,7 @@
 
     @Test
     fun testSingleWithDelay() {
-        val flux = GlobalScope.flux {
+        val flux = flux {
             send(Flux.just("O").delayElements(ofMillis(50)).awaitSingle() + "K")
         }
 
@@ -52,7 +52,7 @@
 
     @Test
     fun testSingleException() {
-        val flux = GlobalScope.flux {
+        val flux = flux {
             send(Flux.just("O", "K").awaitSingle() + "K")
         }
 
@@ -63,7 +63,7 @@
 
     @Test
     fun testAwaitFirst() {
-        val flux = GlobalScope.flux {
+        val flux = flux {
             send(Flux.just("O", "#").awaitFirst() + "K")
         }
 
@@ -74,7 +74,7 @@
 
     @Test
     fun testAwaitFirstOrDefault() {
-        val flux = GlobalScope.flux {
+        val flux = flux {
             send(Flux.empty<String>().awaitFirstOrDefault("O") + "K")
         }
 
@@ -85,7 +85,7 @@
 
     @Test
     fun testAwaitFirstOrDefaultWithValues() {
-        val flux = GlobalScope.flux {
+        val flux = flux {
             send(Flux.just("O", "#").awaitFirstOrDefault("!") + "K")
         }
 
@@ -96,7 +96,7 @@
 
     @Test
     fun testAwaitFirstOrNull() {
-        val flux = GlobalScope.flux<String> {
+        val flux = flux<String?> {
             send(Flux.empty<String>().awaitFirstOrNull() ?: "OK")
         }
 
@@ -107,7 +107,7 @@
 
     @Test
     fun testAwaitFirstOrNullWithValues() {
-        val flux = GlobalScope.flux {
+        val flux = flux {
             send((Flux.just("O", "#").awaitFirstOrNull() ?: "!") + "K")
         }
 
@@ -118,7 +118,7 @@
 
     @Test
     fun testAwaitFirstOrElse() {
-        val flux = GlobalScope.flux {
+        val flux = flux {
             send(Flux.empty<String>().awaitFirstOrElse { "O" } + "K")
         }
 
@@ -129,7 +129,7 @@
 
     @Test
     fun testAwaitFirstOrElseWithValues() {
-        val flux = GlobalScope.flux {
+        val flux = flux {
             send(Flux.just("O", "#").awaitFirstOrElse { "!" } + "K")
         }
 
@@ -140,7 +140,7 @@
 
     @Test
     fun testAwaitLast() {
-        val flux = GlobalScope.flux {
+        val flux = flux {
             send(Flux.just("#", "O").awaitLast() + "K")
         }
 
@@ -151,7 +151,7 @@
 
     @Test
     fun testExceptionFromObservable() {
-        val flux = GlobalScope.flux {
+        val flux = flux {
             try {
                 send(Flux.error<String>(RuntimeException("O")).awaitFirst())
             } catch (e: RuntimeException) {
@@ -166,7 +166,7 @@
 
     @Test
     fun testExceptionFromCoroutine() {
-        val flux = GlobalScope.flux<String> {
+        val flux = flux<String> {
             error(Flux.just("O").awaitSingle() + "K")
         }
 
@@ -178,7 +178,7 @@
 
     @Test
     fun testFluxIteration() {
-        val flux = GlobalScope.flux {
+        val flux = flux {
             var result = ""
             Flux.just("O", "K").collect { result += it }
             send(result)
@@ -191,7 +191,7 @@
 
     @Test
     fun testFluxIterationFailure() {
-        val flux = GlobalScope.flux {
+        val flux = flux {
             try {
                 Flux.error<String>(RuntimeException("OK")).collect { fail("Should not be here") }
                 send("Fail")
diff --git a/reactive/kotlinx-coroutines-reactor/test/FluxTest.kt b/reactive/kotlinx-coroutines-reactor/test/FluxTest.kt
index a0368f8..ee26455 100644
--- a/reactive/kotlinx-coroutines-reactor/test/FluxTest.kt
+++ b/reactive/kotlinx-coroutines-reactor/test/FluxTest.kt
@@ -15,7 +15,7 @@
     @Test
     fun testBasicSuccess() = runBlocking {
         expect(1)
-        val flux = flux {
+        val flux = flux(currentDispatcher()) {
             expect(4)
             send("OK")
         }
@@ -32,7 +32,7 @@
     @Test
     fun testBasicFailure() = runBlocking {
         expect(1)
-        val flux = flux<String>(NonCancellable) {
+        val flux = flux<String>(currentDispatcher()) {
             expect(4)
             throw RuntimeException("OK")
         }
@@ -52,7 +52,7 @@
     @Test
     fun testBasicUnsubscribe() = runBlocking {
         expect(1)
-        val flux = flux<String> {
+        val flux = flux<String>(currentDispatcher()) {
             expect(4)
             yield() // back to main, will get cancelled
             expectUnreached()
@@ -72,23 +72,10 @@
     }
 
     @Test
-    fun testCancelsParentOnFailure() = runTest(
-        expected = { it is RuntimeException && it.message == "OK" }
-    ) {
-        // has parent, so should cancel it on failure
-        flux<Unit> {
-            throw RuntimeException("OK")
-        }.subscribe(
-            { expectUnreached() },
-            { assert(it is RuntimeException) }
-        )
-    }
-
-    @Test
     fun testNotifyOnceOnCancellation() = runTest {
         expect(1)
         val observable =
-            flux {
+            flux(currentDispatcher()) {
                 expect(5)
                 send("OK")
                 try {
@@ -124,7 +111,7 @@
 
     @Test
     fun testFailingConsumer() = runTest {
-        val pub = flux {
+        val pub = flux(currentDispatcher()) {
             repeat(3) {
                 expect(it + 1) // expect(1), expect(2) *should* be invoked
                 send(it)
@@ -138,4 +125,9 @@
             finish(3)
         }
     }
+
+    @Test
+    fun testIllegalArgumentException() {
+        assertFailsWith<IllegalArgumentException> { flux<Int>(Job()) { } }
+    }
 }
\ No newline at end of file
diff --git a/reactive/kotlinx-coroutines-reactor/test/MonoTest.kt b/reactive/kotlinx-coroutines-reactor/test/MonoTest.kt
index 7c72edc..2283d45 100644
--- a/reactive/kotlinx-coroutines-reactor/test/MonoTest.kt
+++ b/reactive/kotlinx-coroutines-reactor/test/MonoTest.kt
@@ -22,14 +22,14 @@
     @Test
     fun testBasicSuccess() = runBlocking {
         expect(1)
-        val mono = mono {
+        val mono = mono(currentDispatcher()) {
             expect(4)
             "OK"
         }
         expect(2)
         mono.subscribe { value ->
             expect(5)
-            Assert.assertThat(value, IsEqual("OK"))
+            assertThat(value, IsEqual("OK"))
         }
         expect(3)
         yield() // to started coroutine
@@ -39,7 +39,7 @@
     @Test
     fun testBasicFailure() = runBlocking {
         expect(1)
-        val mono = mono(NonCancellable) {
+        val mono = mono(currentDispatcher()) {
             expect(4)
             throw RuntimeException("OK")
         }
@@ -48,8 +48,8 @@
             expectUnreached()
         }, { error ->
             expect(5)
-            Assert.assertThat(error, IsInstanceOf(RuntimeException::class.java))
-            Assert.assertThat(error.message, IsEqual("OK"))
+            assertThat(error, IsInstanceOf(RuntimeException::class.java))
+            assertThat(error.message, IsEqual("OK"))
         })
         expect(3)
         yield() // to started coroutine
@@ -59,7 +59,7 @@
     @Test
     fun testBasicEmpty() = runBlocking {
         expect(1)
-        val mono = mono {
+        val mono = mono(currentDispatcher()) {
             expect(4)
             null
         }
@@ -75,7 +75,7 @@
     @Test
     fun testBasicUnsubscribe() = runBlocking {
         expect(1)
-        val mono = mono {
+        val mono = mono(currentDispatcher()) {
             expect(4)
             yield() // back to main, will get cancelled
             expectUnreached()
@@ -97,7 +97,7 @@
 
     @Test
     fun testMonoNoWait() {
-        val mono = GlobalScope.mono {
+        val mono = mono {
             "OK"
         }
 
@@ -113,7 +113,7 @@
 
     @Test
     fun testMonoEmitAndAwait() {
-        val mono = GlobalScope.mono {
+        val mono = mono {
             Mono.just("O").awaitSingle() + "K"
         }
 
@@ -124,7 +124,7 @@
 
     @Test
     fun testMonoWithDelay() {
-        val mono = GlobalScope.mono {
+        val mono = mono {
             Flux.just("O").delayElements(ofMillis(50)).awaitSingle() + "K"
         }
 
@@ -135,7 +135,7 @@
 
     @Test
     fun testMonoException() {
-        val mono = GlobalScope.mono {
+        val mono = mono {
             Flux.just("O", "K").awaitSingle() + "K"
         }
 
@@ -146,7 +146,7 @@
 
     @Test
     fun testAwaitFirst() {
-        val mono = GlobalScope.mono {
+        val mono = mono {
             Flux.just("O", "#").awaitFirst() + "K"
         }
 
@@ -157,7 +157,7 @@
 
     @Test
     fun testAwaitLast() {
-        val mono = GlobalScope.mono {
+        val mono = mono {
             Flux.just("#", "O").awaitLast() + "K"
         }
 
@@ -168,7 +168,7 @@
 
     @Test
     fun testExceptionFromFlux() {
-        val mono = GlobalScope.mono {
+        val mono = mono {
             try {
                 Flux.error<String>(RuntimeException("O")).awaitFirst()
             } catch (e: RuntimeException) {
@@ -183,7 +183,7 @@
 
     @Test
     fun testExceptionFromCoroutine() {
-        val mono = GlobalScope.mono<String> {
+        val mono = mono<String> {
             throw IllegalStateException(Flux.just("O").awaitSingle() + "K")
         }
 
@@ -194,21 +194,8 @@
     }
 
     @Test
-    fun testCancelsParentOnFailure() = runTest(
-        expected = { it is RuntimeException && it.message == "OK" }
-    ) {
-        // has parent, so should cancel it on failure
-        mono<Unit> {
-            throw RuntimeException("OK")
-        }.subscribe(
-            { expectUnreached() },
-            { assert(it is RuntimeException) }
-        )
-    }
-
-    @Test
     fun testSuppressedException() = runTest {
-        val mono = mono(NonCancellable) {
+        val mono = mono(currentDispatcher()) {
             launch(start = CoroutineStart.ATOMIC) {
                 throw TestException() // child coroutine fails
             }
@@ -227,12 +214,14 @@
     }
 
     @Test
-    fun testUnhandledException() = runTest(
-        unhandled = listOf { it -> it is TestException }
-    ) {
+    fun testUnhandledException() = runTest {
         expect(1)
         var subscription: Subscription? = null
-        val mono = mono(NonCancellable) {
+        val mono = mono(currentDispatcher() + CoroutineExceptionHandler { _, t ->
+            assertTrue(t is TestException)
+            expect(5)
+
+        }) {
             expect(4)
             subscription!!.cancel() // cancel our own subscription, so that delay will get cancelled
             try {
@@ -252,6 +241,11 @@
         })
         expect(3)
         yield() // run coroutine
-        finish(5)
+        finish(6)
+    }
+
+    @Test
+    fun testIllegalArgumentException() {
+        assertFailsWith<IllegalArgumentException> { mono(Job()) { } }
     }
 }
diff --git a/reactive/kotlinx-coroutines-reactor/test/ReactorContextTest.kt b/reactive/kotlinx-coroutines-reactor/test/ReactorContextTest.kt
new file mode 100644
index 0000000..1fb4f0b
--- /dev/null
+++ b/reactive/kotlinx-coroutines-reactor/test/ReactorContextTest.kt
@@ -0,0 +1,32 @@
+package kotlinx.coroutines.reactor
+
+import kotlinx.coroutines.*
+import kotlinx.coroutines.reactive.*
+import org.junit.Test
+import reactor.util.context.Context
+import kotlin.test.assertEquals
+
+class ReactorContextTest {
+    @Test
+    fun testMonoHookedContext() = runBlocking {
+        val mono = mono(Context.of(1, "1", 7, "7").asCoroutineContext()) {
+            val ctx = coroutineContext[ReactorContext]?.context
+            buildString {
+                (1..7).forEach { append(ctx?.getOrDefault(it, "noValue")) }
+            }
+        }   .subscriberContext(Context.of(2, "2", 3, "3", 4, "4", 5, "5"))
+            .subscriberContext { ctx -> ctx.put(6, "6") }
+        assertEquals(mono.awaitFirst(), "1234567")
+    }
+
+    @Test
+    fun testFluxContext() = runBlocking<Unit> {
+        val flux = flux(Context.of(1, "1", 7, "7").asCoroutineContext()) {
+            val ctx = coroutineContext[ReactorContext]!!.context
+            (1..7).forEach { send(ctx.getOrDefault(it, "noValue")) }
+        }   .subscriberContext(Context.of(2, "2", 3, "3", 4, "4", 5, "5"))
+            .subscriberContext { ctx -> ctx.put(6, "6") }
+        var i = 0
+        flux.subscribe { str -> i++; assertEquals(str, i.toString()) }
+    }
+}
\ No newline at end of file
diff --git a/reactive/kotlinx-coroutines-rx2/README.md b/reactive/kotlinx-coroutines-rx2/README.md
index f1079b6..fbdf1b3 100644
--- a/reactive/kotlinx-coroutines-rx2/README.md
+++ b/reactive/kotlinx-coroutines-rx2/README.md
@@ -51,11 +51,11 @@
 [ReceiveChannel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/index.html
 <!--- MODULE kotlinx-coroutines-rx2 -->
 <!--- INDEX kotlinx.coroutines.rx2 -->
-[rxCompletable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/kotlinx.coroutines.-coroutine-scope/rx-completable.html
-[rxMaybe]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/kotlinx.coroutines.-coroutine-scope/rx-maybe.html
-[rxSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/kotlinx.coroutines.-coroutine-scope/rx-single.html
-[rxObservable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/kotlinx.coroutines.-coroutine-scope/rx-observable.html
-[rxFlowable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/kotlinx.coroutines.-coroutine-scope/rx-flowable.html
+[rxCompletable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/rx-completable.html
+[rxMaybe]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/rx-maybe.html
+[rxSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/rx-single.html
+[rxObservable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/rx-observable.html
+[rxFlowable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/rx-flowable.html
 [io.reactivex.CompletableSource.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/io.reactivex.-completable-source/await.html
 [io.reactivex.MaybeSource.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/io.reactivex.-maybe-source/await.html
 [io.reactivex.MaybeSource.awaitOrDefault]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/io.reactivex.-maybe-source/await-or-default.html
diff --git a/reactive/kotlinx-coroutines-rx2/src/RxCompletable.kt b/reactive/kotlinx-coroutines-rx2/src/RxCompletable.kt
index f44ecf7..0da0677 100644
--- a/reactive/kotlinx-coroutines-rx2/src/RxCompletable.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/RxCompletable.kt
@@ -1,12 +1,15 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+
 package kotlinx.coroutines.rx2
 
 import io.reactivex.*
 import kotlinx.coroutines.*
 import kotlin.coroutines.*
+import kotlin.internal.*
 
 /**
  * Creates cold [Completable] that runs a given [block] in a coroutine.
@@ -18,19 +21,36 @@
  * | Completes successfully                | `onCompleted`
  * | Failure with exception or unsubscribe | `onError`
  *
- * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument.
+ * Coroutine context can be specified with [context] argument.
  * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used.
- * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden
- * with corresponding [coroutineContext] element.
- *
- * @param context context of the coroutine.
- * @param block the coroutine code.
+ * Method throws [IllegalArgumentException] if provided [context] contains a [Job] instance.
  */
+public fun rxCompletable(
+    context: CoroutineContext = EmptyCoroutineContext,
+    block: suspend CoroutineScope.() -> Unit
+): Completable {
+    require(context[Job] === null) { "Completable context cannot contain job in it." +
+            "Its lifecycle should be managed via Disposable handle. Had $context" }
+    return rxCompletableInternal(GlobalScope, context, block)
+}
+
+@Deprecated(
+    message = "CoroutineScope.rxCompletable is deprecated in favour of top-level rxCompletable",
+    level = DeprecationLevel.WARNING,
+    replaceWith = ReplaceWith("rxCompletable(context, block)")
+) // Since 1.3.0, will be error in 1.3.1 and hidden in 1.4.0
+@LowPriorityInOverloadResolution
 public fun CoroutineScope.rxCompletable(
     context: CoroutineContext = EmptyCoroutineContext,
     block: suspend CoroutineScope.() -> Unit
+): Completable = rxCompletableInternal(this, context, block)
+
+private fun rxCompletableInternal(
+    scope: CoroutineScope, // support for legacy rxCompletable in scope
+    context: CoroutineContext,
+    block: suspend CoroutineScope.() -> Unit
 ): Completable = Completable.create { subscriber ->
-    val newContext = newCoroutineContext(context)
+    val newContext = scope.newCoroutineContext(context)
     val coroutine = RxCompletableCoroutine(newContext, subscriber)
     subscriber.setCancellable(RxCancellable(coroutine))
     coroutine.start(CoroutineStart.DEFAULT, coroutine, block)
@@ -41,12 +61,20 @@
     private val subscriber: CompletableEmitter
 ) : AbstractCoroutine<Unit>(parentContext, true) {
     override fun onCompleted(value: Unit) {
-        if (!subscriber.isDisposed) subscriber.onComplete()
+        try {
+            if (!subscriber.isDisposed) subscriber.onComplete()
+        } catch (e: Throwable) {
+            handleCoroutineException(context, e)
+        }
     }
 
     override fun onCancelled(cause: Throwable, handled: Boolean) {
         if (!subscriber.isDisposed) {
-            subscriber.onError(cause)
+            try {
+                subscriber.onError(cause)
+            } catch (e: Throwable) {
+                handleCoroutineException(context, e)
+            }
         } else if (!handled) {
             handleCoroutineException(context, cause)
         }
diff --git a/reactive/kotlinx-coroutines-rx2/src/RxConvert.kt b/reactive/kotlinx-coroutines-rx2/src/RxConvert.kt
index dbf29f1..d5678de 100644
--- a/reactive/kotlinx-coroutines-rx2/src/RxConvert.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/RxConvert.kt
@@ -25,7 +25,7 @@
  * @param context -- the coroutine context from which the resulting completable is going to be signalled
  */
 @ExperimentalCoroutinesApi
-public fun Job.asCompletable(context: CoroutineContext): Completable = GlobalScope.rxCompletable(context) {
+public fun Job.asCompletable(context: CoroutineContext): Completable = rxCompletable(context) {
     this@asCompletable.join()
 }
 
@@ -42,7 +42,7 @@
  * @param context -- the coroutine context from which the resulting maybe is going to be signalled
  */
 @ExperimentalCoroutinesApi
-public fun <T> Deferred<T?>.asMaybe(context: CoroutineContext): Maybe<T> = GlobalScope.rxMaybe(context) {
+public fun <T> Deferred<T?>.asMaybe(context: CoroutineContext): Maybe<T> = rxMaybe(context) {
     this@asMaybe.await()
 }
 
@@ -59,7 +59,7 @@
  * @param context -- the coroutine context from which the resulting single is going to be signalled
  */
 @ExperimentalCoroutinesApi
-public fun <T : Any> Deferred<T>.asSingle(context: CoroutineContext): Single<T> = GlobalScope.rxSingle(context) {
+public fun <T : Any> Deferred<T>.asSingle(context: CoroutineContext): Single<T> = rxSingle(context) {
     this@asSingle.await()
 }
 
@@ -75,7 +75,7 @@
  * @param context -- the coroutine context from which the resulting observable is going to be signalled
  */
 @ObsoleteCoroutinesApi
-public fun <T : Any> ReceiveChannel<T>.asObservable(context: CoroutineContext): Observable<T> = GlobalScope.rxObservable(context) {
+public fun <T : Any> ReceiveChannel<T>.asObservable(context: CoroutineContext): Observable<T> = rxObservable(context) {
     for (t in this@asObservable)
         send(t)
 }
diff --git a/reactive/kotlinx-coroutines-rx2/src/RxFlowable.kt b/reactive/kotlinx-coroutines-rx2/src/RxFlowable.kt
index 93d6079..beee40e 100644
--- a/reactive/kotlinx-coroutines-rx2/src/RxFlowable.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/RxFlowable.kt
@@ -1,7 +1,9 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+
 package kotlinx.coroutines.rx2
 
 import io.reactivex.*
@@ -9,6 +11,7 @@
 import kotlinx.coroutines.channels.*
 import kotlinx.coroutines.reactive.*
 import kotlin.coroutines.*
+import kotlin.internal.*
 
 /**
  * Creates cold [flowable][Flowable] that will run a given [block] in a coroutine.
@@ -24,19 +27,29 @@
  * | Normal completion or `close` without cause   | `onComplete`
  * | Failure with exception or `close` with cause | `onError`
  *
- * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument.
+ * Coroutine context can be specified with [context] argument.
  * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used.
- * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden
- * with corresponding [coroutineContext] element.
+ * Method throws [IllegalArgumentException] if provided [context] contains a [Job] instance.
  *
  * **Note: This is an experimental api.** Behaviour of publishers that work as children in a parent scope with respect
- *        to cancellation and error handling may change in the future.
- *
- * @param context context of the coroutine.
- * @param block the coroutine code.
  */
 @ExperimentalCoroutinesApi
+public fun <T: Any> rxFlowable(
+    context: CoroutineContext = EmptyCoroutineContext,
+    @BuilderInference block: suspend ProducerScope<T>.() -> Unit
+): Flowable<T> {
+    require(context[Job] === null) { "Flowable context cannot contain job in it." +
+            "Its lifecycle should be managed via Disposable handle. Had $context" }
+    return Flowable.fromPublisher(publishInternal(GlobalScope, context, block))
+}
+
+@Deprecated(
+    message = "CoroutineScope.rxFlowable is deprecated in favour of top-level rxFlowable",
+    level = DeprecationLevel.WARNING,
+    replaceWith = ReplaceWith("rxFlowable(context, block)")
+) // Since 1.3.0, will be error in 1.3.1 and hidden in 1.4.0
+@LowPriorityInOverloadResolution
 public fun <T: Any> CoroutineScope.rxFlowable(
     context: CoroutineContext = EmptyCoroutineContext,
     @BuilderInference block: suspend ProducerScope<T>.() -> Unit
-): Flowable<T> = Flowable.fromPublisher(publish(newCoroutineContext(context), block = block))
+): Flowable<T> = Flowable.fromPublisher(publishInternal(this, context, block))
diff --git a/reactive/kotlinx-coroutines-rx2/src/RxMaybe.kt b/reactive/kotlinx-coroutines-rx2/src/RxMaybe.kt
index 3e3f13b..fbc366c 100644
--- a/reactive/kotlinx-coroutines-rx2/src/RxMaybe.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/RxMaybe.kt
@@ -1,12 +1,15 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+
 package kotlinx.coroutines.rx2
 
 import io.reactivex.*
 import kotlinx.coroutines.*
 import kotlin.coroutines.*
+import kotlin.internal.*
 
 /**
  * Creates cold [maybe][Maybe] that will run a given [block] in a coroutine.
@@ -19,19 +22,36 @@
  * | Returns a null                        | `onComplete`
  * | Failure with exception or unsubscribe | `onError`
  *
- * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument.
+ * Coroutine context can be specified with [context] argument.
  * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used.
- * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden
- * with corresponding [coroutineContext] element.
- *
- * @param context context of the coroutine.
- * @param block the coroutine code.
+ * Method throws [IllegalArgumentException] if provided [context] contains a [Job] instance.
  */
+public fun <T> rxMaybe(
+    context: CoroutineContext = EmptyCoroutineContext,
+    block: suspend CoroutineScope.() -> T?
+): Maybe<T> {
+    require(context[Job] === null) { "Maybe context cannot contain job in it." +
+            "Its lifecycle should be managed via Disposable handle. Had $context" }
+    return rxMaybeInternal(GlobalScope, context, block)
+}
+
+@Deprecated(
+    message = "CoroutineScope.rxMaybe is deprecated in favour of top-level rxMaybe",
+    level = DeprecationLevel.WARNING,
+    replaceWith = ReplaceWith("rxMaybe(context, block)")
+) // Since 1.3.0, will be error in 1.3.1 and hidden in 1.4.0
+@LowPriorityInOverloadResolution
 public fun <T> CoroutineScope.rxMaybe(
     context: CoroutineContext = EmptyCoroutineContext,
     block: suspend CoroutineScope.() -> T?
+): Maybe<T> = rxMaybeInternal(this, context, block)
+
+private fun <T> rxMaybeInternal(
+    scope: CoroutineScope, // support for legacy rxMaybe in scope
+    context: CoroutineContext,
+    block: suspend CoroutineScope.() -> T?
 ): Maybe<T> = Maybe.create { subscriber ->
-    val newContext = newCoroutineContext(context)
+    val newContext = scope.newCoroutineContext(context)
     val coroutine = RxMaybeCoroutine(newContext, subscriber)
     subscriber.setCancellable(RxCancellable(coroutine))
     coroutine.start(CoroutineStart.DEFAULT, coroutine, block)
@@ -43,13 +63,21 @@
 ) : AbstractCoroutine<T>(parentContext, true) {
     override fun onCompleted(value: T) {
         if (!subscriber.isDisposed) {
-            if (value == null) subscriber.onComplete() else subscriber.onSuccess(value)
+            try {
+                if (value == null) subscriber.onComplete() else subscriber.onSuccess(value)
+            } catch(e: Throwable) {
+                handleCoroutineException(context, e)
+            }
         }
     }
 
     override fun onCancelled(cause: Throwable, handled: Boolean) {
         if (!subscriber.isDisposed) {
-            subscriber.onError(cause)
+            try {
+                subscriber.onError(cause)
+            } catch (e: Throwable) {
+                handleCoroutineException(context, e)
+            }
         } else if (!handled) {
             handleCoroutineException(context, cause)
         }
diff --git a/reactive/kotlinx-coroutines-rx2/src/RxObservable.kt b/reactive/kotlinx-coroutines-rx2/src/RxObservable.kt
index f78f5ea..3d0ccd8 100644
--- a/reactive/kotlinx-coroutines-rx2/src/RxObservable.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/RxObservable.kt
@@ -1,16 +1,20 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+
 package kotlinx.coroutines.rx2
 
 import io.reactivex.*
+import io.reactivex.exceptions.*
 import kotlinx.atomicfu.*
 import kotlinx.coroutines.*
 import kotlinx.coroutines.channels.*
 import kotlinx.coroutines.selects.*
 import kotlinx.coroutines.sync.*
 import kotlin.coroutines.*
+import kotlin.internal.*
 
 /**
  * Creates cold [observable][Observable] that will run a given [block] in a coroutine.
@@ -26,23 +30,37 @@
  * | Normal completion or `close` without cause   | `onComplete`
  * | Failure with exception or `close` with cause | `onError`
  *
- * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument.
+ * Coroutine context can be specified with [context] argument.
  * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used.
- * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden
- * with corresponding [coroutineContext] element.
- *
- * **Note: This is an experimental api.** Behaviour of publishers that work as children in a parent scope with respect
- *        to cancellation and error handling may change in the future.
- *
- * @param context context of the coroutine.
- * @param block the coroutine code.
+ * Method throws [IllegalArgumentException] if provided [context] contains a [Job] instance.
  */
 @ExperimentalCoroutinesApi
+public fun <T : Any> rxObservable(
+    context: CoroutineContext = EmptyCoroutineContext,
+    @BuilderInference block: suspend ProducerScope<T>.() -> Unit
+): Observable<T> {
+    require(context[Job] === null) { "Observable context cannot contain job in it." +
+            "Its lifecycle should be managed via Disposable handle. Had $context" }
+    return rxObservableInternal(GlobalScope, context, block)
+}
+
+@Deprecated(
+    message = "CoroutineScope.rxObservable is deprecated in favour of top-level rxObservable",
+    level = DeprecationLevel.WARNING,
+    replaceWith = ReplaceWith("rxObservable(context, block)")
+) // Since 1.3.0, will be error in 1.3.1 and hidden in 1.4.0
+@LowPriorityInOverloadResolution
 public fun <T : Any> CoroutineScope.rxObservable(
     context: CoroutineContext = EmptyCoroutineContext,
     @BuilderInference block: suspend ProducerScope<T>.() -> Unit
+): Observable<T> = rxObservableInternal(this, context, block)
+
+private fun <T : Any> rxObservableInternal(
+    scope: CoroutineScope, // support for legacy rxObservable in scope
+    context: CoroutineContext,
+    block: suspend ProducerScope<T>.() -> Unit
 ): Observable<T> = Observable.create { subscriber ->
-    val newContext = newCoroutineContext(context)
+    val newContext = scope.newCoroutineContext(context)
     val coroutine = RxObservableCoroutine(newContext, subscriber)
     subscriber.setCancellable(RxCancellable(coroutine)) // do it first (before starting coroutine), to await unnecessary suspensions
     coroutine.start(CoroutineStart.DEFAULT, coroutine, block)
@@ -114,15 +132,19 @@
             // to abort the corresponding send/offer invocation. From the standpoint of coroutines machinery,
             // this failure is essentially equivalent to a failure of a child coroutine.
             cancelCoroutine(e)
-            doLockedSignalCompleted(e, false)
+            mutex.unlock()
             throw e
         }
         /*
-           There is no sense to check for `isActive` before doing `unlock`, because cancellation/completion might
-           happen after this check and before `unlock` (see signalCompleted that does not do anything
-           if it fails to acquire the lock that we are still holding).
-           We have to recheck `isCompleted` after `unlock` anyway.
+         * There is no sense to check for `isActive` before doing `unlock`, because cancellation/completion might
+         * happen after this check and before `unlock` (see signalCompleted that does not do anything
+         * if it fails to acquire the lock that we are still holding).
+         * We have to recheck `isCompleted` after `unlock` anyway.
          */
+        unlockAndCheckCompleted()
+    }
+
+    private fun unlockAndCheckCompleted() {
         mutex.unlock()
         // recheck isActive
         if (!isActive && mutex.tryLock())
@@ -131,16 +153,31 @@
 
     // assert: mutex.isLocked()
     private fun doLockedSignalCompleted(cause: Throwable?, handled: Boolean) {
-        // todo: handled is ignored here, might need something like in PublisherCoroutine to process
         // cancellation failures
         try {
             if (_signal.value >= CLOSED) {
                 _signal.value = SIGNALLED // we'll signal onError/onCompleted (that the final state -- no CAS needed)
                 try {
-                    if (cause != null && cause !is CancellationException)
+                    if (cause != null && cause !is CancellationException) {
+                        /*
+                         * Reactive frameworks have two types of exceptions: regular and fatal.
+                         * Regular are passed to onError.
+                         * Fatal can be passed to onError, but even the standard implementations **can just swallow it** (e.g. see #1297).
+                         * Such behaviour is inconsistent, leads to silent failures and we can't possibly know whether
+                         * the cause will be handled by onError (and moreover, it depends on whether a fatal exception was
+                         * thrown by subscriber or upstream).
+                         * To make behaviour consistent and least surprising, we always handle fatal exceptions
+                         * by coroutines machinery, anyway, they should not be present in regular program flow,
+                         * thus our goal here is just to expose it as soon as possible.
+                         */
                         subscriber.onError(cause)
-                    else
+                        if (!handled && cause.isFatal()) {
+                            handleCoroutineException(context, cause)
+                        }
+                    }
+                    else {
                         subscriber.onComplete()
+                    }
                 } catch (e: Throwable) {
                     // Unhandled exception (cannot handle in other way, since we are already complete)
                     handleCoroutineException(context, e)
@@ -164,4 +201,11 @@
     override fun onCancelled(cause: Throwable, handled: Boolean) {
         signalCompleted(cause, handled)
     }
+}
+
+internal fun Throwable.isFatal() = try {
+    Exceptions.throwIfFatal(this) // Rx-consistent behaviour without hardcode
+    false
+} catch (e: Throwable) {
+    true
 }
\ No newline at end of file
diff --git a/reactive/kotlinx-coroutines-rx2/src/RxSingle.kt b/reactive/kotlinx-coroutines-rx2/src/RxSingle.kt
index 53992d4..b6cebf0 100644
--- a/reactive/kotlinx-coroutines-rx2/src/RxSingle.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/RxSingle.kt
@@ -1,12 +1,15 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+
 package kotlinx.coroutines.rx2
 
 import io.reactivex.*
 import kotlinx.coroutines.*
 import kotlin.coroutines.*
+import kotlin.internal.*
 
 /**
  * Creates cold [single][Single] that will run a given [block] in a coroutine.
@@ -18,19 +21,36 @@
  * | Returns a value                       | `onSuccess`
  * | Failure with exception or unsubscribe | `onError`
  *
- * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument.
+ * Coroutine context can be specified with [context] argument.
  * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used.
- * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden
- * with corresponding [coroutineContext] element.
- *
- * @param context context of the coroutine.
- * @param block the coroutine code.
+ * Method throws [IllegalArgumentException] if provided [context] contains a [Job] instance.
  */
+public fun <T : Any> rxSingle(
+    context: CoroutineContext = EmptyCoroutineContext,
+    block: suspend CoroutineScope.() -> T
+): Single<T> {
+    require(context[Job] === null) { "Single context cannot contain job in it." +
+            "Its lifecycle should be managed via Disposable handle. Had $context" }
+    return rxSingleInternal(GlobalScope, context, block)
+}
+
+@Deprecated(
+    message = "CoroutineScope.rxSingle is deprecated in favour of top-level rxSingle",
+    level = DeprecationLevel.WARNING,
+    replaceWith = ReplaceWith("rxSingle(context, block)")
+) // Since 1.3.0, will be error in 1.3.1 and hidden in 1.4.0
+@LowPriorityInOverloadResolution
 public fun <T : Any> CoroutineScope.rxSingle(
     context: CoroutineContext = EmptyCoroutineContext,
     block: suspend CoroutineScope.() -> T
+): Single<T> = rxSingleInternal(this, context, block)
+
+private fun <T : Any> rxSingleInternal(
+    scope: CoroutineScope, // support for legacy rxSingle in scope
+    context: CoroutineContext,
+    block: suspend CoroutineScope.() -> T
 ): Single<T> = Single.create { subscriber ->
-    val newContext = newCoroutineContext(context)
+    val newContext = scope.newCoroutineContext(context)
     val coroutine = RxSingleCoroutine(newContext, subscriber)
     subscriber.setCancellable(RxCancellable(coroutine))
     coroutine.start(CoroutineStart.DEFAULT, coroutine, block)
@@ -41,12 +61,20 @@
     private val subscriber: SingleEmitter<T>
 ) : AbstractCoroutine<T>(parentContext, true) {
     override fun onCompleted(value: T) {
-        if (!subscriber.isDisposed) subscriber.onSuccess(value)
+        try {
+            if (!subscriber.isDisposed) subscriber.onSuccess(value)
+        } catch (e: Throwable) {
+            handleCoroutineException(context, e)
+        }
     }
 
     override fun onCancelled(cause: Throwable, handled: Boolean) {
         if (!subscriber.isDisposed) {
-            subscriber.onError(cause)
+            try {
+                subscriber.onError(cause)
+            } catch (e: Throwable) {
+                handleCoroutineException(context, e)
+            }
         } else if (!handled) {
             handleCoroutineException(context, cause)
         }
diff --git a/reactive/kotlinx-coroutines-rx2/test/CompletableTest.kt b/reactive/kotlinx-coroutines-rx2/test/CompletableTest.kt
index a11807c..a7caea4 100644
--- a/reactive/kotlinx-coroutines-rx2/test/CompletableTest.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/CompletableTest.kt
@@ -15,7 +15,7 @@
     @Test
     fun testBasicSuccess() = runBlocking {
         expect(1)
-        val completable = rxCompletable {
+        val completable = rxCompletable(currentDispatcher()) {
             expect(4)
         }
         expect(2)
@@ -30,7 +30,7 @@
     @Test
     fun testBasicFailure() = runBlocking {
         expect(1)
-        val completable = rxCompletable(NonCancellable) {
+        val completable = rxCompletable(currentDispatcher()) {
             expect(4)
             throw RuntimeException("OK")
         }
@@ -50,7 +50,7 @@
     @Test
     fun testBasicUnsubscribe() = runBlocking {
         expect(1)
-        val completable = rxCompletable {
+        val completable = rxCompletable(currentDispatcher()) {
             expect(4)
             yield() // back to main, will get cancelled
             expectUnreached()
@@ -73,7 +73,7 @@
     @Test
     fun testAwaitSuccess() = runBlocking {
         expect(1)
-        val completable = rxCompletable {
+        val completable = rxCompletable(currentDispatcher()) {
             expect(3)
         }
         expect(2)
@@ -84,7 +84,7 @@
     @Test
     fun testAwaitFailure() = runBlocking {
         expect(1)
-        val completable = rxCompletable(NonCancellable) {
+        val completable = rxCompletable(currentDispatcher()) {
             expect(3)
             throw RuntimeException("OK")
         }
@@ -99,21 +99,8 @@
     }
 
     @Test
-    fun testCancelsParentOnFailure() = runTest(
-        expected = { it is RuntimeException && it.message == "OK" }
-    ) {
-        // has parent, so should cancel it on failure
-        rxCompletable {
-            throw RuntimeException("OK")
-        }.subscribe(
-            { expectUnreached() },
-            { assert(it is RuntimeException) }
-        )
-    }
-
-    @Test
     fun testSuppressedException() = runTest {
-        val completable = rxCompletable(NonCancellable) {
+        val completable = rxCompletable(currentDispatcher()) {
             launch(start = CoroutineStart.ATOMIC) {
                 throw TestException() // child coroutine fails
             }
@@ -132,12 +119,14 @@
     }
 
     @Test
-    fun testUnhandledException() = runTest(
-        unhandled = listOf { it -> it is TestException }
-    ) {
+    fun testUnhandledException() = runTest() {
         expect(1)
         var disposable: Disposable? = null
-        val completable = rxCompletable(NonCancellable) {
+        val eh = CoroutineExceptionHandler { _, t ->
+            assertTrue(t is TestException)
+            expect(5)
+        }
+        val completable = rxCompletable(currentDispatcher() + eh) {
             expect(4)
             disposable!!.dispose() // cancel our own subscription, so that delay will get cancelled
             try {
@@ -156,6 +145,23 @@
         })
         expect(3)
         yield() // run coroutine
-        finish(5)
+        finish(6)
+    }
+
+    @Test
+    fun testFatalExceptionInSubscribe() = runTest {
+        GlobalScope.rxCompletable(Dispatchers.Unconfined + CoroutineExceptionHandler{ _, e -> assertTrue(e is LinkageError); expect(2)}) {
+            expect(1)
+            42
+        }.subscribe({ throw LinkageError() })
+        finish(3)
+    }
+
+    @Test
+    fun testFatalExceptionInSingle() = runTest {
+        GlobalScope.rxCompletable(Dispatchers.Unconfined) {
+            throw LinkageError()
+        }.subscribe({ expectUnreached()  }, { expect(1); assertTrue(it is LinkageError) })
+        finish(2)
     }
 }
diff --git a/reactive/kotlinx-coroutines-rx2/test/ConvertTest.kt b/reactive/kotlinx-coroutines-rx2/test/ConvertTest.kt
index 475ee57..758b632 100644
--- a/reactive/kotlinx-coroutines-rx2/test/ConvertTest.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/ConvertTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines.rx2
@@ -16,7 +16,7 @@
         val job = launch {
             expect(3)
         }
-        val completable = job.asCompletable(coroutineContext)
+        val completable = job.asCompletable(coroutineContext.minusKey(Job))
         completable.subscribe {
             expect(4)
         }
@@ -32,7 +32,7 @@
             expect(3)
             throw RuntimeException("OK")
         }
-        val completable = job.asCompletable(coroutineContext)
+        val completable = job.asCompletable(coroutineContext.minusKey(Job))
         completable.subscribe {
             expect(4)
         }
@@ -140,10 +140,10 @@
             throw TestException("K")
         }
         val observable = c.asObservable(Dispatchers.Unconfined)
-        val single = GlobalScope.rxSingle(Dispatchers.Unconfined) {
+        val single = rxSingle(Dispatchers.Unconfined) {
             var result = ""
             try {
-                observable.consumeEach { result += it }
+                observable.collect { result += it }
             } catch(e: Throwable) {
                 check(e is TestException)
                 result += e.message
diff --git a/reactive/kotlinx-coroutines-rx2/test/FlowableExceptionHandlingTest.kt b/reactive/kotlinx-coroutines-rx2/test/FlowableExceptionHandlingTest.kt
new file mode 100644
index 0000000..4f3e724
--- /dev/null
+++ b/reactive/kotlinx-coroutines-rx2/test/FlowableExceptionHandlingTest.kt
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines.rx2
+
+import kotlinx.coroutines.*
+import org.junit.*
+import org.junit.Test
+import kotlin.test.*
+
+class FlowableExceptionHandlingTest : TestBase() {
+
+    @Before
+    fun setup() {
+        ignoreLostThreads("RxComputationThreadPool-", "RxCachedWorkerPoolEvictor-", "RxSchedulerPurge-")
+    }
+
+    private inline fun <reified T : Throwable> ceh(expect: Int) = CoroutineExceptionHandler { _, t ->
+        assertTrue(t is T)
+        expect(expect)
+    }
+
+    private fun cehUnreached() = CoroutineExceptionHandler { _, _ -> expectUnreached() }
+
+    @Test
+    fun testException() = runTest {
+        rxFlowable<Int>(Dispatchers.Unconfined + cehUnreached()) {
+            expect(1)
+            throw TestException()
+        }.subscribe({
+            expectUnreached()
+        }, {
+            expect(2) // Reported to onError
+        })
+        finish(3)
+    }
+
+    @Test
+    fun testFatalException() = runTest {
+        rxFlowable<Int>(Dispatchers.Unconfined + ceh<LinkageError>(3)) {
+            expect(1)
+            throw LinkageError()
+        }.subscribe({
+            expectUnreached()
+        }, {
+            expect(2) // Fatal exception is reported to both onError and CEH
+        })
+        finish(4)
+    }
+
+    @Test
+    fun testExceptionAsynchronous() = runTest {
+        rxFlowable<Int>(Dispatchers.Unconfined + cehUnreached()) {
+            expect(1)
+            throw TestException()
+        }.publish()
+            .refCount()
+            .subscribe({
+                expectUnreached()
+            }, {
+                expect(2) // Reported to onError
+            })
+        finish(3)
+    }
+
+    @Test
+    fun testFatalExceptionAsynchronous() = runTest {
+        rxFlowable<Int>(Dispatchers.Unconfined + ceh<LinkageError>(3)) {
+            expect(1)
+            throw LinkageError()
+        }.publish()
+            .refCount()
+            .subscribe({
+                expectUnreached()
+            }, {
+                expect(2)
+            })
+        finish(4)
+    }
+
+    @Test
+    fun testFatalExceptionFromSubscribe() = runTest {
+        rxFlowable(Dispatchers.Unconfined + ceh<LinkageError>(4)) {
+            expect(1)
+            send(Unit)
+        }.subscribe({
+            expect(2)
+            throw LinkageError()
+        }, { expect(3) }) // Fatal exception is reported to both onError and CEH
+        finish(5)
+    }
+
+    @Test
+    fun testExceptionFromSubscribe() = runTest {
+        rxFlowable(Dispatchers.Unconfined + cehUnreached()) {
+            expect(1)
+            send(Unit)
+        }.subscribe({
+            expect(2)
+            throw TestException()
+        }, { expect(3) }) // not reported to onError because came from the subscribe itself
+        finish(4)
+    }
+
+    @Test
+    fun testAsynchronousExceptionFromSubscribe() = runTest {
+        rxFlowable(Dispatchers.Unconfined + cehUnreached()) {
+            expect(1)
+            send(Unit)
+        }.publish()
+            .refCount()
+            .subscribe({
+                expect(2)
+                throw RuntimeException()
+            }, { expect(3) })
+        finish(4)
+    }
+
+    @Test
+    fun testAsynchronousFatalExceptionFromSubscribe() = runTest {
+        rxFlowable(Dispatchers.Unconfined + ceh<LinkageError>(3)) {
+            expect(1)
+            send(Unit)
+        }.publish()
+            .refCount()
+            .subscribe({
+                expect(2)
+                throw LinkageError()
+            }, { expectUnreached() })
+        finish(4)
+    }
+}
diff --git a/reactive/kotlinx-coroutines-rx2/test/FlowableTest.kt b/reactive/kotlinx-coroutines-rx2/test/FlowableTest.kt
index 543de09..aebf999 100644
--- a/reactive/kotlinx-coroutines-rx2/test/FlowableTest.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/FlowableTest.kt
@@ -15,7 +15,7 @@
     @Test
     fun testBasicSuccess() = runBlocking {
         expect(1)
-        val observable = rxFlowable {
+        val observable = rxFlowable(currentDispatcher()) {
             expect(4)
             send("OK")
         }
@@ -32,7 +32,7 @@
     @Test
     fun testBasicFailure() = runBlocking {
         expect(1)
-        val observable = rxFlowable<String>(NonCancellable) {
+        val observable = rxFlowable<String>(currentDispatcher()) {
             expect(4)
             throw RuntimeException("OK")
         }
@@ -52,7 +52,7 @@
     @Test
     fun testBasicUnsubscribe() = runBlocking {
         expect(1)
-        val observable = rxFlowable<String> {
+        val observable = rxFlowable<String>(currentDispatcher()) {
             expect(4)
             yield() // back to main, will get cancelled
             expectUnreached()
@@ -72,23 +72,10 @@
     }
 
     @Test
-    fun testCancelsParentOnFailure() = runTest(
-        expected = { it is RuntimeException && it.message == "OK" }
-    ) {
-        // has parent, so should cancel it on failure
-        rxFlowable<Unit> {
-            throw RuntimeException("OK")
-        }.subscribe(
-            { expectUnreached() },
-            { assert(it is RuntimeException) }
-        )
-    }
-
-    @Test
     fun testNotifyOnceOnCancellation() = runTest {
         expect(1)
         val observable =
-            rxFlowable {
+            rxFlowable(currentDispatcher()) {
                 expect(5)
                 send("OK")
                 try {
@@ -124,7 +111,7 @@
 
     @Test
     fun testFailingConsumer() = runTest {
-        val pub = rxFlowable {
+        val pub = rxFlowable(currentDispatcher()) {
             repeat(3) {
                 expect(it + 1) // expect(1), expect(2) *should* be invoked
                 send(it)
diff --git a/reactive/kotlinx-coroutines-rx2/test/IntegrationTest.kt b/reactive/kotlinx-coroutines-rx2/test/IntegrationTest.kt
index 9b55e58..ca7c0ca 100644
--- a/reactive/kotlinx-coroutines-rx2/test/IntegrationTest.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/IntegrationTest.kt
@@ -20,7 +20,7 @@
 ) : TestBase() {
 
     enum class Ctx {
-        MAIN        { override fun invoke(context: CoroutineContext): CoroutineContext = context },
+        MAIN        { override fun invoke(context: CoroutineContext): CoroutineContext = context.minusKey(Job) },
         DEFAULT     { override fun invoke(context: CoroutineContext): CoroutineContext = Dispatchers.Default },
         UNCONFINED  { override fun invoke(context: CoroutineContext): CoroutineContext = Dispatchers.Unconfined };
 
@@ -58,7 +58,7 @@
 
     @Test
     fun testSingle() = runBlocking {
-        val observable = CoroutineScope(ctx(coroutineContext)).rxObservable {
+        val observable = rxObservable(ctx(coroutineContext)) {
             if (delay) delay(1)
             send("OK")
         }
@@ -101,8 +101,7 @@
     fun testCancelWithoutValue() = runTest {
         val job = launch(Job(), start = CoroutineStart.UNDISPATCHED) {
             rxObservable<String> {
-                yield()
-                expectUnreached()
+                hang {  }
             }.awaitFirst()
         }
 
diff --git a/reactive/kotlinx-coroutines-rx2/test/MaybeTest.kt b/reactive/kotlinx-coroutines-rx2/test/MaybeTest.kt
index e97b1f0..dcd6663 100644
--- a/reactive/kotlinx-coroutines-rx2/test/MaybeTest.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/MaybeTest.kt
@@ -24,14 +24,14 @@
     @Test
     fun testBasicSuccess() = runBlocking {
         expect(1)
-        val maybe = rxMaybe {
+        val maybe = rxMaybe(currentDispatcher()) {
             expect(4)
             "OK"
         }
         expect(2)
         maybe.subscribe { value ->
             expect(5)
-            Assert.assertThat(value, IsEqual("OK"))
+            assertThat(value, IsEqual("OK"))
         }
         expect(3)
         yield() // to started coroutine
@@ -41,7 +41,7 @@
     @Test
     fun testBasicEmpty() = runBlocking {
         expect(1)
-        val maybe = rxMaybe {
+        val maybe = rxMaybe(currentDispatcher()) {
             expect(4)
             null
         }
@@ -57,7 +57,7 @@
     @Test
     fun testBasicFailure() = runBlocking {
         expect(1)
-        val maybe = rxMaybe(NonCancellable) {
+        val maybe = rxMaybe(currentDispatcher()) {
             expect(4)
             throw RuntimeException("OK")
         }
@@ -78,7 +78,7 @@
     @Test
     fun testBasicUnsubscribe() = runBlocking {
         expect(1)
-        val maybe = rxMaybe {
+        val maybe = rxMaybe(currentDispatcher()) {
             expect(4)
             yield() // back to main, will get cancelled
             expectUnreached()
@@ -100,7 +100,7 @@
 
     @Test
     fun testMaybeNoWait() {
-        val maybe = GlobalScope.rxMaybe {
+        val maybe = rxMaybe {
             "OK"
         }
 
@@ -121,7 +121,7 @@
 
     @Test
     fun testMaybeEmitAndAwait() {
-        val maybe = GlobalScope.rxMaybe {
+        val maybe = rxMaybe {
             Maybe.just("O").await() + "K"
         }
 
@@ -132,7 +132,7 @@
 
     @Test
     fun testMaybeWithDelay() {
-        val maybe = GlobalScope.rxMaybe {
+        val maybe = rxMaybe {
             Observable.timer(50, TimeUnit.MILLISECONDS).map { "O" }.awaitSingle() + "K"
         }
 
@@ -143,7 +143,7 @@
 
     @Test
     fun testMaybeException() {
-        val maybe = GlobalScope.rxMaybe {
+        val maybe = rxMaybe {
             Observable.just("O", "K").awaitSingle() + "K"
         }
 
@@ -154,7 +154,7 @@
 
     @Test
     fun testAwaitFirst() {
-        val maybe = GlobalScope.rxMaybe {
+        val maybe = rxMaybe {
             Observable.just("O", "#").awaitFirst() + "K"
         }
 
@@ -165,7 +165,7 @@
 
     @Test
     fun testAwaitLast() {
-        val maybe = GlobalScope.rxMaybe {
+        val maybe = rxMaybe {
             Observable.just("#", "O").awaitLast() + "K"
         }
 
@@ -176,7 +176,7 @@
 
     @Test
     fun testExceptionFromObservable() {
-        val maybe = GlobalScope.rxMaybe {
+        val maybe = rxMaybe {
             try {
                 Observable.error<String>(RuntimeException("O")).awaitFirst()
             } catch (e: RuntimeException) {
@@ -191,7 +191,7 @@
 
     @Test
     fun testExceptionFromCoroutine() {
-        val maybe = GlobalScope.rxMaybe<String> {
+        val maybe = rxMaybe<String> {
             throw IllegalStateException(Observable.just("O").awaitSingle() + "K")
         }
 
@@ -202,22 +202,9 @@
     }
 
     @Test
-    fun testCancelsParentOnFailure() = runTest(
-        expected = { it is RuntimeException && it.message == "OK" }
-    ) {
-        // has parent, so should cancel it on failure
-        rxMaybe<Unit> {
-            throw RuntimeException("OK")
-        }.subscribe(
-            { expectUnreached() },
-            { assert(it is RuntimeException) }
-        )
-    }
-
-    @Test
     fun testCancelledConsumer() = runTest {
         expect(1)
-        val maybe = rxMaybe<Int> {
+        val maybe = rxMaybe<Int>(currentDispatcher()) {
             expect(4)
             try {
                 delay(Long.MAX_VALUE)
@@ -242,7 +229,7 @@
 
     @Test
     fun testSuppressedException() = runTest {
-        val maybe = rxMaybe(NonCancellable) {
+        val maybe = rxMaybe(currentDispatcher()) {
             launch(start = CoroutineStart.ATOMIC) {
                 throw TestException() // child coroutine fails
             }
@@ -261,12 +248,14 @@
     }
 
     @Test
-    fun testUnhandledException() = runTest(
-        unhandled = listOf { it -> it is TestException }
-    ) {
+    fun testUnhandledException() = runTest {
         expect(1)
         var disposable: Disposable? = null
-        val maybe = rxMaybe(NonCancellable) {
+        val eh = CoroutineExceptionHandler { _, t ->
+            assertTrue(t is TestException)
+            expect(5)
+        }
+        val maybe = rxMaybe(currentDispatcher() + eh) {
             expect(4)
             disposable!!.dispose() // cancel our own subscription, so that delay will get cancelled
             try {
@@ -286,6 +275,23 @@
         })
         expect(3)
         yield() // run coroutine
-        finish(5)
+        finish(6)
+    }
+
+    @Test
+    fun testFatalExceptionInSubscribe() = runTest {
+        GlobalScope.rxMaybe(Dispatchers.Unconfined + CoroutineExceptionHandler{ _, e -> assertTrue(e is LinkageError); expect(2)}) {
+            expect(1)
+            42
+        }.subscribe({ throw LinkageError() })
+        finish(3)
+    }
+
+    @Test
+    fun testFatalExceptionInSingle() = runTest {
+        GlobalScope.rxMaybe(Dispatchers.Unconfined) {
+            throw LinkageError()
+        }.subscribe({ expectUnreached()  }, { expect(1); assertTrue(it is LinkageError) })
+        finish(2)
     }
 }
diff --git a/reactive/kotlinx-coroutines-rx2/test/ObservableExceptionHandlingTest.kt b/reactive/kotlinx-coroutines-rx2/test/ObservableExceptionHandlingTest.kt
new file mode 100644
index 0000000..6d247cf
--- /dev/null
+++ b/reactive/kotlinx-coroutines-rx2/test/ObservableExceptionHandlingTest.kt
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines.rx2
+
+import kotlinx.coroutines.*
+import org.junit.*
+import org.junit.Test
+import kotlin.test.*
+
+class ObservableExceptionHandlingTest : TestBase() {
+
+    @Before
+    fun setup() {
+        ignoreLostThreads("RxComputationThreadPool-", "RxCachedWorkerPoolEvictor-", "RxSchedulerPurge-")
+    }
+
+    private inline fun <reified T : Throwable> ceh(expect: Int) = CoroutineExceptionHandler { _, t ->
+        assertTrue(t is T)
+        expect(expect)
+    }
+
+    private fun cehUnreached() = CoroutineExceptionHandler { _, _ -> expectUnreached() }
+
+    @Test
+    fun testException() = runTest {
+        rxObservable<Int>(Dispatchers.Unconfined + cehUnreached()) {
+            expect(1)
+            throw TestException()
+        }.subscribe({
+            expectUnreached()
+        }, {
+            expect(2) // Reported to onError
+        })
+        finish(3)
+    }
+
+    @Test
+    fun testFatalException() = runTest {
+        rxObservable<Int>(Dispatchers.Unconfined + ceh<LinkageError>(3)) {
+            expect(1)
+            throw LinkageError()
+        }.subscribe({
+            expectUnreached()
+        }, {
+            expect(2)
+        })
+        finish(4)
+    }
+
+    @Test
+    fun testExceptionAsynchronous() = runTest {
+        rxObservable<Int>(Dispatchers.Unconfined) {
+            expect(1)
+            throw TestException()
+        }.publish()
+            .refCount()
+            .subscribe({
+                expectUnreached()
+            }, {
+                expect(2) // Reported to onError
+            })
+        finish(3)
+    }
+
+    @Test
+    fun testFatalExceptionAsynchronous() = runTest {
+        rxObservable<Int>(Dispatchers.Unconfined + ceh<LinkageError>(3)) {
+            expect(1)
+            throw LinkageError()
+        }.publish()
+            .refCount()
+            .subscribe({
+                expectUnreached()
+            }, {
+                expect(2) // Fatal exception is not reported in onError
+            })
+        finish(4)
+    }
+
+    @Test
+    fun testFatalExceptionFromSubscribe() = runTest {
+        rxObservable(Dispatchers.Unconfined + ceh<LinkageError>(4)) {
+            expect(1)
+            send(Unit)
+        }.subscribe({
+            expect(2)
+            throw LinkageError()
+        }, { expect(3) }) // Unreached because fatal errors are rethrown
+        finish(5)
+    }
+
+    @Test
+    fun testExceptionFromSubscribe() = runTest {
+        rxObservable(Dispatchers.Unconfined) {
+            expect(1)
+            send(Unit)
+        }.subscribe({
+            expect(2)
+            throw TestException()
+        }, { expect(3) }) // not reported to onError because came from the subscribe itself
+        finish(4)
+    }
+
+    @Test
+    fun testAsynchronousExceptionFromSubscribe() = runTest {
+        rxObservable(Dispatchers.Unconfined) {
+            expect(1)
+            send(Unit)
+        }.publish()
+            .refCount()
+            .subscribe({
+                expect(2)
+                throw RuntimeException()
+            }, { expect(3) })
+        finish(4)
+    }
+
+    @Test
+    fun testAsynchronousFatalExceptionFromSubscribe() = runTest {
+        rxObservable(Dispatchers.Unconfined + ceh<LinkageError>(4)) {
+            expect(1)
+            send(Unit)
+        }.publish()
+            .refCount()
+            .subscribe({
+                expect(2)
+                throw LinkageError()
+            }, { expect(3) })
+        finish(5)
+    }
+}
diff --git a/reactive/kotlinx-coroutines-rx2/test/ObservableMultiTest.kt b/reactive/kotlinx-coroutines-rx2/test/ObservableMultiTest.kt
index 9208195..75f79de 100644
--- a/reactive/kotlinx-coroutines-rx2/test/ObservableMultiTest.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/ObservableMultiTest.kt
@@ -76,7 +76,7 @@
             send("O")
             throw IOException("K")
         }
-        val single = GlobalScope.rxSingle {
+        val single = rxSingle {
             var result = ""
             try {
                 observable.consumeEach { result += it }
diff --git a/reactive/kotlinx-coroutines-rx2/test/ObservableTest.kt b/reactive/kotlinx-coroutines-rx2/test/ObservableTest.kt
index 8dc7120..c71ef56 100644
--- a/reactive/kotlinx-coroutines-rx2/test/ObservableTest.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/ObservableTest.kt
@@ -14,7 +14,7 @@
     @Test
     fun testBasicSuccess() = runBlocking {
         expect(1)
-        val observable = rxObservable {
+        val observable = rxObservable(currentDispatcher()) {
             expect(4)
             send("OK")
         }
@@ -31,7 +31,7 @@
     @Test
     fun testBasicFailure() = runBlocking {
         expect(1)
-        val observable = rxObservable<String>(NonCancellable) {
+        val observable = rxObservable<String>(currentDispatcher()) {
             expect(4)
             throw RuntimeException("OK")
         }
@@ -51,7 +51,7 @@
     @Test
     fun testBasicUnsubscribe() = runBlocking {
         expect(1)
-        val observable = rxObservable<String> {
+        val observable = rxObservable<String>(currentDispatcher()) {
             expect(4)
             yield() // back to main, will get cancelled
             expectUnreached()
@@ -71,23 +71,10 @@
     }
 
     @Test
-    fun testCancelsParentOnFailure() = runTest(
-        expected = { it is RuntimeException && it.message == "OK" }
-    ) {
-        // has parent, so should cancel it on failure
-        rxObservable<Unit> {
-            throw RuntimeException("OK")
-        }.subscribe(
-            { expectUnreached() },
-            { assert(it is RuntimeException) }
-        )
-    }
-
-    @Test
     fun testNotifyOnceOnCancellation() = runTest {
         expect(1)
         val observable =
-            rxObservable {
+            rxObservable(currentDispatcher()) {
                 expect(5)
                 send("OK")
                 try {
@@ -124,7 +111,7 @@
     @Test
     fun testFailingConsumer() = runTest {
         expect(1)
-        val pub = rxObservable {
+        val pub = rxObservable(currentDispatcher()) {
             expect(2)
             send("OK")
             try {
diff --git a/reactive/kotlinx-coroutines-rx2/test/SingleTest.kt b/reactive/kotlinx-coroutines-rx2/test/SingleTest.kt
index 2ae9570..fce7723 100644
--- a/reactive/kotlinx-coroutines-rx2/test/SingleTest.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/SingleTest.kt
@@ -6,6 +6,7 @@
 
 import io.reactivex.*
 import io.reactivex.disposables.*
+import io.reactivex.functions.*
 import kotlinx.coroutines.*
 import org.hamcrest.core.*
 import org.junit.*
@@ -21,14 +22,14 @@
     @Test
     fun testBasicSuccess() = runBlocking {
         expect(1)
-        val single = rxSingle {
+        val single = rxSingle(currentDispatcher()) {
             expect(4)
             "OK"
         }
         expect(2)
         single.subscribe { value ->
             expect(5)
-            Assert.assertThat(value, IsEqual("OK"))
+            assertThat(value, IsEqual("OK"))
         }
         expect(3)
         yield() // to started coroutine
@@ -38,7 +39,7 @@
     @Test
     fun testBasicFailure() = runBlocking {
         expect(1)
-        val single = rxSingle(NonCancellable) {
+        val single = rxSingle(currentDispatcher()) {
             expect(4)
             throw RuntimeException("OK")
         }
@@ -47,8 +48,8 @@
             expectUnreached()
         }, { error ->
             expect(5)
-            Assert.assertThat(error, IsInstanceOf(RuntimeException::class.java))
-            Assert.assertThat(error.message, IsEqual("OK"))
+            assertThat(error, IsInstanceOf(RuntimeException::class.java))
+            assertThat(error.message, IsEqual("OK"))
         })
         expect(3)
         yield() // to started coroutine
@@ -59,7 +60,7 @@
     @Test
     fun testBasicUnsubscribe() = runBlocking {
         expect(1)
-        val single = rxSingle {
+        val single = rxSingle(currentDispatcher()) {
             expect(4)
             yield() // back to main, will get cancelled
             expectUnreached()
@@ -82,7 +83,7 @@
 
     @Test
     fun testSingleNoWait() {
-        val single = GlobalScope.rxSingle {
+        val single = rxSingle {
             "OK"
         }
 
@@ -98,7 +99,7 @@
 
     @Test
     fun testSingleEmitAndAwait() {
-        val single = GlobalScope.rxSingle {
+        val single = rxSingle {
             Single.just("O").await() + "K"
         }
 
@@ -109,7 +110,7 @@
 
     @Test
     fun testSingleWithDelay() {
-        val single = GlobalScope.rxSingle {
+        val single = rxSingle {
             Observable.timer(50, TimeUnit.MILLISECONDS).map { "O" }.awaitSingle() + "K"
         }
 
@@ -120,7 +121,7 @@
 
     @Test
     fun testSingleException() {
-        val single = GlobalScope.rxSingle {
+        val single = rxSingle {
             Observable.just("O", "K").awaitSingle() + "K"
         }
 
@@ -131,7 +132,7 @@
 
     @Test
     fun testAwaitFirst() {
-        val single = GlobalScope.rxSingle {
+        val single = rxSingle {
             Observable.just("O", "#").awaitFirst() + "K"
         }
 
@@ -142,7 +143,7 @@
 
     @Test
     fun testAwaitLast() {
-        val single = GlobalScope.rxSingle {
+        val single = rxSingle {
             Observable.just("#", "O").awaitLast() + "K"
         }
 
@@ -153,7 +154,7 @@
 
     @Test
     fun testExceptionFromObservable() {
-        val single = GlobalScope.rxSingle {
+        val single = rxSingle {
             try {
                 Observable.error<String>(RuntimeException("O")).awaitFirst()
             } catch (e: RuntimeException) {
@@ -168,7 +169,7 @@
 
     @Test
     fun testExceptionFromCoroutine() {
-        val single = GlobalScope.rxSingle<String> {
+        val single = rxSingle<String> {
             throw IllegalStateException(Observable.just("O").awaitSingle() + "K")
         }
 
@@ -179,21 +180,8 @@
     }
 
     @Test
-    fun testCancelsParentOnFailure() = runTest(
-        expected = { it is RuntimeException && it.message == "OK" }
-    ) {
-        // has parent, so should cancel it on failure
-        rxSingle<Unit> {
-            throw RuntimeException("OK")
-        }.subscribe(
-            { expectUnreached() },
-            { assert(it is RuntimeException) }
-        )
-    }
-
-    @Test
     fun testSuppressedException() = runTest {
-        val single = rxSingle(NonCancellable) {
+        val single = rxSingle(currentDispatcher()) {
             launch(start = CoroutineStart.ATOMIC) {
                 throw TestException() // child coroutine fails
             }
@@ -212,12 +200,34 @@
     }
 
     @Test
-    fun testUnhandledException() = runTest(
-        unhandled = listOf { it -> it is TestException }
-    ) {
+    fun testFatalExceptionInSubscribe() = runTest {
+        GlobalScope.rxSingle(Dispatchers.Unconfined + CoroutineExceptionHandler { _, e -> assertTrue(e is LinkageError); expect(2) }) {
+            expect(1)
+            42
+        }.subscribe(Consumer {
+            throw LinkageError()
+        })
+        finish(3)
+    }
+
+    @Test
+    fun testFatalExceptionInSingle() = runTest {
+        GlobalScope.rxSingle(Dispatchers.Unconfined) {
+            throw LinkageError()
+        }.subscribe({ _, e ->  assertTrue(e is LinkageError); expect(1) })
+
+        finish(2)
+    }
+
+    @Test
+    fun testUnhandledException() = runTest {
         expect(1)
         var disposable: Disposable? = null
-        val single = rxSingle(NonCancellable) {
+        val eh = CoroutineExceptionHandler { _, t ->
+            assertTrue(t is TestException)
+            expect(5)
+        }
+        val single = rxSingle(currentDispatcher() + eh) {
             expect(4)
             disposable!!.dispose() // cancel our own subscription, so that delay will get cancelled
             try {
@@ -236,6 +246,6 @@
         })
         expect(3)
         yield() // run coroutine
-        finish(5)
+        finish(6)
     }
 }
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-01.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-01.kt
index 19c67f8..f3bc344 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-01.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-01.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-02.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-02.kt
index 6d48cb0..0e0ff2e 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-02.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-02.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-03.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-03.kt
index 5846991..b84fc08 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-03.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-03.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-04.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-04.kt
index 5c373a7..a08c41f 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-04.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-04.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-05.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-05.kt
index 5fa322e..e6428b9 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-05.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-05.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-06.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-06.kt
index 6c730b3..1f3747f 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-06.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-06.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-07.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-07.kt
index 7d4a788..b4cc9fc 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-07.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-07.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-08.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-08.kt
index dae5066..8e17ac9 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-08.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-08.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-09.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-09.kt
index c43b2a6..738c4ab 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-09.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-09.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-01.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-01.kt
index 2b03fbe..b12e92a 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-01.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-01.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-02.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-02.kt
index 9dea738..b87849a 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-02.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-02.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
@@ -10,7 +10,7 @@
 import kotlinx.coroutines.reactive.*
 import kotlin.coroutines.CoroutineContext
 
-fun rangeWithInterval(context: CoroutineContext, time: Long, start: Int, count: Int) = GlobalScope.publish<Int>(context) {
+fun rangeWithInterval(context: CoroutineContext, time: Long, start: Int, count: Int) = publish<Int>(context) {
     for (x in start until start + count) { 
         delay(time) // wait before sending each number
         send(x)
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-03.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-03.kt
index 35757be..1a214ce 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-03.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-03.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
@@ -11,7 +11,7 @@
 import io.reactivex.schedulers.Schedulers
 import kotlin.coroutines.CoroutineContext
 
-fun rangeWithInterval(context: CoroutineContext, time: Long, start: Int, count: Int) = GlobalScope.publish<Int>(context) {
+fun rangeWithInterval(context: CoroutineContext, time: Long, start: Int, count: Int) = publish<Int>(context) {
     for (x in start until start + count) { 
         delay(time) // wait before sending each number
         send(x)
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-04.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-04.kt
index d6d5771..3c5d3fb 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-04.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-04.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-05.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-05.kt
index 614e534..61b54b2 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-05.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-05.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-01.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-01.kt
index bf79a65..8268ef2 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-01.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-01.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-02.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-02.kt
index defd8e5..5f07ba4 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-02.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-02.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
@@ -14,7 +14,7 @@
     context: CoroutineContext,   // the context to execute this coroutine in
     predicate: (T) -> Boolean,   // the filter predicate
     mapper: (T) -> R             // the mapper function
-) = GlobalScope.publish<R>(context) {
+) = publish<R>(context) {
     collect {                    // collect the source stream 
         if (predicate(it))       // filter part
             send(mapper(it))     // map part
@@ -27,6 +27,6 @@
 
 fun main() = runBlocking<Unit> {
    range(1, 5)
-       .fusedFilterMap(coroutineContext, { it % 2 == 0}, { "$it is even" })
+       .fusedFilterMap(Dispatchers.Unconfined, { it % 2 == 0}, { "$it is even" })
        .collect { println(it) } // print all the resulting strings
 }
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-03.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-03.kt
index f1be007..818a792 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-03.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-03.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
@@ -12,7 +12,7 @@
 import org.reactivestreams.*
 import kotlin.coroutines.*
 
-fun <T, U> Publisher<T>.takeUntil(context: CoroutineContext, other: Publisher<U>) = GlobalScope.publish<T>(context) {
+fun <T, U> Publisher<T>.takeUntil(context: CoroutineContext, other: Publisher<U>) = publish<T>(context) {
     this@takeUntil.openSubscription().consume { // explicitly open channel to Publisher<T>
         val current = this
         other.openSubscription().consume { // explicitly open channel to Publisher<U>
@@ -35,5 +35,5 @@
 fun main() = runBlocking<Unit> {
     val slowNums = rangeWithInterval(200, 1, 10)         // numbers with 200ms interval
     val stop = rangeWithInterval(500, 1, 10)             // the first one after 500ms
-    slowNums.takeUntil(coroutineContext, stop).collect { println(it) } // let's test it
+    slowNums.takeUntil(Dispatchers.Unconfined, stop).collect { println(it) } // let's test it
 }
diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-04.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-04.kt
index bbc2e7b..12d9c1f 100644
--- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-04.kt
+++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-04.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit.
@@ -10,7 +10,7 @@
 import org.reactivestreams.*
 import kotlin.coroutines.*
 
-fun <T> Publisher<Publisher<T>>.merge(context: CoroutineContext) = GlobalScope.publish<T>(context) {
+fun <T> Publisher<Publisher<T>>.merge(context: CoroutineContext) = publish<T>(context) {
   collect { pub -> // for each publisher collected
       launch {  // launch a child coroutine
           pub.collect { send(it) } // resend all element from this publisher
@@ -33,5 +33,5 @@
 }
 
 fun main() = runBlocking<Unit> {
-    testPub().merge(coroutineContext).collect { println(it) } // print the whole stream
+    testPub().merge(Dispatchers.Unconfined).collect { println(it) } // print the whole stream
 }
diff --git a/settings.gradle b/settings.gradle
index 46d3d98..aa5c68f 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -25,6 +25,8 @@
 module('kotlinx-coroutines-test')
 module('kotlinx-coroutines-debug')
 module('stdlib-stubs')
+module('kotlinx-coroutines-bom')
+
 
 module('integration/kotlinx-coroutines-guava')
 module('integration/kotlinx-coroutines-jdk8')
diff --git a/ui/coroutines-guide-ui.md b/ui/coroutines-guide-ui.md
index d6e848b..4d12d95 100644
--- a/ui/coroutines-guide-ui.md
+++ b/ui/coroutines-guide-ui.md
@@ -1,6 +1,6 @@
 <!--- INCLUDE .*/example-ui-([a-z]+)-([0-9]+)\.kt 
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
@@ -165,7 +165,7 @@
 `app/build.gradle` file:
 
 ```groovy
-implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0-M2"
+implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0-RC"
 ```
 
 You can clone [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) project from GitHub onto your 
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/build.gradle b/ui/kotlinx-coroutines-android/animation-app/app/build.gradle
index 25106ff..b5919be 100644
--- a/ui/kotlinx-coroutines-android/animation-app/app/build.gradle
+++ b/ui/kotlinx-coroutines-android/animation-app/app/build.gradle
@@ -4,7 +4,6 @@
 
 android {
     compileSdkVersion 27
-    buildToolsVersion '27.0.3'
     defaultConfig {
         applicationId "org.jetbrains.kotlinx.animation"
         minSdkVersion 14
diff --git a/ui/kotlinx-coroutines-android/animation-app/build.gradle b/ui/kotlinx-coroutines-android/animation-app/build.gradle
index 9181f02..f512a87 100644
--- a/ui/kotlinx-coroutines-android/animation-app/build.gradle
+++ b/ui/kotlinx-coroutines-android/animation-app/build.gradle
@@ -6,7 +6,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:3.3.0-alpha04'
+        classpath 'com.android.tools.build:gradle:3.4.1'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
 
         // NOTE: Do not place your application dependencies here; they belong
diff --git a/ui/kotlinx-coroutines-android/animation-app/gradle.properties b/ui/kotlinx-coroutines-android/animation-app/gradle.properties
index ed89e47..1fe12d6 100644
--- a/ui/kotlinx-coroutines-android/animation-app/gradle.properties
+++ b/ui/kotlinx-coroutines-android/animation-app/gradle.properties
@@ -18,6 +18,6 @@
 
 kotlin.coroutines=enable
 
-kotlin_version=1.3.40
-coroutines_version=1.3.0-M2
+kotlin_version=1.3.41
+coroutines_version=1.3.0-RC
 
diff --git a/ui/kotlinx-coroutines-android/animation-app/gradle/wrapper/gradle-wrapper.properties b/ui/kotlinx-coroutines-android/animation-app/gradle/wrapper/gradle-wrapper.properties
index f44ff59..caf54fa 100644
--- a/ui/kotlinx-coroutines-android/animation-app/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/kotlinx-coroutines-android/animation-app/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Sat Aug 25 19:20:16 MSK 2018
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
diff --git a/ui/kotlinx-coroutines-android/example-app/app/build.gradle b/ui/kotlinx-coroutines-android/example-app/app/build.gradle
index 33e1337..98257d3 100644
--- a/ui/kotlinx-coroutines-android/example-app/app/build.gradle
+++ b/ui/kotlinx-coroutines-android/example-app/app/build.gradle
@@ -4,7 +4,6 @@
 
 android {
     compileSdkVersion 27
-    buildToolsVersion '27.0.3'
     defaultConfig {
         applicationId "com.example.app"
         minSdkVersion 14
diff --git a/ui/kotlinx-coroutines-android/example-app/build.gradle b/ui/kotlinx-coroutines-android/example-app/build.gradle
index 9181f02..f512a87 100644
--- a/ui/kotlinx-coroutines-android/example-app/build.gradle
+++ b/ui/kotlinx-coroutines-android/example-app/build.gradle
@@ -6,7 +6,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:3.3.0-alpha04'
+        classpath 'com.android.tools.build:gradle:3.4.1'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
 
         // NOTE: Do not place your application dependencies here; they belong
diff --git a/ui/kotlinx-coroutines-android/example-app/gradle.properties b/ui/kotlinx-coroutines-android/example-app/gradle.properties
index ed89e47..1fe12d6 100644
--- a/ui/kotlinx-coroutines-android/example-app/gradle.properties
+++ b/ui/kotlinx-coroutines-android/example-app/gradle.properties
@@ -18,6 +18,6 @@
 
 kotlin.coroutines=enable
 
-kotlin_version=1.3.40
-coroutines_version=1.3.0-M2
+kotlin_version=1.3.41
+coroutines_version=1.3.0-RC
 
diff --git a/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.properties b/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.properties
index f44ff59..caf54fa 100644
--- a/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Sat Aug 25 19:20:16 MSK 2018
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-01.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-01.kt
index 021d662..58da16d 100644
--- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-01.kt
+++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-01.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-02.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-02.kt
index 41baa2e..a7be2f5 100644
--- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-02.kt
+++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-02.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-03.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-03.kt
index 24c48cd..c2926af 100644
--- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-03.kt
+++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-03.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-advanced-01.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-advanced-01.kt
index 2a1634d..2965c04 100644
--- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-advanced-01.kt
+++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-advanced-01.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-advanced-02.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-advanced-02.kt
index bb7749e..fa27d18 100644
--- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-advanced-02.kt
+++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-advanced-02.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-01.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-01.kt
index 35adb40..d7ea599 100644
--- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-01.kt
+++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-01.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-02.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-02.kt
index ab432ea..45967e7 100644
--- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-02.kt
+++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-02.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-03.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-03.kt
index a05da83..0610660 100644
--- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-03.kt
+++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-03.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-01.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-01.kt
index 71b88d9..2ff5a2f 100644
--- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-01.kt
+++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-01.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-02.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-02.kt
index 0b7a3b2..6a87025 100644
--- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-02.kt
+++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-02.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-03.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-03.kt
index 4215e65..1388e63 100644
--- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-03.kt
+++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-03.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 // This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.