Skip to content

Commit f00d096

Browse files
committed
Always return a Promise from ModuleRecord.Evaluate().
(cherry picked from commit a49fc80)
1 parent da84216 commit f00d096

File tree

5 files changed

+39
-60
lines changed

5 files changed

+39
-60
lines changed

graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java

Lines changed: 29 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -306,13 +306,11 @@ private Object evalModule(JSRealm realm) {
306306
moduleRecord.link(realm);
307307
// On failure, an exception is thrown and this module's [[Status]] remains unlinked.
308308

309-
Object promise = moduleRecord.evaluate(realm);
310-
if (context.isOptionTopLevelAwait()) {
311-
JSFunctionObject onRejected = createTopLevelAwaitReject(context, realm);
312-
JSFunctionObject onAccepted = createTopLevelAwaitResolve(context, realm);
313-
// Non-standard: throw error from onRejected handler.
314-
performPromiseThenNode.execute((JSPromiseObject) promise, onAccepted, onRejected, null);
315-
}
309+
JSPromiseObject promise = moduleRecord.evaluate(realm);
310+
JSFunctionObject onRejected = createTopLevelAwaitReject(context, realm);
311+
JSFunctionObject onAccepted = createTopLevelAwaitResolve(context, realm);
312+
// Non-standard: throw error from onRejected handler.
313+
performPromiseThenNode.execute(promise, onAccepted, onRejected, null);
316314

317315
if (context.getLanguageOptions().esmEvalReturnsExports()) {
318316
JSDynamicObject moduleNamespace = moduleRecord.getModuleNamespace();
@@ -702,47 +700,32 @@ private int innerModuleLinking(JSRealm realm, AbstractModuleRecord abstractModul
702700

703701
@TruffleBoundary
704702
@Override
705-
public Object moduleEvaluation(JSRealm realm, CyclicModuleRecord moduleRecord) {
703+
public JSPromiseObject moduleEvaluation(JSRealm realm, CyclicModuleRecord moduleRecord) {
706704
// Evaluate ( ) Concrete Method
707705
CyclicModuleRecord module = moduleRecord;
706+
assert module.getStatus() == Status.Linked || module.getStatus() == Status.EvaluatingAsync || module.getStatus() == Status.Evaluated : module.getStatus();
707+
if (module.getStatus() == Status.EvaluatingAsync || module.getStatus() == Status.Evaluated) {
708+
module = module.getCycleRoot();
709+
}
710+
if (module.getTopLevelCapability() != null) {
711+
return (JSPromiseObject) module.getTopLevelCapability().getPromise();
712+
}
708713
Deque<CyclicModuleRecord> stack = new ArrayDeque<>(4);
709-
if (realm.getContext().isOptionTopLevelAwait()) {
710-
assert module.getStatus() == Status.Linked || module.getStatus() == Status.EvaluatingAsync || module.getStatus() == Status.Evaluated : module.getStatus();
711-
if (module.getStatus() == Status.EvaluatingAsync || module.getStatus() == Status.Evaluated) {
712-
module = module.getCycleRoot();
713-
}
714-
if (module.getTopLevelCapability() != null) {
715-
return module.getTopLevelCapability().getPromise();
716-
}
717-
PromiseCapabilityRecord capability = NewPromiseCapabilityNode.createDefault(realm);
718-
module.setTopLevelCapability(capability);
719-
try {
720-
innerModuleEvaluation(realm, module, stack, 0);
721-
assert module.getStatus() == Status.EvaluatingAsync || module.getStatus() == Status.Evaluated;
722-
assert module.getEvaluationError() == null;
723-
if (!module.isAsyncEvaluation()) {
724-
assert module.getStatus() == Status.Evaluated;
725-
JSFunction.call(JSArguments.create(Undefined.instance, capability.getResolve(), Undefined.instance));
726-
}
727-
assert stack.isEmpty();
728-
} catch (AbstractTruffleException e) {
729-
handleModuleEvaluationError(module, stack, e);
730-
}
731-
return capability.getPromise();
732-
} else {
733-
try {
734-
innerModuleEvaluation(realm, module, stack, 0);
735-
} catch (AbstractTruffleException e) {
736-
handleModuleEvaluationError(module, stack, e);
737-
throw e;
738-
}
714+
PromiseCapabilityRecord capability = NewPromiseCapabilityNode.createDefault(realm);
715+
module.setTopLevelCapability(capability);
716+
try {
717+
innerModuleEvaluation(realm, module, stack, 0);
739718
assert module.getStatus() == Status.EvaluatingAsync || module.getStatus() == Status.Evaluated;
740719
assert module.getEvaluationError() == null;
741-
720+
if (!module.isAsyncEvaluation()) {
721+
assert module.getStatus() == Status.Evaluated;
722+
JSFunction.call(JSArguments.create(Undefined.instance, capability.getResolve(), Undefined.instance));
723+
}
742724
assert stack.isEmpty();
743-
Object result = module.getExecutionResult();
744-
return result == null ? Undefined.instance : result;
725+
} catch (AbstractTruffleException e) {
726+
handleModuleEvaluationError(module, stack, e);
745727
}
728+
return (JSPromiseObject) capability.getPromise();
746729
}
747730

748731
private static void handleModuleEvaluationError(CyclicModuleRecord module, Deque<CyclicModuleRecord> stack, AbstractTruffleException e) {
@@ -754,9 +737,7 @@ private static void handleModuleEvaluationError(CyclicModuleRecord module, Deque
754737
assert module.getStatus() == Status.Evaluated && module.getEvaluationError() == e;
755738

756739
PromiseCapabilityRecord capability = module.getTopLevelCapability();
757-
if (capability != null) {
758-
JSFunction.call(JSArguments.create(Undefined.instance, capability.getReject(), getErrorObject(e)));
759-
}
740+
JSFunction.call(JSArguments.create(Undefined.instance, capability.getReject(), getErrorObject(e)));
760741
}
761742

762743
private static Object getErrorObject(AbstractTruffleException e) {
@@ -771,12 +752,10 @@ private int innerModuleEvaluation(JSRealm realm, AbstractModuleRecord abstractMo
771752
// InnerModuleEvaluation( module, stack, index )
772753
int index = index0;
773754
if (!(abstractModule instanceof CyclicModuleRecord moduleRecord)) {
774-
Object result = abstractModule.evaluate(realm);
775-
if (result instanceof JSPromiseObject promise) {
776-
assert !JSPromise.isPending(promise);
777-
if (JSPromise.isRejected(promise)) {
778-
throw JSRuntime.getException(JSPromise.getPromiseResult(promise));
779-
}
755+
JSPromiseObject promise = abstractModule.evaluate(realm);
756+
assert !JSPromise.isPending(promise);
757+
if (JSPromise.isRejected(promise)) {
758+
throw JSRuntime.getException(JSPromise.getPromiseResult(promise));
780759
}
781760
return index;
782761
}

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -383,11 +383,10 @@ protected Object executeInRealm(VirtualFrame frame) {
383383

384384
// Evaluate() should always return a promise.
385385
// Yet, if top-level-await is disabled, returns/throws the result instead.
386-
Object evaluatePromise = moduleRecord.evaluate(realm);
386+
JSPromiseObject evaluatePromise = moduleRecord.evaluate(realm);
387387
if (context.isOptionTopLevelAwait() || !(moduleRecord instanceof CyclicModuleRecord cyclicModuleRecord)) {
388-
assert evaluatePromise instanceof JSPromiseObject : evaluatePromise;
389388
JSFunctionObject onFulfilled = createFulfilledClosure(context, realm, captures);
390-
promiseThenNode.execute((JSPromiseObject) evaluatePromise, onFulfilled, onRejected);
389+
promiseThenNode.execute(evaluatePromise, onFulfilled, onRejected);
391390
} else {
392391
// Rethrow any previous execution errors.
393392
cyclicModuleRecord.getExecutionResultOrThrow();

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -111,7 +111,7 @@ public interface Evaluator {
111111

112112
void moduleLinking(JSRealm realm, CyclicModuleRecord moduleRecord);
113113

114-
Object moduleEvaluation(JSRealm realm, CyclicModuleRecord moduleRecord);
114+
JSPromiseObject moduleEvaluation(JSRealm realm, CyclicModuleRecord moduleRecord);
115115

116116
/**
117117
* Parses a script string. Returns an executable script object.

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/AbstractModuleRecord.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -108,7 +108,7 @@ public final void loadRequestedModulesSync(JSRealm realm, Object hostDefinedArg)
108108
*
109109
* Link must have completed successfully prior to invoking this method.
110110
*/
111-
public abstract Object evaluate(JSRealm realm);
111+
public abstract JSPromiseObject evaluate(JSRealm realm);
112112

113113
@TruffleBoundary
114114
public final Collection<TruffleString> getExportedNames() {

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/CyclicModuleRecord.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -51,6 +51,7 @@
5151
import com.oracle.truffle.js.runtime.JSContext;
5252
import com.oracle.truffle.js.runtime.JSRealm;
5353
import com.oracle.truffle.js.runtime.JSRuntime;
54+
import com.oracle.truffle.js.runtime.builtins.JSPromiseObject;
5455

5556
/**
5657
* A Cyclic Module Record is used to represent information about a module that can participate in
@@ -139,7 +140,7 @@ protected CyclicModuleRecord(JSContext context, Source source, Object hostDefine
139140
public abstract Object executeModule(JSRealm realm, PromiseCapabilityRecord capability);
140141

141142
@Override
142-
public final Object evaluate(JSRealm realm) {
143+
public final JSPromiseObject evaluate(JSRealm realm) {
143144
return context.getEvaluator().moduleEvaluation(realm, this);
144145
}
145146

0 commit comments

Comments
 (0)