in src/bun.js/bindings/webcore/JSWorker.cpp [114:278]
template<> JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSWorkerDOMConstructor::construct(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame)
{
VM& vm = lexicalGlobalObject->vm();
auto throwScope = DECLARE_THROW_SCOPE(vm);
auto* castedThis = jsCast<JSWorkerDOMConstructor*>(callFrame->jsCallee());
ASSERT(castedThis);
if (UNLIKELY(callFrame->argumentCount() < 1))
return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
auto* context = castedThis->scriptExecutionContext();
if (UNLIKELY(!context))
return throwConstructorScriptExecutionContextUnavailableError(*lexicalGlobalObject, throwScope, "Worker"_s);
EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0);
auto scriptUrl = convert<IDLUSVString>(*lexicalGlobalObject, argument0.value());
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
EnsureStillAliveScope argument1 = callFrame->argument(1);
auto options = WorkerOptions {};
options.bun.unref = false;
if (JSObject* optionsObject = JSC::jsDynamicCast<JSC::JSObject*>(argument1.value())) {
if (auto nameValue = optionsObject->getIfPropertyExists(lexicalGlobalObject, vm.propertyNames->name)) {
if (nameValue.isString()) {
options.name = nameValue.toWTFString(lexicalGlobalObject);
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
}
}
if (auto miniModeValue = optionsObject->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "smol"_s))) {
options.bun.mini = miniModeValue.toBoolean(lexicalGlobalObject);
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
}
if (auto ref = optionsObject->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "ref"_s))) {
options.bun.unref = !ref.toBoolean(lexicalGlobalObject);
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
}
auto workerData = optionsObject->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "workerData"_s));
if (!workerData) {
workerData = optionsObject->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "data"_s));
}
if (workerData) {
Vector<RefPtr<MessagePort>> ports;
Vector<JSC::Strong<JSC::JSObject>> transferList;
if (JSValue transferListValue = optionsObject->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "transferList"_s))) {
if (transferListValue.isObject()) {
JSC::JSObject* transferListObject = transferListValue.getObject();
if (auto* transferListArray = jsDynamicCast<JSC::JSArray*>(transferListObject)) {
for (unsigned i = 0; i < transferListArray->length(); i++) {
JSC::JSValue transferListValue = transferListArray->get(lexicalGlobalObject, i);
if (transferListValue.isObject()) {
JSC::JSObject* transferListObject = transferListValue.getObject();
transferList.append(JSC::Strong<JSC::JSObject>(vm, transferListObject));
}
}
}
}
}
ExceptionOr<Ref<SerializedScriptValue>> serialized = SerializedScriptValue::create(*lexicalGlobalObject, workerData, WTFMove(transferList), ports, SerializationForStorage::No, SerializationContext::WorkerPostMessage);
if (serialized.hasException()) {
WebCore::propagateException(*lexicalGlobalObject, throwScope, serialized.releaseException());
return encodedJSValue();
}
Vector<TransferredMessagePort> transferredPorts;
if (!ports.isEmpty()) {
auto disentangleResult = MessagePort::disentanglePorts(WTFMove(ports));
if (disentangleResult.hasException()) {
WebCore::propagateException(*lexicalGlobalObject, throwScope, disentangleResult.releaseException());
return encodedJSValue();
}
transferredPorts = disentangleResult.releaseReturnValue();
}
options.bun.data = serialized.releaseReturnValue();
options.bun.dataMessagePorts = WTFMove(transferredPorts);
}
auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
auto envValue = optionsObject->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "env"_s));
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
JSObject* envObject = nullptr;
if (envValue && envValue.isCell()) {
envObject = jsDynamicCast<JSC::JSObject*>(envValue);
} else if (globalObject->m_processEnvObject.isInitialized()) {
envObject = globalObject->processEnvObject();
}
if (envObject) {
if (!envObject->staticPropertiesReified()) {
envObject->reifyAllStaticProperties(globalObject);
RETURN_IF_EXCEPTION(throwScope, {});
}
JSC::PropertyNameArray keys(vm, JSC::PropertyNameMode::Strings, JSC::PrivateSymbolMode::Exclude);
envObject->methodTable()->getOwnPropertyNames(envObject, lexicalGlobalObject, keys, JSC::DontEnumPropertiesMode::Exclude);
RETURN_IF_EXCEPTION(throwScope, {});
HashMap<String, String> env;
for (const auto& key : keys) {
JSValue value = envObject->get(lexicalGlobalObject, key);
RETURN_IF_EXCEPTION(throwScope, {});
String str = value.toWTFString(lexicalGlobalObject).isolatedCopy();
RETURN_IF_EXCEPTION(throwScope, {});
env.add(key.impl()->isolatedCopy(), str);
}
options.bun.env = std::make_unique<HashMap<String, String>>(WTFMove(env));
}
JSValue argvValue = optionsObject->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "argv"_s));
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
if (argvValue && argvValue.isCell() && argvValue.asCell()->type() == JSC::JSType::ArrayType) {
Vector<String> argv;
forEachInIterable(lexicalGlobalObject, argvValue, [&argv](JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSValue nextValue) {
auto scope = DECLARE_THROW_SCOPE(vm);
String str = nextValue.toWTFString(lexicalGlobalObject).isolatedCopy();
if (UNLIKELY(scope.exception()))
return;
argv.append(str);
});
options.bun.argv = std::make_unique<Vector<String>>(WTFMove(argv));
}
JSValue execArgvValue = optionsObject->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "execArgv"_s));
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
if (execArgvValue && execArgvValue.isCell() && execArgvValue.asCell()->type() == JSC::JSType::ArrayType) {
Vector<String> execArgv;
forEachInIterable(lexicalGlobalObject, execArgvValue, [&execArgv](JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSValue nextValue) {
auto scope = DECLARE_THROW_SCOPE(vm);
String str = nextValue.toWTFString(lexicalGlobalObject).isolatedCopy();
if (UNLIKELY(scope.exception()))
return;
execArgv.append(str);
});
options.bun.execArgv = std::make_unique<Vector<String>>(WTFMove(execArgv));
}
}
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
auto object = Worker::create(*context, WTFMove(scriptUrl), WTFMove(options));
if constexpr (IsExceptionOr<decltype(object)>)
RETURN_IF_EXCEPTION(throwScope, {});
static_assert(TypeOrExceptionOrUnderlyingType<decltype(object)>::isRef);
auto jsValue = toJSNewlyCreated<IDLInterface<Worker>>(*lexicalGlobalObject, *castedThis->globalObject(), throwScope, WTFMove(object));
if constexpr (IsExceptionOr<decltype(object)>)
RETURN_IF_EXCEPTION(throwScope, {});
auto& impl = jsCast<JSWorker*>(jsValue)->wrapped();
if (!impl.updatePtr()) {
throwVMError(lexicalGlobalObject, throwScope, "Failed to start Worker thread"_s);
return encodedJSValue();
}
setSubclassStructureIfNeeded<Worker>(lexicalGlobalObject, callFrame, asObject(jsValue));
RETURN_IF_EXCEPTION(throwScope, {});
return JSValue::encode(jsValue);
}