package com.oracle.truffle.js.nodes.promise;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.js.nodes.JavaScriptNode;
import com.oracle.truffle.js.nodes.access.CreateDataPropertyNode;
import com.oracle.truffle.js.nodes.access.CreateObjectNode;
import com.oracle.truffle.js.nodes.access.PropertyGetNode;
import com.oracle.truffle.js.nodes.arguments.AccessIndexedArgumentNode;
import com.oracle.truffle.js.nodes.function.JSFunctionCallNode;
import com.oracle.truffle.js.runtime.JSArguments;
import com.oracle.truffle.js.runtime.JSContext;
import com.oracle.truffle.js.runtime.JSFrameUtil;
import com.oracle.truffle.js.runtime.JavaScriptRootNode;
import com.oracle.truffle.js.runtime.builtins.JSArray;
import com.oracle.truffle.js.runtime.builtins.JSFunction;
import com.oracle.truffle.js.runtime.builtins.JSFunctionData;
import com.oracle.truffle.js.runtime.objects.PromiseCapabilityRecord;
import com.oracle.truffle.js.runtime.objects.Undefined;
import com.oracle.truffle.js.runtime.util.SimpleArrayList;
public class PerformPromiseAllSettledNode extends PerformPromiseAllNode {
protected PerformPromiseAllSettledNode(JSContext context) {
super(context);
}
public static PerformPromiseAllSettledNode create(JSContext context) {
return new PerformPromiseAllSettledNode(context);
}
@Override
protected DynamicObject createResolveElementFunction(int index, SimpleArrayList<Object> values, PromiseCapabilityRecord resultCapability, BoxedInt remainingElementsCount) {
JSFunctionData functionData = context.getOrCreateBuiltinFunctionData(JSContext.BuiltinFunctionKey.PromiseAllSettledResolveElement, (c) -> createResolveElementFunctionImpl(c));
DynamicObject function = JSFunction.create(context.getRealm(), functionData);
setArgs.setValue(function, new ResolveElementArgs(index, values, resultCapability, remainingElementsCount));
return function;
}
@Override
protected Object createRejectElementFunction(int index, SimpleArrayList<Object> values, PromiseCapabilityRecord resultCapability, BoxedInt remainingElementsCount) {
JSFunctionData functionData = context.getOrCreateBuiltinFunctionData(JSContext.BuiltinFunctionKey.PromiseAllSettledRejectElement, (c) -> createRejectElementFunctionImpl(c));
DynamicObject function = JSFunction.create(context.getRealm(), functionData);
setArgs.setValue(function, new ResolveElementArgs(index, values, resultCapability, remainingElementsCount));
return function;
}
private static JSFunctionData createResolveElementFunctionImpl(JSContext context) {
class PromiseAllSEttledResolveElementRootNode extends JavaScriptRootNode {
@Child private JavaScriptNode valueNode = AccessIndexedArgumentNode.create(0);
@Child private PropertyGetNode getArgs = PropertyGetNode.createGetHidden(RESOLVE_ELEMENT_ARGS_KEY, context);
@Child private JSFunctionCallNode callResolve = JSFunctionCallNode.createCall();
@Child private CreateObjectNode objectCreateNode = CreateObjectNode.create(context);
@Child private CreateDataPropertyNode createStatusPropertyNode = CreateDataPropertyNode.create(context, "status");
@Child private CreateDataPropertyNode createValuePropertyNode = CreateDataPropertyNode.create(context, "value");
@Override
public Object execute(VirtualFrame frame) {
DynamicObject functionObject = JSFrameUtil.getFunctionObject(frame);
ResolveElementArgs args = (ResolveElementArgs) getArgs.getValue(functionObject);
if (args.alreadyCalled) {
return Undefined.instance;
}
args.alreadyCalled = true;
Object value = valueNode.execute(frame);
DynamicObject obj = objectCreateNode.execute(frame);
createStatusPropertyNode.executeVoid(obj, "fulfilled");
createValuePropertyNode.executeVoid(obj, value);
args.values.set(args.index, obj);
args.remainingElements.value--;
if (args.remainingElements.value == 0) {
DynamicObject valuesArray = JSArray.createConstantObjectArray(context, args.values.toArray());
return callResolve.executeCall(JSArguments.createOneArg(Undefined.instance, args.capability.getResolve(), valuesArray));
}
return Undefined.instance;
}
}
CallTarget callTarget = Truffle.getRuntime().createCallTarget(new PromiseAllSEttledResolveElementRootNode());
return JSFunctionData.createCallOnly(context, callTarget, 1, "");
}
private static JSFunctionData createRejectElementFunctionImpl(JSContext context) {
class PromiseAllSettledRejectElementRootNode extends JavaScriptRootNode {
@Child private JavaScriptNode valueNode = AccessIndexedArgumentNode.create(0);
@Child private PropertyGetNode getArgs = PropertyGetNode.createGetHidden(RESOLVE_ELEMENT_ARGS_KEY, context);
@Child private JSFunctionCallNode callResolve = JSFunctionCallNode.createCall();
@Child private CreateObjectNode objectCreateNode = CreateObjectNode.create(context);
@Child private CreateDataPropertyNode createStatusPropertyNode = CreateDataPropertyNode.create(context, "status");
@Child private CreateDataPropertyNode createReasonPropertyNode = CreateDataPropertyNode.create(context, "reason");
@Override
public Object execute(VirtualFrame frame) {
DynamicObject functionObject = JSFrameUtil.getFunctionObject(frame);
ResolveElementArgs args = (ResolveElementArgs) getArgs.getValue(functionObject);
if (args.alreadyCalled) {
return Undefined.instance;
}
args.alreadyCalled = true;
Object value = valueNode.execute(frame);
DynamicObject obj = objectCreateNode.execute(frame);
createStatusPropertyNode.executeVoid(obj, "rejected");
createReasonPropertyNode.executeVoid(obj, value);
args.values.set(args.index, obj);
args.remainingElements.value--;
if (args.remainingElements.value == 0) {
DynamicObject valuesArray = JSArray.createConstantObjectArray(context, args.values.toArray());
return callResolve.executeCall(JSArguments.createOneArg(Undefined.instance, args.capability.getResolve(), valuesArray));
}
return Undefined.instance;
}
}
CallTarget callTarget = Truffle.getRuntime().createCallTarget(new PromiseAllSettledRejectElementRootNode());
return JSFunctionData.createCallOnly(context, callTarget, 1, "");
}
}