From 7b134693d65464be28fbbda73a29c640d7dcce94 Mon Sep 17 00:00:00 2001 From: 190n Date: Mon, 28 Apr 2025 15:54:31 -0700 Subject: [PATCH] Revert "Remove most static initializers (#19298)" (#19353) --- cmake/targets/BuildBun.cmake | 4 - src/bake/BakeGlobalObject.cpp | 64 ++++----- src/bake/BakeGlobalObject.h | 2 +- src/bun.js/bindings/JSBuffer.cpp | 57 ++++---- src/bun.js/bindings/ZigGlobalObject.cpp | 113 +++++++-------- src/bun.js/bindings/ZigGlobalObject.h | 9 +- src/bun.js/bindings/ncrypto.cpp | 138 ++++--------------- src/bun.js/bindings/ncrypto.h | 36 ++--- src/bun.js/bindings/v8/V8HandleScope.h | 4 +- src/bun.js/bindings/v8/shim/Handle.h | 8 +- src/bun.js/bindings/v8/shim/Map.cpp | 32 +---- src/bun.js/bindings/v8/shim/Map.h | 25 +--- src/bun.js/bindings/v8/shim/Oddball.h | 2 +- test/js/bun/perf/static-initializers.test.ts | 58 -------- 14 files changed, 183 insertions(+), 369 deletions(-) delete mode 100644 test/js/bun/perf/static-initializers.test.ts diff --git a/cmake/targets/BuildBun.cmake b/cmake/targets/BuildBun.cmake index 62a582b79c..15bc0d0df6 100644 --- a/cmake/targets/BuildBun.cmake +++ b/cmake/targets/BuildBun.cmake @@ -1014,10 +1014,6 @@ if(LINUX) -Wl,--compress-debug-sections=zlib -Wl,-z,lazy -Wl,-z,norelro - # enable string tail merging - -Wl,-O2 - # make debug info faster to load - -Wl,--gdb-index -Wl,-z,combreloc -Wl,--no-eh-frame-hdr -Wl,--sort-section=name diff --git a/src/bake/BakeGlobalObject.cpp b/src/bake/BakeGlobalObject.cpp index b482b0214b..abcaf83f6e 100644 --- a/src/bake/BakeGlobalObject.cpp +++ b/src/bake/BakeGlobalObject.cpp @@ -128,6 +128,34 @@ JSC::JSInternalPromise* bakeModuleLoaderFetch(JSC::JSGlobalObject* globalObject, return Zig::GlobalObject::moduleLoaderFetch(globalObject, loader, key, parameters, script); } +#define INHERIT_HOOK_METHOD(name) \ + Zig::GlobalObject::s_globalObjectMethodTable.name + +const JSC::GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { + INHERIT_HOOK_METHOD(supportsRichSourceInfo), + INHERIT_HOOK_METHOD(shouldInterruptScript), + INHERIT_HOOK_METHOD(javaScriptRuntimeFlags), + INHERIT_HOOK_METHOD(queueMicrotaskToEventLoop), + INHERIT_HOOK_METHOD(shouldInterruptScriptBeforeTimeout), + bakeModuleLoaderImportModule, + bakeModuleLoaderResolve, + bakeModuleLoaderFetch, + INHERIT_HOOK_METHOD(moduleLoaderCreateImportMetaProperties), + INHERIT_HOOK_METHOD(moduleLoaderEvaluate), + INHERIT_HOOK_METHOD(promiseRejectionTracker), + INHERIT_HOOK_METHOD(reportUncaughtExceptionAtEventLoop), + INHERIT_HOOK_METHOD(currentScriptExecutionOwner), + INHERIT_HOOK_METHOD(scriptExecutionStatus), + INHERIT_HOOK_METHOD(reportViolationForUnsafeEval), + INHERIT_HOOK_METHOD(defaultLanguage), + INHERIT_HOOK_METHOD(compileStreaming), + INHERIT_HOOK_METHOD(instantiateStreaming), + INHERIT_HOOK_METHOD(deriveShadowRealmGlobalObject), + INHERIT_HOOK_METHOD(codeForEval), + INHERIT_HOOK_METHOD(canCompileStrings), + INHERIT_HOOK_METHOD(trustedScriptStructure), +}; + GlobalObject* GlobalObject::create(JSC::VM& vm, JSC::Structure* structure, const JSC::GlobalObjectMethodTable* methodTable) { @@ -153,40 +181,6 @@ JSC::Structure* GlobalObject::createStructure(JSC::VM& vm) struct BunVirtualMachine; extern "C" BunVirtualMachine* Bun__getVM(); -const JSC::GlobalObjectMethodTable& GlobalObject::globalObjectMethodTable() -{ - const auto& parent = Zig::GlobalObject::globalObjectMethodTable(); -#define INHERIT_HOOK_METHOD(name) \ - parent.name - - static const JSC::GlobalObjectMethodTable table = { - INHERIT_HOOK_METHOD(supportsRichSourceInfo), - INHERIT_HOOK_METHOD(shouldInterruptScript), - INHERIT_HOOK_METHOD(javaScriptRuntimeFlags), - INHERIT_HOOK_METHOD(queueMicrotaskToEventLoop), - INHERIT_HOOK_METHOD(shouldInterruptScriptBeforeTimeout), - bakeModuleLoaderImportModule, - bakeModuleLoaderResolve, - bakeModuleLoaderFetch, - INHERIT_HOOK_METHOD(moduleLoaderCreateImportMetaProperties), - INHERIT_HOOK_METHOD(moduleLoaderEvaluate), - INHERIT_HOOK_METHOD(promiseRejectionTracker), - INHERIT_HOOK_METHOD(reportUncaughtExceptionAtEventLoop), - INHERIT_HOOK_METHOD(currentScriptExecutionOwner), - INHERIT_HOOK_METHOD(scriptExecutionStatus), - INHERIT_HOOK_METHOD(reportViolationForUnsafeEval), - INHERIT_HOOK_METHOD(defaultLanguage), - INHERIT_HOOK_METHOD(compileStreaming), - INHERIT_HOOK_METHOD(instantiateStreaming), - INHERIT_HOOK_METHOD(deriveShadowRealmGlobalObject), - INHERIT_HOOK_METHOD(codeForEval), - INHERIT_HOOK_METHOD(canCompileStrings), - INHERIT_HOOK_METHOD(trustedScriptStructure), - }; -#undef INHERIT_HOOK_METHOD - return table; -} - // A lot of this function is taken from 'Zig__GlobalObject__create' // TODO: remove this entire method extern "C" GlobalObject* BakeCreateProdGlobal(void* console) @@ -199,7 +193,7 @@ extern "C" GlobalObject* BakeCreateProdGlobal(void* console) JSC::Structure* structure = Bake::GlobalObject::createStructure(vm); Bake::GlobalObject* global = Bake::GlobalObject::create( - vm, structure, &Bake::GlobalObject::globalObjectMethodTable()); + vm, structure, &Bake::GlobalObject::s_globalObjectMethodTable); if (!global) BUN_PANIC("Failed to create BakeGlobalObject"); diff --git a/src/bake/BakeGlobalObject.h b/src/bake/BakeGlobalObject.h index a308fe64c6..a4dcf04a0a 100644 --- a/src/bake/BakeGlobalObject.h +++ b/src/bake/BakeGlobalObject.h @@ -26,7 +26,7 @@ public: [](auto& server) -> JSC::HeapCellType& { return server.m_heapCellTypeForBakeGlobalObject; }); } - static const JSC::GlobalObjectMethodTable& globalObjectMethodTable(); + static const JSC::GlobalObjectMethodTable s_globalObjectMethodTable; static GlobalObject* create(JSC::VM& vm, JSC::Structure* structure, const JSC::GlobalObjectMethodTable* methodTable); static JSC::Structure* createStructure(JSC::VM& vm); diff --git a/src/bun.js/bindings/JSBuffer.cpp b/src/bun.js/bindings/JSBuffer.cpp index 2e6479a4f7..56d7cc035f 100644 --- a/src/bun.js/bindings/JSBuffer.cpp +++ b/src/bun.js/bindings/JSBuffer.cpp @@ -89,33 +89,36 @@ using namespace WebCore; JSC_DECLARE_HOST_FUNCTION(constructJSBuffer); JSC_DECLARE_HOST_FUNCTION(callJSBuffer); -JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_alloc); -JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_allocUnsafe); -JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_allocUnsafeSlow); -JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_byteLength); -JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_compare); -JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_concat); -JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_copyBytesFrom); -JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_isBuffer); -JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_isEncoding); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_alloc); +static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_allocUnsafe); +static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_allocUnsafeSlow); +static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_byteLength); +static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_compare); +static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_concat); +static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_copyBytesFrom); +static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_isBuffer); +static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_isEncoding); -JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_compare); -JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_copy); -JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_equals); -JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_fill); -JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_includes); -JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_indexOf); -JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_inspect); -JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_lastIndexOf); -JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_swap16); -JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_swap32); -JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_swap64); -JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_toString); -JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_write); -JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_writeBigInt64LE); -JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_writeBigInt64BE); -JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_writeBigUInt64LE); -JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_writeBigUInt64BE); +static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_compare); +static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_copy); +static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_equals); +static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_fill); +static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_includes); +static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_indexOf); +static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_inspect); +static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_lastIndexOf); +static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_swap16); +static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_swap32); +static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_swap64); +static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_toString); +static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_write); +static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_writeBigInt64LE); +static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_writeBigInt64BE); +static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_writeBigUInt64LE); +static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_writeBigUInt64BE); +#pragma clang diagnostic pop extern "C" EncodedJSValue WebCore_BufferEncodingType_toJS(JSC::JSGlobalObject* lexicalGlobalObject, WebCore::BufferEncodingType encoding) { @@ -2263,7 +2266,7 @@ class JSBuffer : public JSC::JSNonFinalObject { const ClassInfo JSBuffer::s_info = { "Buffer"_s, - &JSC::JSUint8Array::s_info, + JSC::getUint8ArrayClassInfo(), nullptr, nullptr, CREATE_METHOD_TABLE(JSBuffer) diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 2b8452d33a..5d305fae6f 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -847,14 +847,14 @@ static void cleanupAsyncHooksData(JSC::VM& vm) GlobalObject* GlobalObject::create(JSC::VM& vm, JSC::Structure* structure) { - GlobalObject* ptr = new (NotNull, JSC::allocateCell(vm)) GlobalObject(vm, structure, &globalObjectMethodTable()); + GlobalObject* ptr = new (NotNull, JSC::allocateCell(vm)) GlobalObject(vm, structure, &s_globalObjectMethodTable); ptr->finishCreation(vm); return ptr; } GlobalObject* GlobalObject::create(JSC::VM& vm, JSC::Structure* structure, uint32_t scriptExecutionContextId) { - GlobalObject* ptr = new (NotNull, JSC::allocateCell(vm)) GlobalObject(vm, structure, scriptExecutionContextId, &globalObjectMethodTable()); + GlobalObject* ptr = new (NotNull, JSC::allocateCell(vm)) GlobalObject(vm, structure, scriptExecutionContextId, &s_globalObjectMethodTable); ptr->finishCreation(vm); return ptr; } @@ -954,7 +954,7 @@ extern "C" JSC::JSGlobalObject* Zig__GlobalObject__create(void* console_client, return Zig::EvalGlobalObject::create( vm, structure, - &Zig::EvalGlobalObject::globalObjectMethodTable()); + &Zig::EvalGlobalObject::s_globalObjectMethodTable); } else { auto* structure = Zig::GlobalObject::createStructure(vm); @@ -1189,64 +1189,57 @@ JSC::ScriptExecutionStatus Zig::GlobalObject::scriptExecutionStatus(JSC::JSGloba } } } -const JSC::GlobalObjectMethodTable& GlobalObject::globalObjectMethodTable() -{ - static const JSC::GlobalObjectMethodTable table = { - &supportsRichSourceInfo, - &shouldInterruptScript, - &javaScriptRuntimeFlags, - nullptr, // &queueMicrotaskToEventLoop, // queueTaskToEventLoop - nullptr, // &shouldInterruptScriptBeforeTimeout, - &moduleLoaderImportModule, // moduleLoaderImportModule - &moduleLoaderResolve, // moduleLoaderResolve - &moduleLoaderFetch, // moduleLoaderFetch - &moduleLoaderCreateImportMetaProperties, // moduleLoaderCreateImportMetaProperties - &moduleLoaderEvaluate, // moduleLoaderEvaluate - &promiseRejectionTracker, // promiseRejectionTracker - &reportUncaughtExceptionAtEventLoop, - ¤tScriptExecutionOwner, - &scriptExecutionStatus, - nullptr, // reportViolationForUnsafeEval - nullptr, // defaultLanguage - nullptr, // compileStreaming - nullptr, // instantiateStreaming - &Zig::deriveShadowRealmGlobalObject, - &codeForEval, // codeForEval - &canCompileStrings, // canCompileStrings - &trustedScriptStructure, // trustedScriptStructure - }; - return table; -} -const JSC::GlobalObjectMethodTable& EvalGlobalObject::globalObjectMethodTable() -{ - static const JSC::GlobalObjectMethodTable table = { - &supportsRichSourceInfo, - &shouldInterruptScript, - &javaScriptRuntimeFlags, - // &queueMicrotaskToEventLoop, // queueTaskToEventLoop - nullptr, - nullptr, // &shouldInterruptScriptBeforeTimeout, - &moduleLoaderImportModule, // moduleLoaderImportModule - &moduleLoaderResolve, // moduleLoaderResolve - &moduleLoaderFetch, // moduleLoaderFetch - &moduleLoaderCreateImportMetaProperties, // moduleLoaderCreateImportMetaProperties - &moduleLoaderEvaluate, // moduleLoaderEvaluate - &promiseRejectionTracker, // promiseRejectionTracker - &reportUncaughtExceptionAtEventLoop, - ¤tScriptExecutionOwner, - &scriptExecutionStatus, - nullptr, // reportViolationForUnsafeEval - nullptr, // defaultLanguage - nullptr, // compileStreaming - nullptr, // instantiateStreaming - &Zig::deriveShadowRealmGlobalObject, - &codeForEval, // codeForEval - &canCompileStrings, // canCompileStrings - &trustedScriptStructure, // trustedScriptStructure - }; - return table; -} +const JSC::GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { + &supportsRichSourceInfo, + &shouldInterruptScript, + &javaScriptRuntimeFlags, + nullptr, // &queueMicrotaskToEventLoop, // queueTaskToEventLoop + nullptr, // &shouldInterruptScriptBeforeTimeout, + &moduleLoaderImportModule, // moduleLoaderImportModule + &moduleLoaderResolve, // moduleLoaderResolve + &moduleLoaderFetch, // moduleLoaderFetch + &moduleLoaderCreateImportMetaProperties, // moduleLoaderCreateImportMetaProperties + &moduleLoaderEvaluate, // moduleLoaderEvaluate + &promiseRejectionTracker, // promiseRejectionTracker + &reportUncaughtExceptionAtEventLoop, + ¤tScriptExecutionOwner, + &scriptExecutionStatus, + nullptr, // reportViolationForUnsafeEval + nullptr, // defaultLanguage + nullptr, // compileStreaming + nullptr, // instantiateStreaming + &Zig::deriveShadowRealmGlobalObject, + &codeForEval, // codeForEval + &canCompileStrings, // canCompileStrings + &trustedScriptStructure, // trustedScriptStructure +}; + +const JSC::GlobalObjectMethodTable EvalGlobalObject::s_globalObjectMethodTable = { + &supportsRichSourceInfo, + &shouldInterruptScript, + &javaScriptRuntimeFlags, + // &queueMicrotaskToEventLoop, // queueTaskToEventLoop + nullptr, + nullptr, // &shouldInterruptScriptBeforeTimeout, + &moduleLoaderImportModule, // moduleLoaderImportModule + &moduleLoaderResolve, // moduleLoaderResolve + &moduleLoaderFetch, // moduleLoaderFetch + &moduleLoaderCreateImportMetaProperties, // moduleLoaderCreateImportMetaProperties + &moduleLoaderEvaluate, // moduleLoaderEvaluate + &promiseRejectionTracker, // promiseRejectionTracker + &reportUncaughtExceptionAtEventLoop, + ¤tScriptExecutionOwner, + &scriptExecutionStatus, + nullptr, // reportViolationForUnsafeEval + nullptr, // defaultLanguage + nullptr, // compileStreaming + nullptr, // instantiateStreaming + &Zig::deriveShadowRealmGlobalObject, + &codeForEval, // codeForEval + &canCompileStrings, // canCompileStrings + &trustedScriptStructure, // trustedScriptStructure +}; GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure, const JSC::GlobalObjectMethodTable* methodTable) : Base(vm, structure, methodTable) diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index e2c4cc90cc..ced926324f 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -102,10 +102,9 @@ public: } static const JSC::ClassInfo s_info; - static const JSC::GlobalObjectMethodTable& globalObjectMethodTable(); + static const JSC::GlobalObjectMethodTable s_globalObjectMethodTable; - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { if constexpr (mode == JSC::SubspaceAccess::Concurrently) return nullptr; @@ -701,11 +700,11 @@ private: class EvalGlobalObject : public GlobalObject { public: - static const JSC::GlobalObjectMethodTable& globalObjectMethodTable(); + static const JSC::GlobalObjectMethodTable s_globalObjectMethodTable; static JSC::JSValue moduleLoaderEvaluate(JSGlobalObject*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSValue, JSC::JSValue, JSC::JSValue, JSC::JSValue); EvalGlobalObject(JSC::VM& vm, JSC::Structure* structure) - : GlobalObject(vm, structure, &globalObjectMethodTable()) + : GlobalObject(vm, structure, &s_globalObjectMethodTable) { } }; diff --git a/src/bun.js/bindings/ncrypto.cpp b/src/bun.js/bindings/ncrypto.cpp index 864ac2ee43..0719f65d44 100644 --- a/src/bun.js/bindings/ncrypto.cpp +++ b/src/bun.js/bindings/ncrypto.cpp @@ -1341,25 +1341,18 @@ std::optional X509View::getFingerprint( { unsigned int md_size; unsigned char md[EVP_MAX_MD_SIZE]; - static const char hex[] = "0123456789ABCDEF"; + static constexpr char hex[] = "0123456789ABCDEF"; if (X509_digest(get(), method, md, &md_size)) { if (md_size == 0) return std::nullopt; std::span fingerprint; WTF::String fingerprintStr = WTF::String::createUninitialized((md_size * 3) - 1, fingerprint); - - { - // This function is 650 KB. - // It should not be 650 KB. - unsigned int i = 0; - unsigned int idx = 0; - do { - const unsigned int md_i = md[i++]; - fingerprint[idx++] = hex[(md_i & 0xf0) >> 4]; - fingerprint[idx++] = hex[(md_i & 0x0f)]; - if (i == md_size) break; - fingerprint[idx++] = ':'; - } while (i < md_size); + for (unsigned int i = 0; i < md_size; i++) { + auto idx = 3 * i; + fingerprint[idx] = hex[(md[i] & 0xf0) >> 4]; + fingerprint[idx + 1] = hex[(md[i] & 0x0f)]; + if (i == md_size - 1) break; + fingerprint[idx + 2] = ':'; } return fingerprintStr; @@ -3136,9 +3129,9 @@ const Cipher Cipher::FromName(WTF::StringView name) if (name.startsWithIgnoringASCIICase("aes"_s)) { auto remain = name.substring(3); - if (remain == "128"_s) return Cipher::AES_128_CBC(); - if (remain == "192"_s) return Cipher::AES_192_CBC(); - if (remain == "256"_s) return Cipher::AES_256_CBC(); + if (remain == "128"_s) return Cipher::AES_128_CBC; + if (remain == "192"_s) return Cipher::AES_192_CBC; + if (remain == "256"_s) return Cipher::AES_256_CBC; } auto nameUtf8 = name.utf8(); @@ -3155,71 +3148,19 @@ const Cipher Cipher::FromCtx(const CipherCtxPointer& ctx) return Cipher(EVP_CIPHER_CTX_cipher(ctx.get())); } -const Cipher& Cipher::EMPTY() -{ - static const Cipher cipher = Cipher(); - return cipher; -} -const Cipher& Cipher::AES_128_CBC() -{ - static const Cipher cipher = Cipher::FromNid(NID_aes_128_cbc); - return cipher; -} -const Cipher& Cipher::AES_192_CBC() -{ - static const Cipher cipher = Cipher::FromNid(NID_aes_192_cbc); - return cipher; -} -const Cipher& Cipher::AES_256_CBC() -{ - static const Cipher cipher = Cipher::FromNid(NID_aes_256_cbc); - return cipher; -} -const Cipher& Cipher::AES_128_CTR() -{ - static const Cipher cipher = Cipher::FromNid(NID_aes_128_ctr); - return cipher; -} -const Cipher& Cipher::AES_192_CTR() -{ - static const Cipher cipher = Cipher::FromNid(NID_aes_192_ctr); - return cipher; -} -const Cipher& Cipher::AES_256_CTR() -{ - static const Cipher cipher = Cipher::FromNid(NID_aes_256_ctr); - return cipher; -} -const Cipher& Cipher::AES_128_GCM() -{ - static const Cipher cipher = Cipher::FromNid(NID_aes_128_gcm); - return cipher; -} -const Cipher& Cipher::AES_192_GCM() -{ - static const Cipher cipher = Cipher::FromNid(NID_aes_192_gcm); - return cipher; -} -const Cipher& Cipher::AES_256_GCM() -{ - static const Cipher cipher = Cipher::FromNid(NID_aes_256_gcm); - return cipher; -} -const Cipher& Cipher::AES_128_KW() -{ - static const Cipher cipher = Cipher::FromNid(NID_id_aes128_wrap); - return cipher; -} -const Cipher& Cipher::AES_192_KW() -{ - static const Cipher cipher = Cipher::FromNid(NID_id_aes192_wrap); - return cipher; -} -const Cipher& Cipher::AES_256_KW() -{ - static const Cipher cipher = Cipher::FromNid(NID_id_aes256_wrap); - return cipher; -} +const Cipher Cipher::EMPTY = Cipher(); +const Cipher Cipher::AES_128_CBC = Cipher::FromNid(NID_aes_128_cbc); +const Cipher Cipher::AES_192_CBC = Cipher::FromNid(NID_aes_192_cbc); +const Cipher Cipher::AES_256_CBC = Cipher::FromNid(NID_aes_256_cbc); +const Cipher Cipher::AES_128_CTR = Cipher::FromNid(NID_aes_128_ctr); +const Cipher Cipher::AES_192_CTR = Cipher::FromNid(NID_aes_192_ctr); +const Cipher Cipher::AES_256_CTR = Cipher::FromNid(NID_aes_256_ctr); +const Cipher Cipher::AES_128_GCM = Cipher::FromNid(NID_aes_128_gcm); +const Cipher Cipher::AES_192_GCM = Cipher::FromNid(NID_aes_192_gcm); +const Cipher Cipher::AES_256_GCM = Cipher::FromNid(NID_aes_256_gcm); +const Cipher Cipher::AES_128_KW = Cipher::FromNid(NID_id_aes128_wrap); +const Cipher Cipher::AES_192_KW = Cipher::FromNid(NID_id_aes192_wrap); +const Cipher Cipher::AES_256_KW = Cipher::FromNid(NID_id_aes256_wrap); bool Cipher::isGcmMode() const { @@ -3353,7 +3294,7 @@ int Cipher::bytesToKey(const Digest& digest, unsigned char* iv) const { return EVP_BytesToKey( - *this, Digest::MD5(), nullptr, input.data, input.len, 1, key, iv); + *this, Digest::MD5, nullptr, input.data, input.len, 1, key, iv); } // ============================================================================ @@ -4919,31 +4860,12 @@ size_t Digest::size() const return EVP_MD_size(md_); } -const Digest& Digest::MD5() -{ - static const Digest digest = Digest(EVP_md5()); - return digest; -} -const Digest& Digest::SHA1() -{ - static const Digest digest = Digest(EVP_sha1()); - return digest; -} -const Digest& Digest::SHA256() -{ - static const Digest digest = Digest(EVP_sha256()); - return digest; -} -const Digest& Digest::SHA384() -{ - static const Digest digest = Digest(EVP_sha384()); - return digest; -} -const Digest& Digest::SHA512() -{ - static const Digest digest = Digest(EVP_sha512()); - return digest; -} +const Digest Digest::MD5 = Digest(EVP_md5()); +const Digest Digest::SHA1 = Digest(EVP_sha1()); +const Digest Digest::SHA256 = Digest(EVP_sha256()); +const Digest Digest::SHA384 = Digest(EVP_sha384()); +const Digest Digest::SHA512 = Digest(EVP_sha512()); + const Digest Digest::FromName(WTF::StringView name) { return ncrypto::getDigestByName(name); diff --git a/src/bun.js/bindings/ncrypto.h b/src/bun.js/bindings/ncrypto.h index 3a5e2307f5..8d3010ec86 100644 --- a/src/bun.js/bindings/ncrypto.h +++ b/src/bun.js/bindings/ncrypto.h @@ -273,11 +273,11 @@ public: inline operator const EVP_MD*() const { return md_; } inline operator bool() const { return md_ != nullptr; } - static const Digest& MD5(); - static const Digest& SHA1(); - static const Digest& SHA256(); - static const Digest& SHA384(); - static const Digest& SHA512(); + static const Digest MD5; + static const Digest SHA1; + static const Digest SHA256; + static const Digest SHA384; + static const Digest SHA512; static const Digest FromName(WTF::StringView name); @@ -349,19 +349,19 @@ public: // the result will be an empty Cipher object whose bool operator // will return false. - static const Cipher& EMPTY(); - static const Cipher& AES_128_CBC(); - static const Cipher& AES_192_CBC(); - static const Cipher& AES_256_CBC(); - static const Cipher& AES_128_CTR(); - static const Cipher& AES_192_CTR(); - static const Cipher& AES_256_CTR(); - static const Cipher& AES_128_GCM(); - static const Cipher& AES_192_GCM(); - static const Cipher& AES_256_GCM(); - static const Cipher& AES_128_KW(); - static const Cipher& AES_192_KW(); - static const Cipher& AES_256_KW(); + static const Cipher EMPTY; + static const Cipher AES_128_CBC; + static const Cipher AES_192_CBC; + static const Cipher AES_256_CBC; + static const Cipher AES_128_CTR; + static const Cipher AES_192_CTR; + static const Cipher AES_256_CTR; + static const Cipher AES_128_GCM; + static const Cipher AES_192_GCM; + static const Cipher AES_256_GCM; + static const Cipher AES_128_KW; + static const Cipher AES_192_KW; + static const Cipher AES_256_KW; struct CipherParams { int padding; diff --git a/src/bun.js/bindings/v8/V8HandleScope.h b/src/bun.js/bindings/v8/V8HandleScope.h index 0f91c2234d..8813525e39 100644 --- a/src/bun.js/bindings/v8/V8HandleScope.h +++ b/src/bun.js/bindings/v8/V8HandleScope.h @@ -20,9 +20,9 @@ public: { // TODO(@190n) handle more types if (value.isString()) { - return Local(m_buffer->createHandle(value.asCell(), &shim::Map::string_map(), vm)); + return Local(m_buffer->createHandle(value.asCell(), &shim::Map::string_map, vm)); } else if (value.isCell()) { - return Local(m_buffer->createHandle(value.asCell(), &shim::Map::object_map(), vm)); + return Local(m_buffer->createHandle(value.asCell(), &shim::Map::object_map, vm)); } else if (value.isInt32()) { return Local(m_buffer->createSmiHandle(value.asInt32())); } else if (value.isNumber()) { diff --git a/src/bun.js/bindings/v8/shim/Handle.h b/src/bun.js/bindings/v8/shim/Handle.h index 9164adce3c..bd87f417f0 100644 --- a/src/bun.js/bindings/v8/shim/Handle.h +++ b/src/bun.js/bindings/v8/shim/Handle.h @@ -29,7 +29,7 @@ struct ObjectLayout { } ObjectLayout(double number) - : m_taggedMap(const_cast(&Map::heap_number_map())) + : m_taggedMap(const_cast(&Map::heap_number_map)) , m_contents({ .number = number }) { } @@ -80,10 +80,10 @@ struct Handle { } const Map* map_ptr = m_object.map(); // TODO(@190n) exhaustively switch on InstanceType - if (map_ptr == &Map::object_map() || map_ptr == &Map::string_map()) { + if (map_ptr == &Map::object_map || map_ptr == &Map::string_map) { return true; - } else if (map_ptr == &Map::map_map() || map_ptr == &Map::oddball_map() - || map_ptr == &Map::heap_number_map()) { + } else if (map_ptr == &Map::map_map || map_ptr == &Map::oddball_map + || map_ptr == &Map::heap_number_map) { return false; } else { RELEASE_ASSERT_NOT_REACHED("unknown Map at %p with instance type %" PRIx16, diff --git a/src/bun.js/bindings/v8/shim/Map.cpp b/src/bun.js/bindings/v8/shim/Map.cpp index f4ac5e4f4c..0502ac6b71 100644 --- a/src/bun.js/bindings/v8/shim/Map.cpp +++ b/src/bun.js/bindings/v8/shim/Map.cpp @@ -23,33 +23,11 @@ namespace v8 { namespace shim { // TODO give these more appropriate instance types - -// Prevent static initialization on startup -const Map& Map::map_map() -{ - static const Map map = Map(MapMapTag::MapMap); - return map; -} -const Map& Map::object_map() -{ - static const Map map = Map(InstanceType::Object); - return map; -} -const Map& Map::oddball_map() -{ - static const Map map = Map(InstanceType::Oddball); - return map; -} -const Map& Map::string_map() -{ - static const Map map = Map(InstanceType::String); - return map; -} -const Map& Map::heap_number_map() -{ - static const Map map = Map(InstanceType::HeapNumber); - return map; -} +const Map Map::map_map(InstanceType::Object); +const Map Map::object_map(InstanceType::Object); +const Map Map::oddball_map(InstanceType::Oddball); +const Map Map::string_map(InstanceType::String); +const Map Map::heap_number_map(InstanceType::HeapNumber); } // namespace shim } // namespace v8 diff --git a/src/bun.js/bindings/v8/shim/Map.h b/src/bun.js/bindings/v8/shim/Map.h index 0890e5cff3..95a9d14f6d 100644 --- a/src/bun.js/bindings/v8/shim/Map.h +++ b/src/bun.js/bindings/v8/shim/Map.h @@ -34,38 +34,25 @@ struct Map { InstanceType m_instanceType; // Since maps are V8 objects, they each also have a map pointer at the start, which is this one - static const Map& map_map(); + static const Map map_map; // All V8 values not covered by a more specific map use this one - static const Map& object_map(); + static const Map object_map; // The map used by null, undefined, true, and false. Required since V8 checks these values' // instance type in the inline QuickIs* functions - static const Map& oddball_map(); + static const Map oddball_map; // All strings use this map. Required since V8's inline QuickIsString() checks the instance // type. - static const Map& string_map(); + static const Map string_map; // Handles containing a double instead of a JSCell pointer use this map so that we can tell they // are numbers. - static const Map& heap_number_map(); + static const Map heap_number_map; Map(InstanceType instance_type) - : m_metaMap(const_cast(&map_map())) + : m_metaMap(const_cast(&map_map)) , m_unused(0xaaaaaaaa) , m_instanceType(instance_type) { } - - // Tag it as the map_map() Map - enum class MapMapTag { - MapMap - }; - -public: - Map(MapMapTag) - : m_metaMap(const_cast(this)) - , m_unused(0xaaaaaaaa) - , m_instanceType(InstanceType::Object) - { - } }; static_assert(sizeof(Map) == 16, "Map has wrong layout"); diff --git a/src/bun.js/bindings/v8/shim/Oddball.h b/src/bun.js/bindings/v8/shim/Oddball.h index 85bc9cb24e..272030d1ad 100644 --- a/src/bun.js/bindings/v8/shim/Oddball.h +++ b/src/bun.js/bindings/v8/shim/Oddball.h @@ -21,7 +21,7 @@ struct Oddball { TaggedPointer m_kind; Oddball(Kind kind) - : m_map(const_cast(&Map::oddball_map())) + : m_map(const_cast(&Map::oddball_map)) , m_kind(TaggedPointer(static_cast(kind))) { } diff --git a/test/js/bun/perf/static-initializers.test.ts b/test/js/bun/perf/static-initializers.test.ts deleted file mode 100644 index 27d929616d..0000000000 --- a/test/js/bun/perf/static-initializers.test.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { describe, expect, it } from "bun:test"; -import { bunEnv, bunExe, isMacOS } from "harness"; - -/** - * This test prevents startup performance regressions by ensuring that Bun has - * exactly one static initializer from its own executable. - * - * Static initializers are functions that run automatically when a program starts, before main() is called. - * They're used to initialize global variables and static class members, but come with performance costs: - * - * 1. They always execute at startup, even if the initialized values are never used - * 2. They can't be optimized away by the compiler - * 3. They add to the binary size - * 4. They increase startup time - * 5. They can introduce complex initialization order dependencies - * - * On macOS, we can use DYLD_PRINT_INITIALIZERS to detect static initializers. - * This test verifies that Bun has exactly one static initializer from its own executable. - * - * Adding more static initializers would degrade Bun's startup performance. - */ -describe("static initializers", () => { - // Only macOS has DYLD_PRINT_INITIALIZERS - it.skipIf(!isMacOS || process.arch !== "arm64")("should only have one static initializer from bun itself", () => { - const env = { - ...bunEnv, - DYLD_PRINT_INITIALIZERS: "1", - } as const; - - const result = Bun.spawnSync({ - cmd: [bunExe(), "--version"], - env, - }); - - expect(result.exitCode).toBe(0); - - const stdout = result.stdout.toString(); - const stderr = result.stderr.toString(); - - // Combine stdout and stderr since DYLD_PRINT_INITIALIZERS output goes to stderr - const output = stderr + stdout; - - // Get all lines that contain initializers from the bun executable - const bunInitializers = output - .split("\n") - .map(a => a.trim()) - .filter(line => line.includes("running initializer") && line.includes(bunExe())); - - // We expect exactly one initializer from the bun executable itself - expect( - bunInitializers.length, - `Do not add static initializers to Bun. Static initializers are called when Bun starts up, regardless of whether you use the variables or not. This makes Bun slower.`, - ).toBe(1); - - // Verify the version was printed correctly - expect(stdout.trim()).toMatch(/^\d+\.\d+\.\d+(-[a-z0-9.]+)?$/); - }); -});