Skip to content

Commit

Permalink
[GR-54725] Implement Promise.try proposal.
Browse files Browse the repository at this point in the history
PullRequest: js/3175
  • Loading branch information
woess committed Jun 13, 2024
2 parents c1b74f7 + f29c2f6 commit 52b88d3
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ The main focus is on user-observable behavior of the engine.
Changelog may include unreleased versions.
See [release calendar](https://www.graalvm.org/release-calendar/) for release dates.

## Version 24.2.0
* Implemented the [`Promise.try`](https://github.com/tc39/proposal-promise-try) proposal. It is available in ECMAScript staging mode (`--js.ecmascript-version=staging`).

## Version 24.1.0
* ECMAScript 2024 mode/features enabled by default.
* Implemented the [Make eval-introduced global vars redeclarable](https://github.com/tc39/proposal-redeclarable-global-eval-vars) proposal.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ public class Test262Runnable extends TestRunnable {
"object-spread",
"optional-catch-binding",
"optional-chaining",
"promise-try",
"promise-with-resolvers",
"proxy-missing-checks",
"regexp-dotall",
Expand All @@ -265,7 +266,6 @@ public class Test262Runnable extends TestRunnable {
"Intl.DurationFormat",
"IsHTMLDDA",
"explicit-resource-management",
"promise-try",
"regexp-modifiers",
"tail-call-optimization",
});
Expand All @@ -277,6 +277,7 @@ public class Test262Runnable extends TestRunnable {
"ShadowRealm",
"decorators",
"json-parse-with-source",
"promise-try",
});

public Test262Runnable(TestSuite suite, TestFile testFile) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.oracle.truffle.api.exception.AbstractTruffleException;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.js.builtins.PromiseFunctionBuiltinsFactory.PromiseCombinatorNodeGen;
import com.oracle.truffle.js.builtins.PromiseFunctionBuiltinsFactory.PromiseTryNodeGen;
import com.oracle.truffle.js.builtins.PromiseFunctionBuiltinsFactory.RejectNodeGen;
import com.oracle.truffle.js.builtins.PromiseFunctionBuiltinsFactory.ResolveNodeGen;
import com.oracle.truffle.js.builtins.PromiseFunctionBuiltinsFactory.WithResolversNodeGen;
Expand Down Expand Up @@ -100,7 +101,9 @@ public enum PromiseFunction implements BuiltinEnum<PromiseFunction> {
allSettled(1),
any(1),

withResolvers(0);
withResolvers(0),

try_(1);

private final int length;

Expand All @@ -119,6 +122,7 @@ public int getECMAScriptVersion() {
case any -> JSConfig.ECMAScript2021;
case allSettled -> JSConfig.ECMAScript2020;
case withResolvers -> JSConfig.ECMAScript2024;
case try_ -> JSConfig.StagingECMAScriptVersion;
default -> JSConfig.ECMAScript2015;
};
}
Expand All @@ -141,6 +145,8 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr
return ResolveNodeGen.create(context, builtin, args().withThis().fixedArgs(1).createArgumentNodes(context));
case withResolvers:
return WithResolversNodeGen.create(context, builtin, args().withThis().createArgumentNodes(context));
case try_:
return PromiseTryNodeGen.create(context, builtin, args().withThis().fixedArgs(1).varArgs().createArgumentNodes(context));
}
return null;
}
Expand Down Expand Up @@ -290,4 +296,47 @@ protected JSObject withResolvers(VirtualFrame frame, Object thiz) {
}

}

public abstract static class PromiseTryNode extends JSBuiltinNode {
@Child private NewPromiseCapabilityNode newPromiseCapabilityNode;
@Child private JSFunctionCallNode callCallbackFnNode;
@Child private JSFunctionCallNode callResolveNode;
@Child private JSFunctionCallNode callRejectNode;
@Child private TryCatchNode.GetErrorObjectNode getErrorObjectNode;

protected PromiseTryNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
this.newPromiseCapabilityNode = NewPromiseCapabilityNode.create(context);
this.callCallbackFnNode = JSFunctionCallNode.createCall();
this.callResolveNode = JSFunctionCallNode.createCall();
}

@Specialization
protected final Object doObject(JSObject constructor, Object callbackfn, Object[] args) {
PromiseCapabilityRecord promiseCapability = newPromiseCapabilityNode.execute(constructor);
try {
Object status = callCallbackFnNode.executeCall(JSArguments.create(Undefined.instance, callbackfn, args));
callResolveNode.executeCall(JSArguments.createOneArg(Undefined.instance, promiseCapability.getResolve(), status));
} catch (AbstractTruffleException ex) {
rejectPromise(ex, promiseCapability);
}
return promiseCapability.getPromise();
}

private void rejectPromise(AbstractTruffleException ex, PromiseCapabilityRecord promiseCapability) {
if (callRejectNode == null || getErrorObjectNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
callRejectNode = insert(JSFunctionCallNode.createCall());
getErrorObjectNode = insert(TryCatchNode.GetErrorObjectNode.create(getContext()));
}
Object error = getErrorObjectNode.execute(ex);
callRejectNode.executeCall(JSArguments.createOneArg(Undefined.instance, promiseCapability.getReject(), error));
}

@SuppressWarnings("unused")
@Specialization(guards = "!isJSObject(thisObj)")
protected static Object doNotObject(Object thisObj, Object callbackfn, Object[] args) {
throw Errors.createTypeError("Cannot create promise from this type");
}
}
}

0 comments on commit 52b88d3

Please sign in to comment.