diff options
author | 2022-08-12 01:17:02 -0700 | |
---|---|---|
committer | 2022-08-12 01:18:31 -0700 | |
commit | 5c1ca0cc479526967397247a874ea7792787f249 (patch) | |
tree | e907b58d9bd79b53b61f9f683fe7906ecdd209a7 /src/bun.js | |
parent | 2ac8c83be0fce4f56af3621d637d34f3fc1c39f5 (diff) | |
download | bun-5c1ca0cc479526967397247a874ea7792787f249.tar.gz bun-5c1ca0cc479526967397247a874ea7792787f249.tar.zst bun-5c1ca0cc479526967397247a874ea7792787f249.zip |
[bun.js] up to 60% faster TextEncoder.encodeInto and ~3% faster TextEncoder.encode
Diffstat (limited to 'src/bun.js')
-rw-r--r-- | src/bun.js/bindings/headers-cpp.h | 2 | ||||
-rw-r--r-- | src/bun.js/bindings/headers.h | 2 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/DOMJITCheckDOM.h | 98 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/DOMJITHelpers.cpp | 57 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/DOMJITHelpers.h | 216 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/DOMJITIDLConvert.h | 59 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/DOMJITIDLType.h | 50 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/DOMJITIDLTypeFilter.h | 80 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/JSEventDOMJIT.cpp | 44 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/JSTextEncoder.cpp | 153 | ||||
-rw-r--r-- | src/bun.js/builtins/BunBuiltinNames.h | 1 | ||||
-rw-r--r-- | src/bun.js/webcore/encoding.zig | 144 |
12 files changed, 822 insertions, 84 deletions
diff --git a/src/bun.js/bindings/headers-cpp.h b/src/bun.js/bindings/headers-cpp.h index 4cb7a80e0..0f1772882 100644 --- a/src/bun.js/bindings/headers-cpp.h +++ b/src/bun.js/bindings/headers-cpp.h @@ -1,4 +1,4 @@ -//-- AUTOGENERATED FILE -- 1660175100 +//-- AUTOGENERATED FILE -- 1660283220 // clang-format off #pragma once diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h index 9fd86fb2e..0afc722bf 100644 --- a/src/bun.js/bindings/headers.h +++ b/src/bun.js/bindings/headers.h @@ -1,5 +1,5 @@ // clang-format off -//-- AUTOGENERATED FILE -- 1660175100 +//-- AUTOGENERATED FILE -- 1660283220 #pragma once #include <stddef.h> diff --git a/src/bun.js/bindings/webcore/DOMJITCheckDOM.h b/src/bun.js/bindings/webcore/DOMJITCheckDOM.h new file mode 100644 index 000000000..98554085a --- /dev/null +++ b/src/bun.js/bindings/webcore/DOMJITCheckDOM.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2016 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. + * + */ + +#pragma once + +#include "DOMJITHelpers.h" + +#if ENABLE(JIT) + +// #include "Document.h" +// #include "Element.h" +#include "Event.h" +#include "Node.h" + +namespace WebCore { +namespace DOMJIT { + +template<typename DOMInterface> +struct TypeChecker { +}; + +template<> +struct TypeChecker<Node> { + static CCallHelpers::Jump branchIfFail(CCallHelpers& jit, GPRReg dom) + { + return DOMJIT::branchIfNotNode(jit, dom); + } +}; + +// template<> +// struct TypeChecker<Document> { +// static CCallHelpers::Jump branchIfFail(CCallHelpers& jit, GPRReg dom) +// { +// return DOMJIT::branchIfNotDocumentWrapper(jit, dom); +// } +// }; + +// template<> +// struct TypeChecker<DocumentFragment> { +// static CCallHelpers::Jump branchIfFail(CCallHelpers& jit, GPRReg dom) +// { +// return DOMJIT::branchIfNotDocumentFragment(jit, dom); +// } +// }; + +template<> +struct TypeChecker<Event> { + static CCallHelpers::Jump branchIfFail(CCallHelpers& jit, GPRReg dom) + { + return DOMJIT::branchIfNotEvent(jit, dom); + } +}; + +// template<> +// struct TypeChecker<Element> { +// static CCallHelpers::Jump branchIfFail(CCallHelpers& jit, GPRReg dom) +// { +// return DOMJIT::branchIfNotElement(jit, dom); +// } +// }; + +template<typename DOMInterface> +Ref<JSC::Snippet> checkDOM() +{ + Ref<JSC::Snippet> snippet = JSC::Snippet::create(); + snippet->setGenerator([=](CCallHelpers& jit, JSC::SnippetParams& params) { + return TypeChecker<DOMInterface>::branchIfFail(jit, params[0].gpr()); + }); + return snippet; +} + +} +} + +#endif diff --git a/src/bun.js/bindings/webcore/DOMJITHelpers.cpp b/src/bun.js/bindings/webcore/DOMJITHelpers.cpp new file mode 100644 index 000000000..4666ea358 --- /dev/null +++ b/src/bun.js/bindings/webcore/DOMJITHelpers.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 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 "config.h" +#include "DOMJITHelpers.h" + +#if ENABLE(JIT) + +// #include "Document.h" +#include "JSDOMBinding.h" +#include "Node.h" + +namespace WebCore { +namespace DOMJIT { + +using JSC::CCallHelpers; +using JSC::GPRReg; +using JSC::JSValueRegs; +using JSC::MacroAssembler; + +// void loadDocument(MacroAssembler& jit, GPRReg node, GPRReg output) +// { +// jit.loadPtr(CCallHelpers::Address(node, Node::treeScopeMemoryOffset()), output); +// jit.loadPtr(CCallHelpers::Address(output, TreeScope::documentScopeMemoryOffset()), output); +// } + +// void loadDocumentElement(MacroAssembler& jit, GPRReg document, GPRReg output) +// { +// jit.loadPtr(CCallHelpers::Address(document, Document::documentElementMemoryOffset()), output); +// } + +} +} + +#endif diff --git a/src/bun.js/bindings/webcore/DOMJITHelpers.h b/src/bun.js/bindings/webcore/DOMJITHelpers.h new file mode 100644 index 000000000..73bfc7430 --- /dev/null +++ b/src/bun.js/bindings/webcore/DOMJITHelpers.h @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2016-2019 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. + * + */ + +#pragma once + +#include "JSDOMWrapper.h" +#include "Node.h" +#include <JavaScriptCore/FrameTracers.h> +#include <JavaScriptCore/SnippetParams.h> + +#if ENABLE(JIT) + +IGNORE_WARNINGS_BEGIN("frame-address") + +namespace WebCore { +namespace DOMJIT { + +using JSC::CCallHelpers; +using JSC::GPRReg; +using JSC::JSValueRegs; +using JSC::MacroAssembler; + +static_assert(std::is_same<GPRReg, MacroAssembler::RegisterID>::value, "GPRReg is the alias to the MacroAssembler::RegisterID"); + +inline CCallHelpers::Jump branchIfNotWorldIsNormal(CCallHelpers& jit, GPRReg globalObject) +{ + return jit.branchTest8(CCallHelpers::Zero, CCallHelpers::Address(globalObject, JSDOMGlobalObject::offsetOfWorldIsNormal())); +} + +inline CCallHelpers::Jump branchIfNotWeakIsLive(CCallHelpers& jit, GPRReg weakImpl) +{ + return jit.branchTestPtr(CCallHelpers::NonZero, CCallHelpers::Address(weakImpl, JSC::WeakImpl::offsetOfWeakHandleOwner()), CCallHelpers::TrustedImm32(JSC::WeakImpl::StateMask)); +} + +template<typename WrappedNode> +JSC::EncodedJSValue toWrapperSlowImpl(JSC::JSGlobalObject* globalObject, void* result) +{ + return JSC::JSValue::encode(toJS(globalObject, static_cast<JSDOMGlobalObject*>(globalObject), *static_cast<WrappedNode*>(result))); +} + +template<typename WrappedType> +void tryLookUpWrapperCache(CCallHelpers& jit, CCallHelpers::JumpList& failureCases, GPRReg wrapped, GPRReg resultGPR) +{ + jit.loadPtr(CCallHelpers::Address(wrapped, ScriptWrappable::offsetOfWrapper<WrappedType>()), resultGPR); + failureCases.append(jit.branchTestPtr(CCallHelpers::Zero, resultGPR)); + failureCases.append(branchIfNotWeakIsLive(jit, resultGPR)); + jit.loadPtr(CCallHelpers::Address(resultGPR, JSC::WeakImpl::offsetOfJSValue() + JSC::JSValue::offsetOfPayload()), resultGPR); +} + +template<typename WrappedType, typename ToJSFunction> +void toWrapper(CCallHelpers& jit, JSC::SnippetParams& params, GPRReg wrapped, GPRReg globalObject, JSValueRegs result, ToJSFunction function, JSC::JSValue globalObjectConstant) +{ + ASSERT(wrapped != result.payloadGPR()); + ASSERT(globalObject != result.payloadGPR()); + GPRReg payloadGPR = result.payloadGPR(); + CCallHelpers::JumpList slowCases; + + if (globalObjectConstant) { + if (!JSC::jsCast<JSDOMGlobalObject*>(globalObjectConstant)->worldIsNormal()) { + slowCases.append(jit.jump()); + params.addSlowPathCall(slowCases, jit, function, result, globalObject, wrapped); + return; + } + } else + slowCases.append(branchIfNotWorldIsNormal(jit, globalObject)); + + tryLookUpWrapperCache<WrappedType>(jit, slowCases, wrapped, payloadGPR); + jit.boxCell(payloadGPR, result); + params.addSlowPathCall(slowCases, jit, function, result, globalObject, wrapped); +} + +inline CCallHelpers::Jump branchIfDOMWrapper(CCallHelpers& jit, GPRReg target) +{ + return jit.branch8( + CCallHelpers::AboveOrEqual, + CCallHelpers::Address(target, JSC::JSCell::typeInfoTypeOffset()), + CCallHelpers::TrustedImm32(JSC::JSType(JSDOMWrapperType))); +} + +inline CCallHelpers::Jump branchIfUint8Array(CCallHelpers& jit, GPRReg target) +{ + return jit.branch8( + CCallHelpers::Equal, + CCallHelpers::Address(target, JSC::JSCell::typeInfoTypeOffset()), + CCallHelpers::TrustedImm32(JSC::JSType(Uint8ArrayType))); +} + +inline CCallHelpers::Jump branchIfNotDOMWrapper(CCallHelpers& jit, GPRReg target) +{ + return jit.branch8( + CCallHelpers::Below, + CCallHelpers::Address(target, JSC::JSCell::typeInfoTypeOffset()), + CCallHelpers::TrustedImm32(JSC::JSType(JSDOMWrapperType))); +} + +inline CCallHelpers::Jump branchIfEvent(CCallHelpers& jit, GPRReg target) +{ + return jit.branchIfType(target, JSC::JSType(JSEventType)); +} + +inline CCallHelpers::Jump branchIfNotEvent(CCallHelpers& jit, GPRReg target) +{ + return jit.branchIfNotType(target, JSC::JSType(JSEventType)); +} + +inline CCallHelpers::Jump branchIfNode(CCallHelpers& jit, GPRReg target) +{ + return jit.branch8( + CCallHelpers::AboveOrEqual, + CCallHelpers::Address(target, JSC::JSCell::typeInfoTypeOffset()), + CCallHelpers::TrustedImm32(JSC::JSType(JSNodeType))); +} + +inline CCallHelpers::Jump branchIfNotNode(CCallHelpers& jit, GPRReg target) +{ + return jit.branch8( + CCallHelpers::Below, + CCallHelpers::Address(target, JSC::JSCell::typeInfoTypeOffset()), + CCallHelpers::TrustedImm32(JSC::JSType(JSNodeType))); +} + +// inline CCallHelpers::Jump branchIfElement(CCallHelpers& jit, GPRReg target) +// { +// return jit.branch8( +// CCallHelpers::Equal, +// CCallHelpers::Address(target, JSC::JSCell::typeInfoTypeOffset()), +// CCallHelpers::TrustedImm32(JSC::JSType(JSElementType))); +// } + +// inline CCallHelpers::Jump branchIfNotElement(CCallHelpers& jit, GPRReg target) +// { +// return jit.branch8( +// CCallHelpers::NotEqual, +// CCallHelpers::Address(target, JSC::JSCell::typeInfoTypeOffset()), +// CCallHelpers::TrustedImm32(JSC::JSType(JSElementType))); +// } + +// inline CCallHelpers::Jump branchIfDocumentFragment(CCallHelpers& jit, GPRReg target) +// { +// return jit.branchIfType(target, JSC::JSType(JSDocumentFragmentNodeType)); +// } + +// inline CCallHelpers::Jump branchIfNotDocumentFragment(CCallHelpers& jit, GPRReg target) +// { +// return jit.branchIfNotType(target, JSC::JSType(JSDocumentFragmentNodeType)); +// } + +// inline CCallHelpers::Jump branchIfDocumentWrapper(CCallHelpers& jit, GPRReg target) +// { +// return jit.branchIfType(target, JSC::JSType(JSDocumentWrapperType)); +// } + +// inline CCallHelpers::Jump branchIfNotDocumentWrapper(CCallHelpers& jit, GPRReg target) +// { +// return jit.branchIfNotType(target, JSC::JSType(JSDocumentWrapperType)); +// } + +// void loadDocument(MacroAssembler&, GPRReg node, GPRReg output); +// void loadDocumentElement(MacroAssembler&, GPRReg document, GPRReg output); + +// inline CCallHelpers::Jump branchTestIsElementFlagOnNode(MacroAssembler& jit, CCallHelpers::ResultCondition condition, GPRReg nodeAddress) +// { +// return jit.branchTest32(condition, CCallHelpers::Address(nodeAddress, Node::nodeFlagsMemoryOffset()), CCallHelpers::TrustedImm32(Node::flagIsElement())); +// } + +// inline CCallHelpers::Jump branchTestIsShadowRootFlagOnNode(MacroAssembler& jit, CCallHelpers::ResultCondition condition, GPRReg nodeAddress) +// { +// return jit.branchTest32(condition, CCallHelpers::Address(nodeAddress, Node::nodeFlagsMemoryOffset()), CCallHelpers::TrustedImm32(Node::flagIsShadowRoot())); +// } + +// inline CCallHelpers::Jump branchTestIsElementOrShadowRootFlagOnNode(MacroAssembler& jit, CCallHelpers::ResultCondition condition, GPRReg nodeAddress) +// { +// return jit.branchTest32(condition, CCallHelpers::Address(nodeAddress, Node::nodeFlagsMemoryOffset()), +// CCallHelpers::TrustedImm32(Node::flagIsShadowRoot() | Node::flagIsElement())); +// } + +// inline CCallHelpers::Jump branchTestIsHTMLFlagOnNode(MacroAssembler& jit, CCallHelpers::ResultCondition condition, GPRReg nodeAddress) +// { +// return jit.branchTest32(condition, CCallHelpers::Address(nodeAddress, Node::nodeFlagsMemoryOffset()), CCallHelpers::TrustedImm32(Node::flagIsHTML())); +// } + +JSC_DECLARE_JIT_OPERATION(operationToJSNode, JSC::EncodedJSValue, (JSC::JSGlobalObject*, void*)); +JSC_DECLARE_JIT_OPERATION(operationToJSContainerNode, JSC::EncodedJSValue, (JSC::JSGlobalObject*, void*)); +// JSC_DECLARE_JIT_OPERATION(operationToJSElement, JSC::EncodedJSValue, (JSC::JSGlobalObject*, void*)); +// JSC_DECLARE_JIT_OPERATION(operationToJSHTMLElement, JSC::EncodedJSValue, (JSC::JSGlobalObject*, void*)); +// JSC_DECLARE_JIT_OPERATION(operationToJSDocument, JSC::EncodedJSValue, (JSC::JSGlobalObject*, void*)); + +} +} + +IGNORE_WARNINGS_END + +#endif diff --git a/src/bun.js/bindings/webcore/DOMJITIDLConvert.h b/src/bun.js/bindings/webcore/DOMJITIDLConvert.h new file mode 100644 index 000000000..81395e125 --- /dev/null +++ b/src/bun.js/bindings/webcore/DOMJITIDLConvert.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 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. AND ITS CONTRIBUTORS ``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 ITS 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. + */ + +#pragma once + +#include "IDLTypes.h" + +namespace WebCore { namespace DOMJIT { + +template<typename IDLType> +struct DirectConverter; + +template<> +struct DirectConverter<IDLDOMString> { + static String directConvert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSString* string) + { + return string->value(&lexicalGlobalObject); + } +}; + +template<> +struct DirectConverter<IDLAtomStringAdaptor<IDLDOMString>> { + static AtomString directConvert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSString* string) + { + return string->toAtomString(&lexicalGlobalObject); + } +}; + +template<> +struct DirectConverter<IDLRequiresExistingAtomStringAdaptor<IDLDOMString>> { + static AtomString directConvert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSString* string) + { + return string->toExistingAtomString(&lexicalGlobalObject); + } +}; + +} } diff --git a/src/bun.js/bindings/webcore/DOMJITIDLType.h b/src/bun.js/bindings/webcore/DOMJITIDLType.h new file mode 100644 index 000000000..219468875 --- /dev/null +++ b/src/bun.js/bindings/webcore/DOMJITIDLType.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 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. AND ITS CONTRIBUTORS ``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 ITS 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. + */ + +#pragma once + +#include "IDLTypes.h" + +namespace WebCore { namespace DOMJIT { + +template<typename IDLType> +struct IDLJSArgumentTypeSelect; + +template<> struct IDLJSArgumentTypeSelect<IDLBoolean> { typedef bool type; }; +template<> struct IDLJSArgumentTypeSelect<IDLByte> { typedef int32_t type; }; +template<> struct IDLJSArgumentTypeSelect<IDLOctet> { typedef int32_t type; }; +template<> struct IDLJSArgumentTypeSelect<IDLShort> { typedef int32_t type; }; +template<> struct IDLJSArgumentTypeSelect<IDLUnsignedShort> { typedef int32_t type; }; +template<> struct IDLJSArgumentTypeSelect<IDLLong> { typedef int32_t type; }; +template<> struct IDLJSArgumentTypeSelect<IDLDOMString> { typedef JSC::JSString* type; }; +template<> struct IDLJSArgumentTypeSelect<IDLUint8Array> { typedef JSC::JSUint8Array* type; }; +template<> struct IDLJSArgumentTypeSelect<IDLObject> { typedef JSC::JSObject* type; }; +template<> struct IDLJSArgumentTypeSelect<IDLAtomStringAdaptor<IDLDOMString>> { typedef JSC::JSString* type; }; +template<> struct IDLJSArgumentTypeSelect<IDLRequiresExistingAtomStringAdaptor<IDLDOMString>> { typedef JSC::JSString* type; }; + +template<typename IDLType> +using IDLJSArgumentType = typename IDLJSArgumentTypeSelect<IDLType>::type; + +} } diff --git a/src/bun.js/bindings/webcore/DOMJITIDLTypeFilter.h b/src/bun.js/bindings/webcore/DOMJITIDLTypeFilter.h new file mode 100644 index 000000000..7728db7d2 --- /dev/null +++ b/src/bun.js/bindings/webcore/DOMJITIDLTypeFilter.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2016 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. AND ITS CONTRIBUTORS ``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 ITS 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include <JavaScriptCore/SpeculatedType.h> + +namespace WebCore { namespace DOMJIT { + +template<typename IDLType> +struct IDLArgumentTypeFilter; + +template<> struct IDLArgumentTypeFilter<IDLBoolean> { static const constexpr JSC::SpeculatedType value = JSC::SpecBoolean; }; +template<> struct IDLArgumentTypeFilter<IDLByte> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; }; +template<> struct IDLArgumentTypeFilter<IDLOctet> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; }; +template<> struct IDLArgumentTypeFilter<IDLShort> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; }; +template<> struct IDLArgumentTypeFilter<IDLUnsignedShort> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; }; +template<> struct IDLArgumentTypeFilter<IDLLong> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; }; +template<> struct IDLArgumentTypeFilter<IDLDOMString> { static const constexpr JSC::SpeculatedType value = JSC::SpecString; }; +template<> struct IDLArgumentTypeFilter<IDLAtomStringAdaptor<IDLDOMString>> { static const constexpr JSC::SpeculatedType value = JSC::SpecString; }; +template<> struct IDLArgumentTypeFilter<IDLRequiresExistingAtomStringAdaptor<IDLDOMString>> { static const constexpr JSC::SpeculatedType value = JSC::SpecString; }; +template<> struct IDLArgumentTypeFilter<IDLUint8Array> { static const constexpr JSC::SpeculatedType value = JSC::SpecUint8Array; }; + +template<typename IDLType> +struct IDLResultTypeFilter { + static const constexpr JSC::SpeculatedType value = JSC::SpecFullTop; +}; + +template<> struct IDLResultTypeFilter<IDLAny> { static const constexpr JSC::SpeculatedType value = JSC::SpecHeapTop; }; +template<> struct IDLResultTypeFilter<IDLBoolean> { static const constexpr JSC::SpeculatedType value = JSC::SpecBoolean; }; +template<> struct IDLResultTypeFilter<IDLByte> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; }; +template<> struct IDLResultTypeFilter<IDLOctet> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; }; +template<> struct IDLResultTypeFilter<IDLShort> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; }; +template<> struct IDLResultTypeFilter<IDLUnsignedShort> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; }; +template<> struct IDLResultTypeFilter<IDLLong> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; }; +template<> struct IDLResultTypeFilter<IDLUnsignedLong> { static const constexpr JSC::SpeculatedType value = JSC::SpecBytecodeNumber; }; +template<> struct IDLResultTypeFilter<IDLLongLong> { static const constexpr JSC::SpeculatedType value = JSC::SpecBytecodeNumber; }; +template<> struct IDLResultTypeFilter<IDLUnsignedLongLong> { static const constexpr JSC::SpeculatedType value = JSC::SpecBytecodeNumber; }; +template<> struct IDLResultTypeFilter<IDLFloat> { static const constexpr JSC::SpeculatedType value = JSC::SpecBytecodeNumber; }; +template<> struct IDLResultTypeFilter<IDLUnrestrictedFloat> { static const constexpr JSC::SpeculatedType value = JSC::SpecBytecodeNumber; }; +template<> struct IDLResultTypeFilter<IDLDouble> { static const constexpr JSC::SpeculatedType value = JSC::SpecBytecodeNumber; }; +template<> struct IDLResultTypeFilter<IDLUnrestrictedDouble> { static const constexpr JSC::SpeculatedType value = JSC::SpecBytecodeNumber; }; +template<> struct IDLResultTypeFilter<IDLDOMString> { static const constexpr JSC::SpeculatedType value = JSC::SpecString; }; +template<> struct IDLResultTypeFilter<IDLByteString> { static const constexpr JSC::SpeculatedType value = JSC::SpecString; }; +template<> struct IDLResultTypeFilter<IDLUSVString> { static const constexpr JSC::SpeculatedType value = JSC::SpecString; }; +template<> struct IDLResultTypeFilter<IDLAtomStringAdaptor<IDLDOMString>> { static const constexpr JSC::SpeculatedType value = JSC::SpecString; }; +template<> struct IDLResultTypeFilter<IDLRequiresExistingAtomStringAdaptor<IDLDOMString>> { static const constexpr JSC::SpeculatedType value = JSC::SpecString; }; +template<> struct IDLResultTypeFilter<IDLUint8Array> { static const constexpr JSC::SpeculatedType value = JSC::SpecUint8Array; }; +template<> struct IDLResultTypeFilter<IDLObject> { static const constexpr JSC::SpeculatedType value = JSC::SpecBytecodeTop; }; + + +template<typename T> +struct IDLResultTypeFilter<IDLNullable<T>> { + static const constexpr JSC::SpeculatedType value = JSC::SpecOther | IDLResultTypeFilter<T>::value; +}; + +} } diff --git a/src/bun.js/bindings/webcore/JSEventDOMJIT.cpp b/src/bun.js/bindings/webcore/JSEventDOMJIT.cpp new file mode 100644 index 000000000..f6c6b77d8 --- /dev/null +++ b/src/bun.js/bindings/webcore/JSEventDOMJIT.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * 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 "config.h" +#include "JSEvent.h" + +#if ENABLE(JIT) + +#include "DOMJITCheckDOM.h" + + +namespace WebCore { +using namespace JSC; + +Ref<JSC::Snippet> checkSubClassSnippetForJSEvent() +{ + return DOMJIT::checkDOM<Event>(); +} + +} + +#endif diff --git a/src/bun.js/bindings/webcore/JSTextEncoder.cpp b/src/bun.js/bindings/webcore/JSTextEncoder.cpp index c12c94d56..85157758e 100644 --- a/src/bun.js/bindings/webcore/JSTextEncoder.cpp +++ b/src/bun.js/bindings/webcore/JSTextEncoder.cpp @@ -43,7 +43,7 @@ #include "JSDOMAttribute.h" // #include "JSDOMBinding.h" #include "JSDOMConstructor.h" -// #include "JSDOMConvertBufferSource.h" +#include "JSDOMConvertBufferSource.h" #include "JSDOMConvertInterface.h" #include "JSDOMConvertNumbers.h" #include "JSDOMConvertStrings.h" @@ -55,8 +55,27 @@ // #include "ScriptExecutionContext.h" // #include "WebCoreJSClientData.h" +#include <JavaScriptCore/DOMJITAbstractHeap.h> +#include "DOMJITIDLConvert.h" +#include "DOMJITIDLType.h" +#include "DOMJITIDLTypeFilter.h" +#include "DOMJITHelpers.h" +#include <JavaScriptCore/DFGAbstractHeap.h> + namespace WebCore { using namespace JSC; +using namespace JSC::DOMJIT; + +extern "C" JSC::EncodedJSValue TextEncoder__encode8(JSC::JSGlobalObject* global, const LChar* stringPtr, size_t stringLen); +extern "C" JSC::EncodedJSValue TextEncoder__encode16(JSC::JSGlobalObject* global, const UChar* stringPtr, size_t stringLen); +extern "C" size_t TextEncoder__encodeInto8(const LChar* stringPtr, size_t stringLen, void* ptr, size_t len); +extern "C" size_t TextEncoder__encodeInto16(const UChar* stringPtr, size_t stringLen, void* ptr, size_t len); +extern "C" JSC::EncodedJSValue TextEncoder__encodeRopeString(JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSString* str); + +extern "C" { +static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(jsTextEncoderEncodeWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject*, JSTextEncoder*, DOMJIT::IDLJSArgumentType<IDLDOMString>)); +static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(jsTextEncoderPrototypeFunction_encodeIntoWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, JSTextEncoder* castedThis, DOMJIT::IDLJSArgumentType<IDLDOMString> source, DOMJIT::IDLJSArgumentType<IDLUint8Array> destination)); +} template<> TextEncoder::EncodeIntoResult convertDictionary<TextEncoder::EncodeIntoResult>(JSGlobalObject& lexicalGlobalObject, JSValue value) { @@ -194,15 +213,97 @@ template<> void JSTextEncoderDOMConstructor::initializeProperties(VM& vm, JSDOMG putDirect(vm, vm.propertyNames->prototype, JSTextEncoder::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete); } +constexpr JSC::DFG::AbstractHeapKind heapKinds[] = { JSC::DFG::HeapObjectCount }; + +// This is the equivalent of DataView.set +constexpr JSC::DFG::AbstractHeapKind encodeIntoRead[] = { JSC::DFG::MiscFields, JSC::DFG::TypedArrayProperties }; +constexpr JSC::DFG::AbstractHeapKind encodeIntoWrite[] = { JSC::DFG::TypedArrayProperties }; + +static const JSC::DOMJIT::Signature DOMJITSignatureForJSTextEncoderEncodeWithoutTypeCheck( + jsTextEncoderEncodeWithoutTypeCheck, + JSTextEncoder::info(), + JSC::DOMJIT::Effect::forReadWriteDFG<1, 1>(heapKinds, heapKinds), + DOMJIT::IDLResultTypeFilter<IDLUint8Array>::value, + DOMJIT::IDLArgumentTypeFilter<IDLDOMString>::value); + +static const JSC::DOMJIT::Signature DOMJITSignatureForJSTextEncoderEncodeIntoWithoutTypeCheck( + jsTextEncoderPrototypeFunction_encodeIntoWithoutTypeCheck, + JSTextEncoder::info(), + // this is slightly incorrect + // there could be cases where the object returned by encodeInto will appear to be reused + // it impacts HeapObjectCount + JSC::DOMJIT::Effect::forReadWriteDFG<2, 1>(encodeIntoRead, encodeIntoWrite), + DOMJIT::IDLResultTypeFilter<IDLObject>::value, + DOMJIT::IDLArgumentTypeFilter<IDLDOMString>::value, + DOMJIT::IDLArgumentTypeFilter<IDLUint8Array>::value); + /* Hash table for prototype */ static const HashTableValue JSTextEncoderPrototypeTableValues[] = { { "constructor"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { (intptr_t) static_cast<PropertySlot::GetValueFunc>(jsTextEncoderConstructor), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(0) } }, { "encoding"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { (intptr_t) static_cast<PropertySlot::GetValueFunc>(jsTextEncoder_encoding), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(0) } }, - { "encode"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(jsTextEncoderPrototypeFunction_encode), (intptr_t)(0) } }, - { "encodeInto"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(jsTextEncoderPrototypeFunction_encodeInto), (intptr_t)(2) } }, + { "encode"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(jsTextEncoderPrototypeFunction_encode), (intptr_t) static_cast<const JSC::DOMJIT::Signature*>(&DOMJITSignatureForJSTextEncoderEncodeWithoutTypeCheck) } }, + { "encodeInto"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(jsTextEncoderPrototypeFunction_encodeInto), (intptr_t) static_cast<const JSC::DOMJIT::Signature*>(&DOMJITSignatureForJSTextEncoderEncodeIntoWithoutTypeCheck) } }, }; +JSC_DEFINE_JIT_OPERATION(jsTextEncoderEncodeWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, JSTextEncoder* castedThis, DOMJIT::IDLJSArgumentType<IDLDOMString> input)) +{ + VM& vm = JSC::getVM(lexicalGlobalObject); + IGNORE_WARNINGS_BEGIN("frame-address") + CallFrame* callFrame = DECLARE_CALL_FRAME(vm); + IGNORE_WARNINGS_END + JSC::JITOperationPrologueCallFrameTracer tracer(vm, callFrame); + auto throwScope = DECLARE_THROW_SCOPE(vm); + EncodedJSValue res; + String str; + if (input->is8Bit()) { + if (input->isRope()) { + auto encodedValue = TextEncoder__encodeRopeString(lexicalGlobalObject, input); + if (!JSC::JSValue::decode(encodedValue).isUndefined()) { + RELEASE_AND_RETURN(throwScope, encodedValue); + } + } + + str = input->value(lexicalGlobalObject); + res = TextEncoder__encode8(lexicalGlobalObject, str.characters8(), str.length()); + } else { + str = input->value(lexicalGlobalObject); + res = TextEncoder__encode16(lexicalGlobalObject, str.characters16(), str.length()); + } + + if (UNLIKELY(JSC::JSValue::decode(res).isObject() && JSC::JSValue::decode(res).getObject()->isErrorInstance())) { + throwScope.throwException(lexicalGlobalObject, JSC::JSValue::decode(res)); + return encodedJSValue(); + } + + RELEASE_AND_RETURN(throwScope, res); +} + +JSC_DEFINE_JIT_OPERATION(jsTextEncoderPrototypeFunction_encodeIntoWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, JSTextEncoder* castedThis, DOMJIT::IDLJSArgumentType<IDLDOMString> sourceStr, DOMJIT::IDLJSArgumentType<IDLUint8Array> destination)) +{ + VM& vm = JSC::getVM(lexicalGlobalObject); + IGNORE_WARNINGS_BEGIN("frame-address") + CallFrame* callFrame = DECLARE_CALL_FRAME(vm); + IGNORE_WARNINGS_END + JSC::JITOperationPrologueCallFrameTracer tracer(vm, callFrame); + auto source = sourceStr->value(lexicalGlobalObject); + size_t res = 0; + if (!source.is8Bit()) { + res = TextEncoder__encodeInto16(source.characters16(), source.length(), destination->vector(), destination->length()); + } else { + res = TextEncoder__encodeInto8(source.characters8(), source.length(), destination->vector(), destination->length()); + } + + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto clientData = WebCore::clientData(vm); + + auto* result = JSC::constructEmptyObject(globalObject, globalObject->encodeIntoObjectPrototype(), 2); + result->putDirect(vm, clientData->builtinNames().readPublicName(), JSC::jsNumber(static_cast<uint32_t>(res)), 0); + result->putDirect(vm, clientData->builtinNames().writtenPublicName(), JSC::jsNumber(static_cast<uint32_t>(res >> 32)), 0); + + return JSValue::encode(result); +} + const ClassInfo JSTextEncoderPrototype::s_info = { "TextEncoder"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTextEncoderPrototype) }; void JSTextEncoderPrototype::finishCreation(VM& vm) @@ -271,10 +372,6 @@ JSC_DEFINE_CUSTOM_GETTER(jsTextEncoder_encoding, (JSGlobalObject * lexicalGlobal return IDLAttribute<JSTextEncoder>::get<jsTextEncoder_encodingGetter, CastedThisErrorBehavior::Assert>(*lexicalGlobalObject, thisValue, attributeName); } -extern "C" JSC::EncodedJSValue TextEncoder__encode(JSC::JSGlobalObject* lexicalGlobalObject, const ZigString*); -extern "C" JSC::EncodedJSValue TextEncoder__encodeInto(JSC::JSGlobalObject* lexicalGlobalObject, const ZigString*, void* ptr, size_t len); -extern "C" JSC::EncodedJSValue TextEncoder__encodeRopeString(JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSString* str); - static inline JSC::EncodedJSValue jsTextEncoderPrototypeFunction_encodeBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSTextEncoder>::ClassParameter castedThis) { auto& vm = JSC::getVM(lexicalGlobalObject); @@ -283,19 +380,28 @@ static inline JSC::EncodedJSValue jsTextEncoderPrototypeFunction_encodeBody(JSC: UNUSED_PARAM(callFrame); EnsureStillAliveScope argument0 = callFrame->argument(0); JSC::JSString* input = argument0.value().toStringOrNull(lexicalGlobalObject); - if (input && input->is8Bit() && input->isRope()) { - auto encodedValue = TextEncoder__encodeRopeString(lexicalGlobalObject, input); - if (!JSC::JSValue::decode(encodedValue).isUndefined()) { - RELEASE_AND_RETURN(throwScope, encodedValue); + EncodedJSValue res; + String str; + if (input->is8Bit()) { + if (input->isRope()) { + auto encodedValue = TextEncoder__encodeRopeString(lexicalGlobalObject, input); + if (!JSC::JSValue::decode(encodedValue).isUndefined()) { + RELEASE_AND_RETURN(throwScope, encodedValue); + } } + + str = input->value(lexicalGlobalObject); + res = TextEncoder__encode8(lexicalGlobalObject, str.characters8(), str.length()); + } else { + str = input->value(lexicalGlobalObject); + res = TextEncoder__encode16(lexicalGlobalObject, str.characters16(), str.length()); } - auto str = Zig::toZigString(input->tryGetValue(lexicalGlobalObject)); - auto res = TextEncoder__encode(lexicalGlobalObject, &str); if (UNLIKELY(JSC::JSValue::decode(res).isObject() && JSC::JSValue::decode(res).getObject()->isErrorInstance())) { throwScope.throwException(lexicalGlobalObject, JSC::JSValue::decode(res)); return encodedJSValue(); } + RELEASE_AND_RETURN(throwScope, res); } @@ -323,15 +429,21 @@ static inline JSC::EncodedJSValue jsTextEncoderPrototypeFunction_encodeIntoBody( return encodedJSValue(); } - RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); - auto str = Zig::toZigString(WTFMove(source)); - auto res = TextEncoder__encodeInto(lexicalGlobalObject, &str, destination->vector(), destination->length()); - if (UNLIKELY(JSC::JSValue::decode(res).isObject() && JSC::JSValue::decode(res).getObject()->isErrorInstance())) { - throwScope.throwException(lexicalGlobalObject, JSC::JSValue::decode(res)); - return encodedJSValue(); + size_t res = 0; + if (!source.is8Bit()) { + res = TextEncoder__encodeInto16(source.characters16(), source.length(), destination->vector(), destination->length()); + } else { + res = TextEncoder__encodeInto8(source.characters8(), source.length(), destination->vector(), destination->length()); } - RELEASE_AND_RETURN(throwScope, res); + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto clientData = WebCore::clientData(vm); + + auto* result = JSC::constructEmptyObject(globalObject, globalObject->encodeIntoObjectPrototype(), 2); + result->putDirect(vm, clientData->builtinNames().readPublicName(), JSC::jsNumber(static_cast<uint32_t>(res)), 0); + result->putDirect(vm, clientData->builtinNames().writtenPublicName(), JSC::jsNumber(static_cast<uint32_t>(res >> 32)), 0); + + return JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(jsTextEncoderPrototypeFunction_encodeInto, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) @@ -419,5 +531,4 @@ TextEncoder* JSTextEncoder::toWrapped(JSC::VM&, JSC::JSValue value) return &wrapper->wrapped(); return nullptr; } - } diff --git a/src/bun.js/builtins/BunBuiltinNames.h b/src/bun.js/builtins/BunBuiltinNames.h index cd350f999..b646211eb 100644 --- a/src/bun.js/builtins/BunBuiltinNames.h +++ b/src/bun.js/builtins/BunBuiltinNames.h @@ -237,6 +237,7 @@ using namespace JSC; macro(writeRequests) \ macro(writer) \ macro(writing) \ + macro(written) \ BUN_ADDITIONAL_PRIVATE_IDENTIFIERS(macro) \ class BunBuiltinNames { diff --git a/src/bun.js/webcore/encoding.zig b/src/bun.js/webcore/encoding.zig index b3bea11e5..6e06a06f4 100644 --- a/src/bun.js/webcore/encoding.zig +++ b/src/bun.js/webcore/encoding.zig @@ -45,9 +45,10 @@ pub const TextEncoder = struct { const utf8_string: string = "utf-8"; - pub export fn TextEncoder__encode( + pub export fn TextEncoder__encode8( globalThis: *JSGlobalObject, - zig_str: *const ZigString, + ptr: [*]const u8, + len: usize, ) JSValue { // as much as possible, rely on JSC to own the memory // their code is more battle-tested than bun's code @@ -58,52 +59,63 @@ pub const TextEncoder = struct { // so it's extra good for that case // this also means there won't be reallocations for small strings var buf: [2048]u8 = undefined; - - var ctx = globalThis.ref(); - if (zig_str.is16Bit()) { - const slice = zig_str.utf16Slice(); - // max utf16 -> utf8 length - if (slice.len <= buf.len / 4) { - const result = strings.copyUTF16IntoUTF8(&buf, @TypeOf(slice), slice); - const uint8array = JSC.JSValue.createUninitializedUint8Array(globalThis, result.written); - std.debug.assert(result.written <= buf.len); - std.debug.assert(result.read == slice.len); - const array_buffer = uint8array.asArrayBuffer(globalThis).?; - std.debug.assert(result.written == array_buffer.len); - @memcpy(array_buffer.slice().ptr, &buf, result.written); - return uint8array; - } else { - var bytes = strings.toUTF8AllocWithType( - default_allocator, - @TypeOf(slice), - slice, - ) catch { - return JSC.toInvalidArguments("Out of memory", .{}, ctx); - }; - return ArrayBuffer.fromBytes(bytes, .Uint8Array).toJSUnchecked(ctx, null); - } + const slice = ptr[0..len]; + + if (slice.len <= buf.len / 2) { + const result = strings.copyLatin1IntoUTF8(&buf, []const u8, slice); + const uint8array = JSC.JSValue.createUninitializedUint8Array(globalThis, result.written); + std.debug.assert(result.written <= buf.len); + std.debug.assert(result.read == slice.len); + const array_buffer = uint8array.asArrayBuffer(globalThis).?; + std.debug.assert(result.written == array_buffer.len); + @memcpy(array_buffer.slice().ptr, &buf, result.written); + return uint8array; } else { - const slice = zig_str.slice(); - - if (slice.len <= buf.len / 2) { - const result = strings.copyLatin1IntoUTF8(&buf, []const u8, slice); - const uint8array = JSC.JSValue.createUninitializedUint8Array(globalThis, result.written); - std.debug.assert(result.written <= buf.len); - std.debug.assert(result.read == slice.len); - const array_buffer = uint8array.asArrayBuffer(globalThis).?; - std.debug.assert(result.written == array_buffer.len); - @memcpy(array_buffer.slice().ptr, &buf, result.written); - return uint8array; - } else { - const bytes = strings.allocateLatin1IntoUTF8(globalThis.bunVM().allocator, []const u8, slice) catch { - return JSC.toInvalidArguments("Out of memory", .{}, ctx); - }; - std.debug.assert(bytes.len >= slice.len); - return ArrayBuffer.fromBytes(bytes, .Uint8Array).toJSUnchecked(ctx, null); - } + const bytes = strings.allocateLatin1IntoUTF8(globalThis.bunVM().allocator, []const u8, slice) catch { + return JSC.toInvalidArguments("Out of memory", .{}, globalThis); + }; + std.debug.assert(bytes.len >= slice.len); + return ArrayBuffer.fromBytes(bytes, .Uint8Array).toJSUnchecked(globalThis, null); } + } + + pub export fn TextEncoder__encode16( + globalThis: *JSGlobalObject, + ptr: [*]const u16, + len: usize, + ) JSValue { + // as much as possible, rely on JSC to own the memory + // their code is more battle-tested than bun's code + // so we do a stack allocation here + // and then copy into JSC memory + // unless it's huge + // JSC will GC Uint8Array that occupy less than 512 bytes + // so it's extra good for that case + // this also means there won't be reallocations for small strings + var buf: [2048]u8 = undefined; - unreachable; + const slice = ptr[0..len]; + + // max utf16 -> utf8 length + if (slice.len <= buf.len / 4) { + const result = strings.copyUTF16IntoUTF8(&buf, @TypeOf(slice), slice); + const uint8array = JSC.JSValue.createUninitializedUint8Array(globalThis, result.written); + std.debug.assert(result.written <= buf.len); + std.debug.assert(result.read == slice.len); + const array_buffer = uint8array.asArrayBuffer(globalThis).?; + std.debug.assert(result.written == array_buffer.len); + @memcpy(array_buffer.slice().ptr, &buf, result.written); + return uint8array; + } else { + var bytes = strings.toUTF8AllocWithType( + default_allocator, + @TypeOf(slice), + slice, + ) catch { + return JSC.toInvalidArguments("Out of memory", .{}, globalThis); + }; + return ArrayBuffer.fromBytes(bytes, .Uint8Array).toJSUnchecked(globalThis, null); + } } // This is a fast path for copying a Rope string into a Uint8Array. @@ -194,31 +206,41 @@ pub const TextEncoder = struct { return array; } - const read_key = ZigString.init("read"); - const written_key = ZigString.init("written"); + pub export fn TextEncoder__encodeInto16( + input_ptr: [*]const u16, + input_len: usize, + buf_ptr: [*]u8, + buf_len: usize, + ) u64 { + var output = buf_ptr[0..buf_len]; + const input = input_ptr[0..input_len]; + const result: strings.EncodeIntoResult = + strings.copyUTF16IntoUTF8(output, []const u16, input); + const sized: [2]u32 = .{ result.read, result.written }; + return @bitCast(u64, sized); + } - pub export fn TextEncoder__encodeInto( - globalThis: *JSC.JSGlobalObject, - input: *const ZigString, + pub export fn TextEncoder__encodeInto8( + input_ptr: [*]const u8, + input_len: usize, buf_ptr: [*]u8, buf_len: usize, - ) JSC.JSValue { + ) u64 { var output = buf_ptr[0..buf_len]; - var result: strings.EncodeIntoResult = strings.EncodeIntoResult{ .read = 0, .written = 0 }; - if (input.is16Bit()) { - const utf16_slice = input.utf16Slice(); - result = strings.copyUTF16IntoUTF8(output, @TypeOf(utf16_slice), utf16_slice); - } else { - result = strings.copyLatin1IntoUTF8(output, @TypeOf(input.slice()), input.slice()); - } - return JSC.JSValue.createObject2(globalThis, &read_key, &written_key, JSValue.jsNumber(result.read), JSValue.jsNumber(result.written)); + const input = input_ptr[0..input_len]; + const result: strings.EncodeIntoResult = + strings.copyLatin1IntoUTF8(output, []const u8, input); + const sized: [2]u32 = .{ result.read, result.written }; + return @bitCast(u64, sized); } }; comptime { if (!JSC.is_bindgen) { - _ = TextEncoder.TextEncoder__encode; - _ = TextEncoder.TextEncoder__encodeInto; + _ = TextEncoder.TextEncoder__encode8; + _ = TextEncoder.TextEncoder__encode16; + _ = TextEncoder.TextEncoder__encodeInto8; + _ = TextEncoder.TextEncoder__encodeInto16; _ = TextEncoder.TextEncoder__encodeRopeString; } } |