Skip to content

Commit af9270a

Browse files
committed
src: add encoding_methods with fast api
1 parent 50fb246 commit af9270a

File tree

9 files changed

+119
-38
lines changed

9 files changed

+119
-38
lines changed

lib/internal/bootstrap/loaders.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ const internalBindingAllowlist = new SafeSet([
8585
'constants',
8686
'contextify',
8787
'crypto',
88+
'encoding_methods',
8889
'fs',
8990
'fs_event_wrap',
9091
'http_parser',

lib/internal/encoding.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const {
3737
customInspectSymbol: inspect,
3838
kEmptyObject,
3939
kEnumerableProperty,
40+
getUtf8Length,
4041
} = require('internal/util');
4142

4243
const {
@@ -52,10 +53,13 @@ const {
5253

5354
const {
5455
encodeInto,
55-
encodeUtf8String,
5656
decodeUTF8,
5757
} = internalBinding('buffer');
5858

59+
const {
60+
encodeUtf8,
61+
} = internalBinding('encoding_methods');
62+
5963
let Buffer;
6064
function lazyBuffer() {
6165
if (Buffer === undefined)
@@ -337,7 +341,12 @@ class TextEncoder {
337341

338342
encode(input = '') {
339343
validateEncoder(this);
340-
return encodeUtf8String(`${input}`);
344+
const utf8Length = getUtf8Length(input);
345+
const array = new Uint8Array(utf8Length);
346+
if (utf8Length > 0) {
347+
encodeUtf8(`${input}`, array);
348+
}
349+
return array;
341350
}
342351

343352
encodeInto(src, dest) {

lib/internal/util.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,13 @@ function isArrayBufferDetached(value) {
570570
return false;
571571
}
572572

573+
function getUtf8Length(str) {
574+
let length = 0;
575+
for (let i = 0; i < str.length; i++)
576+
length += str.charCodeAt(i) > 127 ? 2 : 1;
577+
return length;
578+
}
579+
573580
module.exports = {
574581
assertCrypto,
575582
cachedResult,
@@ -585,6 +592,7 @@ module.exports = {
585592
filterOwnProperties,
586593
getConstructorOf,
587594
getInternalGlobal,
595+
getUtf8Length,
588596
getSystemErrorMap,
589597
getSystemErrorName,
590598
isArrayBufferDetached,

node.gyp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,7 @@
498498
'src/node_contextify.cc',
499499
'src/node_credentials.cc',
500500
'src/node_dir.cc',
501+
'src/node_encoding.cc',
501502
'src/node_env_var.cc',
502503
'src/node_errors.cc',
503504
'src/node_external_reference.cc',

src/node_binding.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
V(contextify) \
4444
V(credentials) \
4545
V(errors) \
46+
V(encoding_methods) \
4647
V(fs) \
4748
V(fs_dir) \
4849
V(fs_event_wrap) \

src/node_buffer.cc

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,40 +1146,6 @@ void Swap64(const FunctionCallbackInfo<Value>& args) {
11461146
args.GetReturnValue().Set(args[0]);
11471147
}
11481148

1149-
1150-
// Encode a single string to a UTF-8 Uint8Array (not Buffer).
1151-
// Used in TextEncoder.prototype.encode.
1152-
static void EncodeUtf8String(const FunctionCallbackInfo<Value>& args) {
1153-
Environment* env = Environment::GetCurrent(args);
1154-
Isolate* isolate = env->isolate();
1155-
CHECK_GE(args.Length(), 1);
1156-
CHECK(args[0]->IsString());
1157-
1158-
Local<String> str = args[0].As<String>();
1159-
size_t length = str->Utf8Length(isolate);
1160-
1161-
Local<ArrayBuffer> ab;
1162-
{
1163-
NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
1164-
std::unique_ptr<BackingStore> bs =
1165-
ArrayBuffer::NewBackingStore(isolate, length);
1166-
1167-
CHECK(bs);
1168-
1169-
str->WriteUtf8(isolate,
1170-
static_cast<char*>(bs->Data()),
1171-
-1, // We are certain that `data` is sufficiently large
1172-
nullptr,
1173-
String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8);
1174-
1175-
ab = ArrayBuffer::New(isolate, std::move(bs));
1176-
}
1177-
1178-
auto array = Uint8Array::New(ab, 0, length);
1179-
args.GetReturnValue().Set(array);
1180-
}
1181-
1182-
11831149
static void EncodeInto(const FunctionCallbackInfo<Value>& args) {
11841150
Environment* env = Environment::GetCurrent(args);
11851151
Isolate* isolate = env->isolate();
@@ -1345,7 +1311,6 @@ void Initialize(Local<Object> target,
13451311
SetMethod(context, target, "swap64", Swap64);
13461312

13471313
SetMethod(context, target, "encodeInto", EncodeInto);
1348-
SetMethodNoSideEffect(context, target, "encodeUtf8String", EncodeUtf8String);
13491314

13501315
target
13511316
->Set(context,
@@ -1400,7 +1365,6 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
14001365
registry->Register(Swap64);
14011366

14021367
registry->Register(EncodeInto);
1403-
registry->Register(EncodeUtf8String);
14041368

14051369
registry->Register(StringSlice<ASCII>);
14061370
registry->Register(StringSlice<BASE64>);

src/node_encoding.cc

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#include "env-inl.h"
2+
#include "node.h"
3+
#include "node_external_reference.h"
4+
#include "node_internals.h"
5+
#include "util-inl.h"
6+
#include "v8-fast-api-calls.h"
7+
#include "v8.h"
8+
9+
namespace node {
10+
11+
using v8::ArrayBuffer;
12+
using v8::BackingStore;
13+
using v8::CFunction;
14+
using v8::Context;
15+
using v8::FastApiTypedArray;
16+
using v8::FastOneByteString;
17+
using v8::Isolate;
18+
using v8::Local;
19+
using v8::Object;
20+
using v8::String;
21+
using v8::Uint8Array;
22+
using v8::Value;
23+
24+
namespace encoding_methods {
25+
26+
void EncodeUtf8(const v8::FunctionCallbackInfo<Value>& args) {
27+
Environment* env = Environment::GetCurrent(args);
28+
Isolate* isolate = env->isolate();
29+
CHECK_GE(args.Length(), 2);
30+
CHECK(args[0]->IsString());
31+
CHECK(args[1]->IsUint8Array());
32+
33+
Local<String> str = args[0].As<String>();
34+
Local<Uint8Array> out = args[1].As<Uint8Array>();
35+
Local<ArrayBuffer> buf = out->Buffer();
36+
size_t out_length = out->ByteLength();
37+
char* write_result = static_cast<char*>(buf->Data()) + out->ByteOffset();
38+
39+
str->WriteUtf8(isolate,
40+
write_result,
41+
out_length,
42+
nullptr,
43+
String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8);
44+
}
45+
46+
void latin1_to_utf8(const char* str, char* c) {
47+
for (; *str; ++str) {
48+
if (*str & 0x80) {
49+
*c++ = *str;
50+
} else {
51+
*c++ = (char)(0xc0 | (unsigned)*str >> 6);
52+
*c++ = (char)(0x80 | (*str & 0x3f));
53+
}
54+
}
55+
*c++ = '\0';
56+
}
57+
58+
void FastEncodeUtf8(Local<Value> receiver,
59+
const FastOneByteString& source,
60+
const FastApiTypedArray<uint8_t>& output) {
61+
uint8_t* storage;
62+
auto is_available = output.getStorageIfAligned(&storage);
63+
CHECK(is_available);
64+
latin1_to_utf8(source.data, reinterpret_cast<char*>(storage));
65+
}
66+
67+
CFunction fast_encode_utf8_(CFunction::Make(FastEncodeUtf8));
68+
69+
static void Initialize(Local<Object> target,
70+
Local<Value> unused,
71+
Local<Context> context,
72+
void* priv) {
73+
SetFastMethod(context, target, "encodeUtf8", EncodeUtf8, &fast_encode_utf8_);
74+
}
75+
76+
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
77+
registry->Register(EncodeUtf8);
78+
registry->Register(FastEncodeUtf8);
79+
registry->Register(fast_encode_utf8_.GetTypeInfo());
80+
}
81+
82+
} // namespace encoding_methods
83+
} // namespace node
84+
85+
NODE_BINDING_CONTEXT_AWARE_INTERNAL(encoding_methods,
86+
node::encoding_methods::Initialize)
87+
NODE_BINDING_EXTERNAL_REFERENCE(
88+
encoding_methods, node::encoding_methods::RegisterExternalReferences)

src/node_external_reference.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,14 @@
1010

1111
namespace node {
1212

13+
// TODO(anonrig): Find a good way of reusing existing types for fast api usages.
1314
using CFunctionCallback = void (*)(v8::Local<v8::Value> receiver);
1415

16+
using CFunctionCallbackWithInput =
17+
void (*)(v8::Local<v8::Value> receiver,
18+
const v8::FastOneByteString& input,
19+
const v8::FastApiTypedArray<uint8_t>& output);
20+
1521
// This class manages the external references from the V8 heap
1622
// to the C++ addresses in Node.js.
1723
class ExternalReferenceRegistry {
@@ -20,6 +26,7 @@ class ExternalReferenceRegistry {
2026

2127
#define ALLOWED_EXTERNAL_REFERENCE_TYPES(V) \
2228
V(CFunctionCallback) \
29+
V(CFunctionCallbackWithInput) \
2330
V(const v8::CFunctionInfo*) \
2431
V(v8::FunctionCallback) \
2532
V(v8::AccessorGetterCallback) \
@@ -67,6 +74,7 @@ class ExternalReferenceRegistry {
6774
V(credentials) \
6875
V(env_var) \
6976
V(errors) \
77+
V(encoding_methods) \
7078
V(fs) \
7179
V(fs_dir) \
7280
V(fs_event_wrap) \

test/parallel/test-bootstrap-modules.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const expectedModules = new Set([
1818
'Internal Binding contextify',
1919
'Internal Binding credentials',
2020
'Internal Binding errors',
21+
'Internal Binding encoding_methods',
2122
'Internal Binding fs_dir',
2223
'Internal Binding fs_event_wrap',
2324
'Internal Binding fs',

0 commit comments

Comments
 (0)