Skip to content

Commit 5c34041

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

9 files changed

Lines changed: 137 additions & 38 deletions

File tree

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: 10 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,11 @@ class TextEncoder {
337341

338342
encode(input = '') {
339343
validateEncoder(this);
340-
return encodeUtf8String(`${input}`);
344+
const array = new Uint8Array(input.length);
345+
if (input.length > 0) {
346+
return encodeUtf8(`${input}`, array);
347+
}
348+
return array;
341349
}
342350

343351
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: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
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::FastApiCallbackOptions;
17+
using v8::FastOneByteString;
18+
using v8::Isolate;
19+
using v8::Local;
20+
using v8::Object;
21+
using v8::String;
22+
using v8::Uint8Array;
23+
using v8::Value;
24+
25+
namespace encoding_methods {
26+
27+
void Encode(Isolate* isolate, Local<String> str, Local<Uint8Array> out) {
28+
Local<ArrayBuffer> buf = out->Buffer();
29+
size_t out_length = out->ByteLength();
30+
char* write_result = static_cast<char*>(buf->Data()) + out->ByteOffset();
31+
32+
str->WriteUtf8(isolate,
33+
write_result,
34+
out_length,
35+
nullptr,
36+
String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8);
37+
}
38+
39+
void EncodeUtf8(const v8::FunctionCallbackInfo<Value>& args) {
40+
Environment* env = Environment::GetCurrent(args);
41+
Isolate* isolate = env->isolate();
42+
CHECK_GE(args.Length(), 2);
43+
CHECK(args[0]->IsString());
44+
CHECK(args[1]->IsUint8Array());
45+
46+
Local<String> str = args[0].As<String>();
47+
Local<Uint8Array> out = args[1].As<Uint8Array>();
48+
size_t utf8_length = str->Utf8Length(isolate);
49+
50+
if (utf8_length != out->Length()) {
51+
auto buf = ArrayBuffer::New(isolate, utf8_length);
52+
auto correct_out = Uint8Array::New(buf, 0, utf8_length);
53+
Encode(isolate, str, correct_out);
54+
args.GetReturnValue().Set(correct_out);
55+
return;
56+
}
57+
58+
Encode(isolate, str, out);
59+
args.GetReturnValue().Set(out);
60+
}
61+
62+
void latin1_to_utf8(const char* str, char* c) {
63+
for (; *str; ++str) {
64+
if (*str & 0x80) {
65+
*c++ = *str;
66+
} else {
67+
*c++ = (char)(0xc0 | (unsigned)*str >> 6);
68+
*c++ = (char)(0x80 | (*str & 0x3f));
69+
}
70+
}
71+
*c++ = '\0';
72+
}
73+
74+
void FastEncodeUtf8(Local<Value> receiver,
75+
const FastOneByteString& source,
76+
const FastApiTypedArray<uint8_t>& output,
77+
FastApiCallbackOptions& options) {
78+
options.fallback = true;
79+
// uint8_t* storage;
80+
// auto is_available = output.getStorageIfAligned(&storage);
81+
// CHECK(is_available);
82+
// latin1_to_utf8(source.data, reinterpret_cast<char*>(storage));
83+
}
84+
85+
CFunction fast_encode_utf8_(CFunction::Make(FastEncodeUtf8));
86+
87+
static void Initialize(Local<Object> target,
88+
Local<Value> unused,
89+
Local<Context> context,
90+
void* priv) {
91+
SetFastMethod(context, target, "encodeUtf8", EncodeUtf8, &fast_encode_utf8_);
92+
}
93+
94+
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
95+
registry->Register(EncodeUtf8);
96+
registry->Register(FastEncodeUtf8);
97+
registry->Register(fast_encode_utf8_.GetTypeInfo());
98+
}
99+
100+
} // namespace encoding_methods
101+
} // namespace node
102+
103+
NODE_BINDING_CONTEXT_AWARE_INTERNAL(encoding_methods,
104+
node::encoding_methods::Initialize)
105+
NODE_BINDING_EXTERNAL_REFERENCE(
106+
encoding_methods, node::encoding_methods::RegisterExternalReferences)

src/node_external_reference.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,15 @@
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+
v8::FastApiCallbackOptions& options);
21+
1522
// This class manages the external references from the V8 heap
1623
// to the C++ addresses in Node.js.
1724
class ExternalReferenceRegistry {
@@ -20,6 +27,7 @@ class ExternalReferenceRegistry {
2027

2128
#define ALLOWED_EXTERNAL_REFERENCE_TYPES(V) \
2229
V(CFunctionCallback) \
30+
V(CFunctionCallbackWithInput) \
2331
V(const v8::CFunctionInfo*) \
2432
V(v8::FunctionCallback) \
2533
V(v8::AccessorGetterCallback) \
@@ -67,6 +75,7 @@ class ExternalReferenceRegistry {
6775
V(credentials) \
6876
V(env_var) \
6977
V(errors) \
78+
V(encoding_methods) \
7079
V(fs) \
7180
V(fs_dir) \
7281
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)