Skip to content

Instantly share code, notes, and snippets.

@devsnek
Created June 25, 2020 17:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save devsnek/72c1bf9b94a6515d3bc7fbbdaaacf2a6 to your computer and use it in GitHub Desktop.
Save devsnek/72c1bf9b94a6515d3bc7fbbdaaacf2a6 to your computer and use it in GitHub Desktop.
diff --git a/src/completion.mjs b/src/completion.mjs
index 96a909a..e56da42 100644
--- a/src/completion.mjs
+++ b/src/completion.mjs
@@ -5,6 +5,8 @@ import {
PerformPromiseThen,
PromiseResolve,
SetFunctionLength,
+ ToBoolean,
+ Get,
} from './abstract-ops/all.mjs';
import { Value } from './value.mjs';
import { resume } from './helpers.mjs';
@@ -112,12 +114,28 @@ export function EnsureCompletion(val) {
return NormalCompletion(val);
}
+export function CheckAborted(signal) {
+ const aborted = ToBoolean(Q(Get(signal, new Value('aborted'))));
+ if (aborted === Value.true) {
+ return surroundingAgent.Throw('Error', 'Raw', 'aborted by signal');
+ }
+ return NormalCompletion(undefined);
+}
+
export function AwaitFulfilledFunctions([value]) {
const F = surroundingAgent.activeFunctionObject;
const asyncContext = F.AsyncContext;
const prevContext = surroundingAgent.runningExecutionContext;
// Suspend prevContext
surroundingAgent.executionContextStack.push(asyncContext);
+ if (asyncContext.signal) {
+ const aborted = CheckAborted(asyncContext.signal);
+ if (aborted instanceof AbruptCompletion) {
+ resume(asyncContext, aborted);
+ Assert(surroundingAgent.runningExecutionContext === prevContext);
+ return Value.undefined;
+ }
+ }
resume(asyncContext, NormalCompletion(value));
Assert(surroundingAgent.runningExecutionContext === prevContext);
return Value.undefined;
@@ -129,6 +147,14 @@ function AwaitRejectedFunctions([reason]) {
const prevContext = surroundingAgent.runningExecutionContext;
// Suspend prevContext
surroundingAgent.executionContextStack.push(asyncContext);
+ if (asyncContext.signal) {
+ const aborted = CheckAborted(asyncContext.signal);
+ if (aborted instanceof AbruptCompletion) {
+ resume(asyncContext, aborted);
+ Assert(surroundingAgent.runningExecutionContext === prevContext);
+ return Value.undefined;
+ }
+ }
resume(asyncContext, ThrowCompletion(reason));
Assert(surroundingAgent.runningExecutionContext === prevContext);
return Value.undefined;
@@ -136,6 +162,9 @@ function AwaitRejectedFunctions([reason]) {
export function* Await(value) {
const asyncContext = surroundingAgent.runningExecutionContext;
+ if (asyncContext.signal) {
+ Q(CheckAborted(asyncContext.signal));
+ }
const promise = Q(PromiseResolve(surroundingAgent.intrinsic('%Promise%'), value));
const stepsFulfilled = AwaitFulfilledFunctions;
const onFulfilled = X(CreateBuiltinFunction(stepsFulfilled, ['AsyncContext']));
diff --git a/src/realm.mjs b/src/realm.mjs
index f4fad05..cd61179 100644
--- a/src/realm.mjs
+++ b/src/realm.mjs
@@ -7,9 +7,10 @@ import {
Assert,
DefinePropertyOrThrow,
OrdinaryObjectCreate,
+ CreateBuiltinFunction,
} from './abstract-ops/all.mjs';
import { NewGlobalEnvironment } from './environment.mjs';
-import { Q, X } from './completion.mjs';
+import { Q, X, CheckAborted } from './completion.mjs';
import { BootstrapObjectPrototype } from './intrinsics/ObjectPrototype.mjs';
import { BootstrapObject } from './intrinsics/Object.mjs';
import { BootstrapArrayPrototype } from './intrinsics/ArrayPrototype.mjs';
@@ -389,5 +390,16 @@ export function SetDefaultGlobalBindings(realmRec) {
})));
}
+ Q(DefinePropertyOrThrow(global, new Value('setSignal'), Descriptor({
+ Value: CreateBuiltinFunction(([signal = Value.undefined]) => {
+ Q(CheckAborted(signal));
+ surroundingAgent.executionContextStack[surroundingAgent.executionContextStack.length - 2].signal = signal;
+ return Value.undefined;
+ }, [], realmRec),
+ Writable: Value.true,
+ Enumerable: Value.false,
+ Configurable: Value.true,
+ })));
+
return global;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment