mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
117 lines
6.0 KiB
C++
117 lines
6.0 KiB
C++
// clang-format off
|
|
#pragma once
|
|
#include "JSBuffer.h"
|
|
#include <JavaScriptCore/JSGlobalObject.h>
|
|
#include <JavaScriptCore/ObjectConstructor.h>
|
|
#include "ZigGlobalObject.h"
|
|
|
|
|
|
// These modules are implemented in native code as a function which writes ESM
|
|
// export key+value pairs. The following macros help simplify the implementation
|
|
// of these functions.
|
|
|
|
// To add a new native module
|
|
// 1. Add a new line to `BUN_FOREACH_NATIVE_MODULE`
|
|
// 2. Add a case to `module_loader.zig` that resolves the import.
|
|
// 3. Add a new file in this folder named after the module, camelcase and suffixed with Module,
|
|
// like "NodeBufferModule.h" or "BunJSCModule.h". It should call DEFINE_NATIVE_MODULE(name).
|
|
//
|
|
// The native module function is called to create the module object:
|
|
// - INIT_NATIVE_MODULE(n) is called with the number of exports
|
|
// - put(id, jsvalue) adds an export
|
|
// - putNativeFn(id, nativefn) lets you quickly add from `JSC_DEFINE_HOST_FUNCTION`
|
|
// - NATIVE_MODULE_FINISH() do asserts and finalize everything.
|
|
// If you decide to not use INIT_NATIVE_MODULE. make sure the first property
|
|
// given is the default export
|
|
|
|
#define BUN_FOREACH_ESM_AND_CJS_NATIVE_MODULE(macro) \
|
|
macro("bun:test"_s, BunTest) \
|
|
macro("bun:jsc"_s, BunJSC) \
|
|
macro("node:buffer"_s, NodeBuffer) \
|
|
macro("node:constants"_s, NodeConstants) \
|
|
macro("node:sqlite"_s, NodeSQLite) \
|
|
macro("node:string_decoder"_s, NodeStringDecoder) \
|
|
macro("node:util/types"_s, NodeUtilTypes) \
|
|
macro("utf-8-validate"_s, UTF8Validate) \
|
|
macro("abort-controller"_s, AbortControllerModule)
|
|
|
|
#define BUN_FOREACH_ESM_NATIVE_MODULE(macro) \
|
|
BUN_FOREACH_ESM_AND_CJS_NATIVE_MODULE(macro) \
|
|
macro("node:module"_s, NodeModule) \
|
|
macro("node:process"_s, NodeProcess) \
|
|
macro("bun"_s, BunObject)
|
|
|
|
#define BUN_FOREACH_CJS_NATIVE_MODULE(macro) \
|
|
BUN_FOREACH_ESM_AND_CJS_NATIVE_MODULE(macro)
|
|
|
|
|
|
#if ASSERT_ENABLED
|
|
|
|
// This function is a lie. It doesnt return, but rather it performs an assertion
|
|
// that what you passed to INIT_NATIVE_MODULE is indeed correct.
|
|
#define RETURN_NATIVE_MODULE() \
|
|
ASSERT_WITH_MESSAGE(numberOfActualExportNames == passedNumberOfExportNames, \
|
|
"NATIVE_MODULE_START() was should be given %d", numberOfActualExportNames);
|
|
|
|
#define __NATIVE_MODULE_ASSERT_DECL(numberOfExportNames) \
|
|
[[maybe_unused]] int numberOfActualExportNames = 0; \
|
|
[[maybe_unused]] int passedNumberOfExportNames = numberOfExportNames; \
|
|
|
|
#define __NATIVE_MODULE_ASSERT_INCR numberOfActualExportNames++;
|
|
|
|
#else
|
|
|
|
#define RETURN_NATIVE_MODULE() ;
|
|
#define __NATIVE_MODULE_ASSERT_INCR ;
|
|
#define __NATIVE_MODULE_ASSERT_DECL(numberOfExportNames) ;
|
|
|
|
#endif
|
|
|
|
#define DEFINE_NATIVE_MODULE(name) \
|
|
inline void generateNativeModule_##name( \
|
|
JSC::JSGlobalObject *lexicalGlobalObject, JSC::Identifier moduleKey, \
|
|
Vector<JSC::Identifier, 4> &exportNames, \
|
|
JSC::MarkedArgumentBuffer &exportValues)
|
|
#define DEFINE_NATIVE_MODULE_NOINLINE(name) \
|
|
void generateNativeModule_##name( \
|
|
JSC::JSGlobalObject *lexicalGlobalObject, JSC::Identifier moduleKey, \
|
|
Vector<JSC::Identifier, 4> &exportNames, \
|
|
JSC::MarkedArgumentBuffer &exportValues)
|
|
|
|
#define INIT_NATIVE_MODULE(numberOfExportNames) \
|
|
Zig::GlobalObject *globalObject = \
|
|
reinterpret_cast<Zig::GlobalObject *>(lexicalGlobalObject); \
|
|
JSC::VM &vm = globalObject->vm(); \
|
|
JSC::JSObject *defaultObject = JSC::constructEmptyObject( \
|
|
globalObject, globalObject->objectPrototype(), numberOfExportNames); \
|
|
__NATIVE_MODULE_ASSERT_DECL(numberOfExportNames); \
|
|
[[maybe_unused]] const auto put = [&](JSC::Identifier name, JSC::JSValue value) { \
|
|
defaultObject->putDirect(vm, name, value); \
|
|
exportNames.append(name); \
|
|
exportValues.append(value); \
|
|
__NATIVE_MODULE_ASSERT_INCR \
|
|
}; \
|
|
[[maybe_unused]] const auto putNativeFn = [&](JSC::Identifier name, JSC::NativeFunction ptr) { \
|
|
JSC::JSFunction *value = JSC::JSFunction::create( \
|
|
vm, globalObject, 1, name.string(), ptr, \
|
|
JSC::ImplementationVisibility::Public, JSC::NoIntrinsic, ptr); \
|
|
defaultObject->putDirect(vm, name, value); \
|
|
exportNames.append(name); \
|
|
exportValues.append(value); \
|
|
__NATIVE_MODULE_ASSERT_INCR \
|
|
}; \
|
|
exportNames.reserveCapacity(numberOfExportNames + 1); \
|
|
exportValues.ensureCapacity(numberOfExportNames + 1); \
|
|
exportNames.append(vm.propertyNames->defaultKeyword); \
|
|
exportValues.append(defaultObject); \
|
|
while (0) { \
|
|
}
|
|
|
|
namespace Zig {
|
|
#define FORWARD_DECL_GENERATOR(id, enumName) \
|
|
void generateNativeModule_##enumName( \
|
|
JSC::JSGlobalObject *lexicalGlobalObject, JSC::Identifier moduleKey, \
|
|
Vector<JSC::Identifier, 4> &exportNames, \
|
|
JSC::MarkedArgumentBuffer &exportValues);
|
|
BUN_FOREACH_ESM_NATIVE_MODULE(FORWARD_DECL_GENERATOR)
|
|
} // namespace Zig
|