package com.oracle.truffle.js.runtime.objects;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.js.runtime.JSContext;
import com.oracle.truffle.js.runtime.builtins.JSFunctionData;
import com.oracle.truffle.js.runtime.builtins.JSOrdinary;
import java.util.ArrayList;
import java.util.List;
public final class JSModuleRecord extends ScriptOrModule {
public enum Status {
Unlinked,
Linking,
Linked,
Evaluating,
Evaluated,
}
private final Object module;
private final JSModuleLoader moduleLoader;
private Status status;
private Throwable evaluationError;
private Object executionResult;
private JSFunctionData functionData;
private FrameDescriptor frameDescriptor;
private DynamicObject namespace;
private MaterializedFrame environment;
private DynamicObject importMeta;
private int dfsIndex;
private int dfsAncestorIndex;
private Object topLevelAwaitModuleLoadingContinuation;
public JSModuleRecord(Object module, JSContext context, JSModuleLoader moduleLoader, Source source) {
super(context, source);
this.module = module;
this.moduleLoader = moduleLoader;
setUninstantiated();
}
public Object getModule() {
return module;
}
public JSModuleLoader getModuleLoader() {
return moduleLoader;
}
public JSFunctionData getFunctionData() {
assert functionData != null;
return functionData;
}
public void setFunctionData(JSFunctionData functionData) {
assert this.functionData == null;
this.functionData = functionData;
}
public FrameDescriptor getFrameDescriptor() {
assert frameDescriptor != null;
return frameDescriptor;
}
public void setFrameDescriptor(FrameDescriptor frameDescriptor) {
assert this.frameDescriptor == null;
this.frameDescriptor = frameDescriptor;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public boolean isEvaluated() {
return getStatus() == Status.Evaluated;
}
public Throwable getEvaluationError() {
assert isEvaluated();
return evaluationError;
}
public void setEvaluationError(Throwable evaluationError) {
assert isEvaluated();
this.evaluationError = evaluationError;
}
public DynamicObject getNamespace() {
return namespace;
}
public void setNamespace(DynamicObject namespace) {
assert this.namespace == null;
this.namespace = namespace;
}
public MaterializedFrame getEnvironment() {
return environment;
}
public void setEnvironment(MaterializedFrame environment) {
assert this.environment == null;
assert this.frameDescriptor == environment.getFrameDescriptor();
this.environment = environment;
}
public int getDFSIndex() {
assert dfsIndex >= 0;
return dfsIndex;
}
public void setDFSIndex(int dfsIndex) {
this.dfsIndex = dfsIndex;
}
public int getDFSAncestorIndex() {
assert dfsAncestorIndex >= 0;
return dfsAncestorIndex;
}
public void setDFSAncestorIndex(int dfsAncestorIndex) {
this.dfsAncestorIndex = dfsAncestorIndex;
}
public Object getExecutionResult() {
return executionResult;
}
public void setExecutionResult(Object executionResult) {
this.executionResult = executionResult;
}
public DynamicObject getImportMeta() {
if (importMeta == null) {
importMeta = createMetaObject();
}
return importMeta;
}
private DynamicObject createMetaObject() {
DynamicObject metaObj = JSOrdinary.createWithNullPrototype(context);
if (context.hasImportMetaInitializerBeenSet()) {
context.notifyImportMetaInitializer(metaObj, this);
} else {
initializeMetaObject(metaObj);
}
return metaObj;
}
@TruffleBoundary
private void initializeMetaObject(DynamicObject metaObj) {
JSObject.set(metaObj, "url", getSource().getURI().toString());
}
public void setUninstantiated() {
setStatus(Status.Unlinked);
this.environment = null;
this.dfsIndex = -1;
this.dfsAncestorIndex = -1;
}
private boolean async = false;
private boolean asyncEvaluating = false;
private PromiseCapabilityRecord topLevelPromiseCapability = null;
private List<JSModuleRecord> asyncParentModules = null;
private int pendingAsyncDependencies = 0;
public PromiseCapabilityRecord getTopLevelCapability() {
return topLevelPromiseCapability;
}
public void setTopLevelCapability(PromiseCapabilityRecord capability) {
this.topLevelPromiseCapability = capability;
}
public boolean isAsyncEvaluating() {
return asyncEvaluating;
}
public List<JSModuleRecord> getAsyncParentModules() {
return asyncParentModules;
}
public void setPendingAsyncDependencies(int value) {
pendingAsyncDependencies = value;
}
public void initAsyncParentModules() {
assert asyncParentModules == null;
asyncParentModules = new ArrayList<>();
}
public void incPendingAsyncDependencies() {
pendingAsyncDependencies++;
}
public void decPendingAsyncDependencies() {
pendingAsyncDependencies--;
}
public void appendAsyncParentModules(JSModuleRecord moduleRecord) {
asyncParentModules.add(moduleRecord);
}
public int getPendingAsyncDependencies() {
return pendingAsyncDependencies;
}
public void setAsyncEvaluating(boolean value) {
asyncEvaluating = value;
}
public boolean isTopLevelAsync() {
return async;
}
public void setTopLevelAsync() {
async = true;
}
public void setExecutionContinuation(Object continuation) {
this.topLevelAwaitModuleLoadingContinuation = continuation;
}
public Object getExecutionContinuation() {
return topLevelAwaitModuleLoadingContinuation;
}
}