From 1207719110326c850fee707061877ceaa2388f28 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Wed, 2 Nov 2022 21:34:01 -0400 Subject: [PATCH] util: improve textdecoder decode performance --- benchmark/util/text-decoder.js | 17 ++++++++++++++++ lib/internal/encoding.js | 2 +- src/node_i18n.cc | 37 +++++++++++++++++++++++++--------- 3 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 benchmark/util/text-decoder.js diff --git a/benchmark/util/text-decoder.js b/benchmark/util/text-decoder.js new file mode 100644 index 00000000000000..f7e828fabec199 --- /dev/null +++ b/benchmark/util/text-decoder.js @@ -0,0 +1,17 @@ +'use strict'; + +const common = require('../common.js'); + +const bench = common.createBenchmark(main, { + len: [1, 64, 1024], + n: [1e6] +}); + +function main({ len, n }) { + const buf = Buffer.alloc(len, 42); + const decoder = new TextDecoder(); + + bench.start(); + decoder.decode(buf); + bench.end(n); +} diff --git a/lib/internal/encoding.js b/lib/internal/encoding.js index f9fa43228d5f57..01154958660a0c 100644 --- a/lib/internal/encoding.js +++ b/lib/internal/encoding.js @@ -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; } } diff --git a/src/node_i18n.cc b/src/node_i18n.cc index 581d52a7d05738..6373b77fae4dba 100644 --- a/src/node_i18n.cc +++ b/src/node_i18n.cc @@ -50,6 +50,8 @@ #include "node_buffer.h" #include "node_errors.h" #include "node_internals.h" +#include "string_bytes.h" +#include "string_decoder.h" #include "util-inl.h" #include "v8.h" @@ -502,18 +504,35 @@ void ConverterObject::Decode(const FunctionCallbackInfo& args) { } } ret = ToBufferEndian(env, &result); - if (omit_initial_bom && !ret.IsEmpty()) { - // Perform `ret = ret.slice(2)`. + + if (!ret.IsEmpty()) { CHECK(ret.ToLocalChecked()->IsUint8Array()); - Local orig_ret = ret.ToLocalChecked().As(); - ret = Buffer::New(env, - orig_ret->Buffer(), - orig_ret->ByteOffset() + 2, - orig_ret->ByteLength() - 2) + + if (omit_initial_bom) { + // Perform `ret = ret.slice(2)`. + Local orig_ret = ret.ToLocalChecked().As(); + ret = Buffer::New(env, + orig_ret->Buffer(), + orig_ret->ByteOffset() + 2, + orig_ret->ByteLength() - 2) .FromMaybe(Local()); + } + + Local error; + ArrayBufferViewContents buf(ret.ToLocalChecked()); + MaybeLocal encoded = StringBytes::Encode(env->isolate(), + buf.data(), + buf.length(), + encoding::UCS2, + &error); + + if (!encoded.IsEmpty()) { + args.GetReturnValue().Set(encoded.ToLocalChecked()); + } else { + args.GetReturnValue().Set(error); + } } - if (!ret.IsEmpty()) - args.GetReturnValue().Set(ret.ToLocalChecked()); + return; }