mirror of
https://github.com/oven-sh/bun
synced 2026-02-11 19:38:58 +00:00
[bun:ffi] ~20% faster FFI bindings for functions with arguments
This commit is contained in:
79
src/javascript/jsc/bindings/JSFFIFunction.cpp
Normal file
79
src/javascript/jsc/bindings/JSFFIFunction.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2021 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "root.h"
|
||||
#include "JSFFIFunction.h"
|
||||
|
||||
#include "JavaScriptCore/JSCJSValueInlines.h"
|
||||
#include "JavaScriptCore/VM.h"
|
||||
#include "ZigGlobalObject.h"
|
||||
|
||||
extern "C" Zig::JSFFIFunction* Bun__CreateFFIFunction(Zig::GlobalObject* globalObject, const ZigString* symbolName, unsigned argCount, Zig::FFIFunction functionPointer)
|
||||
{
|
||||
JSC::VM& vm = globalObject->vm();
|
||||
Zig::JSFFIFunction* function = Zig::JSFFIFunction::create(vm, globalObject, argCount, Zig::toStringCopy(*symbolName), functionPointer, JSC::NoIntrinsic);
|
||||
JSC::gcProtect(function);
|
||||
return function;
|
||||
}
|
||||
|
||||
namespace Zig {
|
||||
using namespace JSC;
|
||||
|
||||
const ClassInfo JSFFIFunction::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSFFIFunction) };
|
||||
|
||||
JSFFIFunction::JSFFIFunction(VM& vm, NativeExecutable* executable, JSGlobalObject* globalObject, Structure* structure, FFIFunction&& function)
|
||||
: Base(vm, executable, globalObject, structure)
|
||||
, m_function(WTFMove(function))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Visitor>
|
||||
void JSFFIFunction::visitChildrenImpl(JSCell* cell, Visitor& visitor)
|
||||
{
|
||||
JSFFIFunction* thisObject = jsCast<JSFFIFunction*>(cell);
|
||||
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
|
||||
Base::visitChildren(thisObject, visitor);
|
||||
}
|
||||
|
||||
DEFINE_VISIT_CHILDREN(JSFFIFunction);
|
||||
|
||||
void JSFFIFunction::finishCreation(VM& vm, NativeExecutable* executable, unsigned length, const String& name)
|
||||
{
|
||||
Base::finishCreation(vm, executable, length, name);
|
||||
ASSERT(inherits(vm, info()));
|
||||
}
|
||||
|
||||
JSFFIFunction* JSFFIFunction::create(VM& vm, Zig::GlobalObject* globalObject, unsigned length, const String& name, FFIFunction FFIFunction, Intrinsic intrinsic, NativeFunction nativeConstructor)
|
||||
{
|
||||
|
||||
NativeExecutable* executable = vm.getHostFunction(FFIFunction, intrinsic, nativeConstructor, nullptr, name);
|
||||
|
||||
Structure* structure = globalObject->FFIFunctionStructure();
|
||||
JSFFIFunction* function = new (NotNull, allocateCell<JSFFIFunction>(vm)) JSFFIFunction(vm, executable, globalObject, structure, WTFMove(FFIFunction));
|
||||
function->finishCreation(vm, executable, length, name);
|
||||
return function;
|
||||
}
|
||||
|
||||
} // namespace JSC
|
||||
71
src/javascript/jsc/bindings/JSFFIFunction.h
Normal file
71
src/javascript/jsc/bindings/JSFFIFunction.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
namespace Zig {
|
||||
class GlobalObject;
|
||||
}
|
||||
|
||||
#include "root.h"
|
||||
#include "JavaScriptCore/JSFunction.h"
|
||||
#include "JavaScriptCore/VM.h"
|
||||
|
||||
#include "headers-handwritten.h"
|
||||
#include "BunClientData.h"
|
||||
#include "WebCoreJSBuiltinInternals.h"
|
||||
#include "JavaScriptCore/CallFrame.h"
|
||||
|
||||
namespace JSC {
|
||||
class JSGlobalObject;
|
||||
}
|
||||
|
||||
namespace Zig {
|
||||
|
||||
using namespace JSC;
|
||||
|
||||
using FFIFunction = JSC::EncodedJSValue (*)(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame);
|
||||
|
||||
class JSFFIFunction final : public JSC::JSFunction {
|
||||
public:
|
||||
using Base = JSFunction;
|
||||
|
||||
static constexpr unsigned StructureFlags = Base::StructureFlags;
|
||||
static constexpr bool needsDestruction = false;
|
||||
static void destroy(JSCell* cell)
|
||||
{
|
||||
static_cast<JSFFIFunction*>(cell)->JSFFIFunction::~JSFFIFunction();
|
||||
}
|
||||
|
||||
template<typename, SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
|
||||
{
|
||||
if constexpr (mode == JSC::SubspaceAccess::Concurrently)
|
||||
return nullptr;
|
||||
return WebCore::subspaceForImpl<JSFFIFunction, WebCore::UseCustomHeapCellType::No>(
|
||||
vm,
|
||||
[](auto& spaces) { return spaces.m_clientSubspaceForFFIFunction.get(); },
|
||||
[](auto& spaces, auto&& space) { spaces.m_clientSubspaceForFFIFunction = WTFMove(space); },
|
||||
[](auto& spaces) { return spaces.m_subspaceForFFIFunction.get(); },
|
||||
[](auto& spaces, auto&& space) { spaces.m_subspaceForFFIFunction = WTFMove(space); });
|
||||
}
|
||||
|
||||
DECLARE_EXPORT_INFO;
|
||||
|
||||
JS_EXPORT_PRIVATE static JSFFIFunction* create(VM&, Zig::GlobalObject*, unsigned length, const String& name, FFIFunction, Intrinsic = NoIntrinsic, NativeFunction nativeConstructor = callHostFunctionAsConstructor);
|
||||
|
||||
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
|
||||
{
|
||||
ASSERT(globalObject);
|
||||
return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
|
||||
}
|
||||
|
||||
const FFIFunction function() { return m_function; }
|
||||
|
||||
private:
|
||||
JSFFIFunction(VM&, NativeExecutable*, JSGlobalObject*, Structure*, FFIFunction&&);
|
||||
void finishCreation(VM&, NativeExecutable*, unsigned length, const String& name);
|
||||
DECLARE_VISIT_CHILDREN;
|
||||
|
||||
FFIFunction m_function;
|
||||
};
|
||||
|
||||
} // namespace JSC
|
||||
|
||||
extern "C" Zig::JSFFIFunction* Bun__CreateFFIFunction(Zig::GlobalObject* globalObject, const ZigString* symbolName, unsigned argCount, Zig::FFIFunction functionPointer);
|
||||
@@ -89,6 +89,11 @@
|
||||
#include "JavaScriptCore/RemoteInspectorServer.h"
|
||||
#include "WebCoreJSBuiltinInternals.h"
|
||||
#include "JSBuffer.h"
|
||||
#include "JSFFIFunction.h"
|
||||
#include "JavaScriptCore/InternalFunction.h"
|
||||
#include "JavaScriptCore/LazyClassStructure.h"
|
||||
#include "JavaScriptCore/LazyClassStructureInlines.h"
|
||||
#include "JavaScriptCore/FunctionPrototype.h"
|
||||
|
||||
using JSGlobalObject = JSC::JSGlobalObject;
|
||||
using Exception = JSC::Exception;
|
||||
@@ -857,6 +862,11 @@ void GlobalObject::installAPIGlobals(JSClassRef* globals, int count, JSC::VM& vm
|
||||
|
||||
this->addStaticGlobals(extraStaticGlobals.data(), extraStaticGlobals.size());
|
||||
|
||||
m_JSFFIFunctionStructure.initLater(
|
||||
[](LazyClassStructure::Initializer& init) {
|
||||
init.setStructure(Zig::JSFFIFunction::createStructure(init.vm, init.global, init.global->m_functionPrototype.get()));
|
||||
});
|
||||
|
||||
putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "process"_s), JSC::CustomGetterSetter::create(vm, property_lazyProcessGetter, property_lazyProcessSetter),
|
||||
JSC::PropertyAttribute::CustomAccessor | 0);
|
||||
|
||||
@@ -923,7 +933,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
|
||||
visitor.append(constructor);
|
||||
|
||||
// thisObject->m_builtinInternalFunctions.visit(visitor);
|
||||
|
||||
thisObject->m_JSFFIFunctionStructure.visit(visitor);
|
||||
ScriptExecutionContext* context = thisObject->scriptExecutionContext();
|
||||
visitor.addOpaqueRoot(context);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
namespace JSC {
|
||||
class Structure;
|
||||
class Identifier;
|
||||
class LazyClassStructure;
|
||||
|
||||
} // namespace JSC
|
||||
|
||||
@@ -127,6 +128,7 @@ public:
|
||||
void setConsole(void* console);
|
||||
void installAPIGlobals(JSClassRef* globals, int count, JSC::VM& vm);
|
||||
WebCore::JSBuiltinInternalFunctions& builtinInternalFunctions() { return m_builtinInternalFunctions; }
|
||||
JSC::Structure* FFIFunctionStructure() { return m_JSFFIFunctionStructure.getInitializedOnMainThread(this); }
|
||||
|
||||
private:
|
||||
void addBuiltinGlobals(JSC::VM&);
|
||||
@@ -139,6 +141,7 @@ private:
|
||||
Lock m_gcLock;
|
||||
WebCore::ScriptExecutionContext* m_scriptExecutionContext;
|
||||
Ref<WebCore::DOMWrapperWorld> m_world;
|
||||
LazyClassStructure m_JSFFIFunctionStructure;
|
||||
};
|
||||
|
||||
class JSMicrotaskCallback : public RefCounted<JSMicrotaskCallback> {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Auto-generated by src/javascript/jsc/headergen/sizegen.cpp at 2021-09-05 16:21:1630884091.
|
||||
// Auto-generated by src/javascript/jsc/headergen/sizegen.cpp at 2022-05-02 01:43:1651481039.
|
||||
// These are the byte sizes for the different object types with bindings in JavaScriptCore.
|
||||
// This allows us to safely return stack allocated C++ types to Zig.
|
||||
// It is only safe to do this when these sizes are correct.
|
||||
@@ -15,6 +15,12 @@
|
||||
// Run "jsc-bindings-headers" twice because it uses these values in the output. That's how all the bJSC__.* types are created - from these values.
|
||||
pub const JSC__JSObject = 16;
|
||||
pub const JSC__JSObject_align = 8;
|
||||
pub const WebCore__DOMURL = 112;
|
||||
pub const WebCore__DOMURL_align = 8;
|
||||
pub const WebCore__FetchHeaders = 40;
|
||||
pub const WebCore__FetchHeaders_align = 8;
|
||||
pub const SystemError = 72;
|
||||
pub const SystemError_align = 8;
|
||||
pub const JSC__JSCell = 8;
|
||||
pub const JSC__JSCell_align = 4;
|
||||
pub const JSC__JSString = 16;
|
||||
@@ -35,7 +41,7 @@ pub const JSC__SourceCode = 24;
|
||||
pub const JSC__SourceCode_align = 8;
|
||||
pub const JSC__JSFunction = 32;
|
||||
pub const JSC__JSFunction_align = 8;
|
||||
pub const JSC__JSGlobalObject = 2400;
|
||||
pub const JSC__JSGlobalObject = 2312;
|
||||
pub const JSC__JSGlobalObject_align = 8;
|
||||
pub const WTF__URL = 40;
|
||||
pub const WTF__URL_align = 8;
|
||||
@@ -47,7 +53,7 @@ pub const JSC__PropertyName = 8;
|
||||
pub const JSC__PropertyName_align = 8;
|
||||
pub const JSC__Exception = 40;
|
||||
pub const JSC__Exception_align = 8;
|
||||
pub const JSC__VM = 48824;
|
||||
pub const JSC__VM = 52168;
|
||||
pub const JSC__VM_align = 8;
|
||||
pub const JSC__ThrowScope = 8;
|
||||
pub const JSC__ThrowScope_align = 8;
|
||||
@@ -59,9 +65,16 @@ pub const JSC__Identifier = 8;
|
||||
pub const JSC__Identifier_align = 8;
|
||||
pub const WTF__StringImpl = 24;
|
||||
pub const WTF__StringImpl_align = 8;
|
||||
pub const WTF__ExternalStringImpl = 32;
|
||||
pub const WTF__ExternalStringImpl = 40;
|
||||
pub const WTF__ExternalStringImpl_align = 8;
|
||||
pub const WTF__StringView = 16;
|
||||
pub const WTF__StringView_align = 8;
|
||||
pub const Zig__GlobalObject = 2400;
|
||||
pub const Zig__GlobalObject = 2384;
|
||||
pub const Zig__GlobalObject_align = 8;
|
||||
pub const Bun__Readable = 24;
|
||||
pub const Bun__Readable_align = 4;
|
||||
pub const Bun__Writable = 20;
|
||||
pub const Bun__Writable_align = 4;
|
||||
pub const Bun__Path = 8;
|
||||
pub const Bun__Path_align = 8;
|
||||
pub const Bun_FFI_PointerOffsetToArgumentsList = 6;
|
||||
|
||||
@@ -17,6 +17,7 @@ public:
|
||||
|
||||
/* --- bun --- */
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForBuffer;
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForFFIFunction;
|
||||
/* --- bun --- */
|
||||
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForGlobalObject;
|
||||
|
||||
@@ -17,6 +17,7 @@ public:
|
||||
DOMIsoSubspaces() = default;
|
||||
/*-- BUN --*/
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForBuffer;
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForFFIFunction;
|
||||
/*-- BUN --*/
|
||||
|
||||
// std::unique_ptr<IsoSubspace> m_subspaceForTouch;
|
||||
|
||||
@@ -31,12 +31,18 @@ export class CString extends String {
|
||||
#cachedArrayBuffer;
|
||||
|
||||
get arrayBuffer() {
|
||||
return (this.#cachedArrayBuffer ||= toArrayBuffer.apply(
|
||||
null,
|
||||
typeof this.byteOffset === "number" &&
|
||||
typeof this.byteLength === typeof this.byteOffset
|
||||
? [this.ptr, this.byteOffset, this.byteLength]
|
||||
: [this.ptr]
|
||||
if (this.#cachedArrayBuffer) {
|
||||
return this.#cachedArrayBuffer;
|
||||
}
|
||||
|
||||
if (!this.ptr) {
|
||||
return (this.#cachedArrayBuffer = new ArrayBuffer(0));
|
||||
}
|
||||
|
||||
return (this.#cachedArrayBuffer = toArrayBuffer(
|
||||
this.ptr,
|
||||
this.byteOffset,
|
||||
this.byteLength
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,18 @@
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
#include "root.h"
|
||||
|
||||
#include "ZigGlobalObject.h"
|
||||
|
||||
#include "Path.h"
|
||||
|
||||
#include "DOMURL.h"
|
||||
|
||||
#include "headers-cpp.h"
|
||||
|
||||
#include "JavaScriptCore/CallFrame.h"
|
||||
|
||||
int main() {
|
||||
time_t rawtime;
|
||||
struct tm *timeinfo;
|
||||
@@ -44,6 +54,7 @@ int main() {
|
||||
cout << "pub const " << names[i] << " = " << sizes[i] << ";\n";
|
||||
cout << "pub const " << names[i] << "_align = " << aligns[i] << ";\n";
|
||||
}
|
||||
|
||||
cout << "pub const Bun_FFI_PointerOffsetToArgumentsList = << "
|
||||
<< JSC::CallFrame::argumentOffset(0) << ";\n";
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user