diff options
-rw-r--r-- | src/bun.js/bindings/NodeVMScript.cpp | 332 | ||||
-rw-r--r-- | src/bun.js/bindings/NodeVMScript.h | 79 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.cpp | 37 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.h | 9 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h | 1 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/DOMIsoSubspaces.h | 3 | ||||
-rw-r--r-- | src/bun.js/vm.exports.js | 67 |
7 files changed, 482 insertions, 46 deletions
diff --git a/src/bun.js/bindings/NodeVMScript.cpp b/src/bun.js/bindings/NodeVMScript.cpp new file mode 100644 index 000000000..0b0b7bcd4 --- /dev/null +++ b/src/bun.js/bindings/NodeVMScript.cpp @@ -0,0 +1,332 @@ +#include "root.h" + +#include "NodeVMScript.h" +#include "JavaScriptCore/JSObjectInlines.h" +#include "wtf/text/ExternalStringImpl.h" + +#include "JavaScriptCore/FunctionPrototype.h" +#include "JavaScriptCore/HeapAnalyzer.h" + +#include "JavaScriptCore/JSDestructibleObjectHeapCellType.h" +#include "JavaScriptCore/SlotVisitorMacros.h" +#include "JavaScriptCore/ObjectConstructor.h" +#include "JavaScriptCore/SubspaceInlines.h" +#include "wtf/GetPtr.h" +#include "wtf/PointerPreparations.h" +#include "wtf/URL.h" +#include "JavaScriptCore/TypedArrayInlines.h" +#include "JavaScriptCore/PropertyNameArray.h" +#include "JavaScriptCore/JSWeakMap.h" +#include "JavaScriptCore/JSWeakMapInlines.h" +#include "JavaScriptCore/JSWithScope.h" +#include "Buffer.h" +#include "GCDefferalContext.h" +#include "Buffer.h" + +#include <JavaScriptCore/DOMJITAbstractHeap.h> +#include "DOMJITIDLConvert.h" +#include "DOMJITIDLType.h" +#include "DOMJITIDLTypeFilter.h" +#include "DOMJITHelpers.h" +#include <JavaScriptCore/DFGAbstractHeap.h> + +namespace WebCore { +using namespace JSC; + +static EncodedJSValue constructScript(JSGlobalObject* globalObject, CallFrame* callFrame, JSValue newTarget = JSValue()) +{ + VM& vm = globalObject->vm(); + JSValue callee = callFrame->jsCallee(); + ArgList args(callFrame); + JSValue sourceArg = args.at(0); + String sourceString = sourceArg.isUndefined() ? emptyString() : sourceArg.toWTFString(globalObject); + + JSValue optionsArg = args.at(1); + String filename = ""_s; + OrdinalNumber lineOffset, columnOffset; + if (!optionsArg.isUndefined()) { + if (!optionsArg.isObject()) { + auto scope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(globalObject, scope, "options must be an object"_s); + } + JSObject* options = asObject(optionsArg); + + JSValue filenameOpt = options->get(globalObject, Identifier::fromString(vm, "filename"_s)); + if (filenameOpt.isString()) { + filename = filenameOpt.toWTFString(globalObject); + } + + JSValue lineOffsetOpt = options->get(globalObject, Identifier::fromString(vm, "lineOffset"_s)); + if (lineOffsetOpt.isAnyInt()) { + lineOffset = OrdinalNumber::fromZeroBasedInt(lineOffsetOpt.asAnyInt()); + } + JSValue columnOffsetOpt = options->get(globalObject, Identifier::fromString(vm, "columnOffset"_s)); + if (columnOffsetOpt.isAnyInt()) { + columnOffset = OrdinalNumber::fromZeroBasedInt(columnOffsetOpt.asAnyInt()); + } + + // TODO: cachedData + // TODO: importModuleDynamically + } + + auto* zigGlobalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject); + Structure* structure = zigGlobalObject->NodeVMScriptStructure(); + if (zigGlobalObject->NodeVMScript() != newTarget) { + auto scope = DECLARE_THROW_SCOPE(vm); + JSObject* targetObj = asObject(newTarget); + auto* functionGlobalObject = reinterpret_cast<Zig::GlobalObject*>(getFunctionRealm(globalObject, targetObj)); + RETURN_IF_EXCEPTION(scope, {}); + structure = InternalFunction::createSubclassStructure( + globalObject, targetObj, functionGlobalObject->NodeVMScriptStructure()); + scope.release(); + } + + auto scope = DECLARE_THROW_SCOPE(vm); + SourceCode source( + JSC::StringSourceProvider::create(sourceString, JSC::SourceOrigin(), filename, TextPosition(lineOffset, columnOffset)), + lineOffset.zeroBasedInt(), columnOffset.zeroBasedInt()); + RETURN_IF_EXCEPTION(scope, {}); + NodeVMScript* script = NodeVMScript::create(vm, globalObject, structure, source); + return JSValue::encode(JSValue(script)); +} + +static EncodedJSValue runInContext(JSGlobalObject* globalObject, NodeVMScript* script, JSObject* globalThis, JSScope* scope, JSValue optionsArg) +{ + auto& vm = globalObject->vm(); + + if (!optionsArg.isUndefined()) { + if (!optionsArg.isObject()) { + auto scope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(globalObject, scope, "options must be an object"_s); + } + JSObject* options = asObject(optionsArg); + + // TODO: displayErrors - Not really sure what this option even does or why it's useful + // TODO: timeout - I can't figure out how to make Watchdog work so leaving this for now + // TODO: breakOnSigint - Bun doesn't support signal handlers at all yet I believe + } + + auto err_scope = DECLARE_THROW_SCOPE(vm); + auto* eval = DirectEvalExecutable::create( + globalObject, script->source(), DerivedContextType::None, NeedsClassFieldInitializer::No, PrivateBrandRequirement::None, + false, false, EvalContextType::None, nullptr, nullptr, ECMAMode::sloppy()); + RETURN_IF_EXCEPTION(err_scope, {}); + + return JSValue::encode(vm.interpreter.executeEval(eval, globalThis, scope)); +} + +JSC_DEFINE_HOST_FUNCTION(scriptConstructorCall, (JSGlobalObject* globalObject, CallFrame* callFrame)) +{ + return constructScript(globalObject, callFrame); +} + +JSC_DEFINE_HOST_FUNCTION(scriptConstructorConstruct, (JSGlobalObject* globalObject, CallFrame* callFrame)) +{ + return constructScript(globalObject, callFrame, callFrame->newTarget()); +} + +JSC_DEFINE_CUSTOM_GETTER(scriptGetCachedDataRejected, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName)) +{ + auto& vm = globalObject->vm(); + return JSValue::encode(jsBoolean(true)); // TODO +} +JSC_DEFINE_HOST_FUNCTION(scriptCreateCachedData, (JSGlobalObject* globalObject, CallFrame* callFrame)) +{ + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + return throwVMError(globalObject, scope, "TODO: Script.createCachedData"_s); +} + +JSC_DEFINE_HOST_FUNCTION(scriptRunInContext, (JSGlobalObject* globalObject, CallFrame* callFrame)) +{ + auto& vm = globalObject->vm(); + + JSValue thisValue = callFrame->thisValue(); + auto* script = jsDynamicCast<NodeVMScript*>(thisValue); + if (UNLIKELY(!script)) { + auto scope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(globalObject, scope, "Script.prototype.runInContext can only be called on a Script object"_s); + } + + ArgList args(callFrame); + + JSValue contextArg = args.at(0); + if (!UNLIKELY(contextArg.isObject())) { + auto scope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(globalObject, scope, "context parameter must be a contextified object"_s); + } + JSObject* context = asObject(contextArg); + + auto* zigGlobalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject); + JSValue scopeVal = zigGlobalObject->vmModuleContextMap()->get(context); + if (UNLIKELY(scopeVal.isUndefined())) { + auto scope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(globalObject, scope, "context parameter must be a contextified object"_s); + } + JSScope* scope = jsDynamicCast<JSScope*>(scopeVal); + ASSERT(scope); + + return runInContext(globalObject, script, context, scope, args.at(1)); +} +JSC_DEFINE_HOST_FUNCTION(scriptRunInThisContext, (JSGlobalObject* globalObject, CallFrame* callFrame)) +{ + auto& vm = globalObject->vm(); + JSValue thisValue = callFrame->thisValue(); + auto* script = jsDynamicCast<NodeVMScript*>(thisValue); + if (UNLIKELY(!script)) { + auto scope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(globalObject, scope, "Script.prototype.runInThisContext can only be called on a Script object"_s); + } + + ArgList args(callFrame); + return runInContext(globalObject, script, globalObject->globalThis(), globalObject->globalScope(), args.at(0)); +} + +JSC_DEFINE_CUSTOM_GETTER(scriptGetSourceMapURL, (JSGlobalObject* globalObject, EncodedJSValue thisValueEncoded, PropertyName)) +{ + auto& vm = globalObject->vm(); + JSValue thisValue = JSValue::decode(thisValueEncoded); + auto* script = jsDynamicCast<NodeVMScript*>(thisValue); + if (UNLIKELY(!script)) { + auto scope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(globalObject, scope, "Script.prototype.sourceMapURL getter can only be called on a Script object"_s); + } + + // FIXME: doesn't seem to work? Just returns undefined + const auto& url = script->source().provider()->sourceMappingURLDirective(); + return JSValue::encode(jsString(vm, url)); +} + +JSC_DEFINE_HOST_FUNCTION(vmModule_createContext, (JSGlobalObject* globalObject, CallFrame* callFrame)) +{ + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + ArgList args(callFrame); + JSValue contextArg = args.at(0); + if (!contextArg.isObject()) { + return throwVMTypeError(globalObject, scope, "parameter to createContext must be an object"_s); + } + JSObject* context = asObject(contextArg); + + PropertyDescriptor descriptor; + descriptor.setWritable(false); + descriptor.setEnumerable(false); + descriptor.setValue(context); + JSObject::defineOwnProperty(context, globalObject, Identifier::fromString(vm, "globalThis"_s), descriptor, true); + JSScope* contextScope = JSWithScope::create(vm, globalObject, globalObject->globalScope(), context); + + auto* zigGlobalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject); + zigGlobalObject->vmModuleContextMap()->set(vm, context, contextScope); + + return JSValue::encode(context); +} + +JSC_DEFINE_HOST_FUNCTION(vmModule_isContext, (JSGlobalObject* globalObject, CallFrame* callFrame)) +{ + ArgList args(callFrame); + JSValue contextArg = args.at(0); + bool isContext; + if (!contextArg.isObject()) { + isContext = false; + } else { + auto* zigGlobalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject); + isContext = zigGlobalObject->vmModuleContextMap()->has(asObject(contextArg)); + } + return JSValue::encode(jsBoolean(isContext)); +} + +class NodeVMScriptPrototype final : public JSNonFinalObject { +public: + using Base = JSNonFinalObject; + + static NodeVMScriptPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) + { + NodeVMScriptPrototype* ptr = new (NotNull, allocateCell<NodeVMScriptPrototype>(vm)) NodeVMScriptPrototype(vm, structure); + ptr->finishCreation(vm); + return ptr; + } + + DECLARE_INFO; + template<typename CellType, SubspaceAccess> + static GCClient::IsoSubspace* subspaceFor(VM& vm) + { + return &vm.plainObjectSpace(); + } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + +private: + NodeVMScriptPrototype(VM& vm, Structure* structure) + : Base(vm, structure) + { + } + + void finishCreation(VM&); +}; +STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(NodeVMScriptPrototype, NodeVMScriptPrototype::Base); + +static const struct HashTableValue scriptPrototypeTableValues[] = { + { "cachedDataRejected"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, scriptGetCachedDataRejected, nullptr } }, + { "createCachedData"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, scriptCreateCachedData, 0 } }, + { "runInContext"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, scriptRunInContext, 0 } }, + { "runInThisContext"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, scriptRunInThisContext, 0 } }, + { "sourceMapURL"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, scriptGetSourceMapURL, nullptr } }, +}; + +const ClassInfo NodeVMScriptPrototype::s_info = { "Script"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(NodeVMScriptPrototype) }; +const ClassInfo NodeVMScript::s_info = { "Script"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(NodeVMScript) }; +const ClassInfo NodeVMScriptConstructor::s_info = { "Script"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(NodeVMScriptConstructor) }; + +NodeVMScriptConstructor::NodeVMScriptConstructor(VM& vm, Structure* structure) + : NodeVMScriptConstructor::Base(vm, structure, scriptConstructorCall, scriptConstructorConstruct) +{ +} + +NodeVMScriptConstructor* NodeVMScriptConstructor::create(VM& vm, JSGlobalObject* globalObject, Structure* structure, JSObject* prototype) +{ + NodeVMScriptConstructor* ptr = new (NotNull, allocateCell<NodeVMScriptConstructor>(vm)) NodeVMScriptConstructor(vm, structure); + ptr->finishCreation(vm, prototype); + return ptr; +} + +void NodeVMScriptConstructor::finishCreation(VM& vm, JSObject* prototype) +{ + Base::finishCreation(vm, 1, "Script"_s, PropertyAdditionMode::WithStructureTransition); + putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); + ASSERT(inherits(info())); +} + +void NodeVMScriptPrototype::finishCreation(VM& vm) +{ + Base::finishCreation(vm); + reifyStaticProperties(vm, NodeVMScript::info(), scriptPrototypeTableValues, *this); + JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); +} + +JSObject* NodeVMScript::createPrototype(VM& vm, JSGlobalObject* globalObject) +{ + return NodeVMScriptPrototype::create(vm, globalObject, NodeVMScriptPrototype::createStructure(vm, globalObject, globalObject->objectPrototype())); +} + +NodeVMScript* NodeVMScript::create(VM& vm, JSGlobalObject* globalObject, Structure* structure, SourceCode source) +{ + NodeVMScript* ptr = new (NotNull, allocateCell<NodeVMScript>(vm)) NodeVMScript(vm, structure, source); + ptr->finishCreation(vm); + return ptr; +} + +void NodeVMScript::finishCreation(VM& vm) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); +} + +void NodeVMScript::destroy(JSCell* cell) +{ + static_cast<NodeVMScript*>(cell)->NodeVMScript::~NodeVMScript(); +} + +} diff --git a/src/bun.js/bindings/NodeVMScript.h b/src/bun.js/bindings/NodeVMScript.h new file mode 100644 index 000000000..09878e533 --- /dev/null +++ b/src/bun.js/bindings/NodeVMScript.h @@ -0,0 +1,79 @@ +#pragma once + +#include "root.h" +#include "ZigGlobalObject.h" + +#include "JavaScriptCore/JSFunction.h" +#include "JavaScriptCore/VM.h" + +#include "headers-handwritten.h" +#include "BunClientData.h" +#include "JavaScriptCore/CallFrame.h" + +namespace WebCore { + +class NodeVMScriptConstructor final : public JSC::InternalFunction { +public: + using Base = JSC::InternalFunction; + + static NodeVMScriptConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSC::JSObject* prototype); + + DECLARE_EXPORT_INFO; + + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, Base::StructureFlags), info()); + } + +private: + NodeVMScriptConstructor(JSC::VM& vm, JSC::Structure* structure); + + void finishCreation(JSC::VM&, JSC::JSObject* prototype); +}; +STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(NodeVMScriptConstructor, InternalFunction); + +class NodeVMScript final : public JSC::JSDestructibleObject { +public: + using Base = JSC::JSDestructibleObject; + + static NodeVMScript* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSC::SourceCode source); + + DECLARE_EXPORT_INFO; + template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + return WebCore::subspaceForImpl<NodeVMScript, WebCore::UseCustomHeapCellType::No>( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForNodeVMScript.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForNodeVMScript = std::forward<decltype(space)>(space); }, + [](auto& spaces) { return spaces.m_subspaceForNodeVMScript.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForNodeVMScript = std::forward<decltype(space)>(space); }); + } + + static void destroy(JSC::JSCell*); + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); + } + + static JSObject* createPrototype(VM& vm, JSGlobalObject* globalObject); + + const JSC::SourceCode& source() const { return m_source; } + +private: + JSC::SourceCode m_source; + + NodeVMScript(JSC::VM& vm, JSC::Structure* structure, JSC::SourceCode source) + : Base(vm, structure) + , m_source(source) + { + } + + void finishCreation(JSC::VM&); +}; + +JSC_DECLARE_HOST_FUNCTION(vmModule_createContext); +JSC_DECLARE_HOST_FUNCTION(vmModule_isContext); + +} diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index eeccb6650..84cef9452 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -46,6 +46,7 @@ #include "JavaScriptCore/JSString.h" #include "JavaScriptCore/JSValueInternal.h" #include "JavaScriptCore/JSVirtualMachineInternal.h" +#include "JavaScriptCore/JSWeakMap.h" #include "JavaScriptCore/ObjectConstructor.h" #include "JavaScriptCore/OptionsList.h" #include "JavaScriptCore/ParserError.h" @@ -105,6 +106,7 @@ #include "ReadableStreamBuiltins.h" #include "BunJSCModule.h" #include "ModuleLoader.h" +#include "NodeVMScript.h" #include "ZigGeneratedClasses.h" #include "JavaScriptCore/DateInstance.h" @@ -1209,6 +1211,7 @@ JSC: static NeverDestroyed<const String> noopString(MAKE_STATIC_STRING_IMPL("noop")); static NeverDestroyed<const String> createImportMeta(MAKE_STATIC_STRING_IMPL("createImportMeta")); static NeverDestroyed<const String> masqueradesAsUndefined(MAKE_STATIC_STRING_IMPL("masqueradesAsUndefined")); + static NeverDestroyed<const String> vmString(MAKE_STATIC_STRING_IMPL("vm")); JSC::JSValue moduleName = callFrame->argument(0); if (moduleName.isNumber()) { @@ -1292,6 +1295,20 @@ JSC: return JSValue::encode(InternalFunction::createFunctionThatMasqueradesAsUndefined(vm, globalObject, 0, String(), functionCallNotImplemented)); } + if (string == vmString) { + auto* obj = constructEmptyObject(globalObject); + obj->putDirect( + vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "Script"_s)), + reinterpret_cast<Zig::GlobalObject*>(globalObject)->NodeVMScript(), 0); + obj->putDirect( + vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "createContext"_s)), + JSC::JSFunction::create(vm, globalObject, 0, "createContext"_s, vmModule_createContext, ImplementationVisibility::Public), 0); + obj->putDirect( + vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "isContext"_s)), + JSC::JSFunction::create(vm, globalObject, 0, "isContext"_s, vmModule_isContext, ImplementationVisibility::Public), 0); + return JSValue::encode(obj); + } + if (UNLIKELY(string == noopString)) { auto* obj = constructEmptyObject(globalObject); obj->putDirectCustomAccessor(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "getterSetter"_s)), JSC::CustomGetterSetter::create(vm, noop_getter, noop_setter), 0); @@ -2579,6 +2596,11 @@ void GlobalObject::finishCreation(VM& vm) init.set(dnsObject); }); + m_vmModuleContextMap.initLater( + [](const Initializer<JSWeakMap>& init) { + init.set(JSWeakMap::create(init.vm, init.owner->weakMapStructure())); + }); + m_JSBufferSubclassStructure.initLater( [](const Initializer<Structure>& init) { auto* globalObject = reinterpret_cast<Zig::GlobalObject*>(init.owner); @@ -2849,6 +2871,19 @@ void GlobalObject::finishCreation(VM& vm) init.setStructure(Zig::JSFFIFunction::createStructure(init.vm, init.global, init.global->functionPrototype())); }); + m_NodeVMScriptClassStructure.initLater( + [](LazyClassStructure::Initializer& init) { + auto prototype = NodeVMScript::createPrototype(init.vm, init.global); + auto* structure = NodeVMScript::createStructure(init.vm, init.global, prototype); + auto* constructorStructure = NodeVMScriptConstructor::createStructure( + init.vm, init.global, init.global->m_functionPrototype.get()); + auto* constructor = NodeVMScriptConstructor::create( + init.vm, init.global, constructorStructure, prototype); + init.setPrototype(prototype); + init.setStructure(structure); + init.setConstructor(constructor); + }); + addBuiltinGlobals(vm); #if ENABLE(REMOTE_INSPECTOR) @@ -3672,6 +3707,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) thisObject->m_JSStringDecoderClassStructure.visit(visitor); thisObject->m_NapiClassStructure.visit(visitor); thisObject->m_JSBufferClassStructure.visit(visitor); + thisObject->m_NodeVMScriptClassStructure.visit(visitor); thisObject->m_pendingVirtualModuleResultStructure.visit(visitor); thisObject->m_performMicrotaskFunction.visit(visitor); @@ -3696,6 +3732,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) thisObject->m_requireResolveFunctionStructure.visit(visitor); thisObject->m_resolveFunctionPrototype.visit(visitor); thisObject->m_dnsObject.visit(visitor); + thisObject->m_vmModuleContextMap.visit(visitor); thisObject->m_bunSleepThenCallback.visit(visitor); for (auto& barrier : thisObject->m_thenables) { diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index 879644963..3aa1defa8 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -229,6 +229,10 @@ public: JSC::JSObject* JSReadableState() { return m_JSReadableStateClassStructure.constructorInitializedOnMainThread(this); } JSC::JSValue JSReadableStatePrototype() { return m_JSReadableStateClassStructure.prototypeInitializedOnMainThread(this); } + JSC::Structure* NodeVMScriptStructure() { return m_NodeVMScriptClassStructure.getInitializedOnMainThread(this); } + JSC::JSObject* NodeVMScript() { return m_NodeVMScriptClassStructure.constructorInitializedOnMainThread(this); } + JSC::JSValue NodeVMScriptPrototype() { return m_NodeVMScriptClassStructure.prototypeInitializedOnMainThread(this); } + JSC::JSMap* readableStreamNativeMap() { return m_lazyReadableStreamPrototypeMap.getInitializedOnMainThread(this); } JSC::JSMap* requireMap() { return m_requireMap.getInitializedOnMainThread(this); } JSC::Structure* encodeIntoObjectStructure() { return m_encodeIntoObjectStructure.getInitializedOnMainThread(this); } @@ -250,6 +254,8 @@ public: JSObject* dnsObject() { return m_dnsObject.getInitializedOnMainThread(this); } + JSWeakMap* vmModuleContextMap() { return m_vmModuleContextMap.getInitializedOnMainThread(this); } + JSC::JSObject* processObject() { return m_processObject.getInitializedOnMainThread(this); @@ -423,6 +429,7 @@ private: LazyClassStructure m_NapiClassStructure; LazyClassStructure m_callSiteStructure; LazyClassStructure m_JSBufferClassStructure; + LazyClassStructure m_NodeVMScriptClassStructure; /** * WARNING: You must update visitChildrenImpl() if you add a new field. @@ -455,6 +462,8 @@ private: LazyProperty<JSGlobalObject, JSC::Structure> m_requireResolveFunctionStructure; LazyProperty<JSGlobalObject, JSObject> m_resolveFunctionPrototype; LazyProperty<JSGlobalObject, JSObject> m_dnsObject; + LazyProperty<JSGlobalObject, JSWeakMap> m_vmModuleContextMap; + LazyProperty<JSGlobalObject, JSFunction> m_bunSleepThenCallback; DOMGuardedObjectSet m_guardedObjects WTF_GUARDED_BY_LOCK(m_gcLock); diff --git a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h index 1f7419c88..75fff16a0 100644 --- a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h +++ b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h @@ -32,6 +32,7 @@ public: std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForNapiExternal; std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForRequireResolveFunction; std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForBundlerPlugin; + std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForNodeVMScript; #include "ZigGeneratedClasses+DOMClientIsoSubspaces.h" /* --- bun --- */ diff --git a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h index d55810fcb..2b392a49d 100644 --- a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h +++ b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h @@ -32,6 +32,7 @@ public: std::unique_ptr<IsoSubspace> m_subspaceForNapiExternal; std::unique_ptr<IsoSubspace> m_subspaceForRequireResolveFunction; std::unique_ptr<IsoSubspace> m_subspaceForBundlerPlugin; + std::unique_ptr<IsoSubspace> m_subspaceForNodeVMScript; #include "ZigGeneratedClasses+DOMIsoSubspaces.h" /*-- BUN --*/ @@ -898,4 +899,4 @@ public: namespace WebCore { using DOMIsoSubspaces = WebCore::DOMIsoSubspaces; -}
\ No newline at end of file +} diff --git a/src/bun.js/vm.exports.js b/src/bun.js/vm.exports.js index 77fa31b01..f01a61581 100644 --- a/src/bun.js/vm.exports.js +++ b/src/bun.js/vm.exports.js @@ -1,12 +1,8 @@ -// TODO: Implement vm module - -function hideFromStack(fns) { - for (const fn of fns) { - Object.defineProperty(fn, "name", { - value: "::bunternal::", - }); - } +const lazy = globalThis[Symbol.for("Bun.lazy")]; +if (!lazy || typeof lazy !== "function") { + throw new Error("Something went wrong while loading Bun. Expected 'Bun.lazy' to be defined."); } +const vm = lazy("vm"); class TODO extends Error { constructor(messageName) { @@ -22,23 +18,26 @@ function notimpl(message) { throw new TODO(message); } -function createContext() { - notimpl("createContext"); -} -function createScript() { - notimpl("createScript"); -} -function runInContext() { - notimpl("runInContext"); -} -function runInNewContext() { - notimpl("runInNewContext"); +const createContext = vm.createContext; +const isContext = vm.isContext; +const Script = vm.Script; + +Script.prototype.runInNewContext = function (contextObject, options) { + if (contextObject === undefined) { + contextObject = {}; + } + const context = createContext(contextObject); + this.runInContext(context, options); +}; + +function runInContext(code, context, options) { + new Script(code).runInContext(context, options); } -function runInThisContext() { - notimpl("runInThisContext"); +function runInNewContext(code, contextObject, options) { + new Script(code).runInNewContext(contextObject, options); } -function isContext() { - notimpl("isContext"); +function runInThisContext(code, options) { + new Script(code).runInNewContext(options); } function compileFunction() { notimpl("compileFunction"); @@ -47,15 +46,8 @@ function measureMemory() { notimpl("measureMemory"); } -class Script { - constructor() { - notimpl("Script"); - } -} - const defaultObject = { createContext, - createScript, runInContext, runInNewContext, runInThisContext, @@ -69,7 +61,6 @@ const defaultObject = { export { defaultObject as default, createContext, - createScript, runInContext, runInNewContext, runInThisContext, @@ -78,17 +69,3 @@ export { measureMemory, Script, }; - -hideFromStack([ - TODO.prototype.constructor, - notimpl, - createContext, - createScript, - runInContext, - runInNewContext, - runInThisContext, - isContext, - compileFunction, - measureMemory, - Script.prototype.constructor, -]); |