v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
externalize-string-extension.cc
Go to the documentation of this file.
1// Copyright 2010 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
8#include "src/api/api-inl.h"
9#include "src/base/strings.h"
11#include "src/handles/handles.h"
15
16namespace v8 {
17namespace internal {
18
19template <typename Char, typename Base>
20class SimpleStringResource : public Base {
21 public:
22 // Takes ownership of |data|.
23 SimpleStringResource(Char* data, size_t length)
24 : data_(data),
25 length_(length) {}
26
27 ~SimpleStringResource() override { delete[] data_; }
28
29 const Char* data() const override { return data_; }
30
31 size_t length() const override { return length_; }
32
33 private:
34 Char* const data_;
35 const size_t length_;
36};
37
42
43static constexpr int kMinOneByteLength =
45static constexpr int kMinTwoByteLength =
47static constexpr int kMinOneByteCachedLength =
49static constexpr int kMinTwoByteCachedLength =
51
52// static
53const char* ExternalizeStringExtension::BuildSource(char* buf, size_t size) {
55 "native function externalizeString();"
56 "native function createExternalizableString();"
57 "native function createExternalizableTwoByteString();"
58 "native function isOneByteString();"
59 "let kExternalStringMinOneByteLength = %d;"
60 "let kExternalStringMinTwoByteLength = %d;"
61 "let kExternalStringMinOneByteCachedLength = %d;"
62 "let kExternalStringMinTwoByteCachedLength = %d;",
65 return buf;
66}
69 v8::Isolate* isolate, v8::Local<v8::String> str) {
70 if (strcmp(*v8::String::Utf8Value(isolate, str), "externalizeString") == 0) {
71 return v8::FunctionTemplate::New(isolate,
73 } else if (strcmp(*v8::String::Utf8Value(isolate, str),
74 "createExternalizableString") == 0) {
77 } else if (strcmp(*v8::String::Utf8Value(isolate, str),
78 "createExternalizableTwoByteString") == 0) {
81 } else {
82 DCHECK_EQ(strcmp(*v8::String::Utf8Value(isolate, str), "isOneByteString"),
83 0);
84 return v8::FunctionTemplate::New(isolate,
86 }
87}
88
89namespace {
90
91bool HasExternalForwardingIndex(DirectHandle<String> string) {
92 if (!string->IsShared()) return false;
93 uint32_t raw_hash = string->raw_hash_field(kAcquireLoad);
94 return Name::IsExternalForwardingIndex(raw_hash);
95}
96
97} // namespace
98
102 if (info.Length() < 1 || !info[0]->IsString()) {
103 info.GetIsolate()->ThrowError(
104 "First parameter to externalizeString() must be a string.");
105 return;
106 }
107 bool result = false;
108 DirectHandle<String> string =
109 Utils::OpenDirectHandle(*info[0].As<v8::String>());
110 const bool externalize_as_one_byte = string->IsOneByteRepresentation();
111 if (!string->SupportsExternalization(
112 externalize_as_one_byte ? v8::String::Encoding::ONE_BYTE_ENCODING
114 // If the string is shared, testing with the combination of
115 // --shared-string-table and --isolate in d8 may result in races to
116 // externalize the same string. If GC is stressed in addition, this test
117 // might fail as the string was already externalized (marked for
118 // externalization by another thread and externalized during GC).
119 if (!StringShape(*string).IsExternal()) {
120 info.GetIsolate()->ThrowError("string does not support externalization.");
121 }
122 return;
123 }
124 if (externalize_as_one_byte) {
125 uint8_t* data = new uint8_t[string->length()];
126 String::WriteToFlat(*string, data, 0, string->length());
128 reinterpret_cast<char*>(data), string->length());
129 result = Utils::ToLocal(string)->MakeExternal(info.GetIsolate(), resource);
130 if (!result) delete resource;
131 } else {
132 base::uc16* data = new base::uc16[string->length()];
133 String::WriteToFlat(*string, data, 0, string->length());
135 data, string->length());
136 result = Utils::ToLocal(string)->MakeExternal(info.GetIsolate(), resource);
137 if (!result) delete resource;
138 }
139 // If the string is shared, testing with the combination of
140 // --shared-string-table and --isolate in d8 may result in races to
141 // externalize the same string. Those races manifest as externalization
142 // sometimes failing if another thread won and already forwarded the string to
143 // the external resource. Don't consider those races as failures.
144 if (!result && !HasExternalForwardingIndex(string)) {
145 info.GetIsolate()->ThrowError("externalizeString() failed.");
146 return;
147 }
148}
149
150namespace {
151
152MaybeDirectHandle<String> CopyConsStringToOld(Isolate* isolate,
154 v8::String::Encoding encoding) {
155 DirectHandle<String> first = handle(string->first(), isolate);
156 DirectHandle<String> second = handle(string->second(), isolate);
158 first->IsOneByteRepresentation() && second->IsOneByteRepresentation()) {
159 isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked(
160 "Cannot create externalizable two-byte string from one-byte "
161 "ConsString. Create at least one part of the ConsString with "
162 "createExternalizableTwoByteString()"));
163 return kNullMaybeHandle;
164 }
165 return isolate->factory()->NewConsString(first, second, AllocationType::kOld);
166}
167
168MaybeDirectHandle<String> CreateExternalizableString(
169 v8::Isolate* isolate, DirectHandle<String> string,
170 v8::String::Encoding encoding) {
171 Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
173 string->IsOneByteRepresentation());
174 if (string->SupportsExternalization(encoding)) {
175 return string;
176 }
177 // Return the string if it is already externalized.
178 if (StringShape(*string).IsExternal()) {
179 return string;
180 }
181
182 // Read-only strings are never externalizable. Don't try to copy them as
183 // some parts of the code might rely on some strings being in RO space (i.e.
184 // empty string).
185 if (HeapLayout::InReadOnlySpace(*string)) {
186 isolate->ThrowError("Read-only strings cannot be externalized.");
187 return kNullMaybeHandle;
188 }
189#ifdef V8_COMPRESS_POINTERS
190 // Small strings may not be in-place externalizable.
191 if (string->Size() < static_cast<int>(sizeof(UncachedExternalString))) {
192 isolate->ThrowError("String is too short to be externalized.");
193 return kNullMaybeHandle;
194 }
195#endif
196
197 // Special handling for ConsStrings, as the ConsString -> ExternalString
198 // migration is special for GC (Tagged pointers to Untagged pointers).
199 // Skip if the ConsString is flat, as we won't be guaranteed a string in old
200 // space in that case. Note that this is also true for non-canonicalized
201 // ConsStrings that TurboFan might create (the first part is empty), so we
202 // explicitly check for that case as well.
203 if (IsConsString(*string, i_isolate) && !string->IsFlat() &&
204 Cast<ConsString>(string)->first()->length() != 0) {
205 DirectHandle<String> result;
206 if (CopyConsStringToOld(i_isolate, Cast<ConsString>(string), encoding)
207 .ToHandle(&result)) {
208 DCHECK(result->SupportsExternalization(encoding));
209 return result;
210 } else {
211 return kNullMaybeHandle;
212 }
213 }
214 // All other strings can be implicitly flattened.
215 if (encoding == v8::String::ONE_BYTE_ENCODING) {
216 MaybeDirectHandle<SeqOneByteString> maybe_result =
217 i_isolate->factory()->NewRawOneByteString(string->length(),
219 DirectHandle<SeqOneByteString> result;
220 if (maybe_result.ToHandle(&result)) {
222 String::WriteToFlat(*string, result->GetChars(no_gc), 0,
223 string->length());
224 DCHECK(result->SupportsExternalization(encoding));
225 return result;
226 }
227 } else {
228 MaybeDirectHandle<SeqTwoByteString> maybe_result =
229 i_isolate->factory()->NewRawTwoByteString(string->length(),
231 DirectHandle<SeqTwoByteString> result;
232 if (maybe_result.ToHandle(&result)) {
234 String::WriteToFlat(*string, result->GetChars(no_gc), 0,
235 string->length());
236 DCHECK(result->SupportsExternalization(encoding));
237 return result;
238 }
239 }
240 isolate->ThrowError("Unable to create string");
241 return kNullMaybeHandle;
242}
243
244} // namespace
245
249 if (info.Length() < 1 || !info[0]->IsString()) {
250 info.GetIsolate()->ThrowError(
251 "First parameter to createExternalizableString() must be a string.");
252 return;
253 }
254 v8::Isolate* isolate = info.GetIsolate();
255 DirectHandle<String> string =
256 Utils::OpenDirectHandle(*info[0].As<v8::String>());
257 v8::String::Encoding encoding = string->IsOneByteRepresentation()
260 MaybeDirectHandle<String> maybe_result =
261 i::CreateExternalizableString(isolate, string, encoding);
263 if (maybe_result.ToHandle(&result)) {
264 DCHECK(!isolate->HasPendingException());
265 info.GetReturnValue().Set(Utils::ToLocal(result));
266 } else {
267 DCHECK(isolate->HasPendingException());
268 }
269}
270
274 if (info.Length() < 1 || !info[0]->IsString()) {
275 info.GetIsolate()->ThrowError(
276 "First parameter to createExternalizableString() must be a string.");
277 return;
278 }
279 v8::Isolate* isolate = info.GetIsolate();
280 DirectHandle<String> string =
281 Utils::OpenDirectHandle(*info[0].As<v8::String>());
282 MaybeDirectHandle<String> maybe_result = i::CreateExternalizableString(
285 if (maybe_result.ToHandle(&result)) {
286 DCHECK(!isolate->HasPendingException());
287 info.GetReturnValue().Set(Utils::ToLocal(result));
288 } else {
289 DCHECK(isolate->HasPendingException());
290 }
291}
292
296 if (info.Length() != 1 || !info[0]->IsString()) {
297 info.GetIsolate()->ThrowError(
298 "isOneByteString() requires a single string argument.");
299 return;
300 }
301 bool is_one_byte = Utils::OpenDirectHandle(*info[0].As<v8::String>())
302 ->IsOneByteRepresentation();
303 info.GetReturnValue().Set(is_one_byte);
304}
305
306} // namespace internal
307} // namespace v8
static Local< FunctionTemplate > New(Isolate *isolate, FunctionCallback callback=nullptr, Local< Value > data=Local< Value >(), Local< Signature > signature=Local< Signature >(), int length=0, ConstructorBehavior behavior=ConstructorBehavior::kAllow, SideEffectType side_effect_type=SideEffectType::kHasSideEffect, const CFunction *c_function=nullptr, uint16_t instance_type=0, uint16_t allowed_receiver_instance_type_range_start=0, uint16_t allowed_receiver_instance_type_range_end=0)
Definition api.cc:1101
static v8::internal::DirectHandle< To > OpenDirectHandle(v8::Local< From > handle)
Definition api.h:279
v8::Local< v8::FunctionTemplate > GetNativeFunctionTemplate(v8::Isolate *isolate, v8::Local< v8::String > name) override
static void Externalize(const v8::FunctionCallbackInfo< v8::Value > &info)
static const char * BuildSource(char *buf, size_t size)
static void IsOneByte(const v8::FunctionCallbackInfo< v8::Value > &info)
static void CreateExternalizableTwoByteString(const v8::FunctionCallbackInfo< v8::Value > &info)
static void CreateExternalizableString(const v8::FunctionCallbackInfo< v8::Value > &info)
static V8_INLINE bool InReadOnlySpace(Tagged< HeapObject > object)
V8_WARN_UNUSED_RESULT V8_INLINE bool ToHandle(DirectHandle< S > *out) const
static bool IsExternalForwardingIndex(uint32_t raw_hash_field)
Definition name-inl.h:125
V8_INLINE bool IsExternal() const
Definition string-inl.h:188
static void WriteToFlat(Tagged< String > source, SinkCharT *sink, uint32_t start, uint32_t length)
Definition string.cc:772
Isolate * isolate
double second
ZoneVector< RpoNumber > & result
int SNPrintF(Vector< char > str, const char *format,...)
Definition strings.cc:20
uint16_t uc16
Definition strings.h:18
constexpr Vector< T > VectorOf(T *start, size_t size)
Definition vector.h:360
V8_INLINE constexpr bool IsConsString(InstanceType instance_type)
static constexpr int kMinTwoByteLength
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
constexpr NullMaybeHandleType kNullMaybeHandle
constexpr int kTaggedSize
Definition globals.h:542
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
SimpleStringResource< char, v8::String::ExternalOneByteStringResource > SimpleOneByteStringResource
SimpleStringResource< base::uc16, v8::String::ExternalStringResource > SimpleTwoByteStringResource
bool V8_EXPORT ValidateCallbackInfo(const FunctionCallbackInfo< void > &info)
Definition api.cc:12301
static constexpr int kMinOneByteCachedLength
constexpr int kExternalPointerSlotSize
Definition globals.h:613
static constexpr int kMinOneByteLength
static constexpr int kMinTwoByteCachedLength
template const char * string
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
static constexpr AcquireLoadTag kAcquireLoad
Definition globals.h:2908
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485