Skip to content

Commit dcba3a0

Browse files
joyeecheungtargos
authored andcommitted
src: move encoding bindings to a new binding
Move the bindings used by TextEncoder to a new binding for more self-contained code. PR-URL: #46658 Reviewed-By: Darshan Sen <raisinten@gmail.com>
1 parent 0617c5e commit dcba3a0

File tree

10 files changed

+256
-129
lines changed

10 files changed

+256
-129
lines changed

lib/internal/encoding.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const {
5454
encodeInto,
5555
encodeUtf8String,
5656
decodeUTF8,
57-
} = internalBinding('buffer');
57+
} = internalBinding('encoding_binding');
5858

5959
const { Buffer } = require('buffer');
6060

node.gyp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,7 @@
479479
'src/connection_wrap.cc',
480480
'src/dataqueue/queue.cc',
481481
'src/debug_utils.cc',
482+
'src/encoding_binding.cc',
482483
'src/env.cc',
483484
'src/fs_event_wrap.cc',
484485
'src/handle_wrap.cc',
@@ -585,6 +586,7 @@
585586
'src/dataqueue/queue.h',
586587
'src/debug_utils.h',
587588
'src/debug_utils-inl.h',
589+
'src/encoding_binding.h',
588590
'src/env_properties.h',
589591
'src/env.h',
590592
'src/env-inl.h',

src/base_object_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace node {
1010
// what the class passes to SET_BINDING_ID(), the second argument should match
1111
// the C++ class name.
1212
#define SERIALIZABLE_BINDING_TYPES(V) \
13+
V(encoding_binding_data, encoding_binding::BindingData) \
1314
V(fs_binding_data, fs::BindingData) \
1415
V(v8_binding_data, v8_utils::BindingData) \
1516
V(blob_binding_data, BlobBindingData) \

src/encoding_binding.cc

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
#include "encoding_binding.h"
2+
#include "env-inl.h"
3+
#include "node_errors.h"
4+
#include "node_external_reference.h"
5+
#include "simdutf.h"
6+
#include "string_bytes.h"
7+
#include "v8.h"
8+
9+
#include <cstdint>
10+
11+
namespace node {
12+
namespace encoding_binding {
13+
14+
using v8::ArrayBuffer;
15+
using v8::BackingStore;
16+
using v8::Context;
17+
using v8::FunctionCallbackInfo;
18+
using v8::Isolate;
19+
using v8::Local;
20+
using v8::MaybeLocal;
21+
using v8::Object;
22+
using v8::String;
23+
using v8::Uint8Array;
24+
using v8::Uint32Array;
25+
using v8::Value;
26+
27+
BindingData::BindingData(Environment* env, Local<Object> object)
28+
: SnapshotableObject(env, object, type_int) {}
29+
30+
bool BindingData::PrepareForSerialization(Local<Context> context,
31+
v8::SnapshotCreator* creator) {
32+
// Return true because we need to maintain the reference to the binding from
33+
// JS land.
34+
return true;
35+
}
36+
37+
InternalFieldInfoBase* BindingData::Serialize(int index) {
38+
DCHECK_EQ(index, BaseObject::kEmbedderType);
39+
InternalFieldInfo* info =
40+
InternalFieldInfoBase::New<InternalFieldInfo>(type());
41+
return info;
42+
}
43+
44+
void BindingData::Deserialize(Local<Context> context,
45+
Local<Object> holder,
46+
int index,
47+
InternalFieldInfoBase* info) {
48+
DCHECK_EQ(index, BaseObject::kEmbedderType);
49+
v8::HandleScope scope(context->GetIsolate());
50+
Environment* env = Environment::GetCurrent(context);
51+
// Recreate the buffer in the constructor.
52+
BindingData* binding = env->AddBindingData<BindingData>(context, holder);
53+
CHECK_NOT_NULL(binding);
54+
}
55+
56+
void BindingData::EncodeInto(const FunctionCallbackInfo<Value>& args) {
57+
Environment* env = Environment::GetCurrent(args);
58+
Isolate* isolate = env->isolate();
59+
CHECK_GE(args.Length(), 3);
60+
CHECK(args[0]->IsString());
61+
CHECK(args[1]->IsUint8Array());
62+
CHECK(args[2]->IsUint32Array());
63+
64+
Local<String> source = args[0].As<String>();
65+
66+
Local<Uint8Array> dest = args[1].As<Uint8Array>();
67+
Local<ArrayBuffer> buf = dest->Buffer();
68+
char* write_result = static_cast<char*>(buf->Data()) + dest->ByteOffset();
69+
size_t dest_length = dest->ByteLength();
70+
71+
// results = [ read, written ]
72+
Local<Uint32Array> result_arr = args[2].As<Uint32Array>();
73+
uint32_t* results = reinterpret_cast<uint32_t*>(
74+
static_cast<char*>(result_arr->Buffer()->Data()) +
75+
result_arr->ByteOffset());
76+
77+
int nchars;
78+
int written = source->WriteUtf8(
79+
isolate,
80+
write_result,
81+
dest_length,
82+
&nchars,
83+
String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8);
84+
results[0] = nchars;
85+
results[1] = written;
86+
}
87+
88+
// Encode a single string to a UTF-8 Uint8Array (not Buffer).
89+
// Used in TextEncoder.prototype.encode.
90+
void BindingData::EncodeUtf8String(const FunctionCallbackInfo<Value>& args) {
91+
Environment* env = Environment::GetCurrent(args);
92+
Isolate* isolate = env->isolate();
93+
CHECK_GE(args.Length(), 1);
94+
CHECK(args[0]->IsString());
95+
96+
Local<String> str = args[0].As<String>();
97+
size_t length = str->Utf8Length(isolate);
98+
99+
Local<ArrayBuffer> ab;
100+
{
101+
NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
102+
std::unique_ptr<BackingStore> bs =
103+
ArrayBuffer::NewBackingStore(isolate, length);
104+
105+
CHECK(bs);
106+
107+
str->WriteUtf8(isolate,
108+
static_cast<char*>(bs->Data()),
109+
-1, // We are certain that `data` is sufficiently large
110+
nullptr,
111+
String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8);
112+
113+
ab = ArrayBuffer::New(isolate, std::move(bs));
114+
}
115+
116+
auto array = Uint8Array::New(ab, 0, length);
117+
args.GetReturnValue().Set(array);
118+
}
119+
120+
// Convert the input into an encoded string
121+
void BindingData::DecodeUTF8(const FunctionCallbackInfo<Value>& args) {
122+
Environment* env = Environment::GetCurrent(args); // list, flags
123+
124+
CHECK_GE(args.Length(), 1);
125+
126+
if (!(args[0]->IsArrayBuffer() || args[0]->IsSharedArrayBuffer() ||
127+
args[0]->IsArrayBufferView())) {
128+
return node::THROW_ERR_INVALID_ARG_TYPE(
129+
env->isolate(),
130+
"The \"list\" argument must be an instance of SharedArrayBuffer, "
131+
"ArrayBuffer or ArrayBufferView.");
132+
}
133+
134+
ArrayBufferViewContents<char> buffer(args[0]);
135+
136+
bool ignore_bom = args[1]->IsTrue();
137+
bool has_fatal = args[2]->IsTrue();
138+
139+
const char* data = buffer.data();
140+
size_t length = buffer.length();
141+
142+
if (has_fatal) {
143+
auto result = simdutf::validate_utf8_with_errors(data, length);
144+
145+
if (result.error) {
146+
return node::THROW_ERR_ENCODING_INVALID_ENCODED_DATA(
147+
env->isolate(), "The encoded data was not valid for encoding utf-8");
148+
}
149+
}
150+
151+
if (!ignore_bom && length >= 3) {
152+
if (memcmp(data, "\xEF\xBB\xBF", 3) == 0) {
153+
data += 3;
154+
length -= 3;
155+
}
156+
}
157+
158+
if (length == 0) return args.GetReturnValue().SetEmptyString();
159+
160+
Local<Value> error;
161+
MaybeLocal<Value> maybe_ret =
162+
StringBytes::Encode(env->isolate(), data, length, UTF8, &error);
163+
Local<Value> ret;
164+
165+
if (!maybe_ret.ToLocal(&ret)) {
166+
CHECK(!error.IsEmpty());
167+
env->isolate()->ThrowException(error);
168+
return;
169+
}
170+
171+
args.GetReturnValue().Set(ret);
172+
}
173+
174+
void BindingData::Initialize(Local<Object> target,
175+
Local<Value> unused,
176+
Local<Context> context,
177+
void* priv) {
178+
Environment* env = Environment::GetCurrent(context);
179+
BindingData* const binding_data =
180+
env->AddBindingData<BindingData>(context, target);
181+
if (binding_data == nullptr) return;
182+
183+
SetMethod(context, target, "encodeInto", EncodeInto);
184+
SetMethodNoSideEffect(context, target, "encodeUtf8String", EncodeUtf8String);
185+
SetMethodNoSideEffect(context, target, "decodeUTF8", DecodeUTF8);
186+
}
187+
188+
void BindingData::RegisterTimerExternalReferences(
189+
ExternalReferenceRegistry* registry) {
190+
registry->Register(EncodeInto);
191+
registry->Register(EncodeUtf8String);
192+
registry->Register(DecodeUTF8);
193+
}
194+
195+
} // namespace encoding_binding
196+
} // namespace node
197+
198+
NODE_BINDING_CONTEXT_AWARE_INTERNAL(
199+
encoding_binding, node::encoding_binding::BindingData::Initialize)
200+
NODE_BINDING_EXTERNAL_REFERENCE(
201+
encoding_binding,
202+
node::encoding_binding::BindingData::RegisterTimerExternalReferences)

src/encoding_binding.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#ifndef SRC_ENCODING_BINDING_H_
2+
#define SRC_ENCODING_BINDING_H_
3+
4+
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5+
6+
#include <cinttypes>
7+
#include "aliased_buffer.h"
8+
#include "node_snapshotable.h"
9+
#include "v8-fast-api-calls.h"
10+
11+
namespace node {
12+
class ExternalReferenceRegistry;
13+
14+
namespace encoding_binding {
15+
class BindingData : public SnapshotableObject {
16+
public:
17+
BindingData(Environment* env, v8::Local<v8::Object> obj);
18+
19+
using InternalFieldInfo = InternalFieldInfoBase;
20+
21+
SERIALIZABLE_OBJECT_METHODS()
22+
SET_BINDING_ID(encoding_binding_data)
23+
24+
SET_NO_MEMORY_INFO()
25+
SET_SELF_SIZE(BindingData)
26+
SET_MEMORY_INFO_NAME(BindingData)
27+
28+
static void EncodeInto(const v8::FunctionCallbackInfo<v8::Value>& args);
29+
static void EncodeUtf8String(const v8::FunctionCallbackInfo<v8::Value>& args);
30+
static void DecodeUTF8(const v8::FunctionCallbackInfo<v8::Value>& args);
31+
32+
static void Initialize(v8::Local<v8::Object> target,
33+
v8::Local<v8::Value> unused,
34+
v8::Local<v8::Context> context,
35+
void* priv);
36+
static void RegisterTimerExternalReferences(
37+
ExternalReferenceRegistry* registry);
38+
};
39+
40+
} // namespace encoding_binding
41+
42+
} // namespace node
43+
44+
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
45+
46+
#endif // SRC_ENCODING_BINDING_H_

src/node_binding.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
V(config) \
4343
V(contextify) \
4444
V(credentials) \
45+
V(encoding_binding) \
4546
V(errors) \
4647
V(fs) \
4748
V(fs_dir) \

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy