diff options
author | 2022-12-01 18:51:16 -0800 | |
---|---|---|
committer | 2022-12-01 18:51:16 -0800 | |
commit | 4eed310a459b09d167c85b166472eaaaea1e7db4 (patch) | |
tree | a1cf229d392bc2a4b528e39d4498ba2e1990eded | |
parent | 1daa61a45fb8c91dbc7e658ed29769854162bdd1 (diff) | |
download | bun-4eed310a459b09d167c85b166472eaaaea1e7db4.tar.gz bun-4eed310a459b09d167c85b166472eaaaea1e7db4.tar.zst bun-4eed310a459b09d167c85b166472eaaaea1e7db4.zip |
3x faster `TextEncoder.prototype.encodeInto`
thanks to @Constellation for the tip
-rw-r--r-- | bench/snippets/encode-into.mjs | 10 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.cpp | 22 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.h | 4 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/JSTextEncoder.cpp | 19 |
4 files changed, 32 insertions, 23 deletions
diff --git a/bench/snippets/encode-into.mjs b/bench/snippets/encode-into.mjs new file mode 100644 index 000000000..5275b6f10 --- /dev/null +++ b/bench/snippets/encode-into.mjs @@ -0,0 +1,10 @@ +import { run, bench } from "../node_modules/mitata/src/cli.mjs"; + +const encoder = new TextEncoder(); + +const buffer = new Uint8Array(1024); +bench("encodeInto", () => { + encoder.encodeInto("Hello World!", buffer); +}); + +await run(); diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 467498aae..bcb42dc29 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -2490,12 +2490,18 @@ void GlobalObject::finishCreation(VM& vm) init.set(map); }); - m_encodeIntoObjectPrototype.initLater( - [](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSObject>::Initializer& init) { - JSC::JSObject* object = JSC::constructEmptyObject(init.owner, init.owner->objectPrototype(), 2); - object->putDirect(init.vm, JSC::Identifier::fromString(init.vm, "read"_s), JSC::jsNumber(0), 0); - object->putDirect(init.vm, JSC::Identifier::fromString(init.vm, "written"_s), JSC::jsNumber(0), 0); - init.set(object); + m_encodeIntoObjectStructure.initLater( + [](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::Structure>::Initializer& init) { + auto& vm = init.vm; + auto& globalObject = *init.owner; + Structure* structure = globalObject.structureCache().emptyObjectStructureForPrototype(&globalObject, globalObject.objectPrototype(), 2); + PropertyOffset offset; + auto clientData = WebCore::clientData(vm); + structure = Structure::addPropertyTransition(vm, structure, clientData->builtinNames().readPublicName(), 0, offset); + RELEASE_ASSERT(offset == 0); + structure = Structure::addPropertyTransition(vm, structure, clientData->builtinNames().writtenPublicName(), 0, offset); + RELEASE_ASSERT(offset == 1); + init.set(structure); }); m_JSFileSinkClassStructure.initLater( @@ -3337,7 +3343,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) thisObject->m_performMicrotaskVariadicFunction.visit(visitor); thisObject->m_lazyReadableStreamPrototypeMap.visit(visitor); thisObject->m_requireMap.visit(visitor); - thisObject->m_encodeIntoObjectPrototype.visit(visitor); + thisObject->m_encodeIntoObjectStructure.visit(visitor); thisObject->m_JSArrayBufferControllerPrototype.visit(visitor); thisObject->m_JSFileSinkControllerPrototype.visit(visitor); thisObject->m_JSHTTPSResponseControllerPrototype.visit(visitor); @@ -3608,8 +3614,6 @@ JSC::JSValue GlobalObject::moduleLoaderEvaluate(JSGlobalObject* globalObject, return result; } - - #include "ZigGeneratedClasses+lazyStructureImpl.h" } // namespace Zig diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index b537bbb12..bcc6cb804 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -229,7 +229,7 @@ public: JSC::JSMap* readableStreamNativeMap() { return m_lazyReadableStreamPrototypeMap.getInitializedOnMainThread(this); } JSC::JSMap* requireMap() { return m_requireMap.getInitializedOnMainThread(this); } - JSC::JSObject* encodeIntoObjectPrototype() { return m_encodeIntoObjectPrototype.getInitializedOnMainThread(this); } + JSC::Structure* encodeIntoObjectStructure() { return m_encodeIntoObjectStructure.getInitializedOnMainThread(this); } JSC::Structure* callSiteStructure() const { return m_callSiteStructure.getInitializedOnMainThread(this); } @@ -483,7 +483,7 @@ private: LazyProperty<JSGlobalObject, JSFunction> m_emitReadableNextTickFunction; LazyProperty<JSGlobalObject, JSMap> m_lazyReadableStreamPrototypeMap; LazyProperty<JSGlobalObject, JSMap> m_requireMap; - LazyProperty<JSGlobalObject, JSObject> m_encodeIntoObjectPrototype; + LazyProperty<JSGlobalObject, Structure> m_encodeIntoObjectStructure; LazyProperty<JSGlobalObject, JSObject> m_JSArrayBufferControllerPrototype; LazyProperty<JSGlobalObject, JSObject> m_JSFileSinkControllerPrototype; LazyProperty<JSGlobalObject, JSObject> m_JSHTTPSResponseControllerPrototype; diff --git a/src/bun.js/bindings/webcore/JSTextEncoder.cpp b/src/bun.js/bindings/webcore/JSTextEncoder.cpp index 90092163f..09352b98f 100644 --- a/src/bun.js/bindings/webcore/JSTextEncoder.cpp +++ b/src/bun.js/bindings/webcore/JSTextEncoder.cpp @@ -296,11 +296,9 @@ JSC_DEFINE_JIT_OPERATION(jsTextEncoderPrototypeFunction_encodeIntoWithoutTypeChe } 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); + auto* result = JSC::constructEmptyObject(vm, globalObject->encodeIntoObjectStructure()); + result->putDirectOffset(vm, 0, JSC::jsNumber(static_cast<uint32_t>(res))); + result->putDirectOffset(vm, 1, JSC::jsNumber(static_cast<uint32_t>(res >> 32))); return JSValue::encode(result); } @@ -416,15 +414,13 @@ static inline JSC::EncodedJSValue jsTextEncoderPrototypeFunction_encodeIntoBody( { auto& vm = JSC::getVM(lexicalGlobalObject); auto throwScope = DECLARE_THROW_SCOPE(vm); - UNUSED_PARAM(throwScope); - UNUSED_PARAM(callFrame); if (UNLIKELY(callFrame->argumentCount() < 2)) return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); auto source = argument0.value().toWTFString(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); EnsureStillAliveScope argument1 = callFrame->uncheckedArgument(1); - auto* destination = JSC::jsDynamicCast<JSC::JSUint8Array*>(argument1.value()); + auto* destination = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(argument1.value()); if (!destination) { throwVMTypeError(lexicalGlobalObject, throwScope, "Expected Uint8Array"_s); return encodedJSValue(); @@ -438,11 +434,10 @@ static inline JSC::EncodedJSValue jsTextEncoderPrototypeFunction_encodeIntoBody( } 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); + auto* result = JSC::constructEmptyObject(vm, globalObject->encodeIntoObjectStructure()); + result->putDirectOffset(vm, 0, JSC::jsNumber(static_cast<uint32_t>(res))); + result->putDirectOffset(vm, 1, JSC::jsNumber(static_cast<uint32_t>(res >> 32))); return JSValue::encode(result); } |