aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/bindings/ZigGlobalObject.cpp
diff options
context:
space:
mode:
authorGravatar dave caruso <me@paperdave.net> 2023-07-19 17:20:00 -0700
committerGravatar GitHub <noreply@github.com> 2023-07-19 17:20:00 -0700
commit9b6dc49575df5fb953918c284505f24741138130 (patch)
tree3a052876fa8c6524e0c8d18479aabe38e2d5a52a /src/bun.js/bindings/ZigGlobalObject.cpp
parent723e9d1ea7c7fdb424ecedd0fb023524366322c4 (diff)
downloadbun-9b6dc49575df5fb953918c284505f24741138130.tar.gz
bun-9b6dc49575df5fb953918c284505f24741138130.tar.zst
bun-9b6dc49575df5fb953918c284505f24741138130.zip
Implement `AsyncLocalStorage` (#3089)
* work to get async local storage working. * a * a * everything but queueMicrotask * sdfghj * . * finish * tests * test * ok * done * im so stupid * Upgrade WebKit * refactor * refactor * changes requested * oops * cool * fix runInAsyncScope
Diffstat (limited to 'src/bun.js/bindings/ZigGlobalObject.cpp')
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp99
1 files changed, 74 insertions, 25 deletions
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index 34ef5e38a..602c60f29 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -5,6 +5,7 @@
#include "BunClientData.h"
#include "JavaScriptCore/AggregateError.h"
+#include "JavaScriptCore/InternalFieldTuple.h"
#include "JavaScriptCore/BytecodeIndex.h"
#include "JavaScriptCore/CallFrameInlines.h"
#include "JavaScriptCore/ClassInfo.h"
@@ -92,6 +93,7 @@
#include "JSReadableState.h"
#include "JSReadableHelper.h"
#include "Process.h"
+#include "AsyncContextFrame.h"
#include "WebCoreJSBuiltins.h"
#include "JSBuffer.h"
@@ -1050,9 +1052,10 @@ JSC_DEFINE_HOST_FUNCTION(functionQueueMicrotask,
}
Zig::GlobalObject* global = JSC::jsCast<Zig::GlobalObject*>(globalObject);
+ JSC::JSValue asyncContext = global->m_asyncContextData.get()->getInternalField(0);
// This is a JSC builtin function
- globalObject->queueMicrotask(global->performMicrotaskFunction(), job, JSC::JSValue {},
+ globalObject->queueMicrotask(global->performMicrotaskFunction(), job, asyncContext,
JSC::JSValue {}, JSC::JSValue {});
return JSC::JSValue::encode(JSC::jsUndefined());
@@ -1499,6 +1502,23 @@ JSC_DEFINE_HOST_FUNCTION(functionFileURLToPath, (JSC::JSGlobalObject * globalObj
return JSC::JSValue::encode(JSC::jsString(vm, url.fileSystemPath()));
}
+static void cleanupAsyncHooksData(JSC::VM& vm)
+{
+ vm.setOnEachMicrotaskTick(nullptr);
+ Bun__getDefaultGlobal()->m_asyncContextData.get()->putInternalField(vm, 0, jsUndefined());
+}
+
+// $lazy("async_hooks").cleanupLater
+JSC_DEFINE_HOST_FUNCTION(asyncHooksCleanupLater, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
+{
+ // assumptions and notes:
+ // - nobody else uses setOnEachMicrotaskTick
+ // - this is called by js if we set async context in a way we may not clear it
+ // - AsyncLocalStorage.prototype.run cleans up after itself and does not call this cb
+ globalObject->vm().setOnEachMicrotaskTick(&cleanupAsyncHooksData);
+ return JSC::JSValue::encode(JSC::jsUndefined());
+}
+
JSC_DEFINE_CUSTOM_GETTER(noop_getter, (JSGlobalObject*, EncodedJSValue, PropertyName))
{
return JSC::JSValue::encode(JSC::jsUndefined());
@@ -1563,7 +1583,6 @@ JSC:
return JSC::JSValue::encode(JSC::JSValue {});
}
default: {
-
JSC::JSValue moduleName = callFrame->argument(0);
if (moduleName.isNumber()) {
switch (moduleName.toInt32(globalObject)) {
@@ -1698,6 +1717,20 @@ JSC:
return JSValue::encode(obj);
}
+ if (string == "async_hooks"_s) {
+ auto* obj = constructEmptyObject(globalObject);
+ obj->putDirect(
+ vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "get"_s)),
+ JSC::JSFunction::create(vm, asyncContextGetAsyncContextCodeGenerator(vm), globalObject), 0);
+ obj->putDirect(
+ vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "set"_s)),
+ JSC::JSFunction::create(vm, asyncContextSetAsyncContextCodeGenerator(vm), globalObject), 0);
+ obj->putDirect(
+ vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "cleanupLater"_s)),
+ JSC::JSFunction::create(vm, globalObject, 0, "cleanupLater"_s, asyncHooksCleanupLater, ImplementationVisibility::Public), 0);
+ return JSValue::encode(obj);
+ }
+
if (UNLIKELY(string == "noop"_s)) {
auto* obj = constructEmptyObject(globalObject);
obj->putDirectCustomAccessor(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "getterSetter"_s)), JSC::CustomGetterSetter::create(vm, noop_getter, noop_setter), 0);
@@ -2773,24 +2806,25 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionPerformMicrotask, (JSGlobalObject * globalObj
JSValue result;
WTF::NakedPtr<JSC::Exception> exceptionPtr;
+ JSValue restoreAsyncContext = {};
+ InternalFieldTuple* asyncContextData = nullptr;
+ auto setAsyncContext = callframe->argument(1);
+ if (!setAsyncContext.isUndefined()) {
+ asyncContextData = globalObject->m_asyncContextData.get();
+ restoreAsyncContext = asyncContextData->getInternalField(0);
+ asyncContextData->putInternalField(vm, 0, setAsyncContext);
+ }
+
size_t argCount = callframe->argumentCount();
switch (argCount) {
- case 1: {
- break;
- }
- case 2: {
- arguments.append(callframe->uncheckedArgument(1));
- break;
- }
case 3: {
- arguments.append(callframe->uncheckedArgument(1));
arguments.append(callframe->uncheckedArgument(2));
break;
}
case 4: {
- arguments.append(callframe->uncheckedArgument(1));
arguments.append(callframe->uncheckedArgument(2));
arguments.append(callframe->uncheckedArgument(3));
+ break;
}
default:
break;
@@ -2798,6 +2832,10 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionPerformMicrotask, (JSGlobalObject * globalObj
JSC::call(globalObject, job, callData, jsUndefined(), arguments, exceptionPtr);
+ if (asyncContextData) {
+ asyncContextData->putInternalField(vm, 0, restoreAsyncContext);
+ }
+
if (auto* exception = exceptionPtr.get()) {
Bun__reportUnhandledError(globalObject, JSValue::encode(exception));
}
@@ -2843,12 +2881,25 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionPerformMicrotaskVariadic, (JSGlobalObject * g
WTF::NakedPtr<JSC::Exception> exceptionPtr;
JSValue thisValue = jsUndefined();
- if (callframe->argumentCount() > 2) {
- thisValue = callframe->argument(2);
+ if (callframe->argumentCount() > 3) {
+ thisValue = callframe->argument(3);
+ }
+
+ JSValue restoreAsyncContext = {};
+ InternalFieldTuple* asyncContextData = nullptr;
+ auto setAsyncContext = callframe->argument(2);
+ if (!setAsyncContext.isUndefined()) {
+ asyncContextData = globalObject->m_asyncContextData.get();
+ restoreAsyncContext = asyncContextData->getInternalField(0);
+ asyncContextData->putInternalField(vm, 0, setAsyncContext);
}
JSC::call(globalObject, job, callData, thisValue, arguments, exceptionPtr);
+ if (asyncContextData) {
+ asyncContextData->putInternalField(vm, 0, restoreAsyncContext);
+ }
+
if (auto* exception = exceptionPtr.get()) {
Bun__reportUnhandledError(globalObject, JSValue::encode(exception));
}
@@ -3194,6 +3245,10 @@ void GlobalObject::finishCreation(VM& vm)
[](const Initializer<JSWeakMap>& init) {
init.set(JSWeakMap::create(init.vm, init.owner->weakMapStructure()));
});
+ // m_asyncHooksContext.initLater(
+ // [](const Initializer<JSC::JSMap>& init) {
+ // init.set(JSC::JSMap::create(init.vm, init.owner->mapStructure()));
+ // });
m_JSBufferSubclassStructure.initLater(
[](const Initializer<Structure>& init) {
@@ -3387,6 +3442,11 @@ void GlobalObject::finishCreation(VM& vm)
init.set(Zig::ImportMetaObject::createStructure(init.vm, init.owner));
});
+ m_asyncBoundFunctionStructure.initLater(
+ [](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::Structure>::Initializer& init) {
+ init.set(AsyncContextFrame::createStructure(init.vm, init.owner));
+ });
+
m_JSFileSinkClassStructure.initLater(
[](LazyClassStructure::Initializer& init) {
auto* prototype = createJSSinkPrototype(init.vm, init.global, WebCore::SinkID::FileSink);
@@ -3670,18 +3730,6 @@ JSC_DEFINE_HOST_FUNCTION(functionBunPeekStatus,
return JSValue::encode(jsUndefined());
}
-extern "C" void Bun__setOnEachMicrotaskTick(JSC::VM* vm, void* ptr, void (*callback)(void* ptr))
-{
- if (callback == nullptr) {
- vm->setOnEachMicrotaskTick(nullptr);
- return;
- }
-
- vm->setOnEachMicrotaskTick([=](JSC::VM& vm) {
- callback(ptr);
- });
-}
-
JSC_DEFINE_CUSTOM_GETTER(BunCommonJSModule_getter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName))
{
Zig::GlobalObject* bunGlobalObject = jsCast<Zig::GlobalObject*>(globalObject);
@@ -4548,6 +4596,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
thisObject->m_importMetaRequireFunctionUnbound.visit(visitor);
thisObject->m_importMetaRequireResolveFunctionUnbound.visit(visitor);
thisObject->m_importMetaObjectStructure.visit(visitor);
+ thisObject->m_asyncBoundFunctionStructure.visit(visitor);
thisObject->m_dnsObject.visit(visitor);
thisObject->m_lazyRequireCacheObject.visit(visitor);