      return cachedCwd;
        lastCounter = currentCounter;
        cachedCwd = originalCwd();
        return cachedCwd;
      };
      workerIo.sharedCwdCounter = cwdCounter;
    }

    const isLoaderWorker =
      doEval === 'internal' &&
      filename === require('internal/modules/esm/utils').loaderWorkerId;
    // Disable custom loaders in loader worker.
    setupUserModules(isLoaderWorker);

    if (!hasStdin)
      process.stdin.push(null);

    debug(`[${threadId}] starts worker script ${filename} ` +
          `(eval = ${doEval}) at cwd = ${process.cwd()}`);
    port.postMessage({ type: UP_AND_RUNNING });
    switch (doEval) {
      case 'internal': {
        // Create this WeakMap in js-land because V8 has no C++ API for WeakMap.
        internalBinding('module_wrap').callbackMap = new SafeWeakMap();
        require(filename)(workerData, publicPort);
        break;
      }

      case 'classic': if (getOptionValue('--input-type') !== 'module') {
        const name = '[worker eval]';
        // This is necessary for CJS module compilation.
        // TODO: pass this with something really internal.
        ObjectDefineProperty(process, '_eval', {
          __proto__: null,
          configurable: true,
          enumerable: true,
          value: filename,
        });
        ArrayPrototypeSplice(process.argv, 1, 0, name);
        const tsEnabled = getOptionValue('--experimental-strip-types');
        const inputType = getOptionValue('--input-type');

        if (inputType === 'module-typescript' && tsEnabled) {
          // This is a special case where we want to parse and eval the
          // TypeScript code as a module
          parseAndEvalModuleTypeScript(filename, false);
          break;
        }

        let evalFunction;
        if (inputType === 'commonjs') {
          evalFunction = evalScript;
        } else if (inputType === 'commonjs-typescript' && tsEnabled) {
          evalFunction = parseAndEvalCommonjsTypeScript;
        } else if (tsEnabled) {
          evalFunction = evalTypeScript;
        } else {
          // Default to commonjs.
          evalFunction = evalScript;
        }

        evalFunction(name, filename);
        break;
      }

      // eslint-disable-next-line no-fallthrough
      case 'module': {
        PromisePrototypeThen(evalModuleEntryPoint(filename), undefined, (e) => {
          workerOnGlobalUncaughtException(e, true);
        });
        break;
      }

      default: {
        // script filename
        // runMain here might be monkey-patched by users in --require.
        // XXX: the monkey-patchability here should probably be deprecated.
        ArrayPrototypeSplice(process.argv, 1, 0, filename);
        const CJSLoader = require('internal/modules/cjs/loader');
        CJSLoader.Module.runMain(filename);
        break;
      }
    }
  } else if (message.type === STDIO_PAYLOAD) {
    const { stream, chunks } = message;
    ArrayPrototypeForEach(chunks, ({ chunk, encoding }) => {
      process[stream].push(chunk, encoding);
    });
  } else {
    assert(
      message.type === STDIO_WANTS_MORE_DATA,
      `Unknown worker message type ${message.type}`,
    );
    const { stream } = message;
    process[stream][kStdioWantsMoreDataCallback]();
  }
});

function workerOnGlobalUncaughtException(error, fromPromise) {
  debug(`[${threadId}] gets uncaught exception`);
  let handled = false;
  let handlerThrew = false;
  try {
    handled = onGlobalUncaughtException(error, fromPromise);
  } catch (e) {
    error = e;
    handlerThrew = true;
  }
  debug(`[${threadId}] uncaught exception handled = ${handled}`);

  if (handled) {
    return true;
  }

  if (!process._exiting) {
    try {
      process._exiting = true;
      process.exitCode = kGenericUserError;
      if (!handlerThrew) {
        process.emit('exit', process.exitCode);
      }
    } catch {
      // Continue regardless of error.
    }
  }

  let serialized;
  try {
    const { serializeError } = require('internal/error_serdes');
    serialized = serializeError(error);
  } catch {
    // Continue regardless of error.
  }
  debug(`[${threadId}] uncaught exception serialized = ${!!serialized}`);
  if (serialized)
    port.postMessage({
      type: ERROR_MESSAGE,
      error: serialized,
    });
  else
    port.postMessage({ type: COULD_NOT_SERIALIZE_ERROR });

  const { clearAsyncIdStack } = require('internal/async_hooks');
  clearAsyncIdStack();

  process.exit();
}

// Patch the global uncaught exception handler so it gets picked up by
// node::errors::TriggerUncaughtException().
process._fatalException = workerOnGlobalUncaughtException;

markBootstrapComplete();

// Necessary to reset RegExp statics before user code runs.
RegExpPrototypeExec(/^/, '');

port.start();
