fix node:vm and DOMJIT (#13185)

This commit is contained in:
Dylan Conway
2024-08-09 00:33:49 -07:00
committed by GitHub
parent 22e37a5c8d
commit bfca627dfa
11 changed files with 291 additions and 145 deletions

View File

@@ -0,0 +1,50 @@
#include "root.h"
#include "ZigGlobalObject.h"
#include "BunGlobalScope.h"
#include "JavaScriptCore/VM.h"
#include "JavaScriptCore/VMTraps.h"
#include "JavaScriptCore/VMTrapsInlines.h"
#include "JavaScriptCore/LazyClassStructure.h"
#include "JavaScriptCore/LazyClassStructureInlines.h"
#include "BunClientData.h"
namespace Bun {
using namespace JSC;
void GlobalScope::finishCreation(JSC::VM& vm)
{
Base::finishCreation(vm);
ASSERT(inherits(info()));
m_encodeIntoObjectStructure.initLater(
[](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::Structure>::Initializer& init) {
auto& vm = init.vm;
auto& globalObject = *init.owner;
Structure* structure = globalObject.structureCache().emptyObjectStructureForPrototype(&globalObject, globalObject.objectPrototype(), 2);
PropertyOffset offset;
auto clientData = WebCore::clientData(vm);
structure = Structure::addPropertyTransition(vm, structure, clientData->builtinNames().readPublicName(), 0, offset);
RELEASE_ASSERT(offset == 0);
structure = Structure::addPropertyTransition(vm, structure, clientData->builtinNames().writtenPublicName(), 0, offset);
RELEASE_ASSERT(offset == 1);
init.set(structure);
});
}
DEFINE_VISIT_CHILDREN(GlobalScope);
template<typename Visitor>
void GlobalScope::visitChildrenImpl(JSCell* cell, Visitor& visitor)
{
GlobalScope* thisObject = jsCast<GlobalScope*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
Base::visitChildren(thisObject, visitor);
thisObject->m_encodeIntoObjectStructure.visit(visitor);
}
const JSC::ClassInfo GlobalScope::s_info = { "GlobalScope"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(GlobalScope) };
}

View File

@@ -0,0 +1,45 @@
#pragma once
#include "root.h"
#include "JavaScriptCore/JSGlobalObject.h"
namespace Bun {
using namespace JSC;
class GlobalScope : public JSC::JSGlobalObject {
using Base = JSC::JSGlobalObject;
protected:
void finishCreation(JSC::VM& vm);
public:
GlobalScope(JSC::VM& vm, JSC::Structure* structure)
: Base(vm, structure)
{
}
GlobalScope(JSC::VM& vm, JSC::Structure* structure, const JSC::GlobalObjectMethodTable* methodTable)
: Base(vm, structure, methodTable)
{
}
DECLARE_INFO;
DECLARE_VISIT_CHILDREN;
JSC::Structure* encodeIntoObjectStructure() const { return m_encodeIntoObjectStructure.getInitializedOnMainThread(this); }
/**
* WARNING: You must update visitChildrenImpl() if you add a new field.
*
* That informs the garbage collector that these fields exist. If you don't
* do that, the garbage collector will not know about these fields and will
* not trace them. This will lead to crashes and very strange behavior at runtime.
*
* For example, if you don't add the queueMicrotask functions to visitChildrenImpl(),
* those callbacks will eventually never be called anymore. But it'll work the first time!
*/
LazyProperty<JSGlobalObject, Structure> m_encodeIntoObjectStructure;
};
} // namespace Bun

View File

@@ -5,17 +5,17 @@
namespace WebCore {
WTF_MAKE_ISO_ALLOCATED_IMPL(GlobalScope);
WTF_MAKE_ISO_ALLOCATED_IMPL(WorkerGlobalScope);
MessagePortChannelProvider& GlobalScope::messagePortChannelProvider()
MessagePortChannelProvider& WorkerGlobalScope::messagePortChannelProvider()
{
return *reinterpret_cast<MessagePortChannelProvider*>(&MessagePortChannelProviderImpl::singleton());
}
void GlobalScope::onDidChangeListenerImpl(EventTarget& self, const AtomString& eventType, OnDidChangeListenerKind kind)
void WorkerGlobalScope::onDidChangeListenerImpl(EventTarget& self, const AtomString& eventType, OnDidChangeListenerKind kind)
{
if (eventType == eventNames().messageEvent) {
auto& global = static_cast<GlobalScope&>(self);
auto& global = static_cast<WorkerGlobalScope&>(self);
switch (kind) {
case Add:
if (global.m_messageEventCount == 0) {

View File

@@ -15,15 +15,15 @@ namespace WebCore {
class MessagePortChannelProvider;
class MessagePortChannelProviderImpl;
class GlobalScope : public RefCounted<GlobalScope>, public EventTargetWithInlineData {
WTF_MAKE_ISO_ALLOCATED(GlobalScope);
class WorkerGlobalScope : public RefCounted<WorkerGlobalScope>, public EventTargetWithInlineData {
WTF_MAKE_ISO_ALLOCATED(WorkerGlobalScope);
uint32_t m_messageEventCount{0};
uint32_t m_messageEventCount { 0 };
static void onDidChangeListenerImpl(EventTarget&, const AtomString&, OnDidChangeListenerKind);
public:
GlobalScope(ScriptExecutionContext* context)
WorkerGlobalScope(ScriptExecutionContext* context)
: EventTargetWithInlineData()
, m_context(context)
{
@@ -33,12 +33,12 @@ public:
using RefCounted::deref;
using RefCounted::ref;
static Ref<GlobalScope> create(ScriptExecutionContext* context)
static Ref<WorkerGlobalScope> create(ScriptExecutionContext* context)
{
return adoptRef(*new GlobalScope(context));
return adoptRef(*new WorkerGlobalScope(context));
}
~GlobalScope() = default;
~WorkerGlobalScope() = default;
EventTargetInterface eventTargetInterface() const final { return EventTargetInterface::DOMWindowEventTargetInterfaceType; }
ScriptExecutionContext* scriptExecutionContext() const final { return m_context; }

View File

@@ -26,10 +26,6 @@
#include "JSBuffer.h"
#include <JavaScriptCore/DOMJITAbstractHeap.h>
#include "DOMJITIDLConvert.h"
#include "DOMJITIDLType.h"
#include "DOMJITIDLTypeFilter.h"
#include "DOMJITHelpers.h"
#include <JavaScriptCore/DFGAbstractHeap.h>
#include <JavaScriptCore/Completion.h>
@@ -272,8 +268,8 @@ JSC_DEFINE_HOST_FUNCTION(vmModuleRunInNewContext, (JSGlobalObject * globalObject
auto* zigGlobal = reinterpret_cast<Zig::GlobalObject*>(globalObject);
JSObject* context = asObject(contextObjectValue);
auto* targetContext = JSC::JSGlobalObject::create(
vm, zigGlobal->globalObjectStructure());
auto* targetContext = NodeVMGlobalObject::create(
vm, zigGlobal->NodeVMGlobalObjectStructure());
auto* executable = JSC::DirectEvalExecutable::create(
targetContext, source, NoLexicallyScopedFeatures, DerivedContextType::None, NeedsClassFieldInitializer::No, PrivateBrandRequirement::None,
@@ -394,8 +390,8 @@ JSC_DEFINE_HOST_FUNCTION(scriptRunInNewContext, (JSGlobalObject * globalObject,
auto* zigGlobal = reinterpret_cast<Zig::GlobalObject*>(globalObject);
JSObject* context = asObject(contextObjectValue);
auto* targetContext = JSC::JSGlobalObject::create(
vm, zigGlobal->globalObjectStructure());
auto* targetContext = NodeVMGlobalObject::create(
vm, zigGlobal->NodeVMGlobalObjectStructure());
// auto proxyStructure = JSGlobalProxy::createStructure(vm, globalObject, JSC::jsNull());
// auto proxy = JSGlobalProxy::create(vm, proxyStructure);
@@ -446,6 +442,11 @@ JSC_DEFINE_CUSTOM_GETTER(scriptGetSourceMapURL, (JSGlobalObject * globalObject,
return JSValue::encode(jsString(vm, url));
}
Structure* createNodeVMGlobalObjectStructure(JSC::VM& vm)
{
return NodeVMGlobalObject::createStructure(vm, jsNull());
}
JSC_DEFINE_HOST_FUNCTION(vmModule_createContext, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
auto& vm = globalObject->vm();
@@ -462,8 +463,8 @@ JSC_DEFINE_HOST_FUNCTION(vmModule_createContext, (JSGlobalObject * globalObject,
}
JSObject* context = asObject(contextArg);
auto* zigGlobalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject);
auto* targetContext = JSC::JSGlobalObject::create(
vm, zigGlobalObject->globalObjectStructure());
auto* targetContext = NodeVMGlobalObject::create(
vm, zigGlobalObject->NodeVMGlobalObjectStructure());
auto proxyStructure = zigGlobalObject->globalProxyStructure();
auto proxy = JSGlobalProxy::create(vm, proxyStructure);
@@ -536,6 +537,7 @@ static const struct HashTableValue scriptPrototypeTableValues[] = {
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) };
const ClassInfo NodeVMGlobalObject::s_info = { "NodeVMGlobalObject"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(NodeVMGlobalObject) };
DEFINE_VISIT_CHILDREN(NodeVMScript);

View File

@@ -12,6 +12,8 @@
namespace WebCore {
Structure* createNodeVMGlobalObjectStructure(JSC::VM&);
class NodeVMScriptConstructor final : public JSC::InternalFunction {
public:
using Base = JSC::InternalFunction;
@@ -76,6 +78,18 @@ private:
void finishCreation(JSC::VM&);
};
class NodeVMGlobalObject final : public Bun::GlobalScope {
using Base = Bun::GlobalScope;
public:
NodeVMGlobalObject(JSC::VM& vm, JSC::Structure* structure)
: Base(vm, structure)
{
}
DECLARE_INFO;
};
JSC_DECLARE_HOST_FUNCTION(vmModule_createContext);
JSC_DECLARE_HOST_FUNCTION(vmModule_isContext);
JSC_DECLARE_HOST_FUNCTION(vmModuleRunInNewContext);

View File

@@ -58,7 +58,6 @@
#include "AddEventListenerOptions.h"
#include "AsyncContextFrame.h"
#include "BunClientData.h"
#include "BunClientData.h"
#include "BunObject.h"
#include "BunPlugin.h"
#include "BunProcess.h"
@@ -1050,14 +1049,14 @@ const JSC::GlobalObjectMethodTable EvalGlobalObject::s_globalObjectMethodTable =
};
GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure, const JSC::GlobalObjectMethodTable* methodTable)
: JSC::JSGlobalObject(vm, structure, methodTable)
: Base(vm, structure, methodTable)
, m_bunVM(Bun__getVM())
, m_constructors(makeUnique<WebCore::DOMConstructors>())
, m_world(WebCore::DOMWrapperWorld::create(vm, WebCore::DOMWrapperWorld::Type::Normal))
, m_worldIsNormal(true)
, m_builtinInternalFunctions(vm)
, m_scriptExecutionContext(new WebCore::ScriptExecutionContext(&vm, this))
, globalEventScope(*new Bun::GlobalScope(m_scriptExecutionContext))
, globalEventScope(*new Bun::WorkerGlobalScope(m_scriptExecutionContext))
{
// m_scriptExecutionContext = globalEventScope.m_context;
mockModule = Bun::JSMockModule::create(this);
@@ -1067,14 +1066,14 @@ GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure, const JSC::Gl
}
GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure, WebCore::ScriptExecutionContextIdentifier contextId, const JSC::GlobalObjectMethodTable* methodTable)
: JSC::JSGlobalObject(vm, structure, methodTable)
: Base(vm, structure, methodTable)
, m_bunVM(Bun__getVM())
, m_constructors(makeUnique<WebCore::DOMConstructors>())
, m_world(WebCore::DOMWrapperWorld::create(vm, WebCore::DOMWrapperWorld::Type::Normal))
, m_worldIsNormal(true)
, m_builtinInternalFunctions(vm)
, m_scriptExecutionContext(new WebCore::ScriptExecutionContext(&vm, this, contextId))
, globalEventScope(*new Bun::GlobalScope(m_scriptExecutionContext))
, globalEventScope(*new Bun::WorkerGlobalScope(m_scriptExecutionContext))
{
// m_scriptExecutionContext = globalEventScope.m_context;
mockModule = Bun::JSMockModule::create(this);
@@ -2833,10 +2832,9 @@ void GlobalObject::finishCreation(VM& vm)
Bun::NapiPrototype::createStructure(init.vm, init.owner, init.owner->objectPrototype()));
});
m_cachedGlobalObjectStructure.initLater(
m_cachedNodeVMGlobalObjectStructure.initLater(
[](const JSC::LazyProperty<JSC::JSGlobalObject, Structure>::Initializer& init) {
init.set(
JSC::JSGlobalObject::createStructure(init.vm, JSC::jsNull()));
init.set(WebCore::createNodeVMGlobalObjectStructure(init.vm));
});
m_cachedGlobalProxyStructure.initLater(
@@ -2935,20 +2933,6 @@ void GlobalObject::finishCreation(VM& vm)
init.set(registry);
});
m_encodeIntoObjectStructure.initLater(
[](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::Structure>::Initializer& init) {
auto& vm = init.vm;
auto& globalObject = *init.owner;
Structure* structure = globalObject.structureCache().emptyObjectStructureForPrototype(&globalObject, globalObject.objectPrototype(), 2);
PropertyOffset offset;
auto clientData = WebCore::clientData(vm);
structure = Structure::addPropertyTransition(vm, structure, clientData->builtinNames().readPublicName(), 0, offset);
RELEASE_ASSERT(offset == 0);
structure = Structure::addPropertyTransition(vm, structure, clientData->builtinNames().writtenPublicName(), 0, offset);
RELEASE_ASSERT(offset == 1);
init.set(structure);
});
m_requireFunctionUnbound.initLater(
[](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSObject>::Initializer& init) {
init.set(
@@ -3527,12 +3511,11 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
thisObject->m_asyncBoundFunctionStructure.visit(visitor);
thisObject->m_bunObject.visit(visitor);
thisObject->m_cachedGlobalObjectStructure.visit(visitor);
thisObject->m_cachedNodeVMGlobalObjectStructure.visit(visitor);
thisObject->m_cachedGlobalProxyStructure.visit(visitor);
thisObject->m_callSiteStructure.visit(visitor);
thisObject->m_commonJSModuleObjectStructure.visit(visitor);
thisObject->m_cryptoObject.visit(visitor);
thisObject->m_encodeIntoObjectStructure.visit(visitor);
thisObject->m_errorConstructorPrepareStackTraceInternalValue.visit(visitor);
thisObject->m_esmRegistryMap.visit(visitor);
thisObject->m_importMetaObjectStructure.visit(visitor);

View File

@@ -21,7 +21,7 @@ class ScriptExecutionContext;
class DOMGuardedObject;
class EventLoopTask;
class DOMWrapperWorld;
class GlobalScope;
class WorkerGlobalScope;
class SubtleCrypto;
class EventTarget;
class Performance;
@@ -44,9 +44,10 @@ class InternalModuleRegistry;
#include "WebCoreJSBuiltins.h"
#include "headers-handwritten.h"
#include "BunCommonStrings.h"
#include "BunGlobalScope.h"
namespace WebCore {
class GlobalScope;
class WorkerGlobalScope;
class SubtleCrypto;
class EventTarget;
}
@@ -68,8 +69,8 @@ using DOMGuardedObjectSet = HashSet<WebCore::DOMGuardedObject*>;
#define ZIG_GLOBAL_OBJECT_DEFINED
class GlobalObject : public JSC::JSGlobalObject {
using Base = JSC::JSGlobalObject;
class GlobalObject : public Bun::GlobalScope {
using Base = Bun::GlobalScope;
// Move this to the front for better cache locality.
void* m_bunVM;
@@ -242,7 +243,6 @@ public:
JSC::JSMap* readableStreamNativeMap() const { return m_lazyReadableStreamPrototypeMap.getInitializedOnMainThread(this); }
JSC::JSMap* requireMap() const { return m_requireMap.getInitializedOnMainThread(this); }
JSC::JSMap* esmRegistryMap() const { return m_esmRegistryMap.getInitializedOnMainThread(this); }
JSC::Structure* encodeIntoObjectStructure() const { return m_encodeIntoObjectStructure.getInitializedOnMainThread(this); }
JSC::Structure* callSiteStructure() const { return m_callSiteStructure.getInitializedOnMainThread(this); }
@@ -264,7 +264,7 @@ public:
JSObject* lazyRequireCacheObject() const { return m_lazyRequireCacheObject.getInitializedOnMainThread(this); }
Structure* globalObjectStructure() const { return m_cachedGlobalObjectStructure.getInitializedOnMainThread(this); }
Structure* NodeVMGlobalObjectStructure() const { return m_cachedNodeVMGlobalObjectStructure.getInitializedOnMainThread(this); }
Structure* globalProxyStructure() const { return m_cachedGlobalProxyStructure.getInitializedOnMainThread(this); }
JSObject* lazyTestModuleObject() const { return m_lazyTestModuleObject.getInitializedOnMainThread(this); }
JSObject* lazyPreloadTestModuleObject() const { return m_lazyPreloadTestModuleObject.getInitializedOnMainThread(this); }
@@ -314,7 +314,7 @@ public:
WebCore::EventTarget& eventTarget();
WebCore::ScriptExecutionContext* m_scriptExecutionContext;
Bun::GlobalScope& globalEventScope;
Bun::WorkerGlobalScope& globalEventScope;
void resetOnEachMicrotaskTick();
@@ -531,7 +531,6 @@ public:
LazyProperty<JSGlobalObject, JSMap> m_lazyReadableStreamPrototypeMap;
LazyProperty<JSGlobalObject, JSMap> m_requireMap;
LazyProperty<JSGlobalObject, JSMap> m_esmRegistryMap;
LazyProperty<JSGlobalObject, Structure> m_encodeIntoObjectStructure;
LazyProperty<JSGlobalObject, JSObject> m_JSArrayBufferControllerPrototype;
LazyProperty<JSGlobalObject, JSObject> m_JSHTTPSResponseControllerPrototype;
LazyProperty<JSGlobalObject, JSObject> m_JSFileSinkControllerPrototype;
@@ -543,7 +542,7 @@ public:
LazyProperty<JSGlobalObject, JSObject> m_lazyTestModuleObject;
LazyProperty<JSGlobalObject, JSObject> m_lazyPreloadTestModuleObject;
LazyProperty<JSGlobalObject, JSObject> m_testMatcherUtilsObject;
LazyProperty<JSGlobalObject, Structure> m_cachedGlobalObjectStructure;
LazyProperty<JSGlobalObject, Structure> m_cachedNodeVMGlobalObjectStructure;
LazyProperty<JSGlobalObject, Structure> m_cachedGlobalProxyStructure;
LazyProperty<JSGlobalObject, Structure> m_commonJSModuleObjectStructure;
LazyProperty<JSGlobalObject, Structure> m_JSSocketAddressStructure;
@@ -593,6 +592,21 @@ namespace Bun {
String formatStackTrace(JSC::VM& vm, Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, const WTF::String& name, const WTF::String& message, OrdinalNumber& line, OrdinalNumber& column, WTF::String& sourceURL, Vector<JSC::StackFrame>& stackTrace, JSC::JSObject* errorInstance);
ALWAYS_INLINE void* vm(Zig::GlobalObject* globalObject)
{
return globalObject->bunVM();
}
ALWAYS_INLINE void* vm(JSC::VM& vm)
{
return WebCore::clientData(vm)->bunVM;
}
ALWAYS_INLINE void* vm(JSC::JSGlobalObject* lexicalGlobalObject)
{
return WebCore::clientData(lexicalGlobalObject->vm())->bunVM;
}
}
#ifndef RENAMED_JSDOM_GLOBAL_OBJECT

View File

@@ -113,11 +113,10 @@ static JSC_DECLARE_HOST_FUNCTION(functionPerformanceNow);
static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(functionPerformanceNowWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject*, JSPerformance*));
}
static inline JSC::EncodedJSValue functionPerformanceNowBody(JSGlobalObject* globalObject)
static inline JSC::EncodedJSValue functionPerformanceNowBody(VM& vm)
{
auto* global = reinterpret_cast<GlobalObject*>(globalObject);
// nanoseconds to seconds
double time = static_cast<double>(Bun__readOriginTimer(global->bunVM()));
double time = static_cast<double>(Bun__readOriginTimer(Bun::vm(vm)));
double result = time / 1000000.0;
// https://github.com/oven-sh/bun/issues/5604
@@ -126,7 +125,7 @@ static inline JSC::EncodedJSValue functionPerformanceNowBody(JSGlobalObject* glo
JSC_DEFINE_HOST_FUNCTION(functionPerformanceNow, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
return functionPerformanceNowBody(globalObject);
return functionPerformanceNowBody(globalObject->vm());
}
JSC_DEFINE_JIT_OPERATION(functionPerformanceNowWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, JSPerformance* castedThis))
@@ -136,7 +135,7 @@ JSC_DEFINE_JIT_OPERATION(functionPerformanceNowWithoutTypeCheck, JSC::EncodedJSV
CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
IGNORE_WARNINGS_END
JSC::JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
return { functionPerformanceNowBody(lexicalGlobalObject) };
return { functionPerformanceNowBody(vm) };
}
// -- end copied --

View File

@@ -73,10 +73,10 @@ extern "C" size_t TextEncoder__encodeInto8(const LChar* stringPtr, size_t string
extern "C" size_t TextEncoder__encodeInto16(const UChar* stringPtr, size_t stringLen, void* ptr, size_t len);
extern "C" JSC::EncodedJSValue TextEncoder__encodeRopeString(JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSString* str);
// extern "C" {
// static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(jsTextEncoderEncodeWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject*, JSTextEncoder*, DOMJIT::IDLJSArgumentType<IDLDOMString>));
// static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(jsTextEncoderPrototypeFunction_encodeIntoWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, JSTextEncoder* castedThis, DOMJIT::IDLJSArgumentType<IDLDOMString> source, DOMJIT::IDLJSArgumentType<IDLUint8Array> destination));
// }
extern "C" {
static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(jsTextEncoderEncodeWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject*, JSTextEncoder*, DOMJIT::IDLJSArgumentType<IDLDOMString>));
static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(jsTextEncoderPrototypeFunction_encodeIntoWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, JSTextEncoder* castedThis, DOMJIT::IDLJSArgumentType<IDLDOMString> source, DOMJIT::IDLJSArgumentType<IDLUint8Array> destination));
}
template<> TextEncoder::EncodeIntoResult convertDictionary<TextEncoder::EncodeIntoResult>(JSGlobalObject& lexicalGlobalObject, JSValue value)
{
@@ -214,97 +214,90 @@ template<> void JSTextEncoderDOMConstructor::initializeProperties(VM& vm, JSDOMG
putDirect(vm, vm.propertyNames->prototype, JSTextEncoder::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete);
}
// static const JSC::DOMJIT::Signature DOMJITSignatureForJSTextEncoderEncodeWithoutTypeCheck(
// jsTextEncoderEncodeWithoutTypeCheck,
// JSTextEncoder::info(),
// // https://github.com/oven-sh/bun/issues/9226
// // It's not totally clear what the correct side effects are for this function, so we just make it conservative for now.
// JSC::DOMJIT::Effect {},
// DOMJIT::IDLResultTypeFilter<IDLUint8Array>::value,
// DOMJIT::IDLArgumentTypeFilter<IDLDOMString>::value);
static const JSC::DOMJIT::Signature DOMJITSignatureForJSTextEncoderEncodeWithoutTypeCheck(
jsTextEncoderEncodeWithoutTypeCheck,
JSTextEncoder::info(),
// https://github.com/oven-sh/bun/issues/9226
// It's not totally clear what the correct side effects are for this function, so we just make it conservative for now.
JSC::DOMJIT::Effect {},
DOMJIT::IDLResultTypeFilter<IDLUint8Array>::value,
DOMJIT::IDLArgumentTypeFilter<IDLDOMString>::value);
// static const JSC::DOMJIT::Signature DOMJITSignatureForJSTextEncoderEncodeIntoWithoutTypeCheck(
// jsTextEncoderPrototypeFunction_encodeIntoWithoutTypeCheck,
// JSTextEncoder::info(),
static const JSC::DOMJIT::Signature DOMJITSignatureForJSTextEncoderEncodeIntoWithoutTypeCheck(
jsTextEncoderPrototypeFunction_encodeIntoWithoutTypeCheck,
JSTextEncoder::info(),
// JSC::DOMJIT::Effect {},
// // JSC::DOMJIT::Effect::forReadWriteKinds(encodeIntoRead, encodeIntoWrite),
// DOMJIT::IDLResultTypeFilter<IDLObject>::value,
// DOMJIT::IDLArgumentTypeFilter<IDLDOMString>::value,
// DOMJIT::IDLArgumentTypeFilter<IDLUint8Array>::value);
JSC::DOMJIT::Effect {},
// JSC::DOMJIT::Effect::forReadWriteKinds(encodeIntoRead, encodeIntoWrite),
DOMJIT::IDLResultTypeFilter<IDLObject>::value,
DOMJIT::IDLArgumentTypeFilter<IDLDOMString>::value,
DOMJIT::IDLArgumentTypeFilter<IDLUint8Array>::value);
/* Hash table for prototype */
static const HashTableValue JSTextEncoderPrototypeTableValues[] = {
{ "constructor"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsTextEncoderConstructor, 0 } },
{ "encoding"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, jsTextEncoder_encoding, 0 } },
// TODO: bring these back after fix issue with globalObject pointer argument in `encodeInto`
// REPRO:
// 1. bun create docusaurus
// 2. bun ./node_modules/.bin/docusaurus build --no-minify
// https://github.com/oven-sh/bun/issues/12335
// { "encode"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction), NoIntrinsic, { HashTableValue::DOMJITFunctionType, jsTextEncoderPrototypeFunction_encode, &DOMJITSignatureForJSTextEncoderEncodeWithoutTypeCheck } },
// { "encodeInto"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction), NoIntrinsic, { HashTableValue::DOMJITFunctionType, jsTextEncoderPrototypeFunction_encodeInto, &DOMJITSignatureForJSTextEncoderEncodeIntoWithoutTypeCheck } },
{ "encode"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsTextEncoderPrototypeFunction_encode, 1 } },
{ "encodeInto"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsTextEncoderPrototypeFunction_encodeInto, 2 } },
{ "encode"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction), NoIntrinsic, { HashTableValue::DOMJITFunctionType, jsTextEncoderPrototypeFunction_encode, &DOMJITSignatureForJSTextEncoderEncodeWithoutTypeCheck } },
{ "encodeInto"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction), NoIntrinsic, { HashTableValue::DOMJITFunctionType, jsTextEncoderPrototypeFunction_encodeInto, &DOMJITSignatureForJSTextEncoderEncodeIntoWithoutTypeCheck } },
};
// JSC_DEFINE_JIT_OPERATION(jsTextEncoderEncodeWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, JSTextEncoder* castedThis, DOMJIT::IDLJSArgumentType<IDLDOMString> input))
// {
// VM& vm = JSC::getVM(lexicalGlobalObject);
// IGNORE_WARNINGS_BEGIN("frame-address")
// CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
// IGNORE_WARNINGS_END
// JSC::JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
// auto throwScope = DECLARE_THROW_SCOPE(vm);
// JSC::EncodedJSValue res;
// String str;
// if (input->is8Bit()) {
// if (input->isRope()) {
// GCDeferralContext gcDeferralContext(vm);
// auto encodedValue = TextEncoder__encodeRopeString(lexicalGlobalObject, input);
// if (!JSC::JSValue::decode(encodedValue).isUndefined()) {
// RELEASE_AND_RETURN(throwScope, { encodedValue });
// }
// }
JSC_DEFINE_JIT_OPERATION(jsTextEncoderEncodeWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, JSTextEncoder* castedThis, DOMJIT::IDLJSArgumentType<IDLDOMString> input))
{
VM& vm = JSC::getVM(lexicalGlobalObject);
IGNORE_WARNINGS_BEGIN("frame-address")
CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
IGNORE_WARNINGS_END
JSC::JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
auto throwScope = DECLARE_THROW_SCOPE(vm);
JSC::EncodedJSValue res;
String str;
if (input->is8Bit()) {
if (input->isRope()) {
GCDeferralContext gcDeferralContext(vm);
auto encodedValue = TextEncoder__encodeRopeString(lexicalGlobalObject, input);
if (!JSC::JSValue::decode(encodedValue).isUndefined()) {
RELEASE_AND_RETURN(throwScope, { encodedValue });
}
}
// str = input->value(lexicalGlobalObject);
// res = TextEncoder__encode8(lexicalGlobalObject, str.span8().data(), str.length());
// } else {
// str = input->value(lexicalGlobalObject);
// res = TextEncoder__encode16(lexicalGlobalObject, str.span16().data(), str.length());
// }
str = input->value(lexicalGlobalObject);
res = TextEncoder__encode8(lexicalGlobalObject, str.span8().data(), str.length());
} else {
str = input->value(lexicalGlobalObject);
res = TextEncoder__encode16(lexicalGlobalObject, str.span16().data(), str.length());
}
// if (UNLIKELY(JSC::JSValue::decode(res).isObject() && JSC::JSValue::decode(res).getObject()->isErrorInstance())) {
// throwScope.throwException(lexicalGlobalObject, JSC::JSValue::decode(res));
// return { encodedJSValue() };
// }
if (UNLIKELY(JSC::JSValue::decode(res).isObject() && JSC::JSValue::decode(res).getObject()->isErrorInstance())) {
throwScope.throwException(lexicalGlobalObject, JSC::JSValue::decode(res));
return { encodedJSValue() };
}
// RELEASE_AND_RETURN(throwScope, { res });
// }
RELEASE_AND_RETURN(throwScope, { res });
}
// JSC_DEFINE_JIT_OPERATION(jsTextEncoderPrototypeFunction_encodeIntoWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, JSTextEncoder* castedThis, DOMJIT::IDLJSArgumentType<IDLDOMString> sourceStr, DOMJIT::IDLJSArgumentType<IDLUint8Array> destination))
// {
// VM& vm = JSC::getVM(lexicalGlobalObject);
// IGNORE_WARNINGS_BEGIN("frame-address")
// CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
// IGNORE_WARNINGS_END
// JSC::JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
// String source = sourceStr->value(lexicalGlobalObject);
// size_t res = 0;
// if (!source.is8Bit()) {
// res = TextEncoder__encodeInto16(source.span16().data(), source.length(), destination->vector(), destination->byteLength());
// } else {
// res = TextEncoder__encodeInto8(source.span8().data(), source.length(), destination->vector(), destination->byteLength());
// }
JSC_DEFINE_JIT_OPERATION(jsTextEncoderPrototypeFunction_encodeIntoWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, JSTextEncoder* castedThis, DOMJIT::IDLJSArgumentType<IDLDOMString> sourceStr, DOMJIT::IDLJSArgumentType<IDLUint8Array> destination))
{
VM& vm = JSC::getVM(lexicalGlobalObject);
IGNORE_WARNINGS_BEGIN("frame-address")
CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
IGNORE_WARNINGS_END
JSC::JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
String source = sourceStr->value(lexicalGlobalObject);
size_t res = 0;
if (!source.is8Bit()) {
res = TextEncoder__encodeInto16(source.span16().data(), source.length(), destination->vector(), destination->byteLength());
} else {
res = TextEncoder__encodeInto8(source.span8().data(), source.length(), destination->vector(), destination->byteLength());
}
// Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
// auto* result = JSC::constructEmptyObject(vm, globalObject->encodeIntoObjectStructure());
// result->putDirectOffset(vm, 0, JSC::jsNumber(static_cast<uint32_t>(res)));
// result->putDirectOffset(vm, 1, JSC::jsNumber(static_cast<uint32_t>(res >> 32)));
Bun::GlobalScope* globalScope = reinterpret_cast<Bun::GlobalScope*>(lexicalGlobalObject);
auto* result = JSC::constructEmptyObject(vm, globalScope->encodeIntoObjectStructure());
result->putDirectOffset(vm, 0, JSC::jsNumber(static_cast<uint32_t>(res)));
result->putDirectOffset(vm, 1, JSC::jsNumber(static_cast<uint32_t>(res >> 32)));
// return { JSValue::encode(result) };
// }
return { JSValue::encode(result) };
}
const ClassInfo JSTextEncoderPrototype::s_info = { "TextEncoder"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTextEncoderPrototype) };
@@ -440,9 +433,8 @@ static inline JSC::EncodedJSValue jsTextEncoderPrototypeFunction_encodeIntoBody(
res = TextEncoder__encodeInto8(span.data(), span.size(), destination->vector(), destination->byteLength());
}
Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
auto* result = JSC::constructEmptyObject(vm, globalObject->encodeIntoObjectStructure());
Bun::GlobalScope* globalScope = reinterpret_cast<Bun::GlobalScope*>(lexicalGlobalObject);
auto* result = JSC::constructEmptyObject(vm, globalScope->encodeIntoObjectStructure());
result->putDirectOffset(vm, 0, JSC::jsNumber(static_cast<uint32_t>(res)));
result->putDirectOffset(vm, 1, JSC::jsNumber(static_cast<uint32_t>(res >> 32)));

View File

@@ -5,11 +5,13 @@ import { describe, test, expect } from "bun:test";
import crypto from "crypto";
import { statSync } from "fs";
import { read, ptr } from "bun:ffi";
import vm from "node:vm";
const dirStats = statSync(import.meta.dir);
const buffer = new BigInt64Array(16);
describe("DOMJIT", () => {
const buf = new Uint8Array(4);
for (let iter of [1000, 10000, 100000, 1000000]) {
test("Buffer.alloc", () => {
for (let i = 0; i < iter; i++) {
@@ -43,13 +45,13 @@ describe("DOMJIT", () => {
});
test("TextEncoder.encodeInto", () => {
for (let i = 0; i < iter; i++) {
new TextEncoder().encodeInto("test", new Uint8Array(4));
new TextEncoder().encodeInto("test", buf);
}
expect(true).toBe(true);
});
test("Crypto.timingSafeEqual", () => {
for (let i = 0; i < iter; i++) {
crypto.timingSafeEqual(new Uint8Array(4), new Uint8Array(4));
crypto.timingSafeEqual(buf, buf);
}
expect(true).toBe(true);
});
@@ -61,13 +63,13 @@ describe("DOMJIT", () => {
});
test("Crypto.getRandomValues", () => {
for (let i = 0; i < iter; i++) {
crypto.getRandomValues(new Uint8Array(4));
crypto.getRandomValues(buf);
}
expect(true).toBe(true);
});
test("TextDecoder.decode", () => {
for (let i = 0; i < iter; i++) {
new TextDecoder().decode(new Uint8Array(4));
new TextDecoder().decode(buf);
}
expect(true).toBe(true);
});
@@ -100,4 +102,49 @@ describe("DOMJIT", () => {
expect(true).toBe(true);
});
}
describe("in NodeVM", () => {
const code = `
const buf = new Uint8Array(4);
for (let iter of [100000]) {
for (let i = 0; i < iter; i++) {
performance.now();
}
for (let i = 0; i < iter; i++) {
new TextEncoder().encode("test");
}
for (let i = 0; i < iter; i++) {
new TextEncoder().encodeInto("test", buf);
}
for (let i = 0; i < iter; i++) {
crypto.timingSafeEqual(buf, buf);
}
for (let i = 0; i < iter; i++) {
crypto.randomUUID();
}
for (let i = 0; i < iter; i++) {
crypto.getRandomValues(buf);
}
for (let i = 0; i < iter; i++) {
new TextDecoder().decode(buf);
}
for (let i = 0; i < iter; i++) {
dirStats.isSymbolicLink();
dirStats.isSocket();
dirStats.isFile();
dirStats.isFIFO();
dirStats.isDirectory();
dirStats.isCharacterDevice();
dirStats.isBlockDevice();
}
}
"success";`;
test("Script.runInNewContext", () => {
const script = new vm.Script(code);
expect(script.runInNewContext({ crypto, performance, TextEncoder, TextDecoder, dirStats })).toBe("success");
}, 20_000);
test("vm.runInNewContext", () => {
expect(vm.runInNewContext(code, { crypto, performance, TextEncoder, TextDecoder, dirStats })).toBe("success");
}, 20_000);
});
});