Factory(
        LocalInterpreterProperties interpreterProperties,
        StagingArea stagingArea,
        InterpreterPropsProvider interpreterPropsProvider,
        int moduleId,
        ImmutableList<HasValue> inPortsHasValueList,
        BitSet recomputedInPorts,
        BitSet requestedOutPorts) {
      Objects.requireNonNull(interpreterProperties);
      Objects.requireNonNull(stagingArea);
      Objects.requireNonNull(interpreterPropsProvider);
      Objects.requireNonNull(inPortsHasValueList);
      Objects.requireNonNull(recomputedInPorts);
      Objects.requireNonNull(requestedOutPorts);

      this.interpreterProperties = interpreterProperties;
      this.stagingArea = stagingArea;
      this.interpreterPropsProvider = interpreterPropsProvider;
      RuntimeModule untypedModule = stagingArea.getAnnotatedExecutionTrace().getModule();
      if (untypedModule instanceof RuntimeProxyModule) {
        RuntimeProxyModule proxyModule = (RuntimeProxyModule) untypedModule;
        RuntimeCompositeModuleDeclaration declaration =
            (RuntimeCompositeModuleDeclaration) proxyModule.getDeclaration();
        module = declaration.getTemplate();
      } else {
        module = (RuntimeParentModule) untypedModule;
      }
      this.moduleId = moduleId;
      this.inPortsHasValueList = inPortsHasValueList;
      this.recomputedInPorts = (BitSet) Objects.requireNonNull(recomputedInPorts).clone();
      this.requestedOutPorts = (BitSet) Objects.requireNonNull(requestedOutPorts).clone();
    }
 /**
  * Callback for {@link ComputeResumeState} in order to determine whether a dependency-graph node
  * has a value or not.
  *
  * <p>This method is guaranteed to be called during processing of a message this actor received
  * (in particular, on the same thread).
  */
 private void asynchronousHasValueCheck(ValueNode valueNode) {
   ExecutionTrace executionTrace = valueNode.getExecutionTrace();
   CompletableFuture<Object> messageFuture =
       stagingArea
           .exists(executionTrace)
           .thenApply(exists -> new FinishedStagingAreaOperation(valueNode, exists));
   pipeResultToSelf(
       messageFuture, "checking if staging area contains execution trace '%s'", executionTrace);
 }
  /**
   * Returns, and if necessary creates, the submodule interpreter actor for the given submodule.
   *
   * <p>A submodule interpreter actor is created at most once during the lifetime of the current
   * actor. If the submodule actor is created, it will be supervised by the current actor.
   *
   * <p>This method starts one asynchronous action for each out-port of the submodule that satisfies
   * {@link #isOutPortNeeded(RuntimeOutPort)}; these will be finished in {@link
   * #submoduleOutPortNoLongerNeeded}. This prevents this actor from terminating even though a child
   * interpreter may still send values for out-ports.
   *
   * <p>One additional asynchronous action is started for the child actor, which will be finished in
   * {@link #childActorTerminated(ActorRef)}.
   *
   * @param submodule submodule
   * @return reference to the submodule actor
   */
  private ActorRef getChildExecutor(RuntimeModule submodule) {
    assert state == State.REPLAY || state == State.RUNNING || state == State.ALL_OUTPUTS;

    int submoduleId = submodule.getIndex();
    if (childExecutors[submoduleId] == null) {
      List<SubmoduleInPortNode> submoduleInPortNodes =
          dependencyGraph.submodulesInPortNodes().get(submoduleId);

      ImmutableList<HasValue> submoduleInPortHasValueList =
          submoduleInPortNodes
              .stream()
              .map(SubmoduleInPortNode::getHasValue)
              .collect(ImmutableList.collector());

      BitSet submoduleRecomputedInPorts = new BitSet(submodule.getInPorts().size());
      submoduleInPortNodes
          .stream()
          .filter(node -> node.getPortState() == PortState.RECOMPUTE)
          .forEach(node -> submoduleRecomputedInPorts.set(node.getElement().getInIndex()));

      BitSet submoduleRequestedOutPorts =
          computeResumeState.getSubmodulesNeededOutPorts()[submoduleId];
      submoduleRequestedOutPorts
          .stream()
          .mapToObj(id -> submodule.getOutPorts().get(id))
          .forEach(
              outPort ->
                  startAsynchronousAction(
                      outPort,
                      "waiting for value to pass through submodule out-port %s#%s",
                      submodule.getSimpleName(),
                      outPort.getSimpleName()));

      childExecutors[submoduleId] =
          getContext()
              .actorOf(
                  interpreterPropsProvider.provideInterpreterProps(
                      getInterpreterProperties(),
                      stagingArea.resolveDescendant(
                          ExecutionTrace.empty()
                              .resolveContent()
                              .resolveModule(submodule.getSimpleName())),
                      submoduleId,
                      submoduleInPortHasValueList,
                      submoduleRecomputedInPorts,
                      submoduleRequestedOutPorts),
                  submodule.getSimpleName().toString());
      getContext().watch(childExecutors[submoduleId]);
      childActorMap.put(childExecutors[submoduleId], submodule);
      startAsynchronousAction(
          childExecutors[submoduleId],
          "supervising interpreter for submodule %s",
          submodule.getSimpleName());
    }
    return childExecutors[submoduleId];
  }
  /**
   * Handles event that the value of a submodule's out-port is no longer needed.
   *
   * <p>If the submodule of the given out-port no longer has any (other) out-port whose value is
   * required, this method starts (asynchronously) cleaning all intermediate results for this
   * module.
   *
   * <p>This method also finishes the asynchronous action (waiting for submodule out-port) started
   * previously in {@link #getChildExecutor}.
   *
   * @param outPort out-port whose value is no longer needed
   */
  private void submoduleOutPortNoLongerNeeded(RuntimeOutPort outPort) {
    assert state.compareTo(State.RUNNING) >= 0;

    RuntimeModule submodule = outPort.getModule();
    BitSet neededOutPorts = computeResumeState.getSubmodulesNeededOutPorts()[submodule.getIndex()];
    neededOutPorts.set(outPort.getOutIndex(), false);
    if (neededOutPorts.isEmpty() && getInterpreterProperties().isCleaningRequested()) {
      ExecutionTrace executionTrace =
          ExecutionTrace.empty().resolveContent().resolveModule(submodule.getSimpleName());
      CompletableFuture<Void> future = stagingArea.delete(executionTrace);
      awaitAsynchronousAction(
          future, "cleaning up intermediate output of submodule '%s'", submodule.getSimpleName());
    }

    endAsynchronousAction(outPort);
  }