From 54bbcd44aa05b9b791cd709c22839c37836c2535 Mon Sep 17 00:00:00 2001 From: Meghan Denny Date: Fri, 24 Jan 2025 22:04:31 -0800 Subject: [PATCH 1/3] implement process.binding('buffer') --- cmake/targets/BuildBun.cmake | 2 + src/bun.js/bindings/BunProcess.cpp | 2 +- src/bun.js/bindings/ProcessBindingBuffer.cpp | 159 +++++++++++++++++++ src/bun.js/bindings/ProcessBindingBuffer.h | 37 +++++ src/bun.js/bindings/ZigGlobalObject.cpp | 10 ++ src/bun.js/bindings/ZigGlobalObject.h | 2 + 6 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 src/bun.js/bindings/ProcessBindingBuffer.cpp create mode 100644 src/bun.js/bindings/ProcessBindingBuffer.h diff --git a/cmake/targets/BuildBun.cmake b/cmake/targets/BuildBun.cmake index ad1ce07f33ddc6..1066e31a5d0500 100644 --- a/cmake/targets/BuildBun.cmake +++ b/cmake/targets/BuildBun.cmake @@ -404,6 +404,7 @@ set(BUN_OBJECT_LUT_SOURCES ${CWD}/src/bun.js/bindings/ZigGlobalObject.lut.txt ${CWD}/src/bun.js/bindings/JSBuffer.cpp ${CWD}/src/bun.js/bindings/BunProcess.cpp + ${CWD}/src/bun.js/bindings/ProcessBindingBuffer.cpp ${CWD}/src/bun.js/bindings/ProcessBindingConstants.cpp ${CWD}/src/bun.js/bindings/ProcessBindingNatives.cpp ${CWD}/src/bun.js/modules/NodeModuleModule.cpp @@ -415,6 +416,7 @@ set(BUN_OBJECT_LUT_OUTPUTS ${CODEGEN_PATH}/ZigGlobalObject.lut.h ${CODEGEN_PATH}/JSBuffer.lut.h ${CODEGEN_PATH}/BunProcess.lut.h + ${CODEGEN_PATH}/ProcessBindingBuffer.lut.h ${CODEGEN_PATH}/ProcessBindingConstants.lut.h ${CODEGEN_PATH}/ProcessBindingNatives.lut.h ${CODEGEN_PATH}/NodeModuleModule.lut.h diff --git a/src/bun.js/bindings/BunProcess.cpp b/src/bun.js/bindings/BunProcess.cpp index 57812b1af331af..4e928203fe6e95 100644 --- a/src/bun.js/bindings/BunProcess.cpp +++ b/src/bun.js/bindings/BunProcess.cpp @@ -2533,7 +2533,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionBinding, (JSGlobalObject * jsGlobalObje // clang-format off if (moduleName == "async_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("async_wrap"); - if (moduleName == "buffer"_s) PROCESS_BINDING_NOT_IMPLEMENTED_ISSUE("buffer", "2020"); + if (moduleName == "buffer"_s) return JSValue::encode(globalObject->processBindingBuffer()); if (moduleName == "cares_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("cares_wrap"); if (moduleName == "config"_s) return JSValue::encode(processBindingConfig(globalObject, vm)); if (moduleName == "constants"_s) return JSValue::encode(globalObject->processBindingConstants()); diff --git a/src/bun.js/bindings/ProcessBindingBuffer.cpp b/src/bun.js/bindings/ProcessBindingBuffer.cpp new file mode 100644 index 00000000000000..12acdf0141c7b4 --- /dev/null +++ b/src/bun.js/bindings/ProcessBindingBuffer.cpp @@ -0,0 +1,159 @@ + +#include "ProcessBindingBuffer.h" +#include +#include "JSBuffer.h" + +namespace Bun { +using namespace JSC; + +#define PROCESS_BINDING_NOT_IMPLEMENTED(str) \ + JSC ::EncodedJSValue ProcessBinding_Buffer_##str(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame) \ + { \ + { \ + auto& vm = JSC::getVM(lexicalGlobalObject); \ + auto throwScope = DECLARE_THROW_SCOPE(vm); \ + auto prelude = "process.binding('buffer')."_s; \ + auto name = WTF::ASCIILiteral::fromLiteralUnsafe(#str); \ + auto finale = " is not implemented in Bun. If that breaks something, please file an issue and include a reproducible code sample."_s; \ + auto message = makeString(prelude, name, finale); \ + throwScope.throwException(lexicalGlobalObject, createError(lexicalGlobalObject, message)); \ + return {}; \ + } \ + } + +PROCESS_BINDING_NOT_IMPLEMENTED(asciiSlice) + +PROCESS_BINDING_NOT_IMPLEMENTED(asciiWriteStatic) + +PROCESS_BINDING_NOT_IMPLEMENTED(atob) + +PROCESS_BINDING_NOT_IMPLEMENTED(base64Slice) + +PROCESS_BINDING_NOT_IMPLEMENTED(base64Write) + +PROCESS_BINDING_NOT_IMPLEMENTED(base64urlSlice) + +PROCESS_BINDING_NOT_IMPLEMENTED(base64urlWrite) + +PROCESS_BINDING_NOT_IMPLEMENTED(btoa) + +PROCESS_BINDING_NOT_IMPLEMENTED(byteLengthUtf8) + +PROCESS_BINDING_NOT_IMPLEMENTED(compare) + +PROCESS_BINDING_NOT_IMPLEMENTED(compareOffset) + +PROCESS_BINDING_NOT_IMPLEMENTED(copy) + +PROCESS_BINDING_NOT_IMPLEMENTED(copyArrayBuffer) + +PROCESS_BINDING_NOT_IMPLEMENTED(detachArrayBuffer) + +PROCESS_BINDING_NOT_IMPLEMENTED(fill) + +PROCESS_BINDING_NOT_IMPLEMENTED(getZeroFillToggle) + +PROCESS_BINDING_NOT_IMPLEMENTED(hexSlice) + +PROCESS_BINDING_NOT_IMPLEMENTED(hexWrite) + +PROCESS_BINDING_NOT_IMPLEMENTED(indexOfBuffer) + +PROCESS_BINDING_NOT_IMPLEMENTED(indexOfNumber) + +PROCESS_BINDING_NOT_IMPLEMENTED(indexOfString) + +PROCESS_BINDING_NOT_IMPLEMENTED(isAscii) + +PROCESS_BINDING_NOT_IMPLEMENTED(isUtf8) + +PROCESS_BINDING_NOT_IMPLEMENTED(latin1Slice) + +PROCESS_BINDING_NOT_IMPLEMENTED(latin1WriteStatic) + +PROCESS_BINDING_NOT_IMPLEMENTED(swap16) + +PROCESS_BINDING_NOT_IMPLEMENTED(swap32) + +PROCESS_BINDING_NOT_IMPLEMENTED(swap64) + +PROCESS_BINDING_NOT_IMPLEMENTED(ucs2Slice) + +PROCESS_BINDING_NOT_IMPLEMENTED(ucs2Write) + +PROCESS_BINDING_NOT_IMPLEMENTED(utf8Slice) + +PROCESS_BINDING_NOT_IMPLEMENTED(utf8WriteStatic) + +/* Source for ProcessBindingBuffer.lut.h +@begin processBindingBufferTable + asciiSlice ProcessBinding_Buffer_asciiSlice Function 1 + asciiWriteStatic ProcessBinding_Buffer_asciiWriteStatic Function 1 + atob ProcessBinding_Buffer_atob Function 1 + base64Slice ProcessBinding_Buffer_base64Slice Function 1 + base64Write ProcessBinding_Buffer_base64Write Function 1 + base64urlSlice ProcessBinding_Buffer_base64urlSlice Function 1 + base64urlWrite ProcessBinding_Buffer_base64urlWrite Function 1 + btoa ProcessBinding_Buffer_btoa Function 1 + byteLengthUtf8 ProcessBinding_Buffer_byteLengthUtf8 Function 1 + compare ProcessBinding_Buffer_compare Function 1 + compareOffset ProcessBinding_Buffer_compareOffset Function 1 + copy ProcessBinding_Buffer_copy Function 1 + copyArrayBuffer ProcessBinding_Buffer_copyArrayBuffer Function 1 + detachArrayBuffer ProcessBinding_Buffer_detachArrayBuffer Function 1 + fill ProcessBinding_Buffer_fill Function 1 + getZeroFillToggle ProcessBinding_Buffer_getZeroFillToggle Function 1 + hexSlice ProcessBinding_Buffer_hexSlice Function 1 + hexWrite ProcessBinding_Buffer_hexWrite Function 1 + indexOfBuffer ProcessBinding_Buffer_indexOfBuffer Function 1 + indexOfNumber ProcessBinding_Buffer_indexOfNumber Function 1 + indexOfString ProcessBinding_Buffer_indexOfString Function 1 + isAscii ProcessBinding_Buffer_isAscii Function 1 + isUtf8 ProcessBinding_Buffer_isUtf8 Function 1 + latin1Slice ProcessBinding_Buffer_latin1Slice Function 1 + latin1WriteStatic ProcessBinding_Buffer_latin1WriteStatic Function 1 + swap16 ProcessBinding_Buffer_swap16 Function 1 + swap32 ProcessBinding_Buffer_swap32 Function 1 + swap64 ProcessBinding_Buffer_swap64 Function 1 + ucs2Slice ProcessBinding_Buffer_ucs2Slice Function 1 + ucs2Write ProcessBinding_Buffer_ucs2Write Function 1 + utf8Slice ProcessBinding_Buffer_utf8Slice Function 1 + utf8WriteStatic ProcessBinding_Buffer_utf8WriteStatic Function 1 +@end +*/ +#include "ProcessBindingBuffer.lut.h" + +const ClassInfo ProcessBindingBuffer::s_info = { "ProcessBindingBuffer"_s, &Base::s_info, &processBindingBufferTable, nullptr, CREATE_METHOD_TABLE(ProcessBindingBuffer) }; + +ProcessBindingBuffer* ProcessBindingBuffer::create(VM& vm, Structure* structure) +{ + ProcessBindingBuffer* obj = new (NotNull, allocateCell(vm)) ProcessBindingBuffer(vm, structure); + obj->finishCreation(vm); + return obj; +} + +Structure* ProcessBindingBuffer::createStructure(VM& vm, JSGlobalObject* globalObject) +{ + return Structure::create(vm, globalObject, jsNull(), TypeInfo(ObjectType, StructureFlags), ProcessBindingBuffer::info()); +} + +void ProcessBindingBuffer::finishCreation(JSC::VM& vm) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); + + putDirect(vm, Identifier::fromString(vm, "kMaxLength"_s), jsNumber(Bun::Buffer::kMaxLength), 0); + putDirect(vm, Identifier::fromString(vm, "kStringMaxLength"_s), jsNumber(Bun::Buffer::kStringMaxLength), 0); +} + +template +void ProcessBindingBuffer::visitChildrenImpl(JSCell* cell, Visitor& visitor) +{ + ProcessBindingBuffer* thisObject = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + Base::visitChildren(thisObject, visitor); +} + +DEFINE_VISIT_CHILDREN(ProcessBindingBuffer); + +} // namespace Bun diff --git a/src/bun.js/bindings/ProcessBindingBuffer.h b/src/bun.js/bindings/ProcessBindingBuffer.h new file mode 100644 index 00000000000000..62add4ca3ec4f0 --- /dev/null +++ b/src/bun.js/bindings/ProcessBindingBuffer.h @@ -0,0 +1,37 @@ +#pragma once +#include "root.h" + +namespace Bun { + +using namespace JSC; + +// The object returned from process.binding('buffer') +class ProcessBindingBuffer final : public JSC::JSNonFinalObject { +public: + DECLARE_INFO; + DECLARE_VISIT_CHILDREN; + + using Base = JSC::JSNonFinalObject; + + static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable; + + static ProcessBindingBuffer* create(JSC::VM& vm, JSC::Structure* structure); + static Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject); + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(ProcessBindingBuffer, Base); + return &vm.plainObjectSpace(); + } + +private: + void finishCreation(JSC::VM& vm); + + ProcessBindingBuffer(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure) + { + } +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 93a62b22968e50..062d4c1143a07d 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -161,6 +161,8 @@ #include "JSX509Certificate.h" #include "JSS3File.h" #include "S3Error.h" +#include "ProcessBindingBuffer.h" + #if ENABLE(REMOTE_INSPECTOR) #include "JavaScriptCore/RemoteInspectorServer.h" #endif @@ -3198,6 +3200,14 @@ void GlobalObject::finishCreation(VM& vm) InternalModuleRegistry::createStructure(init.vm, init.owner))); }); + m_processBindingBuffer.initLater( + [](const JSC::LazyProperty::Initializer& init) { + init.set( + ProcessBindingBuffer::create( + init.vm, + ProcessBindingBuffer::createStructure(init.vm, init.owner))); + }); + m_processBindingConstants.initLater( [](const JSC::LazyProperty::Initializer& init) { init.set( diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index da6abf2ccf387d..4d2e0f0f72a374 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -248,6 +248,7 @@ class GlobalObject : public Bun::GlobalScope { JSObject* requireResolveFunctionUnbound() const { return m_requireResolveFunctionUnbound.getInitializedOnMainThread(this); } Bun::InternalModuleRegistry* internalModuleRegistry() const { return m_internalModuleRegistry.getInitializedOnMainThread(this); } + JSObject* processBindingBuffer() const { return m_processBindingBuffer.getInitializedOnMainThread(this); } JSObject* processBindingConstants() const { return m_processBindingConstants.getInitializedOnMainThread(this); } JSObject* lazyRequireCacheObject() const { return m_lazyRequireCacheObject.getInitializedOnMainThread(this); } @@ -578,6 +579,7 @@ class GlobalObject : public Bun::GlobalScope { LazyProperty m_requireFunctionUnbound; LazyProperty m_requireResolveFunctionUnbound; LazyProperty m_internalModuleRegistry; + LazyProperty m_processBindingBuffer; LazyProperty m_processBindingConstants; LazyProperty m_importMetaObjectStructure; LazyProperty m_asyncBoundFunctionStructure; From b3ff04d4045f61b51533214f64de6a772665fd36 Mon Sep 17 00:00:00 2001 From: Meghan Denny Date: Fri, 24 Jan 2025 23:30:40 -0800 Subject: [PATCH 2/3] update test --- src/bun.js/bindings/BunProcess.cpp | 1 + test/js/node/process/process.test.js | 43 +++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/bun.js/bindings/BunProcess.cpp b/src/bun.js/bindings/BunProcess.cpp index 4e928203fe6e95..15981138166703 100644 --- a/src/bun.js/bindings/BunProcess.cpp +++ b/src/bun.js/bindings/BunProcess.cpp @@ -2530,6 +2530,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionBinding, (JSGlobalObject * jsGlobalObje auto globalObject = jsCast(jsGlobalObject); auto process = jsCast(globalObject->processObject()); auto moduleName = callFrame->argument(0).toWTFString(globalObject); + RETURN_IF_EXCEPTION(throwScope, {}); // clang-format off if (moduleName == "async_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("async_wrap"); diff --git a/test/js/node/process/process.test.js b/test/js/node/process/process.test.js index 965105f56bf5a9..b4c71924f9140f 100644 --- a/test/js/node/process/process.test.js +++ b/test/js/node/process/process.test.js @@ -319,7 +319,48 @@ it("process.execArgv", () => { }); it("process.binding", () => { - expect(() => process.binding("buffer")).toThrow(); + expect(() => process.binding("async_wrap")).toThrow(); + expect(() => process.binding("buffer")).not.toThrow(); + expect(() => process.binding("cares_wrap")).toThrow(); + expect(() => process.binding("config")).not.toThrow(); + expect(() => process.binding("constants")).not.toThrow(); + expect(() => process.binding("contextify")).toThrow(); + expect(() => process.binding("crypto")).toThrow(); + expect(() => process.binding("crypto/x509")).not.toThrow(); + expect(() => process.binding("fs")).toThrow(); + expect(() => process.binding("fs_event_wrap")).toThrow(); + expect(() => process.binding("http_parser")).toThrow(); + expect(() => process.binding("icu")).toThrow(); + expect(() => process.binding("inspector")).toThrow(); + expect(() => process.binding("js_stream")).toThrow(); + expect(() => process.binding("natives")).not.toThrow(); + expect(() => process.binding("os")).toThrow(); + expect(() => process.binding("pipe_wrap")).toThrow(); + expect(() => process.binding("process_wrap")).toThrow(); + expect(() => process.binding("signal_wrap")).toThrow(); + expect(() => process.binding("spawn_sync")).toThrow(); + expect(() => process.binding("stream_wrap")).toThrow(); + expect(() => process.binding("tcp_wrap")).toThrow(); + expect(() => process.binding("tls_wrap")).toThrow(); + expect(() => process.binding("tty_wrap")).not.toThrow(); + expect(() => process.binding("udp_wrap")).toThrow(); + expect(() => process.binding("url")).toThrow(); + expect(() => process.binding("util")).not.toThrow(); + expect(() => process.binding("uv")).not.toThrow(); + expect(() => process.binding("v8")).toThrow(); + expect(() => process.binding("zlib")).toThrow(); + + expect(() => process.binding()).toThrow(); + expect(() => process.binding(10)).toThrow(); + expect(() => process.binding(10n)).toThrow(); + expect(() => process.binding(null)).toThrow(); + expect(() => process.binding(true)).toThrow(); + expect(() => process.binding("")).toThrow(); + expect(() => process.binding(function () {})).toThrow(); + expect(() => process.binding(() => {})).toThrow(); + expect(() => process.binding(Symbol("ab"))).toThrow(); + expect(() => process.binding({})).toThrow(); + expect(() => process.binding(Object.freeze({ __proto__: null }))).toThrow(); }); it("process.argv in testing", () => { From b3e4a7aa0a63c5f1a462033fc88676b29dbe7f12 Mon Sep 17 00:00:00 2001 From: Meghan Denny Date: Mon, 27 Jan 2025 16:58:14 -0800 Subject: [PATCH 3/3] use the macro --- src/bun.js/bindings/ProcessBindingBuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bun.js/bindings/ProcessBindingBuffer.cpp b/src/bun.js/bindings/ProcessBindingBuffer.cpp index 12acdf0141c7b4..c0bb0f079c68e0 100644 --- a/src/bun.js/bindings/ProcessBindingBuffer.cpp +++ b/src/bun.js/bindings/ProcessBindingBuffer.cpp @@ -7,7 +7,7 @@ namespace Bun { using namespace JSC; #define PROCESS_BINDING_NOT_IMPLEMENTED(str) \ - JSC ::EncodedJSValue ProcessBinding_Buffer_##str(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame) \ + JSC_DEFINE_HOST_FUNCTION(ProcessBinding_Buffer_##str, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame * callFrame)) \ { \ { \ auto& vm = JSC::getVM(lexicalGlobalObject); \