Skip to content

Commit

Permalink
util: improve textdecoder decode performance
Browse files Browse the repository at this point in the history
PR-URL: nodejs#45294
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Minwoo Jung <nodecorelab@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
  • Loading branch information
anonrig committed Nov 27, 2022
1 parent 9083e49 commit 8bdf693
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 14 deletions.
19 changes: 19 additions & 0 deletions benchmark/util/text-decoder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use strict';

const common = require('../common.js');

const bench = common.createBenchmark(main, {
encoding: ['utf-8', 'latin1', 'iso-8859-3'],
ignoreBOM: [0, 1],
len: [256, 1024 * 16, 1024 * 512],
n: [1e6]
});

function main({ encoding, len, n, ignoreBOM }) {
const buf = Buffer.allocUnsafe(len);
const decoder = new TextDecoder(encoding, { ignoreBOM });

bench.start();
decoder.decode(buf);
bench.end(n);
}
2 changes: 1 addition & 1 deletion lib/internal/encoding.js
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ function makeTextDecoderICU() {
if (typeof ret === 'number') {
throw new ERR_ENCODING_INVALID_ENCODED_DATA(this.encoding, ret);
}
return ret.toString('ucs2');
return ret;
}
}

Expand Down
40 changes: 27 additions & 13 deletions src/node_i18n.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#include "node_buffer.h"
#include "node_errors.h"
#include "node_internals.h"
#include "string_bytes.h"
#include "util-inl.h"
#include "v8.h"

Expand Down Expand Up @@ -96,7 +97,6 @@ using v8::NewStringType;
using v8::Object;
using v8::ObjectTemplate;
using v8::String;
using v8::Uint8Array;
using v8::Value;

namespace i18n {
Expand Down Expand Up @@ -445,7 +445,6 @@ void ConverterObject::Decode(const FunctionCallbackInfo<Value>& args) {

UErrorCode status = U_ZERO_ERROR;
MaybeStackBuffer<UChar> result;
MaybeLocal<Object> ret;

UBool flush = (flags & CONVERTER_FLAGS_FLUSH) == CONVERTER_FLAGS_FLUSH;

Expand Down Expand Up @@ -501,19 +500,34 @@ void ConverterObject::Decode(const FunctionCallbackInfo<Value>& args) {
converter->set_bom_seen(true);
}
}
ret = ToBufferEndian(env, &result);
if (omit_initial_bom && !ret.IsEmpty()) {

Local<Value> error;
UChar* output = result.out();
size_t beginning = 0;
size_t length = result.length() * sizeof(UChar);

if (omit_initial_bom) {
// Perform `ret = ret.slice(2)`.
CHECK(ret.ToLocalChecked()->IsUint8Array());
Local<Uint8Array> orig_ret = ret.ToLocalChecked().As<Uint8Array>();
ret = Buffer::New(env,
orig_ret->Buffer(),
orig_ret->ByteOffset() + 2,
orig_ret->ByteLength() - 2)
.FromMaybe(Local<Uint8Array>());
beginning += 2;
length -= 2;
}
if (!ret.IsEmpty())
args.GetReturnValue().Set(ret.ToLocalChecked());

char* value = reinterpret_cast<char*>(output) + beginning;

if (IsBigEndian()) {
SwapBytes16(value, length);
}

MaybeLocal<Value> encoded =
StringBytes::Encode(env->isolate(), value, length, UCS2, &error);

Local<Value> ret;
if (encoded.ToLocal(&ret)) {
args.GetReturnValue().Set(ret);
} else {
args.GetReturnValue().Set(error);
}

return;
}

Expand Down

0 comments on commit 8bdf693

Please sign in to comment.