Skip to content

Commit

Permalink
util: improve textdecoder decode performance
Browse files Browse the repository at this point in the history
  • Loading branch information
anonrig committed Nov 3, 2022
1 parent f1e9382 commit 1207719
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 10 deletions.
17 changes: 17 additions & 0 deletions 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);
}
2 changes: 1 addition & 1 deletion lib/internal/encoding.js
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
37 changes: 28 additions & 9 deletions src/node_i18n.cc
Expand Up @@ -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"

Expand Down Expand Up @@ -502,18 +504,35 @@ void ConverterObject::Decode(const FunctionCallbackInfo<Value>& args) {
}
}
ret = ToBufferEndian(env, &result);
if (omit_initial_bom && !ret.IsEmpty()) {
// Perform `ret = ret.slice(2)`.

if (!ret.IsEmpty()) {
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)

if (omit_initial_bom) {
// Perform `ret = ret.slice(2)`.
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>());
}

Local<Value> error;
ArrayBufferViewContents<char> buf(ret.ToLocalChecked());
MaybeLocal<Value> 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;
}

Expand Down

0 comments on commit 1207719

Please sign in to comment.