#include "ZigGlobalObject.h" #include "helpers.h" #include "JavaScriptCore/AggregateError.h" #include "JavaScriptCore/BytecodeIndex.h" #include "JavaScriptCore/CallFrameInlines.h" #include "JavaScriptCore/ClassInfo.h" #include "JavaScriptCore/CodeBlock.h" #include "JavaScriptCore/CodeCache.h" #include "JavaScriptCore/Completion.h" #include "JavaScriptCore/Error.h" #include "JavaScriptCore/ErrorInstance.h" #include "JavaScriptCore/Exception.h" #include "JavaScriptCore/ExceptionScope.h" #include "JavaScriptCore/FunctionConstructor.h" #include "JavaScriptCore/HashMapImpl.h" #include "JavaScriptCore/HashMapImplInlines.h" #include "JavaScriptCore/Heap.h" #include "JavaScriptCore/Identifier.h" #include "JavaScriptCore/InitializeThreading.h" #include "JavaScriptCore/IteratorOperations.h" #include "JavaScriptCore/JSArray.h" #include "JavaScriptCore/JSCallbackConstructor.h" #include "JavaScriptCore/JSCallbackObject.h" #include "JavaScriptCore/JSCast.h" #include "JavaScriptCore/JSClassRef.h" #include "JavaScriptCore/JSMicrotask.h" #include "ZigConsoleClient.h" // #include "JavaScriptCore/JSContextInternal.h" #include "JavaScriptCore/CatchScope.h" #include "JavaScriptCore/DeferredWorkTimer.h" #include "JavaScriptCore/JSInternalPromise.h" #include "JavaScriptCore/JSLock.h" #include "JavaScriptCore/JSMap.h" #include "JavaScriptCore/JSModuleLoader.h" #include "JavaScriptCore/JSModuleRecord.h" #include "JavaScriptCore/JSNativeStdFunction.h" #include "JavaScriptCore/JSObject.h" #include "JavaScriptCore/JSPromise.h" #include "JavaScriptCore/JSSet.h" #include "JavaScriptCore/JSSourceCode.h" #include "JavaScriptCore/JSString.h" #include "JavaScriptCore/JSValueInternal.h" #include "JavaScriptCore/JSVirtualMachineInternal.h" #include "JavaScriptCore/ObjectConstructor.h" #include "JavaScriptCore/OptionsList.h" #include "JavaScriptCore/ParserError.h" #include "JavaScriptCore/ScriptExecutable.h" #include "JavaScriptCore/SourceOrigin.h" #include "JavaScriptCore/StackFrame.h" #include "JavaScriptCore/StackVisitor.h" #include "JavaScriptCore/VM.h" #include "JavaScriptCore/VMEntryScope.h" #include "JavaScriptCore/WasmFaultSignalHandler.h" #include "wtf/Gigacage.h" #include "wtf/URL.h" #include "wtf/text/ExternalStringImpl.h" #include "wtf/text/StringCommon.h" #include "wtf/text/StringImpl.h" #include "wtf/text/StringView.h" #include "wtf/text/WTFString.h" #include "wtf/text/Base64.h" // #include "JavaScriptCore/CachedType.h" #include "JavaScriptCore/JSCallbackObject.h" #include "JavaScriptCore/JSClassRef.h" #include "BunClientData.h" #include "ZigSourceProvider.h" #include "JSDOMURL.h" #include "JSURLSearchParams.h" #include "JSDOMException.h" #include "JSEventTarget.h" #include "EventTargetConcrete.h" #include "JSAbortSignal.h" #include "JSCustomEvent.h" #include "JSAbortController.h" #include "JSEvent.h" #include "JSErrorEvent.h" #include "JSFetchHeaders.h" #include "Process.h" #include "JavaScriptCore/RemoteInspectorServer.h" #include "JSDOMGuardedObject.h" using JSGlobalObject = JSC::JSGlobalObject; using Exception = JSC::Exception; using JSValue = JSC::JSValue; using JSString = JSC::JSString; using JSModuleLoader = JSC::JSModuleLoader; using JSModuleRecord = JSC::JSModuleRecord; using Identifier = JSC::Identifier; using SourceOrigin = JSC::SourceOrigin; using JSObject = JSC::JSObject; using JSNonFinalObject = JSC::JSNonFinalObject; namespace JSCastingHelpers = JSC::JSCastingHelpers; static bool has_loaded_jsc = false; extern "C" void JSCInitialize() { if (has_loaded_jsc) return; has_loaded_jsc = true; JSC::Config::enableRestrictedOptions(); std::set_terminate([]() { Zig__GlobalObject__onCrash(); }); WTF::initializeMainThread(); JSC::initialize(); { JSC::Options::AllowUnfinalizedAccessScope scope; JSC::Options::useConcurrentJIT() = true; JSC::Options::useSigillCrashAnalyzer() = true; JSC::Options::useWebAssembly() = true; JSC::Options::useSourceProviderCache() = true; // JSC::Options::useUnlinkedCodeBlockJettisoning() = false; JSC::Options::exposeInternalModuleLoader() = true; JSC::Options::useSharedArrayBuffer() = true; JSC::Options::useJIT() = true; JSC::Options::useBBQJIT() = true; JSC::Options::ensureOptionsAreCoherent(); } } extern "C" JSC__JSGlobalObject* Zig__GlobalObject__create(JSClassRef* globalObjectClass, int count, void* console_client) { auto heapSize = JSC::HeapType::Large; JSC::VM& vm = JSC::VM::create(heapSize).leakRef(); JSC::Wasm::enableFastMemory(); // This must happen before JSVMClientData::create vm.heap.acquireAccess(); WebCore::JSVMClientData::create(&vm); JSC::JSLockHolder locker(vm); Zig::GlobalObject* globalObject = Zig::GlobalObject::create(vm, Zig::GlobalObject::createStructure(vm, JSC::JSGlobalObject::create(vm, JSC::JSGlobalObject::createStructure(vm, JSC::jsNull())), JSC::jsNull())); globalObject->setConsole(globalObject); if (count > 0) { globalObject->installAPIGlobals(globalObjectClass, count, vm); } JSC::gcProtect(globalObject); vm.ref(); return globalObject; } extern "C" void* Zig__GlobalObject__getModuleRegistryMap(JSC__JSGlobalObject* arg0) { if (JSC::JSObject* loader = JSC::jsDynamicCast(arg0->vm(), arg0->moduleLoader())) { JSC::JSMap* map = JSC::jsDynamicCast( arg0->vm(), loader->getDirect(arg0->vm(), JSC::Identifier::fromString(arg0->vm(), "registry"))); JSC::JSMap* cloned = map->clone(arg0, arg0->vm(), arg0->mapStructure()); JSC::gcProtect(cloned); return cloned; } return nullptr; } extern "C" bool Zig__GlobalObject__resetModuleRegistryMap(JSC__JSGlobalObject* globalObject, void* map_ptr) { if (map_ptr == nullptr) return false; JSC::JSMap* map = reinterpret_cast(map_ptr); JSC::VM& vm = globalObject->vm(); if (JSC::JSObject* obj = JSC::jsDynamicCast(globalObject->vm(), globalObject->moduleLoader())) { auto identifier = JSC::Identifier::fromString(globalObject->vm(), "registry"); if (JSC::JSMap* oldMap = JSC::jsDynamicCast( globalObject->vm(), obj->getDirect(globalObject->vm(), identifier))) { vm.finalizeSynchronousJSExecution(); obj->putDirect(globalObject->vm(), identifier, map->clone(globalObject, globalObject->vm(), globalObject->mapStructure())); // vm.deleteAllLinkedCode(JSC::DeleteAllCodeEffort::DeleteAllCodeIfNotCollecting); // JSC::Heap::PreventCollectionScope(vm.heap); oldMap->clear(globalObject); JSC::gcUnprotect(oldMap); // vm.heap.completeAllJITPlans(); // vm.forEachScriptExecutableSpace([&](auto &spaceAndSet) { // JSC::HeapIterationScope heapIterationScope(vm.heap); // auto &set = spaceAndSet.set; // set.forEachLiveCell([&](JSC::HeapCell *cell, JSC::HeapCell::Kind) { // if (JSC::ModuleProgramExecutable *executable = // JSC::jsDynamicCast(cell)) { // executable->clearCode(set); // } // }); // }); // globalObject->vm().heap.deleteAllUnlinkedCodeBlocks( // JSC::DeleteAllCodeEffort::PreventCollectionAndDeleteAllCode); } } // map // } return true; } namespace Zig { using namespace WebCore; const JSC::ClassInfo GlobalObject::s_info = { "GlobalObject"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(GlobalObject) }; extern "C" JSClassRef* Zig__getAPIGlobals(size_t* count); extern "C" const JSC__JSValue* Zig__getAPIConstructors(size_t* count, JSC__JSGlobalObject*); static JSGlobalObject* deriveShadowRealmGlobalObject(JSGlobalObject* globalObject) { auto& vm = globalObject->vm(); Zig::GlobalObject* shadow = Zig::GlobalObject::create(vm, Zig::GlobalObject::createStructure(vm, JSC::JSGlobalObject::create(vm, JSC::JSGlobalObject::createStructure(vm, JSC::jsNull())), JSC::jsNull())); shadow->setConsole(shadow); size_t count = 0; JSClassRef* globalObjectClass = Zig__getAPIGlobals(&count); shadow->setConsole(shadow); if (count > 0) { shadow->installAPIGlobals(globalObjectClass, count, vm); } return shadow; } extern "C" JSC__JSValue JSC__JSValue__makeWithNameAndPrototype(JSC__JSGlobalObject* globalObject, void* arg1, void* arg2, const ZigString* visibleInterfaceName) { auto& vm = globalObject->vm(); JSClassRef jsClass = reinterpret_cast(arg1); JSClassRef protoClass = reinterpret_cast(arg2); JSObjectRef objectRef = JSObjectMakeConstructor(reinterpret_cast(globalObject), protoClass, jsClass->callAsConstructor); JSObjectRef wrappedRef = JSObjectMake(reinterpret_cast(globalObject), jsClass, nullptr); JSC::JSObject* object = JSC::JSValue::decode(reinterpret_cast(objectRef)).getObject(); JSC::JSObject* wrapped = JSC::JSValue::decode(reinterpret_cast(wrappedRef)).getObject(); object->setPrototypeDirect(vm, wrapped); JSString* nameString = JSC::jsNontrivialString(vm, Zig::toString(*visibleInterfaceName)); object->putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); object->putDirect(vm, vm.propertyNames->toStringTagSymbol, nameString, JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly); return JSC::JSValue::encode(JSC::JSValue(object)); } const JSC::GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, &queueMicrotaskToEventLoop, // queueTaskToEventLoop nullptr, // &shouldInterruptScriptBeforeTimeout, &moduleLoaderImportModule, // moduleLoaderImportModule &moduleLoaderResolve, // moduleLoaderResolve &moduleLoaderFetch, // moduleLoaderFetch &moduleLoaderCreateImportMetaProperties, // moduleLoaderCreateImportMetaProperties &moduleLoaderEvaluate, // moduleLoaderEvaluate &promiseRejectionTracker, // promiseRejectionTracker &reportUncaughtExceptionAtEventLoop, ¤tScriptExecutionOwner, &scriptExecutionStatus, nullptr, // defaultLanguage nullptr, // compileStreaming nullptr, // instantiateStreaming nullptr, &Zig::deriveShadowRealmGlobalObject }; GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure) : JSC::JSGlobalObject(vm, structure, &s_globalObjectMethodTable) , m_constructors(makeUnique()) , m_world(WebCore::DOMWrapperWorld::create(vm, WebCore::DOMWrapperWorld::Type::Normal)) , m_worldIsNormal(true) , m_guardedObjects() { m_scriptExecutionContext = new WebCore::ScriptExecutionContext(&vm, this); } WebCore::ScriptExecutionContext* GlobalObject::scriptExecutionContext() { return m_scriptExecutionContext; } WebCore::ScriptExecutionContext* GlobalObject::scriptExecutionContext() const { return m_scriptExecutionContext; } void GlobalObject::reportUncaughtExceptionAtEventLoop(JSGlobalObject* globalObject, JSC::Exception* exception) { Zig__GlobalObject__reportUncaughtException(globalObject, exception); } void GlobalObject::promiseRejectionTracker(JSGlobalObject* obj, JSC::JSPromise* prom, JSC::JSPromiseRejectionOperation reject) { Zig__GlobalObject__promiseRejectionTracker( obj, prom, reject == JSC::JSPromiseRejectionOperation::Reject ? 0 : 1); } static Zig::ConsoleClient* m_console; void GlobalObject::setConsole(void* console) { m_console = new Zig::ConsoleClient(console); this->setConsoleClient(m_console); } #pragma mark - Globals JSC_DECLARE_CUSTOM_GETTER(JSDOMURL_getter); JSC_DEFINE_CUSTOM_GETTER(JSDOMURL_getter, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) { Zig::GlobalObject* thisObject = JSC::jsCast(lexicalGlobalObject); return JSC::JSValue::encode( WebCore::JSDOMURL::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject)); } JSC_DECLARE_CUSTOM_GETTER(JSURLSearchParams_getter); JSC_DEFINE_CUSTOM_GETTER(JSURLSearchParams_getter, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) { Zig::GlobalObject* thisObject = JSC::jsCast(lexicalGlobalObject); return JSC::JSValue::encode( WebCore::JSURLSearchParams::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject)); } JSC_DECLARE_CUSTOM_GETTER(JSErrorEvent_getter); JSC_DEFINE_CUSTOM_GETTER(JSErrorEvent_getter, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) { Zig::GlobalObject* thisObject = JSC::jsCast(lexicalGlobalObject); return JSC::JSValue::encode( WebCore::JSErrorEvent::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject)); } JSC_DECLARE_CUSTOM_GETTER(JSEvent_getter); JSC_DEFINE_CUSTOM_GETTER(JSEvent_getter, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) { Zig::GlobalObject* thisObject = JSC::jsCast(lexicalGlobalObject); return JSC::JSValue::encode( WebCore::JSEvent::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject)); } JSC_DECLARE_CUSTOM_GETTER(JSCustomEvent_getter); JSC_DEFINE_CUSTOM_GETTER(JSCustomEvent_getter, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) { Zig::GlobalObject* thisObject = JSC::jsCast(lexicalGlobalObject); return JSC::JSValue::encode( WebCore::JSCustomEvent::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject)); } JSC_DECLARE_CUSTOM_GETTER(JSFetchHeaders_getter); JSC_DEFINE_CUSTOM_GETTER(JSFetchHeaders_getter, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) { Zig::GlobalObject* thisObject = JSC::jsCast(lexicalGlobalObject); return JSC::JSValue::encode( WebCore::JSFetchHeaders::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject)); } JSC_DECLARE_CUSTOM_GETTER(JSEventTarget_getter); JSC_DEFINE_CUSTOM_GETTER(JSEventTarget_getter, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) { Zig::GlobalObject* thisObject = JSC::jsCast(lexicalGlobalObject); return JSC::JSValue::encode( WebCore::JSEventTarget::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject)); } JSC_DECLARE_CUSTOM_GETTER(JSDOMAbortController_getter); JSC_DEFINE_CUSTOM_GETTER(JSDOMAbortController_getter, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) { Zig::GlobalObject* thisObject = JSC::jsCast(lexicalGlobalObject); return JSC::JSValue::encode( WebCore::JSAbortController::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject)); } JSC_DECLARE_CUSTOM_GETTER(JSDOMAbortSignal_getter); JSC_DEFINE_CUSTOM_GETTER(JSDOMAbortSignal_getter, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) { Zig::GlobalObject* thisObject = JSC::jsCast(lexicalGlobalObject); return JSC::JSValue::encode( WebCore::JSAbortSignal::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject)); } JSC_DECLARE_CUSTOM_GETTER(JSDOMException_getter); JSC_DEFINE_CUSTOM_GETTER(JSDOMException_getter, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) { Zig::GlobalObject* thisObject = JSC::jsCast(lexicalGlobalObject); return JSC::JSValue::encode( WebCore::JSDOMException::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject)); } static JSC_DECLARE_CUSTOM_SETTER(property_lazyProcessSetter); static JSC_DECLARE_CUSTOM_GETTER(property_lazyProcessGetter); JSC_DEFINE_CUSTOM_SETTER(property_lazyProcessSetter, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue value, JSC::PropertyName)) { return false; } static JSClassRef dot_env_class_ref; JSC_DEFINE_CUSTOM_GETTER(property_lazyProcessGetter, (JSC::JSGlobalObject * _globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) { Zig::GlobalObject* globalObject = reinterpret_cast(_globalObject); JSC::VM& vm = globalObject->vm(); auto clientData = WebCore::clientData(vm); JSC::JSValue processPrivate = globalObject->getIfPropertyExists(globalObject, clientData->builtinNames().processPrivateName()); if (LIKELY(processPrivate)) { return JSC::JSValue::encode(processPrivate); } auto* process = Zig::Process::create( vm, Zig::Process::createStructure(vm, globalObject, globalObject->objectPrototype())); { auto jsClass = dot_env_class_ref; JSC::JSCallbackObject* object = JSC::JSCallbackObject::create( globalObject, globalObject->callbackObjectStructure(), jsClass, nullptr); if (JSObject* prototype = jsClass->prototype(globalObject)) object->setPrototypeDirect(vm, prototype); process->putDirect(vm, JSC::Identifier::fromString(vm, "env"), JSC::JSValue(object), JSC::PropertyAttribute::DontDelete | 0); JSC::gcProtect(JSC::JSValue(object)); } globalObject->putDirect(vm, clientData->builtinNames().processPrivateName(), JSC::JSValue(process), 0); JSC::gcProtect(JSC::JSValue(process)); return JSC::JSValue::encode(JSC::JSValue(process)); } void JSDOMGlobalObject::clearDOMGuardedObjects() const { // No locking is necessary here since we are not directly modifying the returned container. // Calling JSDOMGuardedObject::clear() will however modify the guarded objects container but // it will grab the lock as needed. auto guardedObjectsCopy = guardedObjects(); for (auto& guarded : guardedObjectsCopy) guarded->clear(); } static JSC_DECLARE_HOST_FUNCTION(functionQueueMicrotask); static JSC_DEFINE_HOST_FUNCTION(functionQueueMicrotask, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { JSC::VM& vm = globalObject->vm(); if (callFrame->argumentCount() == 0) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); JSC::throwTypeError(globalObject, scope, "queueMicrotask requires 1 argument (a function)"_s); return JSC::JSValue::encode(JSC::JSValue {}); } JSC::JSValue job = callFrame->argument(0); if (!job.isObject() || !job.getObject()->isCallable(vm)) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); JSC::throwTypeError(globalObject, scope, "queueMicrotask expects a function"_s); return JSC::JSValue::encode(JSC::JSValue {}); } // This is a JSC builtin function globalObject->queueMicrotask(JSC::createJSMicrotask(vm, job, JSC::JSValue {}, JSC::JSValue {}, JSC::JSValue {}, JSC::JSValue {})); return JSC::JSValue::encode(JSC::jsUndefined()); } static JSC_DECLARE_HOST_FUNCTION(functionSetTimeout); static JSC_DEFINE_HOST_FUNCTION(functionSetTimeout, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { JSC::VM& vm = globalObject->vm(); if (callFrame->argumentCount() == 0) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); JSC::throwTypeError(globalObject, scope, "setTimeout requires 1 argument (a function)"_s); return JSC::JSValue::encode(JSC::JSValue {}); } JSC::JSValue job = callFrame->argument(0); if (!job.isObject() || !job.getObject()->isCallable(vm)) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); JSC::throwTypeError(globalObject, scope, "setTimeout expects a function"_s); return JSC::JSValue::encode(JSC::JSValue {}); } if (callFrame->argumentCount() == 1) { globalObject->queueMicrotask(JSC::createJSMicrotask(vm, job, JSC::JSValue {}, JSC::JSValue {}, JSC::JSValue {}, JSC::JSValue {})); return JSC::JSValue::encode(JSC::jsNumber(Bun__Timer__getNextID())); } JSC::JSValue num = callFrame->argument(1); return Bun__Timer__setTimeout(globalObject, JSC::JSValue::encode(job), JSC::JSValue::encode(num)); } static JSC_DECLARE_HOST_FUNCTION(functionSetInterval); static JSC_DEFINE_HOST_FUNCTION(functionSetInterval, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { JSC::VM& vm = globalObject->vm(); if (callFrame->argumentCount() == 0) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); JSC::throwTypeError(globalObject, scope, "setInterval requires 2 arguments (a function)"_s); return JSC::JSValue::encode(JSC::JSValue {}); } JSC::JSValue job = callFrame->argument(0); if (!job.isObject() || !job.getObject()->isCallable(vm)) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); JSC::throwTypeError(globalObject, scope, "setInterval expects a function"_s); return JSC::JSValue::encode(JSC::JSValue {}); } JSC::JSValue num = callFrame->argument(1); return Bun__Timer__setInterval(globalObject, JSC::JSValue::encode(job), JSC::JSValue::encode(num)); } static JSC_DECLARE_HOST_FUNCTION(functionClearInterval); static JSC_DEFINE_HOST_FUNCTION(functionClearInterval, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { JSC::VM& vm = globalObject->vm(); if (callFrame->argumentCount() == 0) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); JSC::throwTypeError(globalObject, scope, "clearInterval requires 1 argument (a number)"_s); return JSC::JSValue::encode(JSC::JSValue {}); } JSC::JSValue num = callFrame->argument(0); return Bun__Timer__clearInterval(globalObject, JSC::JSValue::encode(num)); } static JSC_DECLARE_HOST_FUNCTION(functionClearTimeout); static JSC_DEFINE_HOST_FUNCTION(functionClearTimeout, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { JSC::VM& vm = globalObject->vm(); if (callFrame->argumentCount() == 0) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); JSC::throwTypeError(globalObject, scope, "clearTimeout requires 1 argument (a number)"_s); return JSC::JSValue::encode(JSC::JSValue {}); } JSC::JSValue num = callFrame->argument(0); return Bun__Timer__clearTimeout(globalObject, JSC::JSValue::encode(num)); } static JSC_DECLARE_HOST_FUNCTION(functionBTOA); static JSC_DEFINE_HOST_FUNCTION(functionBTOA, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { JSC::VM& vm = globalObject->vm(); if (callFrame->argumentCount() == 0) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); JSC::throwTypeError(globalObject, scope, "btoa requires 1 argument (a string)"_s); return JSC::JSValue::encode(JSC::JSValue {}); } const String& stringToEncode = callFrame->argument(0).toWTFString(globalObject); if (!stringToEncode || stringToEncode.isNull()) { return JSC::JSValue::encode(JSC::jsString(vm, WTF::String())); } if (!stringToEncode.isAllLatin1()) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); // TODO: DOMException JSC::throwTypeError(globalObject, scope, "The string contains invalid characters."_s); return JSC::JSValue::encode(JSC::JSValue {}); } return JSC::JSValue::encode(JSC::jsString(vm, WTF::base64EncodeToString(stringToEncode.latin1()))); } static JSC_DECLARE_HOST_FUNCTION(functionATOB); static JSC_DEFINE_HOST_FUNCTION(functionATOB, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { JSC::VM& vm = globalObject->vm(); if (callFrame->argumentCount() == 0) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); JSC::throwTypeError(globalObject, scope, "atob requires 1 argument (a string)"_s); return JSC::JSValue::encode(JSC::JSValue {}); } const WTF::String& encodedString = callFrame->argument(0).toWTFString(globalObject); if (encodedString.isNull()) { return JSC::JSValue::encode(JSC::jsString(vm, "")); } auto decodedData = WTF::base64Decode(encodedString, { WTF::Base64DecodeOptions::ValidatePadding, WTF::Base64DecodeOptions::IgnoreSpacesAndNewLines, WTF::Base64DecodeOptions::DiscardVerticalTab, }); if (!decodedData) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); // TODO: DOMException JSC::throwTypeError(globalObject, scope, "The string contains invalid characters."_s); return JSC::JSValue::encode(JSC::JSValue {}); } return JSC::JSValue::encode(JSC::jsString(vm, WTF::String(decodedData->data(), decodedData->size()))); } extern "C" JSC__JSValue Bun__resolve(JSC::JSGlobalObject* global, JSC__JSValue specifier, JSC__JSValue from); static JSC_DECLARE_HOST_FUNCTION(functionImportMeta__resolve); static JSC_DEFINE_HOST_FUNCTION(functionImportMeta__resolve, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { JSC::VM& vm = globalObject->vm(); switch (callFrame->argumentCount()) { case 0: { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); // not "requires" because "require" could be confusing JSC::throwTypeError(globalObject, scope, "import.meta.resolve needs 1 argument (a string)"_s); scope.release(); return JSC::JSValue::encode(JSC::JSValue {}); } default: { JSC::JSValue moduleName = callFrame->argument(0); if (moduleName.isUndefinedOrNull()) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); JSC::throwTypeError(globalObject, scope, "import.meta.resolve expects a string"_s); scope.release(); return JSC::JSValue::encode(JSC::JSValue {}); } JSC__JSValue from; if (callFrame->argumentCount() > 1) { from = JSC::JSValue::encode(callFrame->argument(1)); } else { JSC::JSObject* thisObject = JSC::jsDynamicCast(vm, callFrame->thisValue()); if (UNLIKELY(!thisObject)) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); JSC::throwTypeError(globalObject, scope, "import.meta.resolve must be bound to an import.meta object"_s); return JSC::JSValue::encode(JSC::JSValue {}); } auto clientData = WebCore::clientData(vm); from = JSC::JSValue::encode(thisObject->get(globalObject, clientData->builtinNames().pathPublicName())); } return Bun__resolve(globalObject, JSC::JSValue::encode(moduleName), from); } } } extern "C" void Bun__reportError(JSC__JSGlobalObject*, JSC__JSValue); static JSC_DECLARE_HOST_FUNCTION(functionReportError); static JSC_DEFINE_HOST_FUNCTION(functionReportError, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { switch (callFrame->argumentCount()) { case 0: { return JSC::JSValue::encode(JSC::jsUndefined()); } default: { Bun__reportError(globalObject, JSC::JSValue::encode(callFrame->argument(0))); } } return JSC::JSValue::encode(JSC::jsUndefined()); } // This is not a publicly exposed API currently. // This is used by the bundler to make Response, Request, FetchEvent, // and any other objects available globally. void GlobalObject::installAPIGlobals(JSClassRef* globals, int count, JSC::VM& vm) { auto clientData = WebCore::clientData(vm); size_t constructor_count = 0; JSC__JSValue const* constructors = Zig__getAPIConstructors(&constructor_count, this); WTF::Vector extraStaticGlobals; extraStaticGlobals.reserveCapacity((size_t)count + constructor_count + 3 + 10); int i = 0; for (; i < constructor_count; i++) { auto* object = JSC::jsDynamicCast(vm, JSC::JSValue::decode(constructors[i]).asCell()->getObject()); extraStaticGlobals.uncheckedAppend( GlobalPropertyInfo { JSC::Identifier::fromString(vm, object->get(this, vm.propertyNames->name).toWTFString(this)), JSC::JSValue(object), JSC::PropertyAttribute::DontDelete | 0 }); } int j = 0; for (; j < count - 1; j++) { auto jsClass = globals[j]; JSC::JSCallbackObject* object = JSC::JSCallbackObject::create(this, this->callbackObjectStructure(), jsClass, nullptr); if (JSObject* prototype = object->classRef()->prototype(this)) object->setPrototypeDirect(vm, prototype); extraStaticGlobals.uncheckedAppend( GlobalPropertyInfo { JSC::Identifier::fromString(vm, jsClass->className()), JSC::JSValue(object), JSC::PropertyAttribute::DontDelete | 0 }); } // The last one must be "process.env" // Runtime-support is for if they change dot_env_class_ref = globals[j]; // // The last one must be "process.env" // // Runtime-support is for if they change // { // auto jsClass = globals[i]; // JSC::JSCallbackObject *object = // JSC::JSCallbackObject::create(this, this->callbackObjectStructure(), // jsClass, nullptr); // if (JSObject *prototype = jsClass->prototype(this)) object->setPrototypeDirect(vm, // prototype); // process->putDirect(this->vm, JSC::Identifier::fromString(this->vm, "env"), // JSC::JSValue(object), JSC::PropertyAttribute::DontDelete | 0); // } JSC::Identifier queueMicrotaskIdentifier = JSC::Identifier::fromString(vm, "queueMicrotask"_s); extraStaticGlobals.uncheckedAppend( GlobalPropertyInfo { queueMicrotaskIdentifier, JSC::JSFunction::create(vm, JSC::jsCast(globalObject()), 0, "queueMicrotask", functionQueueMicrotask), JSC::PropertyAttribute::DontDelete | 0 }); JSC::Identifier setTimeoutIdentifier = JSC::Identifier::fromString(vm, "setTimeout"_s); extraStaticGlobals.uncheckedAppend( GlobalPropertyInfo { setTimeoutIdentifier, JSC::JSFunction::create(vm, JSC::jsCast(globalObject()), 0, "setTimeout", functionSetTimeout), JSC::PropertyAttribute::DontDelete | 0 }); JSC::Identifier clearTimeoutIdentifier = JSC::Identifier::fromString(vm, "clearTimeout"_s); extraStaticGlobals.uncheckedAppend( GlobalPropertyInfo { clearTimeoutIdentifier, JSC::JSFunction::create(vm, JSC::jsCast(globalObject()), 0, "clearTimeout", functionClearTimeout), JSC::PropertyAttribute::DontDelete | 0 }); JSC::Identifier setIntervalIdentifier = JSC::Identifier::fromString(vm, "setInterval"_s); extraStaticGlobals.uncheckedAppend( GlobalPropertyInfo { setIntervalIdentifier, JSC::JSFunction::create(vm, JSC::jsCast(globalObject()), 0, "setInterval", functionSetInterval), JSC::PropertyAttribute::DontDelete | 0 }); JSC::Identifier clearIntervalIdentifier = JSC::Identifier::fromString(vm, "clearInterval"_s); extraStaticGlobals.uncheckedAppend( GlobalPropertyInfo { clearIntervalIdentifier, JSC::JSFunction::create(vm, JSC::jsCast(globalObject()), 0, "clearInterval", functionClearInterval), JSC::PropertyAttribute::DontDelete | 0 }); JSC::Identifier atobIdentifier = JSC::Identifier::fromString(vm, "atob"_s); extraStaticGlobals.uncheckedAppend( GlobalPropertyInfo { atobIdentifier, JSC::JSFunction::create(vm, JSC::jsCast(globalObject()), 0, "atob", functionATOB), JSC::PropertyAttribute::DontDelete | 0 }); JSC::Identifier btoaIdentifier = JSC::Identifier::fromString(vm, "btoa"_s); extraStaticGlobals.uncheckedAppend( GlobalPropertyInfo { btoaIdentifier, JSC::JSFunction::create(vm, JSC::jsCast(globalObject()), 0, "btoa", functionBTOA), JSC::PropertyAttribute::DontDelete | 0 }); JSC::Identifier reportErrorIdentifier = JSC::Identifier::fromString(vm, "reportError"_s); extraStaticGlobals.uncheckedAppend( GlobalPropertyInfo { reportErrorIdentifier, JSC::JSFunction::create(vm, JSC::jsCast(globalObject()), 0, "reportError", functionReportError), JSC::PropertyAttribute::DontDelete | 0 }); this->addStaticGlobals(extraStaticGlobals.data(), extraStaticGlobals.size()); putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "process"_s), JSC::CustomGetterSetter::create(vm, property_lazyProcessGetter, property_lazyProcessSetter), JSC::PropertyAttribute::CustomAccessor | 0); putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "URL"_s), JSC::CustomGetterSetter::create(vm, JSDOMURL_getter, nullptr), JSC::PropertyAttribute::DontDelete | 0); putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "URLSearchParams"_s), JSC::CustomGetterSetter::create(vm, JSURLSearchParams_getter, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "DOMException"_s), JSC::CustomGetterSetter::create(vm, JSDOMException_getter, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "Event"_s), JSC::CustomGetterSetter::create(vm, JSEvent_getter, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "EventTarget"_s), JSC::CustomGetterSetter::create(vm, JSEventTarget_getter, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "AbortController"_s), JSC::CustomGetterSetter::create(vm, JSDOMAbortController_getter, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "AbortSignal"_s), JSC::CustomGetterSetter::create(vm, JSDOMAbortSignal_getter, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "CustomEvent"_s), JSC::CustomGetterSetter::create(vm, JSCustomEvent_getter, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "Headers"_s), JSC::CustomGetterSetter::create(vm, JSFetchHeaders_getter, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "ErrorEvent"_s), JSC::CustomGetterSetter::create(vm, JSErrorEvent_getter, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); extraStaticGlobals.releaseBuffer(); this->setRemoteDebuggingEnabled(true); // auto& server = Inspector::RemoteInspectorServer::singleton(); // if (server.start("localhost", 9222)) { // } } template void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) { GlobalObject* thisObject = jsCast(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); Base::visitChildren(thisObject, visitor); { // The GC thread has to grab the GC lock even though it is not mutating the containers. Locker locker { thisObject->m_gcLock }; for (auto& structure : thisObject->m_structures.values()) visitor.append(structure); for (auto& guarded : thisObject->m_guardedObjects) guarded->visitAggregate(visitor); } for (auto& constructor : thisObject->constructors().array()) visitor.append(constructor); // thisObject->m_builtinInternalFunctions.visit(visitor); ScriptExecutionContext* context = thisObject->scriptExecutionContext(); visitor.addOpaqueRoot(context); } DEFINE_VISIT_CHILDREN(GlobalObject); // void GlobalObject::destroy(JSCell* cell) // { // static_cast(cell)->Zig::GlobalObject::~Zig::GlobalObject(); // } // template // void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) // { // Zig::GlobalObject* thisObject = jsCast(cell); // ASSERT_GC_OBJECT_INHERITS(thisObject, info()); // Base::visitChildren(thisObject, visitor); // { // // The GC thread has to grab the GC lock even though it is not mutating the containers. // Locker locker { thisObject->m_gcLock }; // for (auto& structure : thisObject->m_structures.values()) // visitor.append(structure); // for (auto& guarded : thisObject->m_guardedObjects) // guarded->visitAggregate(visitor); // } // for (auto& constructor : thisObject->constructors().array()) // visitor.append(constructor); // thisObject->m_builtinInternalFunctions.visit(visitor); // } // DEFINE_VISIT_CHILDREN(Zig::GlobalObject); JSC::Identifier GlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject, JSModuleLoader* loader, JSValue key, JSValue referrer, JSValue origin) { ErrorableZigString res; res.success = false; ZigString keyZ = toZigString(key, globalObject); ZigString referrerZ = referrer.isString() ? toZigString(referrer, globalObject) : ZigStringEmpty; Zig__GlobalObject__resolve(&res, globalObject, &keyZ, &referrerZ); if (res.success) { return toIdentifier(res.result.value, globalObject); } else { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); throwException(scope, res.result.err, globalObject); return globalObject->vm().propertyNames->emptyIdentifier; } } JSC::JSInternalPromise* GlobalObject::moduleLoaderImportModule(JSGlobalObject* globalObject, JSModuleLoader*, JSString* moduleNameValue, JSValue parameters, const SourceOrigin& sourceOrigin) { JSC::VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); auto* promise = JSC::JSInternalPromise::create(vm, globalObject->internalPromiseStructure()); RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope)); auto sourceURL = sourceOrigin.url(); ErrorableZigString resolved; auto moduleNameZ = toZigString(moduleNameValue, globalObject); auto sourceOriginZ = sourceURL.isEmpty() ? ZigStringCwd : toZigString(sourceURL.fileSystemPath()); resolved.success = false; Zig__GlobalObject__resolve(&resolved, globalObject, &moduleNameZ, &sourceOriginZ); if (!resolved.success) { throwException(scope, resolved.result.err, globalObject); return promise->rejectWithCaughtException(globalObject, scope); } auto result = JSC::importModule(globalObject, toIdentifier(resolved.result.value, globalObject), parameters, JSC::jsUndefined()); RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope)); return result; } JSC::JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalObject, JSModuleLoader* loader, JSValue key, JSValue value1, JSValue value2) { JSC::VM& vm = globalObject->vm(); JSC::JSInternalPromise* promise = JSC::JSInternalPromise::create(vm, globalObject->internalPromiseStructure()); auto scope = DECLARE_THROW_SCOPE(vm); auto rejectWithError = [&](JSC::JSValue error) { promise->reject(globalObject, error); return promise; }; auto moduleKey = key.toWTFString(globalObject); RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope)); auto moduleKeyZig = toZigString(moduleKey); auto source = Zig::toZigString(value1, globalObject); ErrorableResolvedSource res; res.success = false; res.result.err.code = 0; res.result.err.ptr = nullptr; Zig__GlobalObject__fetch(&res, globalObject, &moduleKeyZig, &source); if (!res.success) { throwException(scope, res.result.err, globalObject); RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope)); } if (res.result.value.tag == 1) { auto buffer = Vector(res.result.value.source_code.ptr, res.result.value.source_code.len); auto source = JSC::SourceCode( JSC::WebAssemblySourceProvider::create(WTFMove(buffer), JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(Zig::toString(res.result.value.source_url))), WTFMove(moduleKey))); auto sourceCode = JSSourceCode::create(vm, WTFMove(source)); RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope)); promise->resolve(globalObject, sourceCode); scope.release(); globalObject->vm().drainMicrotasks(); return promise; } else { auto provider = Zig::SourceProvider::create(res.result.value); auto jsSourceCode = JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)); promise->resolve(globalObject, jsSourceCode); } // if (provider.ptr()->isBytecodeCacheEnabled()) { // provider.ptr()->readOrGenerateByteCodeCache(vm, jsSourceCode->sourceCode()); // } scope.release(); globalObject->vm().drainMicrotasks(); return promise; } JSC::JSObject* GlobalObject::moduleLoaderCreateImportMetaProperties(JSGlobalObject* globalObject, JSModuleLoader* loader, JSValue key, JSModuleRecord* record, JSValue val) { JSC::VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSC::JSObject* metaProperties = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure()); RETURN_IF_EXCEPTION(scope, nullptr); auto clientData = WebCore::clientData(vm); JSString* keyString = key.toStringOrNull(globalObject); if (UNLIKELY(!keyString)) { return metaProperties; } auto view = keyString->value(globalObject); auto index = view.reverseFind('/', view.length()); if (index != WTF::notFound) { metaProperties->putDirect(vm, clientData->builtinNames().dirPublicName(), JSC::jsSubstring(globalObject, keyString, 0, index)); metaProperties->putDirect( vm, clientData->builtinNames().filePublicName(), JSC::jsSubstring(globalObject, keyString, index + 1, keyString->length() - index - 1)); metaProperties->putDirect( vm, clientData->builtinNames().filePublicName(), JSC::jsSubstring(globalObject, keyString, index + 1, keyString->length() - index - 1)); metaProperties->putDirect(vm, clientData->builtinNames().resolvePublicName(), JSC::JSFunction::create(vm, JSC::jsCast(globalObject), 0, WTF::String("resolve"_s), functionImportMeta__resolve), 0); } metaProperties->putDirect(vm, clientData->builtinNames().pathPublicName(), key); metaProperties->putDirect(vm, clientData->builtinNames().urlPublicName(), JSC::JSValue(JSC::jsString(vm, WTF::URL::fileURLWithFileSystemPath(view).string()))); RETURN_IF_EXCEPTION(scope, nullptr); return metaProperties; } JSC::JSValue GlobalObject::moduleLoaderEvaluate(JSGlobalObject* globalObject, JSModuleLoader* moduleLoader, JSValue key, JSValue moduleRecordValue, JSValue scriptFetcher, JSValue sentValue, JSValue resumeMode) { JSC::JSValue result = moduleLoader->evaluateNonVirtual(globalObject, key, moduleRecordValue, scriptFetcher, sentValue, resumeMode); return result; } void GlobalObject::queueMicrotaskToEventLoop(JSC::JSGlobalObject& global, Ref&& task) { Zig__GlobalObject__queueMicrotaskToEventLoop( &global, &JSMicrotaskCallback::create(global, WTFMove(task)).leakRef()); } } // namespace Zig