#include "root.h" #include "_NativeModule.h" #include "ExceptionOr.h" #include "JavaScriptCore/CallData.h" #include "JavaScriptCore/ArgList.h" #include "JavaScriptCore/ExceptionScope.h" #include "JavaScriptCore/JSCJSValue.h" #include "JavaScriptCore/JSGlobalObject.h" #include "JavaScriptCore/JSNativeStdFunction.h" #include "MessagePort.h" #include "SerializedScriptValue.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BunProcess.h" #include #if ENABLE(REMOTE_INSPECTOR) #include #endif #include "JSDOMConvertBase.h" #include "ZigSourceProvider.h" #include "mimalloc.h" #include #if OS(DARWIN) #if ASSERT_ENABLED #if !__has_feature(address_sanitizer) #include #define IS_MALLOC_DEBUGGING_ENABLED 1 #endif #endif #endif using namespace JSC; using namespace WTF; using namespace WebCore; JSC_DECLARE_HOST_FUNCTION(functionStartRemoteDebugger); JSC_DEFINE_HOST_FUNCTION(functionStartRemoteDebugger, (JSGlobalObject * globalObject, CallFrame* callFrame)) { #if ENABLE(REMOTE_INSPECTOR) static const char* defaultHost = "127.0.0.1\0"; static uint16_t defaultPort = 9230; // node + 1 auto& vm = JSC::getVM(globalObject); auto scope = DECLARE_THROW_SCOPE(vm); JSC::JSValue hostValue = callFrame->argument(0); JSC::JSValue portValue = callFrame->argument(1); const char* host = defaultHost; if (hostValue.isString()) { auto str = hostValue.toWTFString(globalObject); if (!str.isEmpty()) host = toCString(str).span().data(); } else if (!hostValue.isUndefined()) { throwVMError(globalObject, scope, createTypeError(globalObject, "host must be a string"_s)); return JSC::JSValue::encode(JSC::jsUndefined()); } uint16_t port = defaultPort; if (portValue.isNumber()) { auto port_int = portValue.toUInt32(globalObject); if (!(port_int > 0 && port_int < 65536)) { throwVMError( globalObject, scope, createRangeError(globalObject, "port must be between 0 and 65535"_s)); return JSC::JSValue::encode(JSC::jsUndefined()); } port = port_int; } else if (!portValue.isUndefined()) { throwVMError( globalObject, scope, createTypeError(globalObject, "port must be a number between 0 and 65535"_s)); return JSC::JSValue::encode(JSC::jsUndefined()); } globalObject->setInspectable(true); auto& server = Inspector::RemoteInspectorServer::singleton(); if (!server.start(reinterpret_cast(host), port)) { throwVMError( globalObject, scope, createError(globalObject, makeString("Failed to start server \""_s, reinterpret_cast(host), ":"_s, port, "\". Is port already in use?"_s))); return JSC::JSValue::encode(JSC::jsUndefined()); } RELEASE_AND_RETURN(scope, JSC::JSValue::encode(JSC::jsUndefined())); #else auto& vm = JSC::getVM(globalObject); auto scope = DECLARE_THROW_SCOPE(vm); throwVMError(globalObject, scope, createTypeError( globalObject, "Remote inspector is not enabled in this build of Bun"_s)); return JSC::JSValue::encode(JSC::jsUndefined()); #endif } JSC_DECLARE_HOST_FUNCTION(functionDescribe); JSC_DEFINE_HOST_FUNCTION(functionDescribe, (JSGlobalObject * globalObject, CallFrame* callFrame)) { VM& vm = globalObject->vm(); if (callFrame->argumentCount() < 1) return JSValue::encode(jsUndefined()); return JSValue::encode(jsString(vm, toString(callFrame->argument(0)))); } JSC_DECLARE_HOST_FUNCTION(functionDescribeArray); JSC_DEFINE_HOST_FUNCTION(functionDescribeArray, (JSGlobalObject * globalObject, CallFrame* callFrame)) { if (callFrame->argumentCount() < 1) return JSValue::encode(jsUndefined()); VM& vm = globalObject->vm(); JSObject* object = jsDynamicCast(callFrame->argument(0)); if (!object) return JSValue::encode(jsNontrivialString(vm, ""_s)); return JSValue::encode(jsNontrivialString( vm, toString("butterfly()), "; public length: ", object->getArrayLength(), "; vector length: ", object->getVectorLength(), ">"))); } JSC_DECLARE_HOST_FUNCTION(functionGCAndSweep); JSC_DEFINE_HOST_FUNCTION(functionGCAndSweep, (JSGlobalObject * globalObject, CallFrame*)) { VM& vm = globalObject->vm(); JSLockHolder lock(vm); vm.heap.collectNow(Sync, CollectionScope::Full); return JSValue::encode(jsNumber(vm.heap.sizeAfterLastFullCollection())); } JSC_DECLARE_HOST_FUNCTION(functionFullGC); JSC_DEFINE_HOST_FUNCTION(functionFullGC, (JSGlobalObject * globalObject, CallFrame*)) { VM& vm = globalObject->vm(); JSLockHolder lock(vm); vm.heap.collectSync(CollectionScope::Full); return JSValue::encode(jsNumber(vm.heap.sizeAfterLastFullCollection())); } JSC_DECLARE_HOST_FUNCTION(functionEdenGC); JSC_DEFINE_HOST_FUNCTION(functionEdenGC, (JSGlobalObject * globalObject, CallFrame*)) { VM& vm = globalObject->vm(); JSLockHolder lock(vm); vm.heap.collectSync(CollectionScope::Eden); return JSValue::encode(jsNumber(vm.heap.sizeAfterLastEdenCollection())); } JSC_DECLARE_HOST_FUNCTION(functionHeapSize); JSC_DEFINE_HOST_FUNCTION(functionHeapSize, (JSGlobalObject * globalObject, CallFrame*)) { VM& vm = globalObject->vm(); JSLockHolder lock(vm); return JSValue::encode(jsNumber(vm.heap.size())); } JSC::Structure* createMemoryFootprintStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject) { JSC::Structure* structure = globalObject->structureCache().emptyObjectStructureForPrototype( globalObject, globalObject->objectPrototype(), 5); JSC::PropertyOffset offset; structure = structure->addPropertyTransition( vm, structure, Identifier::fromString(vm, "current"_s), 0, offset); structure = structure->addPropertyTransition( vm, structure, Identifier::fromString(vm, "peak"_s), 0, offset); structure = structure->addPropertyTransition( vm, structure, Identifier::fromString(vm, "currentCommit"_s), 0, offset); structure = structure->addPropertyTransition( vm, structure, Identifier::fromString(vm, "peakCommit"_s), 0, offset); structure = structure->addPropertyTransition( vm, structure, Identifier::fromString(vm, "pageFaults"_s), 0, offset); return structure; } JSC_DECLARE_HOST_FUNCTION(functionMemoryUsageStatistics); JSC_DEFINE_HOST_FUNCTION(functionMemoryUsageStatistics, (JSGlobalObject * globalObject, CallFrame*)) { auto& vm = JSC::getVM(globalObject); if (vm.heap.size() == 0) { vm.heap.collectNow(Sync, CollectionScope::Full); } const auto createdSortedTypeCounts = [&](JSC::TypeCountSet* typeCounts) -> JSC::JSValue { WTF::Vector> counts; counts.reserveInitialCapacity(typeCounts->size()); for (auto& it : *typeCounts) { if (it.value > 0) counts.append( std::make_pair(Identifier::fromString(vm, it.key), it.value)); } // Sort by count first, then by name. std::sort(counts.begin(), counts.end(), [](const std::pair& a, const std::pair& b) { if (a.second == b.second) { WTF::StringView left = a.first.string(); WTF::StringView right = b.first.string(); unsigned originalLeftLength = left.length(); unsigned originalRightLength = right.length(); unsigned size = std::min(left.length(), right.length()); left = left.substring(0, size); right = right.substring(0, size); std::strong_ordering result = WTF::codePointCompare(right, left); if (result == std::strong_ordering::equal) { return originalLeftLength > originalRightLength; } return result == std::strong_ordering::greater; } return a.second > b.second; }); auto* objectTypeCounts = constructEmptyObject(globalObject); for (auto& it : counts) { objectTypeCounts->putDirect(vm, it.first, jsNumber(it.second)); } return objectTypeCounts; }; JSValue objectTypeCounts = createdSortedTypeCounts(vm.heap.objectTypeCounts().get()); JSValue protectedCounts = createdSortedTypeCounts(vm.heap.protectedObjectTypeCounts().get()); JSObject* object = constructEmptyObject(globalObject); object->putDirect(vm, Identifier::fromString(vm, "objectTypeCounts"_s), objectTypeCounts); object->putDirect(vm, Identifier::fromString(vm, "protectedObjectTypeCounts"_s), protectedCounts); object->putDirect(vm, Identifier::fromString(vm, "heapSize"_s), jsNumber(vm.heap.size())); object->putDirect(vm, Identifier::fromString(vm, "heapCapacity"_s), jsNumber(vm.heap.capacity())); object->putDirect(vm, Identifier::fromString(vm, "extraMemorySize"_s), jsNumber(vm.heap.extraMemorySize())); object->putDirect(vm, Identifier::fromString(vm, "objectCount"_s), jsNumber(vm.heap.objectCount())); object->putDirect(vm, Identifier::fromString(vm, "protectedObjectCount"_s), jsNumber(vm.heap.protectedObjectCount())); object->putDirect(vm, Identifier::fromString(vm, "globalObjectCount"_s), jsNumber(vm.heap.globalObjectCount())); object->putDirect(vm, Identifier::fromString(vm, "protectedGlobalObjectCount"_s), jsNumber(vm.heap.protectedGlobalObjectCount())); #if IS_MALLOC_DEBUGGING_ENABLED #if OS(DARWIN) { vm_address_t* zones; unsigned count; // Zero out the structures in case a zone is missing malloc_statistics_t zone_stats; zone_stats.blocks_in_use = 0; zone_stats.size_in_use = 0; zone_stats.max_size_in_use = 0; zone_stats.size_allocated = 0; malloc_zone_pressure_relief(nullptr, 0); malloc_get_all_zones(mach_task_self(), 0, &zones, &count); Vector> zoneSizes; zoneSizes.reserveInitialCapacity(count); for (unsigned i = 0; i < count; i++) { auto zone = reinterpret_cast(zones[i]); if (const char* name = malloc_get_zone_name(zone)) { malloc_zone_statistics(reinterpret_cast(zones[i]), &zone_stats); zoneSizes.append( std::make_pair(Identifier::fromString(vm, String::fromUTF8(name)), zone_stats.size_in_use)); } } std::sort(zoneSizes.begin(), zoneSizes.end(), [](const std::pair& a, const std::pair& b) { // Sort by name if the sizes are the same. if (a.second == b.second) { WTF::StringView left = a.first.string(); WTF::StringView right = b.first.string(); unsigned originalLeftLength = left.length(); unsigned originalRightLength = right.length(); unsigned size = std::min(left.length(), right.length()); left = left.substring(0, size); right = right.substring(0, size); std::strong_ordering result = WTF::codePointCompare(right, left); if (result == std::strong_ordering::equal) { return originalLeftLength > originalRightLength; } return result == std::strong_ordering::greater; } return a.second > b.second; }); auto* zoneSizesObject = constructEmptyObject(globalObject); for (auto& it : zoneSizes) { zoneSizesObject->putDirect(vm, it.first, jsDoubleNumber(it.second)); } object->putDirect(vm, Identifier::fromString(vm, "zones"_s), zoneSizesObject); } #endif #endif return JSValue::encode(object); } JSC_DECLARE_HOST_FUNCTION(functionCreateMemoryFootprint); JSC_DEFINE_HOST_FUNCTION(functionCreateMemoryFootprint, (JSGlobalObject * globalObject, CallFrame*)) { size_t elapsed_msecs = 0; size_t user_msecs = 0; size_t system_msecs = 0; size_t current_rss = 0; size_t peak_rss = 0; size_t current_commit = 0; size_t peak_commit = 0; size_t page_faults = 0; mi_process_info(&elapsed_msecs, &user_msecs, &system_msecs, ¤t_rss, &peak_rss, ¤t_commit, &peak_commit, &page_faults); // mi_process_info produces incorrect rss size on linux. Bun::getRSS(¤t_rss); VM& vm = globalObject->vm(); JSC::JSObject* object = JSC::constructEmptyObject( vm, JSC::jsCast(globalObject)->memoryFootprintStructure()); object->putDirectOffset(vm, 0, jsNumber(current_rss)); object->putDirectOffset(vm, 1, jsNumber(peak_rss)); object->putDirectOffset(vm, 2, jsNumber(current_commit)); object->putDirectOffset(vm, 3, jsNumber(peak_commit)); object->putDirectOffset(vm, 4, jsNumber(page_faults)); return JSValue::encode(object); } JSC_DECLARE_HOST_FUNCTION(functionNeverInlineFunction); JSC_DEFINE_HOST_FUNCTION(functionNeverInlineFunction, (JSGlobalObject * globalObject, CallFrame* callFrame)) { return JSValue::encode(setNeverInline(globalObject, callFrame)); } extern "C" bool Bun__mkdirp(JSC::JSGlobalObject*, const char*); JSC_DECLARE_HOST_FUNCTION(functionStartSamplingProfiler); JSC_DEFINE_HOST_FUNCTION(functionStartSamplingProfiler, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { auto& vm = JSC::getVM(globalObject); JSC::SamplingProfiler& samplingProfiler = vm.ensureSamplingProfiler(WTF::Stopwatch::create()); JSC::JSValue directoryValue = callFrame->argument(0); JSC::JSValue sampleValue = callFrame->argument(1); auto scope = DECLARE_THROW_SCOPE(vm); if (directoryValue.isString()) { auto path = directoryValue.toWTFString(globalObject); if (!path.isEmpty()) { StringPrintStream pathOut; auto pathCString = toCString(String(path)); if (!Bun__mkdirp(globalObject, pathCString.span().data())) { throwVMError( globalObject, scope, createTypeError(globalObject, "directory couldn't be created"_s)); return {}; } Options::samplingProfilerPath() = pathCString.span().data(); samplingProfiler.registerForReportAtExit(); } } if (sampleValue.isNumber()) { unsigned sampleInterval = sampleValue.toUInt32(globalObject); samplingProfiler.setTimingInterval( Seconds::fromMicroseconds(sampleInterval)); } samplingProfiler.noticeCurrentThreadAsJSCExecutionThread(); samplingProfiler.start(); return JSC::JSValue::encode(jsUndefined()); } JSC_DECLARE_HOST_FUNCTION(functionSamplingProfilerStackTraces); JSC_DEFINE_HOST_FUNCTION(functionSamplingProfilerStackTraces, (JSC::JSGlobalObject * globalObject, JSC::CallFrame*)) { auto& vm = JSC::getVM(globalObject); JSC::DeferTermination deferScope(vm); auto scope = DECLARE_THROW_SCOPE(vm); if (!vm.samplingProfiler()) return JSC::JSValue::encode(throwException( globalObject, scope, createError(globalObject, "Sampling profiler was never started"_s))); WTF::String jsonString = vm.samplingProfiler()->stackTracesAsJSON()->toJSONString(); JSC::EncodedJSValue result = JSC::JSValue::encode(JSONParse(globalObject, jsonString)); scope.releaseAssertNoException(); return result; } JSC_DECLARE_HOST_FUNCTION(functionGetRandomSeed); JSC_DEFINE_HOST_FUNCTION(functionGetRandomSeed, (JSGlobalObject * globalObject, CallFrame*)) { return JSValue::encode(jsNumber(globalObject->weakRandom().seed())); } JSC_DECLARE_HOST_FUNCTION(functionSetRandomSeed); JSC_DEFINE_HOST_FUNCTION(functionSetRandomSeed, (JSGlobalObject * globalObject, CallFrame* callFrame)) { VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); unsigned seed = callFrame->argument(0).toUInt32(globalObject); RETURN_IF_EXCEPTION(scope, {}); globalObject->weakRandom().setSeed(seed); return JSValue::encode(jsUndefined()); } JSC_DECLARE_HOST_FUNCTION(functionIsRope); JSC_DEFINE_HOST_FUNCTION(functionIsRope, (JSGlobalObject*, CallFrame* callFrame)) { JSValue argument = callFrame->argument(0); if (!argument.isString()) return JSValue::encode(jsBoolean(false)); const StringImpl* impl = asString(argument)->tryGetValueImpl(); return JSValue::encode(jsBoolean(!impl)); } JSC_DECLARE_HOST_FUNCTION(functionCallerSourceOrigin); JSC_DEFINE_HOST_FUNCTION(functionCallerSourceOrigin, (JSGlobalObject * globalObject, CallFrame* callFrame)) { VM& vm = globalObject->vm(); SourceOrigin sourceOrigin = callFrame->callerSourceOrigin(vm); if (sourceOrigin.url().isNull()) return JSValue::encode(jsNull()); return JSValue::encode(jsString(vm, sourceOrigin.string())); } JSC_DECLARE_HOST_FUNCTION(functionNoFTL); JSC_DEFINE_HOST_FUNCTION(functionNoFTL, (JSGlobalObject*, CallFrame* callFrame)) { if (callFrame->argumentCount()) { FunctionExecutable* executable = getExecutableForFunction(callFrame->argument(0)); if (executable) executable->setNeverFTLOptimize(true); } return JSValue::encode(jsUndefined()); } JSC_DECLARE_HOST_FUNCTION(functionNoOSRExitFuzzing); JSC_DEFINE_HOST_FUNCTION(functionNoOSRExitFuzzing, (JSGlobalObject * globalObject, CallFrame* callFrame)) { return JSValue::encode(setCannotUseOSRExitFuzzing(globalObject, callFrame)); } JSC_DECLARE_HOST_FUNCTION(functionOptimizeNextInvocation); JSC_DEFINE_HOST_FUNCTION(functionOptimizeNextInvocation, (JSGlobalObject * globalObject, CallFrame* callFrame)) { return JSValue::encode(optimizeNextInvocation(globalObject, callFrame)); } JSC_DECLARE_HOST_FUNCTION(functionNumberOfDFGCompiles); JSC_DEFINE_HOST_FUNCTION(functionNumberOfDFGCompiles, (JSGlobalObject * globalObject, CallFrame* callFrame)) { return JSValue::encode(numberOfDFGCompiles(globalObject, callFrame)); } JSC_DECLARE_HOST_FUNCTION(functionReleaseWeakRefs); JSC_DEFINE_HOST_FUNCTION(functionReleaseWeakRefs, (JSGlobalObject * globalObject, CallFrame* callFrame)) { globalObject->vm().finalizeSynchronousJSExecution(); return JSValue::encode(jsUndefined()); } JSC_DECLARE_HOST_FUNCTION(functionTotalCompileTime); JSC_DEFINE_HOST_FUNCTION(functionTotalCompileTime, (JSGlobalObject*, CallFrame*)) { return JSValue::encode(jsNumber(JIT::totalCompileTime().milliseconds())); } JSC_DECLARE_HOST_FUNCTION(functionGetProtectedObjects); JSC_DEFINE_HOST_FUNCTION(functionGetProtectedObjects, (JSGlobalObject * globalObject, CallFrame*)) { MarkedArgumentBuffer list; globalObject->vm().heap.forEachProtectedCell( [&](JSCell* cell) { list.append(cell); }); RELEASE_ASSERT(!list.hasOverflowed()); return JSC::JSValue::encode(constructArray( globalObject, static_cast(nullptr), list)); } JSC_DECLARE_HOST_FUNCTION(functionReoptimizationRetryCount); JSC_DEFINE_HOST_FUNCTION(functionReoptimizationRetryCount, (JSGlobalObject*, CallFrame* callFrame)) { if (callFrame->argumentCount() < 1) return JSValue::encode(jsUndefined()); CodeBlock* block = getSomeBaselineCodeBlockForFunction(callFrame->argument(0)); if (!block) return JSValue::encode(jsNumber(0)); return JSValue::encode(jsNumber(block->reoptimizationRetryCounter())); } extern "C" void Bun__drainMicrotasks(); JSC_DECLARE_HOST_FUNCTION(functionDrainMicrotasks); JSC_DEFINE_HOST_FUNCTION(functionDrainMicrotasks, (JSGlobalObject * globalObject, CallFrame*)) { VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); vm.drainMicrotasks(); RETURN_IF_EXCEPTION(scope, {}); Bun__drainMicrotasks(); RETURN_IF_EXCEPTION(scope, {}); return JSValue::encode(jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(functionSetTimeZone, (JSGlobalObject * globalObject, CallFrame* callFrame)) { VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (callFrame->argumentCount() < 1) { throwTypeError(globalObject, scope, "setTimeZone requires a timezone string"_s); return {}; } if (!callFrame->argument(0).isString()) { throwTypeError(globalObject, scope, "setTimeZone requires a timezone string"_s); return {}; } String timeZoneName = callFrame->argument(0).toWTFString(globalObject); RETURN_IF_EXCEPTION(scope, {}); if (!WTF::setTimeZoneOverride(timeZoneName)) { throwTypeError(globalObject, scope, makeString("Invalid timezone: \""_s, timeZoneName, "\""_s)); return {}; } vm.dateCache.resetIfNecessarySlow(); WTF::Vector buffer; WTF::getTimeZoneOverride(buffer); WTF::String timeZoneString(buffer.span()); return JSValue::encode(jsString(vm, timeZoneString)); } JSC_DEFINE_HOST_FUNCTION(functionRunProfiler, (JSGlobalObject * globalObject, CallFrame* callFrame)) { auto& vm = JSC::getVM(globalObject); JSC::SamplingProfiler& samplingProfiler = vm.ensureSamplingProfiler(WTF::Stopwatch::create()); JSC::JSValue callbackValue = callFrame->argument(0); JSC::JSValue sampleValue = callFrame->argument(1); MarkedArgumentBuffer args; if (callFrame->argumentCount() > 2) { size_t count = callFrame->argumentCount(); args.ensureCapacity(count - 2); for (size_t i = 2; i < count; i++) { args.append(callFrame->argument(i)); } } auto throwScope = DECLARE_THROW_SCOPE(vm); if (callbackValue.isUndefinedOrNull() || !callbackValue.isCallable()) { throwException( globalObject, throwScope, createTypeError(globalObject, "First argument must be a function."_s)); return JSValue::encode(JSValue {}); } JSC::JSFunction* function = jsCast(callbackValue); if (sampleValue.isNumber()) { unsigned sampleInterval = sampleValue.toUInt32(globalObject); samplingProfiler.setTimingInterval( Seconds::fromMicroseconds(sampleInterval)); } const auto report = [](JSC::VM& vm, JSC::JSGlobalObject* globalObject) -> JSC::JSValue { auto throwScope = DECLARE_THROW_SCOPE(vm); auto& samplingProfiler = *vm.samplingProfiler(); StringPrintStream topFunctions; samplingProfiler.reportTopFunctions(topFunctions); StringPrintStream byteCodes; samplingProfiler.reportTopBytecodes(byteCodes); JSValue stackTraces = JSONParse( globalObject, samplingProfiler.stackTracesAsJSON()->toJSONString()); samplingProfiler.shutdown(); RETURN_IF_EXCEPTION(throwScope, {}); JSObject* result = constructEmptyObject(globalObject, globalObject->objectPrototype(), 3); result->putDirect(vm, Identifier::fromString(vm, "functions"_s), jsString(vm, topFunctions.toString())); result->putDirect(vm, Identifier::fromString(vm, "bytecodes"_s), jsString(vm, byteCodes.toString())); result->putDirect(vm, Identifier::fromString(vm, "stackTraces"_s), stackTraces); return result; }; const auto reportFailure = [](JSC::VM& vm) -> JSC::JSValue { if (auto* samplingProfiler = vm.samplingProfiler()) { samplingProfiler->pause(); samplingProfiler->shutdown(); samplingProfiler->clearData(); } return {}; }; JSC::CallData callData = JSC::getCallData(function); samplingProfiler.noticeCurrentThreadAsJSCExecutionThread(); samplingProfiler.start(); JSValue returnValue = JSC::profiledCall(globalObject, ProfilingReason::API, function, callData, JSC::jsUndefined(), args); if (returnValue.isEmpty() || throwScope.exception()) { return JSValue::encode(reportFailure(vm)); } if (auto* promise = jsDynamicCast(returnValue)) { auto afterOngoingPromiseCapability = JSC::JSPromise::create(vm, globalObject->promiseStructure()); RETURN_IF_EXCEPTION(throwScope, {}); JSNativeStdFunction* resolve = JSNativeStdFunction::create( vm, globalObject, 0, "resolve"_s, [report](JSGlobalObject* globalObject, CallFrame* callFrame) { return JSValue::encode(JSPromise::resolvedPromise( globalObject, report(globalObject->vm(), globalObject))); }); JSNativeStdFunction* reject = JSNativeStdFunction::create( vm, globalObject, 0, "reject"_s, [reportFailure](JSGlobalObject* globalObject, CallFrame* callFrame) { EnsureStillAliveScope error = callFrame->argument(0); auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); reportFailure(globalObject->vm()); throwException(globalObject, scope, error.value()); return JSValue::encode({}); }); promise->performPromiseThen(globalObject, resolve, reject, afterOngoingPromiseCapability); return JSValue::encode(afterOngoingPromiseCapability); } return JSValue::encode(report(vm, globalObject)); } JSC_DECLARE_HOST_FUNCTION(functionGenerateHeapSnapshotForDebugging); JSC_DEFINE_HOST_FUNCTION(functionGenerateHeapSnapshotForDebugging, (JSGlobalObject * globalObject, CallFrame*)) { VM& vm = globalObject->vm(); JSLockHolder lock(vm); DeferTermination deferScope(vm); auto scope = DECLARE_THROW_SCOPE(vm); String jsonString; { DeferGCForAWhile deferGC(vm); // Prevent concurrent GC from interfering with // the full GC that the snapshot does. HeapSnapshotBuilder snapshotBuilder( vm.ensureHeapProfiler(), HeapSnapshotBuilder::SnapshotType::GCDebuggingSnapshot); snapshotBuilder.buildSnapshot(); jsonString = snapshotBuilder.json(); } scope.releaseAssertNoException(); return JSValue::encode(JSONParse(globalObject, WTFMove(jsonString))); } JSC_DEFINE_HOST_FUNCTION(functionSerialize, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) { auto* globalObject = jsCast(lexicalGlobalObject); auto& vm = JSC::getVM(globalObject); auto throwScope = DECLARE_THROW_SCOPE(vm); JSValue value = callFrame->argument(0); JSValue optionsObject = callFrame->argument(1); bool asNodeBuffer = false; if (optionsObject.isObject()) { JSC::JSObject* options = optionsObject.getObject(); auto binaryTypeValue = options->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "binaryType"_s)); RETURN_IF_EXCEPTION(throwScope, {}); if (binaryTypeValue) { if (!binaryTypeValue.isString()) { throwTypeError(globalObject, throwScope, "binaryType must be a string"_s); return {}; } asNodeBuffer = binaryTypeValue.toWTFString(globalObject) == "nodebuffer"_s; RETURN_IF_EXCEPTION(throwScope, {}); } } Vector> transferList; Vector> dummyPorts; ExceptionOr> serialized = SerializedScriptValue::create(*globalObject, value, WTFMove(transferList), dummyPorts); if (serialized.hasException()) { WebCore::propagateException(*globalObject, throwScope, serialized.releaseException()); RELEASE_AND_RETURN(throwScope, {}); } auto serializedValue = serialized.releaseReturnValue(); auto arrayBuffer = serializedValue->toArrayBuffer(); if (asNodeBuffer) { size_t byteLength = arrayBuffer->byteLength(); auto* subclassStructure = globalObject->JSBufferSubclassStructure(); JSC::JSUint8Array* uint8Array = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, WTFMove(arrayBuffer), 0, byteLength); return JSValue::encode(uint8Array); } if (arrayBuffer->isShared()) { return JSValue::encode( JSArrayBuffer::create(vm, globalObject->arrayBufferStructureWithSharingMode< ArrayBufferSharingMode::Shared>(), WTFMove(arrayBuffer))); } return JSValue::encode(JSArrayBuffer::create( vm, globalObject->arrayBufferStructure(), WTFMove(arrayBuffer))); } JSC_DEFINE_HOST_FUNCTION(functionDeserialize, (JSGlobalObject * globalObject, CallFrame* callFrame)) { auto& vm = JSC::getVM(globalObject); auto throwScope = DECLARE_THROW_SCOPE(vm); JSValue value = callFrame->argument(0); JSValue result; if (auto* jsArrayBuffer = jsDynamicCast(value)) { result = SerializedScriptValue::fromArrayBuffer( *globalObject, globalObject, jsArrayBuffer->impl(), 0, jsArrayBuffer->impl()->byteLength()); } else if (auto* view = jsDynamicCast(value)) { auto arrayBuffer = view->possiblySharedImpl()->possiblySharedBuffer(); result = SerializedScriptValue::fromArrayBuffer( *globalObject, globalObject, arrayBuffer.get(), view->byteOffset(), view->byteLength()); } else { throwTypeError(globalObject, throwScope, "First argument must be an ArrayBuffer"_s); return {}; } RETURN_IF_EXCEPTION(throwScope, {}); RELEASE_AND_RETURN(throwScope, JSValue::encode(result)); } extern "C" JSC::EncodedJSValue ByteRangeMapping__findExecutedLines( JSC::JSGlobalObject*, BunString sourceURL, BasicBlockRange* ranges, size_t len, size_t functionOffset, bool ignoreSourceMap); JSC_DEFINE_HOST_FUNCTION(functionCodeCoverageForFile, (JSGlobalObject * globalObject, CallFrame* callFrame)) { VM& vm = globalObject->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); String fileName = callFrame->argument(0).toWTFString(globalObject); RETURN_IF_EXCEPTION(throwScope, {}); bool ignoreSourceMap = callFrame->argument(1).toBoolean(globalObject); auto sourceID = Zig::sourceIDForSourceURL(fileName); if (!sourceID) { throwException(globalObject, throwScope, createError(globalObject, "No source for file"_s)); return {}; } auto basicBlocks = vm.controlFlowProfiler()->getBasicBlocksForSourceIDWithoutFunctionRange( sourceID, vm); if (basicBlocks.isEmpty()) { return JSC::JSValue::encode( JSC::constructEmptyArray(globalObject, nullptr, 0)); } size_t functionStartOffset = basicBlocks.size(); const Vector>& functionRanges = vm.functionHasExecutedCache()->getFunctionRanges(sourceID); basicBlocks.reserveCapacity(functionRanges.size() + basicBlocks.size()); for (const auto& functionRange : functionRanges) { BasicBlockRange range; range.m_hasExecuted = std::get<0>(functionRange); range.m_startOffset = static_cast(std::get<1>(functionRange)); range.m_endOffset = static_cast(std::get<2>(functionRange)); range.m_executionCount = range.m_hasExecuted ? 1 : 0; // This is a hack. We don't actually count this. basicBlocks.append(range); } return ByteRangeMapping__findExecutedLines( globalObject, Bun::toString(fileName), basicBlocks.begin(), basicBlocks.size(), functionStartOffset, ignoreSourceMap); } JSC_DEFINE_HOST_FUNCTION(functionEstimateDirectMemoryUsageOf, (JSGlobalObject * globalObject, CallFrame* callFrame)) { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); JSValue value = callFrame->argument(0); if (value.isCell()) { auto& vm = JSC::getVM(globalObject); EnsureStillAliveScope alive = value; return JSValue::encode(jsDoubleNumber(alive.value().asCell()->estimatedSizeInBytes(vm))); } return JSValue::encode(jsNumber(0)); } #if USE(BMALLOC_MEMORY_FOOTPRINT_API) #include JSC_DEFINE_HOST_FUNCTION(functionPercentAvailableMemoryInUse, (JSGlobalObject * globalObject, CallFrame* callFrame)) { return JSValue::encode(jsDoubleNumber(bmalloc::api::percentAvailableMemoryInUse())); } #else JSC_DEFINE_HOST_FUNCTION(functionPercentAvailableMemoryInUse, (JSGlobalObject * globalObject, CallFrame* callFrame)) { return JSValue::encode(jsNull()); } #endif // clang-format off /* Source for BunJSCModuleTable.lut.h @begin BunJSCModuleTable callerSourceOrigin functionCallerSourceOrigin Function 0 jscDescribe functionDescribe Function 0 jscDescribeArray functionDescribeArray Function 0 drainMicrotasks functionDrainMicrotasks Function 0 edenGC functionEdenGC Function 0 fullGC functionFullGC Function 0 gcAndSweep functionGCAndSweep Function 0 getRandomSeed functionGetRandomSeed Function 0 heapSize functionHeapSize Function 0 heapStats functionMemoryUsageStatistics Function 0 startSamplingProfiler functionStartSamplingProfiler Function 0 samplingProfilerStackTraces functionSamplingProfilerStackTraces Function 0 noInline functionNeverInlineFunction Function 0 isRope functionIsRope Function 0 memoryUsage functionCreateMemoryFootprint Function 0 noFTL functionNoFTL Function 0 noOSRExitFuzzing functionNoOSRExitFuzzing Function 0 numberOfDFGCompiles functionNumberOfDFGCompiles Function 0 optimizeNextInvocation functionOptimizeNextInvocation Function 0 releaseWeakRefs functionReleaseWeakRefs Function 0 reoptimizationRetryCount functionReoptimizationRetryCount Function 0 setRandomSeed functionSetRandomSeed Function 0 startRemoteDebugger functionStartRemoteDebugger Function 0 totalCompileTime functionTotalCompileTime Function 0 getProtectedObjects functionGetProtectedObjects Function 0 generateHeapSnapshotForDebugging functionGenerateHeapSnapshotForDebugging Function 0 profile functionRunProfiler Function 0 setTimeZone functionSetTimeZone Function 0 serialize functionSerialize Function 0 deserialize functionDeserialize Function 0 estimateShallowMemoryUsageOf functionEstimateDirectMemoryUsageOf Function 1 percentAvailableMemoryInUse functionPercentAvailableMemoryInUse Function 0 @end */ namespace Zig { DEFINE_NATIVE_MODULE(BunJSC) { INIT_NATIVE_MODULE(36); putNativeFn(Identifier::fromString(vm, "callerSourceOrigin"_s), functionCallerSourceOrigin); putNativeFn(Identifier::fromString(vm, "jscDescribe"_s), functionDescribe); putNativeFn(Identifier::fromString(vm, "jscDescribeArray"_s), functionDescribeArray); putNativeFn(Identifier::fromString(vm, "drainMicrotasks"_s), functionDrainMicrotasks); putNativeFn(Identifier::fromString(vm, "edenGC"_s), functionEdenGC); putNativeFn(Identifier::fromString(vm, "fullGC"_s), functionFullGC); putNativeFn(Identifier::fromString(vm, "gcAndSweep"_s), functionGCAndSweep); putNativeFn(Identifier::fromString(vm, "getRandomSeed"_s), functionGetRandomSeed); putNativeFn(Identifier::fromString(vm, "heapSize"_s), functionHeapSize); putNativeFn(Identifier::fromString(vm, "heapStats"_s), functionMemoryUsageStatistics); putNativeFn(Identifier::fromString(vm, "startSamplingProfiler"_s), functionStartSamplingProfiler); putNativeFn(Identifier::fromString(vm, "samplingProfilerStackTraces"_s), functionSamplingProfilerStackTraces); putNativeFn(Identifier::fromString(vm, "noInline"_s), functionNeverInlineFunction); putNativeFn(Identifier::fromString(vm, "isRope"_s), functionIsRope); putNativeFn(Identifier::fromString(vm, "memoryUsage"_s), functionCreateMemoryFootprint); putNativeFn(Identifier::fromString(vm, "noFTL"_s), functionNoFTL); putNativeFn(Identifier::fromString(vm, "noOSRExitFuzzing"_s), functionNoOSRExitFuzzing); putNativeFn(Identifier::fromString(vm, "numberOfDFGCompiles"_s), functionNumberOfDFGCompiles); putNativeFn(Identifier::fromString(vm, "optimizeNextInvocation"_s), functionOptimizeNextInvocation); putNativeFn(Identifier::fromString(vm, "releaseWeakRefs"_s), functionReleaseWeakRefs); putNativeFn(Identifier::fromString(vm, "reoptimizationRetryCount"_s), functionReoptimizationRetryCount); putNativeFn(Identifier::fromString(vm, "setRandomSeed"_s), functionSetRandomSeed); putNativeFn(Identifier::fromString(vm, "startRemoteDebugger"_s), functionStartRemoteDebugger); putNativeFn(Identifier::fromString(vm, "totalCompileTime"_s), functionTotalCompileTime); putNativeFn(Identifier::fromString(vm, "getProtectedObjects"_s), functionGetProtectedObjects); putNativeFn(Identifier::fromString(vm, "generateHeapSnapshotForDebugging"_s), functionGenerateHeapSnapshotForDebugging); putNativeFn(Identifier::fromString(vm, "profile"_s), functionRunProfiler); putNativeFn(Identifier::fromString(vm, "codeCoverageForFile"_s), functionCodeCoverageForFile); putNativeFn(Identifier::fromString(vm, "setTimeZone"_s), functionSetTimeZone); putNativeFn(Identifier::fromString(vm, "serialize"_s), functionSerialize); putNativeFn(Identifier::fromString(vm, "deserialize"_s), functionDeserialize); putNativeFn(Identifier::fromString(vm, "estimateShallowMemoryUsageOf"_s), functionEstimateDirectMemoryUsageOf); putNativeFn(Identifier::fromString(vm, "percentAvailableMemoryInUse"_s), functionPercentAvailableMemoryInUse); // Deprecated putNativeFn(Identifier::fromString(vm, "describe"_s), functionDescribe); putNativeFn(Identifier::fromString(vm, "describeArray"_s), functionDescribeArray); putNativeFn(Identifier::fromString(vm, "setTimezone"_s), functionSetTimeZone); RETURN_NATIVE_MODULE(); } } // namespace Zig