Skip to content

Commit 635769a

Browse files
committed
src: improve TextEncoder encodeInto performance
1 parent 44b4354 commit 635769a

File tree

3 files changed

+55
-1
lines changed

3 files changed

+55
-1
lines changed

src/encoding_binding.cc

+43-1
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
#include "ada.h"
33
#include "env-inl.h"
44
#include "node_buffer.h"
5+
#include "node_debug.h"
56
#include "node_errors.h"
67
#include "node_external_reference.h"
78
#include "simdutf.h"
89
#include "string_bytes.h"
10+
#include "v8-fast-api-calls.h"
911
#include "v8.h"
1012

1113
#include <cstdint>
@@ -16,7 +18,9 @@ namespace encoding_binding {
1618
using v8::ArrayBuffer;
1719
using v8::BackingStore;
1820
using v8::BackingStoreInitializationMode;
21+
using v8::CFunction;
1922
using v8::Context;
23+
using v8::FastApiCallbackOptions;
2024
using v8::FunctionCallbackInfo;
2125
using v8::HandleScope;
2226
using v8::Isolate;
@@ -113,6 +117,42 @@ void BindingData::EncodeInto(const FunctionCallbackInfo<Value>& args) {
113117
binding_data->encode_into_results_buffer_[1] = written;
114118
}
115119

120+
void BindingData::FastEncodeInto(
121+
Local<Value> receiver,
122+
Local<Value> source,
123+
Local<Value> dest,
124+
// NOLINTNEXTLINE(runtime/references) This is V8 api.
125+
FastApiCallbackOptions& options) {
126+
TRACK_V8_FAST_API_CALL("encoding_binding.encodeInto");
127+
CHECK(source->IsString());
128+
CHECK(dest->IsUint8Array());
129+
130+
HandleScope scope(options.isolate);
131+
auto context = options.isolate->GetCurrentContext();
132+
Realm* realm = Realm::GetCurrent(context);
133+
BindingData* binding_data = realm->GetBindingData<BindingData>();
134+
135+
auto source_ = source.As<String>();
136+
auto dest_ = dest.As<Uint8Array>();
137+
Local<ArrayBuffer> buf = dest_->Buffer();
138+
char* write_result = static_cast<char*>(buf->Data()) + dest_->ByteOffset();
139+
size_t dest_length = dest_->ByteLength();
140+
141+
int nchars;
142+
int written = source_->WriteUtf8(
143+
options.isolate,
144+
write_result,
145+
dest_length,
146+
&nchars,
147+
String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8);
148+
149+
binding_data->encode_into_results_buffer_[0] = nchars;
150+
binding_data->encode_into_results_buffer_[1] = written;
151+
}
152+
153+
static CFunction fast_encode_into_ =
154+
CFunction::Make(BindingData::FastEncodeInto);
155+
116156
// Encode a single string to a UTF-8 Uint8Array (not Buffer).
117157
// Used in TextEncoder.prototype.encode.
118158
void BindingData::EncodeUtf8String(const FunctionCallbackInfo<Value>& args) {
@@ -218,7 +258,7 @@ void BindingData::ToUnicode(const FunctionCallbackInfo<Value>& args) {
218258
void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
219259
Local<ObjectTemplate> target) {
220260
Isolate* isolate = isolate_data->isolate();
221-
SetMethod(isolate, target, "encodeInto", EncodeInto);
261+
SetFastMethod(isolate, target, "encodeInto", EncodeInto, &fast_encode_into_);
222262
SetMethodNoSideEffect(isolate, target, "encodeUtf8String", EncodeUtf8String);
223263
SetMethodNoSideEffect(isolate, target, "decodeUTF8", DecodeUTF8);
224264
SetMethodNoSideEffect(isolate, target, "toASCII", ToASCII);
@@ -237,6 +277,8 @@ void BindingData::CreatePerContextProperties(Local<Object> target,
237277
void BindingData::RegisterTimerExternalReferences(
238278
ExternalReferenceRegistry* registry) {
239279
registry->Register(EncodeInto);
280+
registry->Register(FastEncodeInto);
281+
registry->Register(fast_encode_into_.GetTypeInfo());
240282
registry->Register(EncodeUtf8String);
241283
registry->Register(DecodeUTF8);
242284
registry->Register(ToASCII);

src/encoding_binding.h

+4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ class BindingData : public SnapshotableObject {
2929
SET_MEMORY_INFO_NAME(BindingData)
3030

3131
static void EncodeInto(const v8::FunctionCallbackInfo<v8::Value>& args);
32+
static void FastEncodeInto(v8::Local<v8::Value> receiver,
33+
v8::Local<v8::Value> source,
34+
v8::Local<v8::Value> dest,
35+
v8::FastApiCallbackOptions& options);
3236
static void EncodeUtf8String(const v8::FunctionCallbackInfo<v8::Value>& args);
3337
static void DecodeUTF8(const v8::FunctionCallbackInfo<v8::Value>& args);
3438
static void DecodeLatin1(const v8::FunctionCallbackInfo<v8::Value>& args);

src/node_external_reference.h

+8
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ using CFunctionBufferCopy =
9191
uint32_t source_start,
9292
uint32_t to_copy);
9393

94+
using CFunctionEncodeInto =
95+
void (*)(v8::Local<v8::Value> receiver,
96+
v8::Local<v8::Value> source,
97+
v8::Local<v8::Value> dest,
98+
// NOLINTNEXTLINE(runtime/references) This is V8 api.
99+
v8::FastApiCallbackOptions& options);
100+
94101
// This class manages the external references from the V8 heap
95102
// to the C++ addresses in Node.js.
96103
class ExternalReferenceRegistry {
@@ -120,6 +127,7 @@ class ExternalReferenceRegistry {
120127
V(CFunctionWithBool) \
121128
V(CFunctionBufferCopy) \
122129
V(CFunctionWriteString) \
130+
V(CFunctionEncodeInto) \
123131
V(const v8::CFunctionInfo*) \
124132
V(v8::FunctionCallback) \
125133
V(v8::AccessorNameGetterCallback) \

0 commit comments

Comments
 (0)