Skip to content

Commit bf02552

Browse files
committed
feat: add atomic string v8 impl.
1 parent 2463c92 commit bf02552

13 files changed

+466
-34
lines changed

bridge/CMakeLists.txt

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,31 @@ if ($ENV{WEBF_JS_ENGINE} MATCHES "quickjs")
236236
list(APPEND BRIDGE_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/modp_b64/include)
237237
list(APPEND BRIDGE_LINK_LIBS quickjs)
238238

239+
list(APPEND BRIDGE_SOURCE
240+
# Binding files
241+
bindings/qjs/dictionary_base.cc
242+
bindings/qjs/js_based_event_listener.cc
243+
bindings/qjs/js_event_handler.cc
244+
bindings/qjs/js_event_listener.cc
245+
bindings/qjs/binding_initializer.cc
246+
bindings/qjs/member_installer.cc
247+
bindings/qjs/source_location.cc
248+
bindings/qjs/cppgc/gc_visitor.cc
249+
bindings/qjs/cppgc/mutation_scope.cc
250+
bindings/qjs/script_wrappable.cc
251+
bindings/qjs/native_string_utils.cc
252+
bindings/qjs/qjs_engine_patch.cc
253+
bindings/qjs/qjs_function.cc
254+
bindings/qjs/script_value.cc
255+
bindings/qjs/script_promise.cc
256+
bindings/qjs/script_promise_resolver.cc
257+
bindings/qjs/atomic_string.cc
258+
bindings/qjs/exception_state.cc
259+
bindings/qjs/exception_message.cc
260+
bindings/qjs/rejected_promises.cc
261+
bindings/qjs/union_base.cc
262+
)
263+
239264
# Gen sources.
240265
list(APPEND BRIDGE_SOURCE
241266
out/names_installer.cc
@@ -394,40 +419,30 @@ if ($ENV{WEBF_JS_ENGINE} MATCHES "quickjs")
394419
target_compile_options(quickjs PUBLIC -DCONFIG_VERSION=${\"QUICKJS_VERSION\"})
395420

396421
elseif ($ENV{WEBF_JS_ENGINE} MATCHES "v8")
422+
423+
add_compile_options(-DWEBF_V8_JS_ENGINE=1)
424+
425+
list(APPEND BRIDGE_SOURCE
426+
# Binding files
427+
bindings/v8/atomic_string.cc
428+
)
429+
397430
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
398-
find_library(v8
399-
NAMES v8
400-
HINTS "third_party/v8/lib/macos/libv8.dylib")
401-
list(APPEND BRIDGE_LINK_LIBS v8)
431+
add_library(v8 SHARED IMPORTED)
432+
set_target_properties(v8 PROPERTIES IMPORTED_LOCATION "third_party/v8/lib/macos/arm64/libv8.dylib")
433+
add_library(v8_platform SHARED IMPORTED)
434+
set_target_properties(v8_platform PROPERTIES IMPORTED_LOCATION "third_party/v8/lib/macos/arm64/libv8_libplatform.dylib")
435+
list(APPEND BRIDGE_LINK_LIBS v8 v8_platform)
402436
endif()
403437
list(APPEND BRIDGE_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/v8/include)
438+
list(APPEND BRIDGE_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/v8/include/v8)
439+
list(APPEND BRIDGE_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/v8/include/v8/cppgc)
440+
list(APPEND BRIDGE_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/v8/include/v8/libplatform)
404441
endif()
405442

406443
list(APPEND BRIDGE_LINK_LIBS modb)
407444

408445
list(APPEND BRIDGE_SOURCE
409-
# Binding files
410-
bindings/qjs/dictionary_base.cc
411-
bindings/qjs/js_based_event_listener.cc
412-
bindings/qjs/js_event_handler.cc
413-
bindings/qjs/js_event_listener.cc
414-
bindings/qjs/binding_initializer.cc
415-
bindings/qjs/member_installer.cc
416-
bindings/qjs/source_location.cc
417-
bindings/qjs/cppgc/gc_visitor.cc
418-
bindings/qjs/cppgc/mutation_scope.cc
419-
bindings/qjs/script_wrappable.cc
420-
bindings/qjs/native_string_utils.cc
421-
bindings/qjs/qjs_engine_patch.cc
422-
bindings/qjs/qjs_function.cc
423-
bindings/qjs/script_value.cc
424-
bindings/qjs/script_promise.cc
425-
bindings/qjs/script_promise_resolver.cc
426-
bindings/qjs/atomic_string.cc
427-
bindings/qjs/exception_state.cc
428-
bindings/qjs/exception_message.cc
429-
bindings/qjs/rejected_promises.cc
430-
bindings/qjs/union_base.cc
431446
# Core sources
432447
webf_bridge.cc
433448
core/api/api.cc

bridge/bindings/v8/atomic_string.cc

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
/*
2+
* Copyright (C) 2019-2022 The Kraken authors. All rights reserved.
3+
* Copyright (C) 2022-present The WebF authors. All rights reserved.
4+
*/
5+
6+
#include "atomic_string.h"
7+
#include <algorithm>
8+
#include <vector>
9+
#include "built_in_string.h"
10+
#include "foundation/native_string.h"
11+
12+
namespace webf {
13+
14+
AtomicString AtomicString::Empty() {
15+
return built_in_string::kempty_string;
16+
}
17+
18+
AtomicString AtomicString::Null() {
19+
return built_in_string::kNULL;
20+
}
21+
22+
namespace {
23+
24+
AtomicString::StringKind GetStringKind(const std::string& string, size_t length) {
25+
char first_char = string[0];
26+
27+
if (first_char < 0 || first_char > 255) {
28+
return AtomicString::StringKind::kUnknown;
29+
}
30+
31+
AtomicString::StringKind predictKind =
32+
std::islower(string[0]) ? AtomicString::StringKind::kIsLowerCase : AtomicString::StringKind::kIsUpperCase;
33+
for (int i = 0; i < length; i++) {
34+
char c = string[i];
35+
36+
if (c < 0 || c > 255) {
37+
return AtomicString::StringKind::kUnknown;
38+
}
39+
40+
if (predictKind == AtomicString::StringKind::kIsUpperCase && !std::isupper(c)) {
41+
return AtomicString::StringKind::kIsMixed;
42+
} else if (predictKind == AtomicString::StringKind::kIsLowerCase && !std::islower(c)) {
43+
return AtomicString::StringKind::kIsMixed;
44+
}
45+
}
46+
return predictKind;
47+
}
48+
49+
AtomicString::StringKind GetStringKind(const SharedNativeString* native_string) {
50+
if (!native_string->length()) {
51+
return AtomicString::StringKind::kIsMixed;
52+
}
53+
54+
AtomicString::StringKind predictKind = std::islower(native_string->string()[0])
55+
? AtomicString::StringKind::kIsLowerCase
56+
: AtomicString::StringKind::kIsUpperCase;
57+
for (int i = 0; i < native_string->length(); i++) {
58+
uint16_t c = native_string->string()[i];
59+
if (predictKind == AtomicString::StringKind::kIsUpperCase && !std::isupper(c)) {
60+
return AtomicString::StringKind::kIsMixed;
61+
} else if (predictKind == AtomicString::StringKind::kIsLowerCase && !std::islower(c)) {
62+
return AtomicString::StringKind::kIsMixed;
63+
}
64+
}
65+
66+
return predictKind;
67+
}
68+
69+
} // namespace
70+
71+
class AtomicStringOneByteResource : public v8::String::ExternalOneByteStringResource {
72+
public:
73+
AtomicStringOneByteResource(const std::string& string) : string_(string){};
74+
75+
const char* data() const override { return string_.data(); };
76+
size_t length() const override { return string_.length(); };
77+
78+
private:
79+
std::string string_;
80+
};
81+
82+
class AtomicStringTwoByteResource : public v8::String::ExternalStringResource {
83+
public:
84+
AtomicStringTwoByteResource(std::unique_ptr<AutoFreeNativeString>&& native_string)
85+
: string_(std::move(native_string)) {}
86+
87+
const uint16_t* data() const override { return string_->string(); }
88+
size_t length() const override { return string_->length(); }
89+
90+
private:
91+
std::unique_ptr<AutoFreeNativeString> string_;
92+
};
93+
94+
AtomicString::AtomicString(v8::Isolate* isolate, const std::string& string)
95+
: kind_(GetStringKind(string, string.size())) {
96+
auto* external_string_resource = new AtomicStringOneByteResource(string);
97+
string_ = v8::String::NewExternalOneByte(isolate, external_string_resource).ToLocalChecked();
98+
}
99+
100+
AtomicString::AtomicString(v8::Isolate* isolate, const char* str, size_t length) : kind_(GetStringKind(str, length)) {
101+
auto* external_string_resource = new AtomicStringOneByteResource(std::string(str, length));
102+
string_ = v8::String::NewExternalOneByte(isolate, external_string_resource).ToLocalChecked();
103+
}
104+
105+
AtomicString::AtomicString(v8::Isolate* isolate, std::unique_ptr<AutoFreeNativeString>&& native_string) {
106+
auto* external_resource = new AtomicStringTwoByteResource(std::move(native_string));
107+
kind_ = GetStringKind(native_string.get());
108+
string_ = v8::String::NewExternalTwoByte(isolate, external_resource).ToLocalChecked();
109+
}
110+
111+
AtomicString::AtomicString(v8::Isolate* isolate, const uint16_t* str, size_t length) {
112+
auto native_string = std::unique_ptr<AutoFreeNativeString>(
113+
reinterpret_cast<AutoFreeNativeString*>(new SharedNativeString(str, length)));
114+
kind_ = GetStringKind(native_string.get());
115+
auto* external_resource = new AtomicStringTwoByteResource(std::move(native_string));
116+
string_ = v8::String::NewExternalTwoByte(isolate, external_resource).ToLocalChecked();
117+
}
118+
119+
bool AtomicString::IsEmpty() const {
120+
return *this == built_in_string::kempty_string || IsNull();
121+
}
122+
123+
bool AtomicString::IsNull() const {
124+
return string_->IsNull();
125+
}
126+
127+
bool AtomicString::Is8Bit() const {
128+
return string_->IsExternalOneByte();
129+
}
130+
131+
const uint8_t* AtomicString::Character8() const {
132+
assert(string_->IsExternal());
133+
return reinterpret_cast<const uint8_t*>(string_->GetExternalOneByteStringResource()->data());
134+
}
135+
136+
const uint16_t* AtomicString::Character16() const {
137+
assert(string_->IsExternal());
138+
return string_->GetExternalStringResource()->data();
139+
}
140+
141+
int AtomicString::Find(bool (*CharacterMatchFunction)(char)) const {
142+
// return JS_FindCharacterInAtom(runtime_, atom_, CharacterMatchFunction);
143+
}
144+
145+
int AtomicString::Find(bool (*CharacterMatchFunction)(uint16_t)) const {
146+
// return JS_FindWCharacterInAtom(runtime_, atom_, CharacterMatchFunction);
147+
}
148+
149+
std::string AtomicString::ToStdString(v8::Isolate* isolate) const {
150+
if (IsEmpty())
151+
return "";
152+
153+
if (string_->IsExternalOneByte()) {
154+
return {string_->GetExternalOneByteStringResource()->data()};
155+
}
156+
157+
std::string result;
158+
size_t length = string_->Utf8Length(isolate);
159+
result.reserve(length);
160+
161+
string_->WriteUtf8(isolate, result.data(), length);
162+
return result;
163+
}
164+
165+
std::unique_ptr<SharedNativeString> AtomicString::ToNativeString(v8::Isolate* isolate) const {
166+
if (IsNull()) {
167+
// Null string is same like empty string
168+
return built_in_string::kempty_string.ToNativeString(isolate);
169+
}
170+
171+
if (string_->IsExternalTwoByte()) {
172+
auto* resource = string_->GetExternalStringResource();
173+
return SharedNativeString::FromTemporaryString(resource->data(), resource->length());
174+
}
175+
176+
size_t length = string_->Length();
177+
std::vector<uint16_t> buffer;
178+
buffer.reserve(length);
179+
180+
string_->Write(isolate, buffer.data(), length);
181+
return SharedNativeString::FromTemporaryString(buffer.data(), buffer.size());
182+
}
183+
184+
StringView AtomicString::ToStringView() const {
185+
if (IsNull()) {
186+
return built_in_string::kempty_string.ToStringView();
187+
}
188+
189+
if (string_->IsExternalOneByte()) {
190+
auto* resource = string_->GetExternalOneByteStringResource();
191+
return StringView((void*)(resource->data()), resource->length(), false);
192+
}
193+
194+
auto* resource = string_->GetExternalStringResource();
195+
196+
return StringView((void*)(resource->data()), resource->length(), true);
197+
}
198+
199+
AtomicString AtomicString::ToUpperIfNecessary(v8::Isolate* isolate) const {
200+
if (kind_ == StringKind::kIsUpperCase) {
201+
return *this;
202+
}
203+
if (!string_upper_->IsNull() || IsNull())
204+
return *this;
205+
AtomicString upperString = ToUpperSlow(isolate);
206+
string_upper_ = v8::Local<v8::String>(upperString.string_);
207+
return upperString;
208+
}
209+
210+
AtomicString AtomicString::ToUpperSlow(v8::Isolate* isolate) const {
211+
std::string str = ToStdString(isolate);
212+
std::transform(str.begin(), str.end(), str.begin(), toupper);
213+
return {isolate, str};
214+
}
215+
216+
AtomicString AtomicString::ToLowerIfNecessary(v8::Isolate* isolate) const {
217+
if (kind_ == StringKind::kIsLowerCase) {
218+
return *this;
219+
}
220+
if (!string_lower_->IsNull() || IsNull())
221+
return *this;
222+
AtomicString lowerString = ToLowerSlow(isolate);
223+
string_lower_ = lowerString.string_;
224+
return lowerString;
225+
}
226+
227+
AtomicString AtomicString::ToLowerSlow(v8::Isolate* isolate) const {
228+
std::string str = ToStdString(isolate);
229+
std::transform(str.begin(), str.end(), str.begin(), tolower);
230+
return {isolate, str};
231+
}
232+
233+
template <typename CharType>
234+
inline AtomicString RemoveCharactersInternal(v8::Isolate* isolate,
235+
const AtomicString& self,
236+
const CharType* characters,
237+
size_t len,
238+
CharacterMatchFunctionPtr find_match) {
239+
const CharType* from = characters;
240+
const CharType* fromend = from + len;
241+
242+
// Assume the common case will not remove any characters
243+
while (from != fromend && !find_match(*from))
244+
++from;
245+
if (from == fromend)
246+
return self;
247+
248+
auto* to = (CharType*)malloc(len);
249+
size_t outc = static_cast<size_t>(from - characters);
250+
251+
if (outc)
252+
memcpy(to, characters, outc * sizeof(CharType));
253+
254+
while (true) {
255+
while (from != fromend && find_match(*from))
256+
++from;
257+
while (from != fromend && !find_match(*from))
258+
to[outc++] = *from++;
259+
if (from == fromend)
260+
break;
261+
}
262+
263+
AtomicString str;
264+
265+
if (outc == 0) {
266+
return AtomicString::Empty();
267+
}
268+
269+
auto data = (CharType*)malloc(outc);
270+
memcpy(data, to, outc);
271+
free(to);
272+
if (self.Is8Bit()) {
273+
str = AtomicString(isolate, reinterpret_cast<const char*>(data), outc);
274+
} else {
275+
str = AtomicString(isolate, reinterpret_cast<const uint16_t*>(data), outc);
276+
}
277+
278+
free(data);
279+
return str;
280+
}
281+
282+
AtomicString AtomicString::RemoveCharacters(v8::Isolate* isolate, CharacterMatchFunctionPtr find_match) {
283+
if (IsEmpty())
284+
return AtomicString::Empty();
285+
if (Is8Bit())
286+
return RemoveCharactersInternal(isolate, *this, Character8(), string_->Utf8Length(isolate), find_match);
287+
return RemoveCharactersInternal(isolate, *this, Character16(), string_->Length(), find_match);
288+
}
289+
290+
AtomicString::AtomicString(const webf::AtomicString& value) {
291+
string_ = v8::Local<v8::String>(value.string_);
292+
}
293+
AtomicString& AtomicString::operator=(const webf::AtomicString& other) {
294+
string_ = v8::Local<v8::String>(other.string_);
295+
}
296+
297+
AtomicString::AtomicString(webf::AtomicString&& value) noexcept {
298+
string_ = v8::Local<v8::String>(value.string_);
299+
}
300+
AtomicString& AtomicString::operator=(webf::AtomicString&& value) noexcept {
301+
string_ = v8::Local<v8::String>(value.string_);
302+
}
303+
304+
} // namespace webf

0 commit comments

Comments
 (0)