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

implement process.binding('buffer') #16741

Merged
merged 6 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmake/targets/BuildBun.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/bun.js/bindings/BunProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2565,10 +2565,11 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionBinding, (JSGlobalObject * jsGlobalObje
auto globalObject = jsCast<Zig::GlobalObject*>(jsGlobalObject);
auto process = jsCast<Process*>(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");
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());
Expand Down
159 changes: 159 additions & 0 deletions src/bun.js/bindings/ProcessBindingBuffer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@

#include "ProcessBindingBuffer.h"
#include <JavaScriptCore/ObjectConstructor.h>
#include "JSBuffer.h"

namespace Bun {
using namespace JSC;

#define PROCESS_BINDING_NOT_IMPLEMENTED(str) \
JSC_DEFINE_HOST_FUNCTION(ProcessBinding_Buffer_##str, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::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<ProcessBindingBuffer>(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<typename Visitor>
void ProcessBindingBuffer::visitChildrenImpl(JSCell* cell, Visitor& visitor)
{
ProcessBindingBuffer* thisObject = jsCast<ProcessBindingBuffer*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
Base::visitChildren(thisObject, visitor);
}

DEFINE_VISIT_CHILDREN(ProcessBindingBuffer);

} // namespace Bun
37 changes: 37 additions & 0 deletions src/bun.js/bindings/ProcessBindingBuffer.h
Original file line number Diff line number Diff line change
@@ -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<typename CellType, JSC::SubspaceAccess>
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
10 changes: 10 additions & 0 deletions src/bun.js/bindings/ZigGlobalObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,9 @@
#include "JSX509Certificate.h"
#include "JSS3File.h"
#include "S3Error.h"
#include "ProcessBindingBuffer.h"
#include <JavaScriptCore/JSBasePrivate.h>

#if ENABLE(REMOTE_INSPECTOR)
#include "JavaScriptCore/RemoteInspectorServer.h"
#endif
Expand Down Expand Up @@ -3224,6 +3226,14 @@ void GlobalObject::finishCreation(VM& vm)
InternalModuleRegistry::createStructure(init.vm, init.owner)));
});

m_processBindingBuffer.initLater(
[](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSObject>::Initializer& init) {
init.set(
ProcessBindingBuffer::create(
init.vm,
ProcessBindingBuffer::createStructure(init.vm, init.owner)));
});

m_processBindingConstants.initLater(
[](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSObject>::Initializer& init) {
init.set(
Expand Down
2 changes: 2 additions & 0 deletions src/bun.js/bindings/ZigGlobalObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
Expand Down Expand Up @@ -579,6 +580,7 @@ class GlobalObject : public Bun::GlobalScope {
LazyProperty<JSGlobalObject, JSObject> m_requireFunctionUnbound;
LazyProperty<JSGlobalObject, JSObject> m_requireResolveFunctionUnbound;
LazyProperty<JSGlobalObject, Bun::InternalModuleRegistry> m_internalModuleRegistry;
LazyProperty<JSGlobalObject, JSObject> m_processBindingBuffer;
LazyProperty<JSGlobalObject, JSObject> m_processBindingConstants;
LazyProperty<JSGlobalObject, Structure> m_importMetaObjectStructure;
LazyProperty<JSGlobalObject, Structure> m_asyncBoundFunctionStructure;
Expand Down
43 changes: 42 additions & 1 deletion test/js/node/process/process.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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", () => {
Expand Down