diff options
Diffstat (limited to 'src/bun.js/bindings/helpers.h')
-rw-r--r-- | src/bun.js/bindings/helpers.h | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/src/bun.js/bindings/helpers.h b/src/bun.js/bindings/helpers.h new file mode 100644 index 000000000..5b5fb5fd2 --- /dev/null +++ b/src/bun.js/bindings/helpers.h @@ -0,0 +1,327 @@ +#pragma once + +#include "root.h" + +#include "headers.h" + +#include "JavaScriptCore/Error.h" +#include "JavaScriptCore/Exception.h" +#include "JavaScriptCore/Identifier.h" +#include "JavaScriptCore/JSGlobalObject.h" +#include "JavaScriptCore/JSString.h" +#include "JavaScriptCore/JSValueInternal.h" +#include "JavaScriptCore/ThrowScope.h" +#include "JavaScriptCore/VM.h" + +template<class CppType, typename ZigType> class Wrap { +public: + Wrap() {}; + + Wrap(ZigType zig) + { + result = zig; + cpp = static_cast<CppType*>(static_cast<void*>(&zig)); + }; + + Wrap(ZigType* zig) { cpp = static_cast<CppType*>(static_cast<void*>(&zig)); }; + + Wrap(CppType _cpp) + { + auto buffer = alignedBuffer(); + cpp = new (buffer) CppType(_cpp); + }; + + ~Wrap() {}; + + unsigned char* alignedBuffer() + { + return result.bytes + alignof(CppType) - reinterpret_cast<intptr_t>(result.bytes) % alignof(CppType); + } + + ZigType result; + CppType* cpp; + + static ZigType wrap(CppType obj) { return *static_cast<ZigType*>(static_cast<void*>(&obj)); } + + static CppType unwrap(ZigType obj) { return *static_cast<CppType*>(static_cast<void*>(&obj)); } + + static CppType* unwrap(ZigType* obj) { return static_cast<CppType*>(static_cast<void*>(obj)); } +}; + +template<class To, class From> To cast(From v) +{ + return *static_cast<To*>(static_cast<void*>(v)); +} + +template<class To, class From> To ccast(From v) +{ + return *static_cast<const To*>(static_cast<const void*>(v)); +} + +static const JSC::ArgList makeArgs(JSC__JSValue* v, size_t count) +{ + JSC::MarkedArgumentBuffer args = JSC::MarkedArgumentBuffer(); + args.ensureCapacity(count); + for (size_t i = 0; i < count; ++i) { + args.append(JSC::JSValue::decode(v[i])); + } + + return JSC::ArgList(args); +} + +namespace Zig { + +// 8 bit byte +// we tag the final two bits +// so 56 bits are copied over +// rest we zero out for consistentcy +static const unsigned char* untag(const unsigned char* ptr) +{ + return reinterpret_cast<const unsigned char*>( + ((reinterpret_cast<uintptr_t>(ptr) & ~(static_cast<uint64_t>(1) << 63) & ~(static_cast<uint64_t>(1) << 62)) & ~(static_cast<uint64_t>(1) << 61))); +} + +static void* untagVoid(const unsigned char* ptr) +{ + return const_cast<void*>(reinterpret_cast<const void*>(untag(ptr))); +} + +static void* untagVoid(const char16_t* ptr) +{ + return untagVoid(reinterpret_cast<const unsigned char*>(ptr)); +} + +static const JSC::Identifier toIdentifier(ZigString str, JSC::JSGlobalObject* global) +{ + if (str.len == 0 || str.ptr == nullptr) { + return JSC::Identifier::EmptyIdentifier; + } + + return JSC::Identifier::fromString(global->vm(), untag(str.ptr), str.len); +} + +static bool isTaggedUTF16Ptr(const unsigned char* ptr) +{ + return (reinterpret_cast<uintptr_t>(ptr) & (static_cast<uint64_t>(1) << 63)) != 0; +} + +// Do we need to convert the string from UTF-8 to UTF-16? +static bool isTaggedUTF8Ptr(const unsigned char* ptr) +{ + return (reinterpret_cast<uintptr_t>(ptr) & (static_cast<uint64_t>(1) << 61)) != 0; +} + +static bool isTaggedExternalPtr(const unsigned char* ptr) +{ + return (reinterpret_cast<uintptr_t>(ptr) & (static_cast<uint64_t>(1) << 62)) != 0; +} + +static void free_global_string(void* str, void* ptr, unsigned len) +{ + // i don't understand why this happens + if (ptr == nullptr) + return; + + ZigString__free_global(reinterpret_cast<const unsigned char*>(ptr), len); +} + +// Switching to AtomString doesn't yield a perf benefit because we're recreating it each time. +static const WTF::String toString(ZigString str) +{ + if (str.len == 0 || str.ptr == nullptr) { + return WTF::String(); + } + if (UNLIKELY(isTaggedUTF8Ptr(str.ptr))) { + return WTF::String::fromUTF8(untag(str.ptr), str.len); + } + + if (UNLIKELY(isTaggedExternalPtr(str.ptr))) { + return !isTaggedUTF16Ptr(str.ptr) + ? WTF::String(WTF::ExternalStringImpl::create(untag(str.ptr), str.len, untagVoid(str.ptr), free_global_string)) + : WTF::String(WTF::ExternalStringImpl::create( + reinterpret_cast<const UChar*>(untag(str.ptr)), str.len, untagVoid(str.ptr), free_global_string)); + } + + return !isTaggedUTF16Ptr(str.ptr) + ? WTF::String(WTF::StringImpl::createWithoutCopying(untag(str.ptr), str.len)) + : WTF::String(WTF::StringImpl::createWithoutCopying( + reinterpret_cast<const UChar*>(untag(str.ptr)), str.len)); +} + +static const WTF::String toString(ZigString str, StringPointer ptr) +{ + if (str.len == 0 || str.ptr == nullptr || ptr.len == 0) { + return WTF::String(); + } + if (UNLIKELY(isTaggedUTF8Ptr(str.ptr))) { + return WTF::String::fromUTF8(&untag(str.ptr)[ptr.off], ptr.len); + } + + return !isTaggedUTF16Ptr(str.ptr) + ? WTF::String(WTF::StringImpl::createWithoutCopying(&untag(str.ptr)[ptr.off], ptr.len)) + : WTF::String(WTF::StringImpl::createWithoutCopying( + &reinterpret_cast<const UChar*>(untag(str.ptr))[ptr.off], ptr.len)); +} + +static const WTF::String toStringCopy(ZigString str, StringPointer ptr) +{ + if (str.len == 0 || str.ptr == nullptr || ptr.len == 0) { + return WTF::String(); + } + if (UNLIKELY(isTaggedUTF8Ptr(str.ptr))) { + return WTF::String::fromUTF8(&untag(str.ptr)[ptr.off], ptr.len); + } + + return !isTaggedUTF16Ptr(str.ptr) + ? WTF::String(WTF::StringImpl::create(&untag(str.ptr)[ptr.off], ptr.len)) + : WTF::String(WTF::StringImpl::create( + &reinterpret_cast<const UChar*>(untag(str.ptr))[ptr.off], ptr.len)); +} + +static const WTF::String toStringCopy(ZigString str) +{ + if (str.len == 0 || str.ptr == nullptr) { + return WTF::String(); + } + if (UNLIKELY(isTaggedUTF8Ptr(str.ptr))) { + return WTF::String::fromUTF8(untag(str.ptr), str.len); + } + + return !isTaggedUTF16Ptr(str.ptr) ? WTF::String(WTF::StringImpl::create(untag(str.ptr), str.len)) + : WTF::String(WTF::StringImpl::create( + reinterpret_cast<const UChar*>(untag(str.ptr)), str.len)); +} + +static WTF::String toStringNotConst(ZigString str) { return toString(str); } + +static const JSC::JSString* toJSString(ZigString str, JSC::JSGlobalObject* global) +{ + return JSC::jsOwnedString(global->vm(), toString(str)); +} + +static const JSC::JSValue toJSStringValue(ZigString str, JSC::JSGlobalObject* global) +{ + return JSC::JSValue(toJSString(str, global)); +} + +static const JSC::JSString* toJSStringGC(ZigString str, JSC::JSGlobalObject* global) +{ + return JSC::jsString(global->vm(), toStringCopy(str)); +} + +static const JSC::JSValue toJSStringValueGC(ZigString str, JSC::JSGlobalObject* global) +{ + return JSC::JSValue(toJSString(str, global)); +} + +static const ZigString ZigStringEmpty = ZigString { nullptr, 0 }; +static const unsigned char __dot_char = '.'; +static const ZigString ZigStringCwd = ZigString { &__dot_char, 1 }; + +static const unsigned char* taggedUTF16Ptr(const UChar* ptr) +{ + return reinterpret_cast<const unsigned char*>(reinterpret_cast<uintptr_t>(ptr) | (static_cast<uint64_t>(1) << 63)); +} + +static ZigString toZigString(WTF::String* str) +{ + return str->isEmpty() + ? ZigStringEmpty + : ZigString { str->is8Bit() ? str->characters8() : taggedUTF16Ptr(str->characters16()), + str->length() }; +} + +static ZigString toZigString(WTF::StringImpl& str) +{ + return str.isEmpty() + ? ZigStringEmpty + : ZigString { str.is8Bit() ? str.characters8() : taggedUTF16Ptr(str.characters16()), + str.length() }; +} + +static ZigString toZigString(WTF::StringView& str) +{ + return str.isEmpty() + ? ZigStringEmpty + : ZigString { str.is8Bit() ? str.characters8() : taggedUTF16Ptr(str.characters16()), + str.length() }; +} + +static ZigString toZigString(const WTF::StringView& str) +{ + return str.isEmpty() + ? ZigStringEmpty + : ZigString { str.is8Bit() ? str.characters8() : taggedUTF16Ptr(str.characters16()), + str.length() }; +} + +static ZigString toZigString(JSC::JSString& str, JSC::JSGlobalObject* global) +{ + return toZigString(str.value(global)); +} + +static ZigString toZigString(JSC::JSString* str, JSC::JSGlobalObject* global) +{ + return toZigString(str->value(global)); +} + +static ZigString toZigString(JSC::Identifier& str, JSC::JSGlobalObject* global) +{ + return toZigString(str.string()); +} + +static ZigString toZigString(JSC::Identifier* str, JSC::JSGlobalObject* global) +{ + return toZigString(str->string()); +} + +static WTF::StringView toStringView(ZigString str) +{ + return WTF::StringView(untag(str.ptr), str.len); +} + +static void throwException(JSC::ThrowScope& scope, ZigErrorType err, JSC::JSGlobalObject* global) +{ + scope.throwException(global, + JSC::Exception::create(global->vm(), JSC::JSValue((JSC::JSCell*)err.ptr))); +} + +static ZigString toZigString(JSC::JSValue val, JSC::JSGlobalObject* global) +{ + auto scope = DECLARE_THROW_SCOPE(global->vm()); + WTF::String str = val.toWTFString(global); + + if (scope.exception()) { + scope.clearException(); + scope.release(); + return ZigStringEmpty; + } + + scope.release(); + + return toZigString(str); +} + +static JSC::JSValue getErrorInstance(const ZigString* str, JSC__JSGlobalObject* globalObject) +{ + JSC::VM& vm = globalObject->vm(); + + JSC::JSObject* result = JSC::createError(globalObject, toString(*str)); + JSC::EnsureStillAliveScope ensureAlive(result); + + return JSC::JSValue(result); +} + +}; // namespace Zig + +template<typename WebCoreType, typename OutType> +OutType* WebCoreCast(JSC__JSValue JSValue0) +{ + // we must use jsDynamicCast here so that we check that the type is correct + WebCoreType* jsdomURL = JSC::jsDynamicCast<WebCoreType*>(JSC::JSValue::decode(JSValue0)); + if (jsdomURL == nullptr) { + return nullptr; + } + + return reinterpret_cast<OutType*>(&jsdomURL->wrapped()); +} |