diff --git a/scripts/build/deps/webkit.ts b/scripts/build/deps/webkit.ts index f4ffdb22eb45..0e90a21f3856 100644 --- a/scripts/build/deps/webkit.ts +++ b/scripts/build/deps/webkit.ts @@ -3,7 +3,7 @@ * for local mode. Override via `--webkit-version=` to test a branch. * From https://github.com/oven-sh/WebKit releases. */ -export const WEBKIT_VERSION = "5718a6ec579b98362ea7276a426deedcc6281ef5"; +export const WEBKIT_VERSION = "0c06faadf65bf8e8c8ad3a5a8aca83e1e9ed653f"; /** * WebKit (JavaScriptCore) — the JS engine. diff --git a/src/jsc/bindings/BunProcess.cpp b/src/jsc/bindings/BunProcess.cpp index efd62913ade4..c8bfaaf838ad 100644 --- a/src/jsc/bindings/BunProcess.cpp +++ b/src/jsc/bindings/BunProcess.cpp @@ -502,7 +502,7 @@ JSC_DEFINE_HOST_FUNCTION_WITH_ATTRIBUTES(Process_functionDlopen, __attribute__(( filename = fileURL.fileSystemPath(); } - CString utf8; + UTF8CString utf8; // Support embedded .node files // See src/standalone_graph/StandaloneModuleGraph.rs for what this "$bunfs" thing is @@ -558,7 +558,7 @@ JSC_DEFINE_HOST_FUNCTION_WITH_ATTRIBUTES(Process_functionDlopen, __attribute__(( // See https://github.com/oven-sh/bun/issues/15753. if (!fromEmbedded) { char soname[64] = { 0 }; - if (Bun__addonNeedsGlibcOnMusl(utf8.data(), utf8.length(), soname, sizeof(soname))) [[unlikely]] { + if (Bun__addonNeedsGlibcOnMusl(utf8.legacyCStringPointer(), utf8.length(), soname, sizeof(soname))) [[unlikely]] { WTF::StringBuilder msg; msg.append(filename); msg.append(" is linked against glibc (DT_NEEDED "_s); @@ -568,8 +568,8 @@ JSC_DEFINE_HOST_FUNCTION_WITH_ATTRIBUTES(Process_functionDlopen, __attribute__(( } } #endif - CrashHandler__setDlOpenAction(utf8.data()); - void* handle = dlopen(utf8.data(), RTLD_LAZY); + CrashHandler__setDlOpenAction(utf8.legacyCStringPointer()); + void* handle = dlopen(utf8.legacyCStringPointer(), RTLD_LAZY); CrashHandler__setDlOpenAction(nullptr); #endif @@ -761,7 +761,7 @@ JSC_DEFINE_HOST_FUNCTION_WITH_ATTRIBUTES(Process_functionDlopen, __attribute__(( EncodedJSValue exportsValue = JSC::JSValue::encode(exports); - char* filename_cstr = toFileURI(utf8.span()); + char* filename_cstr = toFileURI(byteCast(utf8.span())); napi_module nmodule { .nm_version = module_version, @@ -1962,7 +1962,7 @@ JSC_DEFINE_HOST_FUNCTION_WITH_ATTRIBUTES(Process_functionExecve, __attribute__(( RETURN_IF_EXCEPTION(scope, {}); } - Vector argvStorage; + Vector argvStorage; argvStorage.reserveInitialCapacity(argsLength); for (unsigned i = 0; i < argsLength; i++) { @@ -1990,7 +1990,7 @@ JSC_DEFINE_HOST_FUNCTION_WITH_ATTRIBUTES(Process_functionExecve, __attribute__(( RETURN_IF_EXCEPTION(scope, {}); } - Vector envStorage; + Vector envStorage; { Bun::V::validateObject(scope, globalObject, envValue, "env"_s); RETURN_IF_EXCEPTION(scope, {}); @@ -2026,7 +2026,7 @@ JSC_DEFINE_HOST_FUNCTION_WITH_ATTRIBUTES(Process_functionExecve, __attribute__(( } } - CString execPathUtf8 = execPath.utf8(); + UTF8CString execPathUtf8 = execPath.utf8(); // Build the null-terminated argv/envp pointer arrays only after the // backing storage is fully populated so there is no risk of pointers @@ -2034,13 +2034,13 @@ JSC_DEFINE_HOST_FUNCTION_WITH_ATTRIBUTES(Process_functionExecve, __attribute__(( Vector argv; argv.reserveInitialCapacity(argvStorage.size() + 1); for (auto& s : argvStorage) - argv.append(const_cast(s.data())); + argv.append(const_cast(s.legacyCStringPointer())); argv.append(nullptr); Vector envp; envp.reserveInitialCapacity(envStorage.size() + 1); for (auto& s : envStorage) - envp.append(const_cast(s.data())); + envp.append(const_cast(s.legacyCStringPointer())); envp.append(nullptr); // Set stdin, stdout and stderr to be non-close-on-exec so that the new @@ -2087,7 +2087,7 @@ JSC_DEFINE_HOST_FUNCTION_WITH_ATTRIBUTES(Process_functionExecve, __attribute__(( posix_spawn_file_actions_addinherit_np(&actions, 2); pid_t pid; - savedErrno = posix_spawn(&pid, execPathUtf8.data(), &actions, &attrs, argv.begin(), envp.begin()); + savedErrno = posix_spawn(&pid, execPathUtf8.legacyCStringPointer(), &actions, &attrs, argv.begin(), envp.begin()); // With POSIX_SPAWN_SETEXEC a successful call never returns; reaching // here means it failed and the return value is the errno. posix_spawn_file_actions_destroy(&actions); @@ -2118,7 +2118,7 @@ JSC_DEFINE_HOST_FUNCTION_WITH_ATTRIBUTES(Process_functionExecve, __attribute__(( sigemptyset(&emptyMask); pthread_sigmask(SIG_SETMASK, &emptyMask, &previousMask); - ::execve(execPathUtf8.data(), argv.begin(), envp.begin()); + ::execve(execPathUtf8.legacyCStringPointer(), argv.begin(), envp.begin()); savedErrno = errno; // execve(2) failed; put back the signal mask we cleared above. @@ -3573,7 +3573,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functioninitgroups, (JSGlobalObject * globalObj // initgroups(3) takes a user *name*. Node passes a string user through // as-is (initgroups(3) reports EPERM/ENOMEM/etc. itself); only a numeric // uid is pre-resolved through passwd so we have a name to pass. - CString userNameUTF8; + UTF8CString userNameUTF8; const char* userName = nullptr; struct passwd pwd; struct passwd* pp = nullptr; @@ -3582,7 +3582,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functioninitgroups, (JSGlobalObject * globalObj auto str = user.getString(globalObject); RETURN_IF_EXCEPTION(scope, {}); userNameUTF8 = str.utf8(); - userName = userNameUTF8.data(); + userName = userNameUTF8.legacyCStringPointer(); } else { uid_t uid = static_cast(user.toUInt32(globalObject)); RETURN_IF_EXCEPTION(scope, {}); @@ -4723,8 +4723,8 @@ JSC_DEFINE_CUSTOM_SETTER(setProcessTitle, (JSC::JSGlobalObject * globalObject, J // call is best-effort (it fails in console-less processes). BunString str = Bun::toString(wtfStr); Bun__Process__setTitle(globalObject, &str); - CString cstr = wtfStr.utf8(); - uv_set_process_title(cstr.data()); + UTF8CString cstr = wtfStr.utf8(); + uv_set_process_title(cstr.legacyCStringPointer()); return true; #endif } diff --git a/src/jsc/bindings/BunString.h b/src/jsc/bindings/BunString.h index 2d94a08bce85..d72c8fe933e1 100644 --- a/src/jsc/bindings/BunString.h +++ b/src/jsc/bindings/BunString.h @@ -39,7 +39,7 @@ class UTF8View { std::span span() const { if (m_isConverted) - return m_converted.span(); + return byteCast(m_converted.span()); return byteCast(m_borrowed.span8()); } @@ -47,7 +47,7 @@ class UTF8View { UTF8View() = default; WTF::StringView m_borrowed {}; - WTF::CString m_converted {}; + WTF::UTF8CString m_converted {}; bool m_isConverted { false }; }; diff --git a/src/jsc/bindings/JSBundlerPlugin.cpp b/src/jsc/bindings/JSBundlerPlugin.cpp index ca57cc2450dc..3fc0a012114b 100644 --- a/src/jsc/bindings/JSBundlerPlugin.cpp +++ b/src/jsc/bindings/JSBundlerPlugin.cpp @@ -388,13 +388,13 @@ JSC_DEFINE_HOST_FUNCTION(jsBundlerPluginFunction_onBeforeParse, (JSC::JSGlobalOb } Bun::NapiModuleMeta* meta = (Bun::NapiModuleMeta*)napi_external->value(); void* dlopen_handle = meta->dlopenHandle; - CString utf8 = on_before_parse_symbol.utf8(); + UTF8CString utf8 = on_before_parse_symbol.utf8(); #if OS(WINDOWS) - void* on_before_parse_symbol_ptr = GetProcAddress((HMODULE)dlopen_handle, utf8.data()); + void* on_before_parse_symbol_ptr = GetProcAddress((HMODULE)dlopen_handle, utf8.legacyCStringPointer()); const char** native_plugin_name = (const char**)GetProcAddress((HMODULE)dlopen_handle, "BUN_PLUGIN_NAME"); #else - void* on_before_parse_symbol_ptr = dlsym(dlopen_handle, utf8.data()); + void* on_before_parse_symbol_ptr = dlsym(dlopen_handle, utf8.legacyCStringPointer()); const char** native_plugin_name = (const char**)dlsym(dlopen_handle, "BUN_PLUGIN_NAME"); #endif diff --git a/src/jsc/bindings/JSONRowsToJS.cpp b/src/jsc/bindings/JSONRowsToJS.cpp index bfdba120acbb..93f7b15abb1c 100644 --- a/src/jsc/bindings/JSONRowsToJS.cpp +++ b/src/jsc/bindings/JSONRowsToJS.cpp @@ -1,6 +1,6 @@ // Builds JS values from the immutable JSON AST rows (`E::JsonTape`, see src/ast/e.rs) that the // JSON and XML parsers produce: one call for the whole document, keys and short values through -// the VM's JSONAtomStringCache the way JSON.parse does it. +// the VM's JSONCache the way JSON.parse does it. #include "root.h" @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include @@ -165,10 +165,10 @@ class RowsToJS { ALWAYS_INLINE Identifier identifier(const RowStr& key) { if constexpr (encoding == RowEncoding::Utf16) - return Identifier::fromString(m_vm, m_vm.jsonAtomStringCache.makeIdentifier(utf16(key))); + return Identifier::fromString(m_vm, m_vm.jsonCache().makeIdentifier(m_vm, utf16(key))); else { if (encoding == RowEncoding::Latin1 || charactersAreAllASCII(key.span())) [[likely]] - return Identifier::fromString(m_vm, m_vm.jsonAtomStringCache.makeIdentifier(key.span())); + return Identifier::fromString(m_vm, m_vm.jsonCache().makeIdentifier(m_vm, key.span())); JSValue decoded = utf8(key); if (!decoded) [[unlikely]] return {}; @@ -180,11 +180,11 @@ class RowsToJS { { JSString* result; if constexpr (encoding == RowEncoding::Utf16) - result = m_vm.jsonAtomStringCache.tryMakeJSString(utf16(s)); + result = m_vm.jsonCache().tryMakeJSString(m_vm, utf16(s)); else { if (encoding == RowEncoding::Utf8 && !charactersAreAllASCII(s.span())) [[unlikely]] return utf8(s); - result = m_vm.jsonAtomStringCache.tryMakeJSString(s.span()); + result = m_vm.jsonCache().tryMakeJSString(m_vm, s.span()); } if (!result) [[unlikely]] { auto scope = DECLARE_THROW_SCOPE(m_vm); diff --git a/src/jsc/bindings/JSX509CertificatePrototype.cpp b/src/jsc/bindings/JSX509CertificatePrototype.cpp index a7c858146270..aeb5ac2dcecb 100644 --- a/src/jsc/bindings/JSX509CertificatePrototype.cpp +++ b/src/jsc/bindings/JSX509CertificatePrototype.cpp @@ -310,13 +310,13 @@ JSC_DEFINE_HOST_FUNCTION(jsX509CertificateProtoFuncCheckIP, (JSGlobalObject * gl RETURN_IF_EXCEPTION(scope, {}); auto view = ipString->view(globalObject); RETURN_IF_EXCEPTION(scope, {}); - WTF::CString ip = view->utf8(); + WTF::UTF8CString ip = view->utf8(); // ignore flags // uint32_t flags = getFlags(vm, globalObject, scope, callFrame->argument(1)); // RETURN_IF_EXCEPTION(scope, {}); - auto check = thisObject->checkIP(globalObject, ip.data()); + auto check = thisObject->checkIP(globalObject, ip.legacyCStringPointer()); RETURN_IF_EXCEPTION(scope, {}); if (!check) return JSValue::encode(jsUndefined()); return JSValue::encode(ipString); diff --git a/src/jsc/bindings/NodeTLS.cpp b/src/jsc/bindings/NodeTLS.cpp index ef8377ee9878..f1e2aca878b6 100644 --- a/src/jsc/bindings/NodeTLS.cpp +++ b/src/jsc/bindings/NodeTLS.cpp @@ -179,7 +179,7 @@ static int noPasswordCallback(char*, int, int, void*) // because forEachInIterable drives the iterator protocol and a tampered // %ArrayIteratorPrototype%.next can detach an earlier element between pass-1 // callbacks. -using CACertInput = std::variant; +using CACertInput = std::variant; JSC_DEFINE_HOST_FUNCTION(parseCACertificates, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { @@ -234,7 +234,7 @@ JSC_DEFINE_HOST_FUNCTION(parseCACertificates, (JSC::JSGlobalObject * globalObjec for (auto& in : inputs) { std::span bytes; - if (auto* utf8 = std::get_if(&in)) { + if (auto* utf8 = std::get_if(&in)) { bytes = { reinterpret_cast(utf8->data()), utf8->length() }; } else { auto* view = std::get(in); diff --git a/src/jsc/bindings/Secrets.h b/src/jsc/bindings/Secrets.h index c27081b8aad0..59fbb28f4c33 100644 --- a/src/jsc/bindings/Secrets.h +++ b/src/jsc/bindings/Secrets.h @@ -42,11 +42,11 @@ enum class Persist : uint8_t { // Sync platform-specific implementations (used by threadpool) // These use CString for thread safety - only called from threadpool -Error setPassword(const WTF::CString& service, const WTF::CString& name, WTF::CString&& password, bool allowUnrestrictedAccess, Persist persist); +Error setPassword(const WTF::UTF8CString& service, const WTF::UTF8CString& name, WTF::UTF8CString&& password, bool allowUnrestrictedAccess, Persist persist); // Use a WTF::Vector here so we can zero out the memory. -std::optional> getPassword(const WTF::CString& service, const WTF::CString& name, Error& error); -bool deletePassword(const WTF::CString& service, const WTF::CString& name, Error& error); +std::optional> getPassword(const WTF::UTF8CString& service, const WTF::UTF8CString& name, Error& error); +bool deletePassword(const WTF::UTF8CString& service, const WTF::UTF8CString& name, Error& error); } // namespace Secrets diff --git a/src/jsc/bindings/SecretsDarwin.cpp b/src/jsc/bindings/SecretsDarwin.cpp index 57bea53f0cd3..d47c46ed8e4e 100644 --- a/src/jsc/bindings/SecretsDarwin.cpp +++ b/src/jsc/bindings/SecretsDarwin.cpp @@ -275,15 +275,15 @@ static void updateError(Error& err, OSStatus status) } } -static ScopedCFRef createQuery(const CString& service, const CString& name) +static ScopedCFRef createQuery(const UTF8CString& service, const UTF8CString& name) { auto* framework = securityFramework(); if (!framework) return ScopedCFRef(nullptr); ScopedCFRef cfServiceName(framework->CFStringCreateWithCString( - framework->kCFAllocatorDefault, service.data(), kCFStringEncodingUTF8)); + framework->kCFAllocatorDefault, service.legacyCStringPointer(), kCFStringEncodingUTF8)); ScopedCFRef cfUser(framework->CFStringCreateWithCString( - framework->kCFAllocatorDefault, name.data(), kCFStringEncodingUTF8)); + framework->kCFAllocatorDefault, name.legacyCStringPointer(), kCFStringEncodingUTF8)); if (!cfServiceName || !cfUser) return ScopedCFRef(nullptr); @@ -301,7 +301,7 @@ static ScopedCFRef createQuery(const CString& service, const CString& name) return ScopedCFRef(query); } -Error setPassword(const CString& service, const CString& name, CString&& password, bool allowUnrestrictedAccess, Persist) +Error setPassword(const UTF8CString& service, const UTF8CString& name, UTF8CString&& password, bool allowUnrestrictedAccess, Persist) { Error err; @@ -392,7 +392,7 @@ Error setPassword(const CString& service, const CString& name, CString&& passwor return err; } -std::optional> getPassword(const CString& service, const CString& name, Error& err) +std::optional> getPassword(const UTF8CString& service, const UTF8CString& name, Error& err) { err = Error {}; @@ -429,7 +429,7 @@ std::optional> getPassword(const CString& service, const CS return std::nullopt; } -bool deletePassword(const CString& service, const CString& name, Error& err) +bool deletePassword(const UTF8CString& service, const UTF8CString& name, Error& err) { err = Error {}; diff --git a/src/jsc/bindings/SecretsLinux.cpp b/src/jsc/bindings/SecretsLinux.cpp index 30efe5daeef1..d38cfc974e0a 100644 --- a/src/jsc/bindings/SecretsLinux.cpp +++ b/src/jsc/bindings/SecretsLinux.cpp @@ -269,7 +269,7 @@ static void updateError(Error& err, GError* gerror) } } -Error setPassword(const CString& service, const CString& name, CString&& password, bool allowUnrestrictedAccess, Persist) +Error setPassword(const UTF8CString& service, const UTF8CString& name, UTF8CString&& password, bool allowUnrestrictedAccess, Persist) { Error err; @@ -293,18 +293,18 @@ Error setPassword(const CString& service, const CString& name, CString&& passwor GError* gerror = nullptr; // Combine service and name for label - auto label = makeString(String::fromUTF8(service.data()), "/"_s, String::fromUTF8(name.data())); + auto label = makeString(String::fromUTF8(service.span()), "/"_s, String::fromUTF8(name.span())); auto labelUtf8 = label.utf8(); gboolean result = framework->secret_password_store_sync( get_bun_schema(), nullptr, // Let libsecret handle collection creation automatically labelUtf8.legacyCStringPointer(), - password.data(), + password.legacyCStringPointer(), nullptr, // cancellable &gerror, - "service", service.data(), - "account", name.data(), + "service", service.legacyCStringPointer(), + "account", name.legacyCStringPointer(), nullptr // end of attributes ); @@ -319,7 +319,7 @@ Error setPassword(const CString& service, const CString& name, CString&& passwor return err; } -std::optional> getPassword(const CString& service, const CString& name, Error& err) +std::optional> getPassword(const UTF8CString& service, const UTF8CString& name, Error& err) { err = Error {}; @@ -336,8 +336,8 @@ std::optional> getPassword(const CString& service, const CS get_bun_schema(), nullptr, // cancellable &gerror, - "service", service.data(), - "account", name.data(), + "service", service.legacyCStringPointer(), + "account", name.legacyCStringPointer(), nullptr // end of attributes ); @@ -363,7 +363,7 @@ std::optional> getPassword(const CString& service, const CS return result; } -bool deletePassword(const CString& service, const CString& name, Error& err) +bool deletePassword(const UTF8CString& service, const UTF8CString& name, Error& err) { err = Error {}; @@ -380,8 +380,8 @@ bool deletePassword(const CString& service, const CString& name, Error& err) get_bun_schema(), nullptr, // cancellable &gerror, - "service", service.data(), - "account", name.data(), + "service", service.legacyCStringPointer(), + "account", name.legacyCStringPointer(), nullptr // end of attributes ); diff --git a/src/jsc/bindings/SecretsWindows.cpp b/src/jsc/bindings/SecretsWindows.cpp index ce0faf0295bc..d28b06e42294 100644 --- a/src/jsc/bindings/SecretsWindows.cpp +++ b/src/jsc/bindings/SecretsWindows.cpp @@ -64,19 +64,19 @@ static CredentialFramework* credentialFramework() } // Convert CString to Windows wide string -static std::vector cstringToWideChar(const CString& str) +static std::vector cstringToWideChar(const UTF8CString& str) { - if (!str.data()) { + if (str.isNull()) { return std::vector(1, L'\0'); } - int wideLength = MultiByteToWideChar(CP_UTF8, 0, str.data(), -1, nullptr, 0); + int wideLength = MultiByteToWideChar(CP_UTF8, 0, str.legacyCStringPointer(), -1, nullptr, 0); if (wideLength == 0) { return std::vector(1, L'\0'); } std::vector result(wideLength); - MultiByteToWideChar(CP_UTF8, 0, str.data(), -1, result.data(), wideLength); + MultiByteToWideChar(CP_UTF8, 0, str.legacyCStringPointer(), -1, result.data(), wideLength); return result; } @@ -154,7 +154,7 @@ static DWORD toCredPersist(Persist persist) RELEASE_ASSERT_NOT_REACHED(); } -Error setPassword(const CString& service, const CString& name, CString&& password, bool allowUnrestrictedAccess, Persist persist) +Error setPassword(const UTF8CString& service, const UTF8CString& name, UTF8CString&& password, bool allowUnrestrictedAccess, Persist persist) { Error err; @@ -177,7 +177,7 @@ Error setPassword(const CString& service, const CString& name, CString&& passwor } // Create target name as "service/name" - String targetName = makeString(String::fromUTF8(service.data()), "/"_s, String::fromUTF8(name.data())); + String targetName = makeString(String::fromUTF8(service.span()), "/"_s, String::fromUTF8(name.span())); auto targetNameUtf8 = targetName.utf8(); auto targetNameWide = cstringToWideChar(targetNameUtf8); auto nameNameWide = cstringToWideChar(name); @@ -196,12 +196,12 @@ Error setPassword(const CString& service, const CString& name, CString&& passwor // Best-effort scrub of plaintext from memory. if (password.length()) - SecureZeroMemory(const_cast(password.data()), password.length()); + SecureZeroMemory(const_cast(password.legacyCStringPointer()), password.length()); return err; } -std::optional> getPassword(const CString& service, const CString& name, Error& err) +std::optional> getPassword(const UTF8CString& service, const UTF8CString& name, Error& err) { err = Error {}; @@ -212,7 +212,7 @@ std::optional> getPassword(const CString& service, const CS return std::nullopt; } - String targetName = makeString(String::fromUTF8(service.data()), "/"_s, String::fromUTF8(name.data())); + String targetName = makeString(String::fromUTF8(service.span()), "/"_s, String::fromUTF8(name.span())); auto targetNameUtf8 = targetName.utf8(); auto targetNameWide = cstringToWideChar(targetNameUtf8); @@ -238,7 +238,7 @@ std::optional> getPassword(const CString& service, const CS return result; } -bool deletePassword(const CString& service, const CString& name, Error& err) +bool deletePassword(const UTF8CString& service, const UTF8CString& name, Error& err) { err = Error {}; @@ -249,7 +249,7 @@ bool deletePassword(const CString& service, const CString& name, Error& err) return false; } - String targetName = makeString(String::fromUTF8(service.data()), "/"_s, String::fromUTF8(name.data())); + String targetName = makeString(String::fromUTF8(service.span()), "/"_s, String::fromUTF8(name.span())); auto targetNameUtf8 = targetName.utf8(); auto targetNameWide = cstringToWideChar(targetNameUtf8); diff --git a/src/jsc/bindings/ZigGlobalObject.cpp b/src/jsc/bindings/ZigGlobalObject.cpp index 241d75d1ee06..889d9bc80089 100644 --- a/src/jsc/bindings/ZigGlobalObject.cpp +++ b/src/jsc/bindings/ZigGlobalObject.cpp @@ -1869,7 +1869,7 @@ JSC_DEFINE_HOST_FUNCTION(makeGetterTypeErrorForBuiltins, (JSGlobalObject * globa auto attributeName = callFrame->uncheckedArgument(1).getString(globalObject); RETURN_IF_EXCEPTION(scope, {}); - auto error = static_cast(createTypeError(globalObject, JSC::makeDOMAttributeGetterTypeErrorMessage(interfaceName.utf8().legacyCStringPointer(), attributeName))); + auto error = static_cast(createTypeError(globalObject, JSC::makeDOMAttributeGetterTypeErrorMessage(interfaceName, attributeName))); error->setNativeGetterTypeError(); return JSValue::encode(error); } @@ -3291,14 +3291,14 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) #undef VISIT_GLOBALOBJECT_GC_MEMBER // This runs on a concurrent GC helper thread. Fetch the VM through the - // visitor (AbstractSlotVisitor::vm() returns m_heap.vm(), guaranteed alive - // for the duration of marking) rather than thisObject->vm() which + // visitor (its collector's heap, guaranteed alive for the duration of + // marking) rather than thisObject->vm() which // dereferences JSGlobalObject::m_vm and can read stale bytes if the cell // was picked up via conservative scan mid-recycle (see the // visitGlobalObjectMember(unique_ptr) guard above for the same window). // A stale m_vm surfaces as a SEGV in TypeCastTraits::isType // when downcast<> calls the virtual isWebCoreJSClientData() on garbage. - WebCore::clientData(visitor.vm())->httpHeaderIdentifiers().template visit(visitor); + WebCore::clientData(visitor.collector().heap().vm())->httpHeaderIdentifiers().template visit(visitor); thisObject->visitGeneratedLazyClasses(thisObject, visitor); thisObject->visitAdditionalChildrenInGCThread(visitor); @@ -3519,13 +3519,13 @@ JSC::Identifier GlobalObject::moduleLoaderResolve(JSGlobalObject* jsGlobalObject auto moduleName = uncheckedDowncast(key)->value(globalObject); RETURN_IF_EXCEPTION(scope, {}); if (!globalObject->onLoadPlugins.hasVirtualModules() && !Bun__hasPlugins(globalObject)) { - CString narrowed; + Latin1CString narrowed; std::span chars; if (moduleName->is8Bit()) chars = moduleName->span8(); else if (moduleName->containsOnlyLatin1()) { narrowed = moduleName->latin1(); - chars = { std::bit_cast(narrowed.data()), narrowed.length() }; + chars = narrowed.span(); } if (chars.data()) { if (int index = ModuleLoader__builtinAliasIndex(chars.data(), chars.size()); index >= 0) diff --git a/src/jsc/bindings/node/crypto/CryptoGenEcKeyPair.cpp b/src/jsc/bindings/node/crypto/CryptoGenEcKeyPair.cpp index 6757a16c6b61..25da4d7cb256 100644 --- a/src/jsc/bindings/node/crypto/CryptoGenEcKeyPair.cpp +++ b/src/jsc/bindings/node/crypto/CryptoGenEcKeyPair.cpp @@ -115,9 +115,9 @@ std::optional EcKeyPairJobCtx::fromJS(JSGlobalObject* globalObj GCOwnedDataScope namedCurveView = namedCurveString->view(globalObject); RETURN_IF_EXCEPTION(scope, std::nullopt); - CString curveName = namedCurveView->utf8(); + UTF8CString curveName = namedCurveView->utf8(); - int curveNid = ncrypto::Ec::GetCurveIdFromName(curveName.data()); + int curveNid = ncrypto::Ec::GetCurveIdFromName(curveName.legacyCStringPointer()); if (curveNid == NID_undef) { ERR::CRYPTO_INVALID_CURVE(scope, globalObject); return std::nullopt; diff --git a/src/jsc/bindings/sqlite/JSSQLStatement.cpp b/src/jsc/bindings/sqlite/JSSQLStatement.cpp index 949228d753d6..95e8561b0660 100644 --- a/src/jsc/bindings/sqlite/JSSQLStatement.cpp +++ b/src/jsc/bindings/sqlite/JSSQLStatement.cpp @@ -1225,7 +1225,7 @@ JSC_DEFINE_HOST_FUNCTION(jsSQLStatementSetCustomSQLite, (JSC::JSGlobalObject * l #if LAZY_LOAD_SQLITE auto requestedPath = sqliteStrValue.toWTFString(lexicalGlobalObject); RETURN_IF_EXCEPTION(scope, {}); - static CString sqlite3_lib_path_storage; + static UTF8CString sqlite3_lib_path_storage; static String selectedSQLitePath; auto requestedPathUTF8 = requestedPath.utf8(); RETURN_IF_EXCEPTION(scope, {}); @@ -1239,7 +1239,7 @@ JSC_DEFINE_HOST_FUNCTION(jsSQLStatementSetCustomSQLite, (JSC::JSGlobalObject * l } else { // Keep the selected path alive for the process-global SQLite handle. sqlite3_lib_path_storage = requestedPathUTF8; - sqlite3_lib_path = sqlite3_lib_path_storage.data(); + sqlite3_lib_path = sqlite3_lib_path_storage.legacyCStringPointer(); WTF::String msg; if (lazyLoadSQLiteUnlocked(&msg) == -1) { throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, msg)); @@ -1974,7 +1974,7 @@ JSC_DEFINE_HOST_FUNCTION(jsSQLStatementFcntlFunction, (JSC::JSGlobalObject * lex return JSValue::encode(jsUndefined()); } - CString fileNameStr; + UTF8CString fileNameStr; if (databaseFileName.isString()) { fileNameStr = databaseFileName.toWTFString(lexicalGlobalObject).utf8(); @@ -2013,7 +2013,7 @@ JSC_DEFINE_HOST_FUNCTION(jsSQLStatementFcntlFunction, (JSC::JSGlobalObject * lex return {}; } - int statusCode = sqlite3_file_control(db, fileNameStr.isNull() ? nullptr : fileNameStr.data(), op, resultPtr); + int statusCode = sqlite3_file_control(db, fileNameStr.isNull() ? nullptr : fileNameStr.legacyCStringPointer(), op, resultPtr); if (statusCode == SQLITE_ERROR) { throwException(lexicalGlobalObject, scope, createSQLiteError(lexicalGlobalObject, db)); diff --git a/src/jsc/bindings/sqlite/NodeSqlite.cpp b/src/jsc/bindings/sqlite/NodeSqlite.cpp index 5cbf3864266f..abd241452b12 100644 --- a/src/jsc/bindings/sqlite/NodeSqlite.cpp +++ b/src/jsc/bindings/sqlite/NodeSqlite.cpp @@ -1436,7 +1436,7 @@ JSC_DEFINE_HOST_FUNCTION(jsDatabaseSyncLoadExtension, (JSGlobalObject * globalOb RETURN_IF_EXCEPTION(scope, {}); auto pathUtf8 = path.utf8(); - WTF::CString entryUtf8; + WTF::UTF8CString entryUtf8; const char* entryPtr = nullptr; JSValue entryVal = callFrame->argument(1); if (!entryVal.isUndefined()) { @@ -1446,7 +1446,7 @@ JSC_DEFINE_HOST_FUNCTION(jsDatabaseSyncLoadExtension, (JSGlobalObject * globalOb auto entry = entryVal.toWTFString(globalObject); RETURN_IF_EXCEPTION(scope, {}); entryUtf8 = entry.utf8(); - entryPtr = entryUtf8.data(); + entryPtr = entryUtf8.legacyCStringPointer(); } char* errmsg = nullptr; diff --git a/src/jsc/bindings/v8/V8CpuProfiler.cpp b/src/jsc/bindings/v8/V8CpuProfiler.cpp index c80db710ff13..828db20f85e8 100644 --- a/src/jsc/bindings/v8/V8CpuProfiler.cpp +++ b/src/jsc/bindings/v8/V8CpuProfiler.cpp @@ -69,8 +69,8 @@ static void buildProfileTree(JSC::VM& vm, CpuProfileImpl& profile, int64_t start auto makeRoot = [&]() -> CpuProfileNodeImpl* { auto root = makeUnique(); root->id = 1; - root->functionName = "(root)"; - root->scriptResourceName = ""; + root->functionName = "(root)"_s; + root->scriptResourceName = ""_s; CpuProfileNodeImpl* ptr = root.get(); profile.m_nodes.append(WTF::move(root)); profile.m_root = ptr; @@ -326,7 +326,7 @@ Local CpuProfileNode::GetFunctionName() const const char* CpuProfileNode::GetFunctionNameStr() const { - return toImpl(this)->functionName.data(); + return toImpl(this)->functionName.legacyCStringPointer(); } int CpuProfileNode::GetScriptId() const diff --git a/src/jsc/bindings/v8/shim/CpuProfiler.h b/src/jsc/bindings/v8/shim/CpuProfiler.h index 0a6c9b22f223..976478b10e2c 100644 --- a/src/jsc/bindings/v8/shim/CpuProfiler.h +++ b/src/jsc/bindings/v8/shim/CpuProfiler.h @@ -26,8 +26,8 @@ struct CpuProfileNodeImpl { unsigned id { 0 }; // UTF-8 copies kept for the profile's lifetime so GetFunctionNameStr()/ // GetScriptResourceNameStr() can return stable `const char*`. - WTF::CString functionName; - WTF::CString scriptResourceName; + WTF::UTF8CString functionName; + WTF::UTF8CString scriptResourceName; int scriptId { 0 }; // 1-based; 0 == kNoLineNumberInfo / kNoColumnNumberInfo. int lineNumber { 0 }; diff --git a/src/jsc/bindings/webcore/SerializedScriptValue.cpp b/src/jsc/bindings/webcore/SerializedScriptValue.cpp index 6ec3e5f55dfd..cea213dc9ef8 100644 --- a/src/jsc/bindings/webcore/SerializedScriptValue.cpp +++ b/src/jsc/bindings/webcore/SerializedScriptValue.cpp @@ -1185,7 +1185,7 @@ class CloneSerializer : public CloneBase { return true; write(RegExpTag); write(regExp->regExp()->pattern()); - write(String::fromLatin1(JSC::Yarr::flagsString(regExp->regExp()->flags()).data())); + write(String(JSC::Yarr::flagsString(regExp->regExp()->flags()).span())); return true; } if (auto* errorInstance = dynamicDowncast(obj)) { diff --git a/src/jsc/bindings/webcore/streams/JSCompressionStreamShared.cpp b/src/jsc/bindings/webcore/streams/JSCompressionStreamShared.cpp index 9f8b6c039217..7ae78090a752 100644 --- a/src/jsc/bindings/webcore/streams/JSCompressionStreamShared.cpp +++ b/src/jsc/bindings/webcore/streams/JSCompressionStreamShared.cpp @@ -111,7 +111,7 @@ CodecOptions parseCodecOptions(JSGlobalObject* globalObject, JSValue strategy, s // BufferSource → (ptr, len). `scratch` owns the bytes when `chunk` is a string // (Node-compat: node:zlib-backed CompressionStream accepts string chunks). -static std::optional> bufferSourceBytes(JSGlobalObject* globalObject, JSValue chunk, WTF::CString& scratch) +static std::optional> bufferSourceBytes(JSGlobalObject* globalObject, JSValue chunk, WTF::UTF8CString& scratch) { auto& vm = getVM(globalObject); auto scope = DECLARE_THROW_SCOPE(vm); @@ -378,7 +378,7 @@ static JSPromise* compressionStreamTransformImpl(JSGlobalObject* globalObject, J { return promiseFromSteps(globalObject, [&] -> JSPromise* { auto scope = DECLARE_THROW_SCOPE(getVM(globalObject)); - WTF::CString scratch; + WTF::UTF8CString scratch; std::optional> bytes = bufferSourceBytes(globalObject, chunk, scratch); RETURN_IF_EXCEPTION(scope, nullptr); if (!bytes) [[unlikely]] diff --git a/src/jsc/modules/BunJSCModule.h b/src/jsc/modules/BunJSCModule.h index 4ef53d4f62a0..f94f4bafe4fe 100644 --- a/src/jsc/modules/BunJSCModule.h +++ b/src/jsc/modules/BunJSCModule.h @@ -122,7 +122,7 @@ JSC_DEFINE_HOST_FUNCTION(functionStartRemoteDebugger, globalObject->setInspectable(true); auto& server = Inspector::RemoteInspectorServer::singleton(); - if (!server.start(reinterpret_cast(host), port)) { + if (!server.start(WTF::UTF8CStringView::unsafeFromUTF8(host), port)) { throwVMError( globalObject, scope, createError(globalObject, diff --git a/src/runtime/webview/ChromeBackend.cpp b/src/runtime/webview/ChromeBackend.cpp index adea04d47792..8744953d8ad7 100644 --- a/src/runtime/webview/ChromeBackend.cpp +++ b/src/runtime/webview/ChromeBackend.cpp @@ -290,19 +290,19 @@ bool Transport::ensureSpawned(Zig::GlobalObject* zig, const WTF::String& userDat // Empty string ≠ null. WTF::String() utf8's to an empty CString (not // isNull), which the spawner passes as "" into --user-data-dir= and // Chrome falls back to the default profile → ProcessSingleton abort. - WTF::CString dir = userDataDir.utf8(); - WTF::CString pathC = path.utf8(); + WTF::UTF8CString dir = userDataDir.utf8(); + WTF::UTF8CString pathC = path.utf8(); // Two-level pack: CString owns the bytes, ptrVec holds data() pointers. // Both live until Bun__Chrome__ensure returns (spawn copies argv). - WTF::Vector argvC; + WTF::Vector argvC; WTF::Vector argvPtrs; for (auto& s : extraArgv) { argvC.append(s.utf8()); - argvPtrs.append(argvC.last().data()); + argvPtrs.append(argvC.last().legacyCStringPointer()); } int32_t rc = Bun__Chrome__ensure(zig, - dir.length() ? dir.data() : nullptr, - pathC.length() ? pathC.data() : nullptr, + dir.length() ? dir.legacyCStringPointer() : nullptr, + pathC.length() ? pathC.legacyCStringPointer() : nullptr, argvPtrs.isEmpty() ? nullptr : argvPtrs.span().data(), static_cast(argvPtrs.size()), stdoutInherit, stderrInherit); @@ -713,7 +713,7 @@ static void rejectViewSlotsAsHandled(JSGlobalObject* g, JSWebView* view, JSValue static JSValue errorFromExceptionDetails(JSGlobalObject* g, std::span excDetails) { auto root = JSON::Value::parseJSON( - StringView::fromLatin1(std::span( + StringView(std::span( reinterpret_cast(excDetails.data()), excDetails.size()))); auto d = root ? root->asObject() : nullptr; if (!d) return createError(g, "JavaScript exception"_s); @@ -863,7 +863,7 @@ void Transport::handleResponse(uint32_t id, std::span result, std::s // navigateToHistoryEntry. WTF::JSON parses to a C++ tree — no // JSValue allocation for a structure we only read once. auto root = JSON::Value::parseJSON( - StringView::fromLatin1(std::span( + StringView(std::span( reinterpret_cast(result.data()), result.size()))); auto o = root ? root->asObject() : nullptr; if (!o) { diff --git a/src/runtime/webview/ObjCRuntime.h b/src/runtime/webview/ObjCRuntime.h index 1db74575b76a..87a15bd356dc 100644 --- a/src/runtime/webview/ObjCRuntime.h +++ b/src/runtime/webview/ObjCRuntime.h @@ -83,8 +83,8 @@ struct NSString : Ref { // Returns autoreleased; callers pass to ObjC methods that retain. static NSString fromWTF(const WTF::String &s) { - WTF::CString utf8 = s.utf8(); - return msgCls(cls, s_stringWithUTF8String, utf8.data()); + WTF::UTF8CString utf8 = s.utf8(); + return msgCls(cls, s_stringWithUTF8String, utf8.legacyCStringPointer()); } WTF::String toWTF() const { diff --git a/test/bundler/bundler_bytecode_portable.test.ts b/test/bundler/bundler_bytecode_portable.test.ts index 7c8f07040d02..9e6fd7510cc8 100644 --- a/test/bundler/bundler_bytecode_portable.test.ts +++ b/test/bundler/bundler_bytecode_portable.test.ts @@ -440,8 +440,8 @@ describe("bytecode cache portability", () => { ).toMatchInlineSnapshot(` { "builtin corpus": { - "bytes": 5112, - "sha256": "fd6efe1732b59e723212534fea7c1bdbbbcb894a35eb5ed90184af0e6c63f81a", + "bytes": 5120, + "sha256": "c6c9a9cb623d2ba1bd6389d6aee7d860077bbd840a8083961e7e03b41f768448", }, "builtin corpus strings": { "bytes": 1044, @@ -450,150 +450,150 @@ describe("bytecode cache portability", () => { "bun build --bytecode --minify all.js": { "js": "50b3e5192dd86a205c73583d585884c1b414467b14db54d03c77d3026bf236ff", "jsc": { - "bytes": 1730832, - "sha256": "5e132599b3db8e752f8fa5aca7145b52b2710e4ea29c292814bd9401d93803f1", + "bytes": 1730896, + "sha256": "d0fdc8d6b0c5433d168d633c53398e5bda3a491f1661912fd7527a569a88384d", }, }, "bun build --bytecode --minify features.js": { "js": "d30a5febed53e316cc2dd2b076502079e809bb0c201ef1671e9a190ecdcf093d", "jsc": { - "bytes": 41608, - "sha256": "94b6a35f31767ad86d484d265bde375a375701986d788ef2c89a75a75760f391", + "bytes": 41624, + "sha256": "7635c882a17363a996de2a04ab0e3f01fe1f25b1567c722f9acfccb2a14e5f58", }, }, "bun build --bytecode --minify records.js": { "js": "889cbb2c9525ff69a2676a6e81d97bb87760bdee65178b836c9c1d6808ac7c6e", "jsc": { - "bytes": 79904, - "sha256": "11b548c73adb35f713d833d7aba725a8aabf685c071b64de02326858ee84a4e9", + "bytes": 79944, + "sha256": "445cdf340504fe89e37ae4e31c15d1520372a965bac969394bfc19bf766b8be0", }, }, "bun build --bytecode acorn/dist/acorn.mjs": { "js": "aa22cb20382fa5d66ff2ddd90817c0899f82b346bdd1da87dc9e193d203a0ce9", "jsc": { "bytes": 236680, - "sha256": "12d58bda2efd0613cffd6fc44112f41e876d7ef3f5610ea9268ddf4b9f5dce0d", + "sha256": "53f1fe77c52e658ed56140e6aa2179a3f9094e5460a3e893a8ca021f069f8ac8", }, }, "bun build --bytecode all.js": { "js": "ce4cf9db35e0aa3257f982fb756363a5686fb52a3b7cc63ac0c66bdcaf13a849", "jsc": { - "bytes": 1875144, - "sha256": "6b31c552469cd37410775759f28e8d11f33bde48c0cc24066408776340ba2c3f", + "bytes": 1875200, + "sha256": "607d1cf75a299900a465c6d1e73128259112984da6f59f6dbcfefb48a4005b32", }, }, "bun build --bytecode big.js": { "js": "df5367354d3dbd2b81114585fb2a21d058910c869ece4404ef015c0efaf5c689", "jsc": { "bytes": 146384, - "sha256": "eb6ca586f10b2f0095e9f9c16aad64276a2ed549c39ac56b33d3972bb33512bb", + "sha256": "eb12bac00ddccf705f8b5e31953c730712499ab325e74bec29aff4c53058a5a9", }, }, "bun build --bytecode features.js": { "js": "2ee211924620db96d6e99e9490bfe0ee60a3bc6b003f37940c5631e6eabc2c73", "jsc": { - "bytes": 43376, - "sha256": "4bc95dedb6e669b970c1f24a366fa68cfd8693e82aa03b185242262ffea90819", + "bytes": 43392, + "sha256": "9aeaaf8a34d216f515082895549b05ed2fbe8c5139deadcfa8747a6a5ae6aaf2", }, }, "bun build --bytecode happy-dom/lib/index.js": { "js": "1415a67d0da987f3bb7fc68ca431e222b3898fa14be8af88e2845813c4120f43", "jsc": { - "bytes": 2217136, - "sha256": "8a7491fa66bc608ec7e5010cd21140effd23ce1f8b221dc2193491312631b403", + "bytes": 2218280, + "sha256": "a955535bb5547c3d6107b8cd85de98e12acc256222aceb0c9bc86afc89af1297", }, }, "bun build --bytecode immutable/dist/immutable.es.js": { "js": "d011b6c5105dad96f17aaf541c848b8d2be1b2e65a1de050112380352979bb6b", "jsc": { - "bytes": 239392, - "sha256": "b51ef5944ab01c34d4924fbb193681ad03bf13c186e692224abb02f4d4a667bb", + "bytes": 239400, + "sha256": "280d1800c117eb89b217d050b63d55d8831db4dc7a2f74bf8b6fe0235e5bcc9d", }, }, "bun build --bytecode libraries.js": { "js": "493bab674ff49b287f26be3f356a3ad6681afb0c7eeffaa590f10cdcd8b58724", "jsc": { - "bytes": 21206912, - "sha256": "49e423d3252b0e1ed7e9529d6475026ccb9fb8af73e746cad15d8420e07fae54", + "bytes": 21212376, + "sha256": "deccfd76d81939ab870a750637e77f0f7255df628e2d4c16dbe214df42025535", }, }, "bun build --bytecode lodash/lodash.js": { "js": "9951d06da1bf94c69dece1b23f304c1cbf4018b894e398ac5ea10f35b5600187", "jsc": { "bytes": 303616, - "sha256": "938db7ba736422ed3fb13ea36fed36866d215f7e8c52ac9a98f784f7bfa22dd4", + "sha256": "4b10e11aecfe92ad601a526855548658c0bb0a1a7af9668140d3d8c4e49375fd", }, }, "bun build --bytecode react-dom/cjs/react-dom.development.js": { "js": "3392a38ccef2f1bb7b1c8c8cbfc8111b45f6cf6f8dec3c72a99f13a6568fd5a1", "jsc": { "bytes": 829944, - "sha256": "5c43775f2fef779fe9182c922085a508c8e14b9c3b1672d68f4ac6ae3ca0d7e6", + "sha256": "2ef931c269adbcb55ddcb3a548c5bb2e036ccc1b3b5103fad90a04ad2ef45ff7", }, }, "bun build --bytecode records.js": { "js": "c87ea35df4ad6b2063402c9901ef4775a82f12594f280db76f50695f4b0eba13", "jsc": { - "bytes": 82624, - "sha256": "dcfe5ef1387fc91c86773631207d64f3fabfb3849ccbda647c34af5e0e4705a0", + "bytes": 82664, + "sha256": "34573c43813caa443cc5b3aef814f65769c2c291d355a5b58ad7a8241eb50962", }, }, "bun build --bytecode shapes.js": { "js": "dfcf0136de2c98f6a29d2c41477637879ccae98385a1bf30c666b85002bcae07", "jsc": { "bytes": 214224, - "sha256": "e988b04f67438a2874f44b146d563f3dc85153c1a467aadf9039079cae643a59", + "sha256": "5b3cb32b71313ab5d36baa8eef461b52be2e1c792b76a0dd552387678d02df82", }, }, "bun build --bytecode svelte/compiler/index.js": { "js": "17e7431a6f28a4b6b5d356fc815b0876ebd9613ae6c25a98dc4c5560004341ce", "jsc": { - "bytes": 1819256, - "sha256": "105f71afea22ac553d395a85ae19a94e3046a7309f4e6af074960bdde31b2e51", + "bytes": 1820320, + "sha256": "90f10bf35bb735f362240835c4fd9d281462497127d835c0ab5dc3ead5b5fa9f", }, }, "bun build --bytecode undici/index.js": { "js": "e1c4f1494711ecaae57a6d63dfb8ac6096629582f55cc42530ff5a156b70c9de", "jsc": { - "bytes": 852320, - "sha256": "d5e2784842420c5b561d4cab1089e726b71a121fdc135bcf7ce9a1c45a5eae53", + "bytes": 852600, + "sha256": "5ee6a96a6645573a6567c190cc8f68106c9c3fed4ad7970a766974816a28fb7c", }, }, "vm.Script big.js": { "bytes": 169496, - "sha256": "168ca743d84155d6835f42959bd8aa877e117386d06b17d69728db46a5f3d507", + "sha256": "65b311a2fab26d51db7b7ffd3e399b225ad5e74b0f622439b6d53f4cd6dc689f", }, "vm.Script features.js": { - "bytes": 45224, - "sha256": "e4e85c56f73874171a5cc3d2e34744edd65e2000be2adf028ee633228ff3df4c", + "bytes": 45240, + "sha256": "554cf423e60ad55981b5025dec7c23440f3c0fe87d9d5100ca01c4860709eb3e", }, "vm.Script lodash.js": { "bytes": 342992, - "sha256": "247576a30d4fb1f5d4d11026dfe402fddeaa19c742a97a88d653e58709797e34", + "sha256": "5066d916e3a303739b503d5ad1a0a92d379f09fd306deb75002ad9b5ff36ef98", }, "vm.Script records.js": { - "bytes": 86632, - "sha256": "5498f71aaecf017cdf7dae6f00dd3895e41efb8b598f0fce9358a2759715d85a", + "bytes": 86656, + "sha256": "3d63c310491ae836741c03d881b840f5e55e3a9d74cb35c832080f6f056964f6", }, "vm.Script shapes.js": { "bytes": 257488, - "sha256": "2ee4c40927e20b58bc88fb86cceb02e20a83e79919f83d0262ab9c14d26eb225", + "sha256": "200a618a258aaa621e17950c479afdac20d1a6e49416c77744282ad751f16034", }, "vm.Script source-forms.js": { "bytes": 4712, - "sha256": "0d7dff7ebf9297fb7a62885866a481f848922a28ef7ecf52cf14ebe711ec8a8f", + "sha256": "0369108eea0729ee4075e5e2e9d371835c63af9f10262ba27d3b4f18429ea5b8", }, "vm.Script typescript.js": { - "bytes": 11321768, - "sha256": "5a98fdadb0c24521c95ecafa775905fde382e919e036bb42035fec3f06e1263b", + "bytes": 11326400, + "sha256": "7cbdd3a281991f76b431a0aa11824870941ff09983bed76efa59cb9722790190", }, "vm.SourceTextModule acorn.mjs": { "bytes": 255472, - "sha256": "a119209080e08df932391a57f430b7a21600ff715a1b0a62e80c5fafe2fdee11", + "sha256": "1d42c1c696bc08ca000343ebb1a387ccb0b6119b504a4946f75781d1f40110f7", }, "vm.SourceTextModule module.js": { - "bytes": 9096, - "sha256": "06001f422d67089789a1ad5be52d9c1c85ac3afe5dcc5cb460f4d64183a4d84b", + "bytes": 9104, + "sha256": "67c94acc5a5d3ba8d9067948080070fefc95611297d3e8033b292291d992c0ea", }, } `); diff --git a/test/js/bun/jsc/webkit-upgrade-dbdca7545d.test.ts b/test/js/bun/jsc/webkit-upgrade-dbdca7545d.test.ts new file mode 100644 index 000000000000..b38a11c94d35 --- /dev/null +++ b/test/js/bun/jsc/webkit-upgrade-dbdca7545d.test.ts @@ -0,0 +1,134 @@ +import { describe, expect, test } from "bun:test"; + +// Coverage for the WebKit dbdca7545d sync. Each case pins an observable difference between +// the old and the new JavaScriptCore. The sources that depend on how JavaScriptCore parses +// are compiled with `new Function` or an indirect eval, so that Bun's transpiler leaves them alone. + +describe.concurrent("WebKit dbdca7545d upgrade", () => { + test("the call in `(a?.b)(x)` is outside the optional chain (63b7d629dd1)", () => { + const log: string[] = []; + const call = new Function("a", "arg", "return (a?.b)(arg());"); + expect(() => call(undefined, () => log.push("arg"))).toThrow(TypeError); + // The arguments are evaluated before the call throws: the chain ended at the closing parenthesis. + expect(log).toEqual(["arg"]); + // Without the parentheses the call is still part of the chain. + expect(new Function("a", "arg", "return a?.b(arg());")(undefined, () => log.push("arg"))).toBeUndefined(); + expect(log).toEqual(["arg"]); + }); + + test("a parenthesized optional chain used as a template tag keeps its `this` (7fbe85cfbfd)", () => { + const receiver = { + tag() { + "use strict"; + return this; + }, + }; + expect(new Function("o", "return (o?.tag)`x`;")(receiver)).toBe(receiver); + expect(new Function("o", "return (o?.['tag'])`x`;")(receiver)).toBe(receiver); + }); + + test("`super.tag` used as a template tag is called with the current `this` (24e354459de)", () => { + class Base { + tag() { + return this; + } + } + const Derived = new Function("Base", "return class extends Base { run() { return super.tag`x`; } };")(Base); + const instance = new Derived(); + expect(instance.run()).toBe(instance); + }); + + test("a catch parameter named `await` is a SyntaxError where `await` is not an identifier (edb17fbf37d)", () => { + expect(() => (0, eval)("(async function () { try {} catch (await) {} })")).toThrow(SyntaxError); + expect(() => (0, eval)("(async function () { try {} catch (aw\\u0061it) {} })")).toThrow(SyntaxError); + // In a plain function `await` is an ordinary identifier. + expect(new Function("try { throw 1; } catch (await) { return await; }")()).toBe(1); + }); + + // TODO: any SyntaxError from the Function constructor aborts a build that validates exception checks + // (BUN_JSC_validateExceptionChecks=1, which the ASAN lane sets), `new Function("(")` included: + // + // ERROR: Unchecked JS exception: + // This scope can throw a JS exception: computeErrorInfoToJSValueWithoutSkipping @ src/jsc/bindings/FormatStackTraceForJS.cpp + // But the exception was unchecked as of this scope: constructFunctionSkippingEvalEnabledCheck @ Source/JavaScriptCore/runtime/FunctionConstructor.cpp + // ASSERTION FAILED: exception check validation failed + // + // JavaScriptCore's addErrorInfo() runs the stack formatting hook while the parser's error object is made, and the + // Function constructor then throws that error with no exception check in between. eval and vm.Script check, which is + // why the test above uses an indirect eval. The assertions below hold on a build without the validation. + test.todo("the Function constructor throws that SyntaxError too", () => { + expect(() => new Function("return async function () { try {} catch (await) {} };")).toThrow(SyntaxError); + expect(() => new Function("return async function () { try {} catch (aw\\u0061it) {} };")).toThrow(SyntaxError); + }); + + test("`await` is an identifier in a non-async function nested in an async function's parameters (09c4cfc7d73)", async () => { + const f = new Function( + "return async function (a = function () { var await = 42; return await; }) { return a(); };", + )(); + expect(await f()).toBe(42); + }); + + test("new Array(length) reads newTarget.prototype before it throws for an invalid length (e4e335cf8df)", () => { + const newTarget = new Proxy(function () {}, { + get() { + throw new EvalError("prototype read"); + }, + }); + for (const length of [-1, 1.5, 2 ** 32, Infinity]) { + expect(() => Reflect.construct(Array, [length], newTarget)).toThrow(EvalError); + } + expect(() => new Array(-1)).toThrow(RangeError); + }); + + test("Intl.DurationFormat keeps the minus sign of a fraction between -1 and 0 (501d1f661f9)", () => { + const format = (options: Intl.DurationFormatOptions, duration: Intl.DurationInput) => + new Intl.DurationFormat("en", options).format(duration); + expect(format({ seconds: "numeric" }, { milliseconds: -500 })).toBe("-0.5"); + expect(format({ seconds: "2-digit" }, { milliseconds: -500 })).toBe("-00.5"); + expect(format({ seconds: "numeric" }, { nanoseconds: -1 })).toBe("-0.000000001"); + }); + + test("Intl.Segmenter containing() finds the segment of a low surrogate (3e27303e85c)", () => { + const input = "a\u{1F600}b"; + const segments = new Intl.Segmenter("en", { granularity: "grapheme" }).segment(input); + const iterated = [...segments]; + for (let index = 0; index < input.length; index++) { + const expected = iterated.find(s => index >= s.index && index < s.index + s.segment.length)!; + const hit = segments.containing(index)!; + expect({ segment: hit.segment, index: hit.index }).toEqual({ segment: expected.segment, index: expected.index }); + } + }); + + test("for-of and destructuring over Arrays and Strings close the iteration when asked to (35637c64339, 5330149c555)", () => { + // Neither loop allocates an iterator object any more. One has to appear when `return` does. + const calls: string[] = []; + const arrayIteratorPrototype = Object.getPrototypeOf([][Symbol.iterator]()); + const stringIteratorPrototype = Object.getPrototypeOf(""[Symbol.iterator]()); + function firstOf(iterable: Iterable) { + for (const value of iterable) return value; + } + try { + for (let i = 0; i < 100; i++) { + expect(firstOf([i, 2, 3])).toBe(i); + expect(firstOf("\u{1F600}bc")).toBe("\u{1F600}"); + } + arrayIteratorPrototype.return = function () { + calls.push("array"); + return {}; + }; + stringIteratorPrototype.return = function () { + calls.push("string"); + return {}; + }; + expect(firstOf([1, 2, 3])).toBe(1); + expect(firstOf("abc")).toBe("a"); + const [first] = [7, 8]; + const [head] = "xyz"; + expect([first, head]).toEqual([7, "x"]); + expect(calls).toEqual(["array", "string", "array", "string"]); + } finally { + delete arrayIteratorPrototype.return; + delete stringIteratorPrototype.return; + } + }); +}); diff --git a/test/leaksan.supp b/test/leaksan.supp index 098d6d600881..42535f742fb2 100644 --- a/test/leaksan.supp +++ b/test/leaksan.supp @@ -118,11 +118,11 @@ leak:WebCore::JSReadableStreamDefaultControllerPrototype::finishCreation leak:jsc.Debugger.startJSDebuggerThread # test/js/sql/sqlite-sql.test.ts leak:WebCore::jsSQLStatementOpenStatementFunction -# test/js/web/atomics.test.ts — RunLoop::dispatchAfter's DispatchTimer captures +# test/js/web/atomics.test.ts — RunLoop::scheduleTimer's DispatchTimer captures # a Ref to itself in m_function; the cycle only breaks when fired(). If stop() # is called before firing (WaiterListManager::clearTimer on notify/unregister), # the DispatchTimer and its Bun-side WTFTimer Box leak. JSC-owned ref-cycle. -leak:WTF::RunLoop::dispatchAfter +leak:WTF::RunLoop::scheduleTimer # test/cli/run/workspaces.test.ts, test/regression/issue/26207.test.ts — # run_scripts_with_filter ends with Global::exit() so pre_script_name / # post_script_name / script_name_owned locals never Drop (intentional per the