Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: bun --print #9358

Merged
merged 13 commits into from Mar 13, 2024
2 changes: 1 addition & 1 deletion src/bun.js/ConsoleObject.zig
Expand Up @@ -85,7 +85,7 @@ pub fn messageWithTypeAndLevel(
//message_level: u32,
level: MessageLevel,
global: *JSGlobalObject,
vals: [*]JSValue,
vals: [*]const JSValue,
len: usize,
) callconv(.C) void {
if (comptime is_bindgen) {
Expand Down
27 changes: 27 additions & 0 deletions src/bun.js/bindings/CommonJSModuleRecord.cpp
Expand Up @@ -92,6 +92,9 @@ static bool canPerformFastEnumeration(Structure* s)
return true;
}

extern "C" bool Bun__VM__specifierIsEvalEntryPoint(void*, EncodedJSValue);
extern "C" void Bun__VM__setEntryPointEvalResult(void*, EncodedJSValue);

static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObject, JSCommonJSModule* moduleObject, JSString* dirname, JSValue filename, WTF::NakedPtr<Exception>& exception)
{
JSSourceCode* code = moduleObject->sourceCode.get();
Expand Down Expand Up @@ -119,6 +122,30 @@ static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObj

moduleObject->hasEvaluated = true;

if (Bun__VM__specifierIsEvalEntryPoint(globalObject->bunVM(), JSValue::encode(filename))) {

// Using same approach as node, `arguments` in the entry point isn't defined
// https://github.com/nodejs/node/blob/592c6907bfe1922f36240e9df076be1864c3d1bd/lib/internal/process/execution.js#L92
globalObject->putDirect(vm, Identifier::fromLatin1(vm, "exports"_s), moduleObject->exportsObject(), 0);
globalObject->putDirect(vm, Identifier::fromLatin1(vm, "require"_s), requireFunction, 0);
globalObject->putDirect(vm, Identifier::fromLatin1(vm, "module"_s), moduleObject, 0);
globalObject->putDirect(vm, Identifier::fromLatin1(vm, "__filename"_s), filename, 0);
globalObject->putDirect(vm, Identifier::fromLatin1(vm, "__dirname"_s), dirname, 0);

JSValue result = JSC::evaluate(globalObject, code->sourceCode(), jsUndefined(), exception);

if (UNLIKELY(exception.get() || result.isEmpty())) {
moduleObject->sourceCode.clear();
return false;
}

Bun__VM__setEntryPointEvalResult(globalObject->bunVM(), JSValue::encode(result));

moduleObject->sourceCode.clear();

return true;
}

// This will return 0 if there was a syntax error or an allocation failure
JSValue fnValue = JSC::evaluate(globalObject, code->sourceCode(), jsUndefined(), exception);

Expand Down
70 changes: 63 additions & 7 deletions src/bun.js/bindings/ZigGlobalObject.cpp
Expand Up @@ -742,7 +742,7 @@ static void resetOnEachMicrotaskTick(JSC::VM& vm, Zig::GlobalObject* globalObjec
}
}

extern "C" JSC__JSGlobalObject* Zig__GlobalObject__create(void* console_client, int32_t executionContextId, bool miniMode, void* worker_ptr)
extern "C" JSC__JSGlobalObject* Zig__GlobalObject__create(void* console_client, int32_t executionContextId, bool miniMode, bool evalMode, void* worker_ptr)
{

auto heapSize = miniMode ? JSC::HeapType::Small : JSC::HeapType::Large;
Expand Down Expand Up @@ -779,6 +779,13 @@ extern "C" JSC__JSGlobalObject* Zig__GlobalObject__create(void* console_client,
globalObject->m_processEnvObject.set(vm, globalObject, env);
}
}
} else if (evalMode) {
globalObject = Zig::EvalGlobalObject::create(
vm,
Zig::EvalGlobalObject::createStructure(vm, JSC::JSGlobalObject::create(vm, JSC::JSGlobalObject::createStructure(vm, JSC::jsNull())),
JSC::jsNull()),
&Zig::EvalGlobalObject::s_globalObjectMethodTable);

} else {
globalObject = Zig::GlobalObject::create(
vm,
Expand Down Expand Up @@ -993,15 +1000,38 @@ const JSC::GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = {
&reportUncaughtExceptionAtEventLoop,
&currentScriptExecutionOwner,
&scriptExecutionStatus,
nullptr, // reportViolationForUnsafeEval
nullptr, // defaultLanguage
nullptr, // compileStreaming
nullptr, // instantiateStreaming
&Zig::deriveShadowRealmGlobalObject
};

const JSC::GlobalObjectMethodTable EvalGlobalObject::s_globalObjectMethodTable = {
&supportsRichSourceInfo,
&shouldInterruptScript,
&javaScriptRuntimeFlags,
// &queueMicrotaskToEventLoop, // queueTaskToEventLoop
nullptr,
nullptr, // &shouldInterruptScriptBeforeTimeout,
&moduleLoaderImportModule, // moduleLoaderImportModule
&moduleLoaderResolve, // moduleLoaderResolve
&moduleLoaderFetch, // moduleLoaderFetch
&moduleLoaderCreateImportMetaProperties, // moduleLoaderCreateImportMetaProperties
&moduleLoaderEvaluate, // moduleLoaderEvaluate
&promiseRejectionTracker, // promiseRejectionTracker
&reportUncaughtExceptionAtEventLoop,
&currentScriptExecutionOwner,
&scriptExecutionStatus,
nullptr, // reportViolationForUnsafeEval
nullptr, // defaultLanguage
nullptr, // compileStreaming
nullptr, // instantiateStreaming
&Zig::deriveShadowRealmGlobalObject
};

GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure)
: JSC::JSGlobalObject(vm, structure, &s_globalObjectMethodTable)
GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure, const JSC::GlobalObjectMethodTable* methodTable)
: JSC::JSGlobalObject(vm, structure, methodTable)
, m_bunVM(Bun__getVM())
, m_constructors(makeUnique<WebCore::DOMConstructors>())
, m_world(WebCore::DOMWrapperWorld::create(vm, WebCore::DOMWrapperWorld::Type::Normal))
Expand All @@ -1017,8 +1047,8 @@ GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure)
globalEventScope.relaxAdoptionRequirement();
}

GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure, WebCore::ScriptExecutionContextIdentifier contextId)
: JSC::JSGlobalObject(vm, structure, &s_globalObjectMethodTable)
GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure, WebCore::ScriptExecutionContextIdentifier contextId, const JSC::GlobalObjectMethodTable* methodTable)
: JSC::JSGlobalObject(vm, structure, methodTable)
, m_bunVM(Bun__getVM())
, m_constructors(makeUnique<WebCore::DOMConstructors>())
, m_world(WebCore::DOMWrapperWorld::create(vm, WebCore::DOMWrapperWorld::Type::Normal))
Expand Down Expand Up @@ -4478,21 +4508,47 @@ JSC::JSObject* GlobalObject::moduleLoaderCreateImportMetaProperties(JSGlobalObje
return Zig::ImportMetaObject::create(globalObject, keyString);
}

JSC::JSValue GlobalObject::moduleLoaderEvaluate(JSGlobalObject* globalObject,
extern "C" void Bun__VM__setEvalResultIfEntryPoint(void*, EncodedJSValue, EncodedJSValue);

JSC::JSValue GlobalObject::moduleLoaderEvaluate(JSGlobalObject* lexicalGlobalObject,
JSModuleLoader* moduleLoader, JSValue key,
JSValue moduleRecordValue, JSValue scriptFetcher,
JSValue sentValue, JSValue resumeMode)
{
Zig::GlobalObject* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);

if (UNLIKELY(scriptFetcher && scriptFetcher.isObject())) {
return scriptFetcher;
}

JSC::JSValue result = moduleLoader->evaluateNonVirtual(globalObject, key, moduleRecordValue,
JSC::JSValue result = moduleLoader->evaluateNonVirtual(lexicalGlobalObject, key, moduleRecordValue,
scriptFetcher, sentValue, resumeMode);

return result;
}

JSC::JSValue EvalGlobalObject::moduleLoaderEvaluate(JSGlobalObject* lexicalGlobalObject,
JSModuleLoader* moduleLoader, JSValue key,
JSValue moduleRecordValue, JSValue scriptFetcher,
JSValue sentValue, JSValue resumeMode)
{
Zig::GlobalObject* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);

if (UNLIKELY(scriptFetcher && scriptFetcher.isObject())) {
Bun__VM__setEvalResultIfEntryPoint(globalObject->bunVM(), JSValue::encode(key), JSValue::encode(scriptFetcher));
return scriptFetcher;
}

JSC::JSValue result = moduleLoader->evaluateNonVirtual(lexicalGlobalObject, key, moduleRecordValue,
scriptFetcher, sentValue, resumeMode);

// need to check each module evaluated to cover cases like these (23 should be the result):
// `import "./foo"; 23; import "./bar"`
Bun__VM__setEvalResultIfEntryPoint(globalObject->bunVM(), JSValue::encode(key), JSValue::encode(result));

return result;
}

GlobalObject::PromiseFunctions GlobalObject::promiseHandlerID(EncodedJSValue (*handler)(JSC__JSGlobalObject* arg0, JSC__CallFrame* arg1))
{
if (handler == Bun__HTTPRequestContext__onReject) {
Expand Down
35 changes: 31 additions & 4 deletions src/bun.js/bindings/ZigGlobalObject.h
Expand Up @@ -92,6 +92,9 @@ class GlobalObject : public JSC::JSGlobalObject {
// Make binding code generation easier.
GlobalObject* globalObject() { return this; }

GlobalObject(JSC::VM& vm, JSC::Structure* structure, const JSC::GlobalObjectMethodTable*);
GlobalObject(JSC::VM& vm, JSC::Structure* structure, uint32_t, const JSC::GlobalObjectMethodTable*);

DOMGuardedObjectSet& guardedObjects() WTF_REQUIRES_LOCK(m_gcLock) { return m_guardedObjects; }

const DOMGuardedObjectSet& guardedObjects() const WTF_IGNORES_THREAD_SAFETY_ANALYSIS
Expand All @@ -107,14 +110,28 @@ class GlobalObject : public JSC::JSGlobalObject {

static GlobalObject* create(JSC::VM& vm, JSC::Structure* structure)
{
GlobalObject* ptr = new (NotNull, JSC::allocateCell<GlobalObject>(vm)) GlobalObject(vm, structure);
GlobalObject* ptr = new (NotNull, JSC::allocateCell<GlobalObject>(vm)) GlobalObject(vm, structure, &s_globalObjectMethodTable);
ptr->finishCreation(vm);
return ptr;
}

static GlobalObject* create(JSC::VM& vm, JSC::Structure* structure, uint32_t scriptExecutionContextId)
{
GlobalObject* ptr = new (NotNull, JSC::allocateCell<GlobalObject>(vm)) GlobalObject(vm, structure, scriptExecutionContextId);
GlobalObject* ptr = new (NotNull, JSC::allocateCell<GlobalObject>(vm)) GlobalObject(vm, structure, scriptExecutionContextId, &s_globalObjectMethodTable);
ptr->finishCreation(vm);
return ptr;
}

static GlobalObject* create(JSC::VM& vm, JSC::Structure* structure, const JSC::GlobalObjectMethodTable* methodTable)
{
GlobalObject* ptr = new (NotNull, JSC::allocateCell<GlobalObject>(vm)) GlobalObject(vm, structure, methodTable);
ptr->finishCreation(vm);
return ptr;
}

static GlobalObject* create(JSC::VM& vm, JSC::Structure* structure, uint32_t scriptExecutionContextId, const JSC::GlobalObjectMethodTable* methodTable)
{
GlobalObject* ptr = new (NotNull, JSC::allocateCell<GlobalObject>(vm)) GlobalObject(vm, structure, scriptExecutionContextId, methodTable);
ptr->finishCreation(vm);
return ptr;
}
Expand Down Expand Up @@ -169,6 +186,7 @@ class GlobalObject : public JSC::JSGlobalObject {
static JSC::JSInternalPromise* moduleLoaderFetch(JSGlobalObject*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSValue, JSC::JSValue);
static JSC::JSObject* moduleLoaderCreateImportMetaProperties(JSGlobalObject*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSModuleRecord*, JSC::JSValue);
static JSC::JSValue moduleLoaderEvaluate(JSGlobalObject*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSValue, JSC::JSValue, JSC::JSValue, JSC::JSValue);

static ScriptExecutionStatus scriptExecutionStatus(JSGlobalObject*, JSObject*);
static void promiseRejectionTracker(JSGlobalObject*, JSC::JSPromise*, JSC::JSPromiseRejectionOperation);
void setConsole(void* console);
Expand Down Expand Up @@ -452,8 +470,6 @@ class GlobalObject : public JSC::JSGlobalObject {
void finishCreation(JSC::VM&);
friend void WebCore::JSBuiltinInternalFunctions::initialize(Zig::GlobalObject&);
WebCore::JSBuiltinInternalFunctions m_builtinInternalFunctions;
GlobalObject(JSC::VM& vm, JSC::Structure* structure);
GlobalObject(JSC::VM& vm, JSC::Structure* structure, uint32_t);
std::unique_ptr<WebCore::DOMConstructors> m_constructors;
uint8_t m_worldIsNormal;
JSDOMStructureMap m_structures WTF_GUARDED_BY_LOCK(m_gcLock);
Expand Down Expand Up @@ -556,6 +572,17 @@ class GlobalObject : public JSC::JSGlobalObject {
WTF::Vector<JSC::Strong<JSC::JSFunction>> m_ffiFunctions;
};

class EvalGlobalObject : public GlobalObject {
public:
static const JSC::GlobalObjectMethodTable s_globalObjectMethodTable;
static JSC::JSValue moduleLoaderEvaluate(JSGlobalObject*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSValue, JSC::JSValue, JSC::JSValue, JSC::JSValue);

EvalGlobalObject(JSC::VM& vm, JSC::Structure* structure)
: GlobalObject(vm, structure, &s_globalObjectMethodTable)
{
}
};

} // namespace Zig

// TODO: move this
Expand Down
17 changes: 17 additions & 0 deletions src/bun.js/bindings/bindings.zig
Expand Up @@ -14,6 +14,7 @@ const is_bindgen: bool = std.meta.globalOption("bindgen", bool) orelse false;
const ArrayBuffer = @import("../base.zig").ArrayBuffer;
const JSC = @import("root").bun.JSC;
const Shimmer = JSC.Shimmer;
const ConsoleObject = JSC.ConsoleObject;
const FFI = @import("./FFI.zig");
const NullableAllocator = @import("../../nullable_allocator.zig").NullableAllocator;
const MutableString = bun.MutableString;
Expand Down Expand Up @@ -4074,6 +4075,22 @@ pub const JSValue = enum(JSValueReprInt) {
});
}

pub fn print(
this: JSValue,
globalObject: *JSGlobalObject,
message_type: ConsoleObject.MessageType,
message_level: ConsoleObject.MessageLevel,
) void {
JSC.ConsoleObject.messageWithTypeAndLevel(
undefined,
message_type,
message_level,
globalObject,
&[_]JSC.JSValue{this},
1,
);
}

/// Create a JSValue string from a zig format-print (fmt + args)
pub fn printString(globalThis: *JSGlobalObject, comptime stack_buffer_size: usize, comptime fmt: []const u8, args: anytype) !JSValue {
var stack_fallback = std.heap.stackFallback(stack_buffer_size, globalThis.allocator());
Expand Down
3 changes: 2 additions & 1 deletion src/bun.js/bindings/exports.zig
Expand Up @@ -45,9 +45,10 @@ pub const ZigGlobalObject = extern struct {
console: *anyopaque,
context_id: i32,
mini_mode: bool,
eval_mode: bool,
worker_ptr: ?*anyopaque,
) *JSGlobalObject {
const global = shim.cppFn("create", .{ console, context_id, mini_mode, worker_ptr });
const global = shim.cppFn("create", .{ console, context_id, mini_mode, eval_mode, worker_ptr });
Backtrace.reloadHandlers() catch unreachable;
return global;
}
Expand Down
2 changes: 1 addition & 1 deletion src/bun.js/bindings/headers.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/bun.js/bindings/headers.zig

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.