v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
ast-value-factory.cc
Go to the documentation of this file.
1// Copyright 2014 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
29
31#include "src/base/logging.h"
32#include "src/common/globals.h"
36#include "src/roots/roots.h"
38#include "src/utils/utils-inl.h"
39
40namespace v8 {
41namespace internal {
42
43namespace {
44
45// For using StringToIndex.
46class OneByteStringStream {
47 public:
48 explicit OneByteStringStream(base::Vector<const uint8_t> lb)
49 : literal_bytes_(lb), pos_(0) {}
50
51 bool HasMore() { return pos_ < literal_bytes_.length(); }
52 uint16_t GetNext() { return literal_bytes_[pos_++]; }
53
54 private:
55 base::Vector<const uint8_t> literal_bytes_;
56 int pos_;
57};
58
59} // namespace
60
61template <typename IsolateT>
62void AstRawString::Internalize(IsolateT* isolate) {
63 DCHECK(!has_string_);
64 if (literal_bytes_.empty()) {
65 set_string(isolate->factory()->empty_string());
66 } else if (is_one_byte()) {
68 set_string(isolate->factory()->InternalizeStringWithKey(&key));
69 } else {
72 set_string(isolate->factory()->InternalizeStringWithKey(&key));
73 }
74}
75
80
81bool AstRawString::AsArrayIndex(uint32_t* index) const {
82 // The StringHasher will set up the hash. Bail out early if we know it
83 // can't be convertible to an array index.
84 if (!IsIntegerIndex()) return false;
87 return true;
88 }
89 // Might be an index, but too big to cache it. Do the slow conversion. This
90 // might fail if the string is outside uint32_t (but within "safe integer")
91 // range.
92 OneByteStringStream stream(literal_bytes_);
93 return StringToIndex(&stream, index);
94}
95
99
100bool AstRawString::IsOneByteEqualTo(const char* data) const {
101 if (!is_one_byte()) return false;
102
103 size_t length = literal_bytes_.size();
104 if (length != strlen(data)) return false;
105
106 return 0 == strncmp(reinterpret_cast<const char*>(literal_bytes_.begin()),
107 data, length);
108}
109
111 if (is_one_byte()) return literal_bytes_[0];
112 const uint16_t* c = reinterpret_cast<const uint16_t*>(literal_bytes_.begin());
113 return *c;
114}
115
116bool AstRawString::Equal(const AstRawString* lhs, const AstRawString* rhs) {
117 DCHECK_EQ(lhs->Hash(), rhs->Hash());
118
119 if (lhs->length() != rhs->length()) return false;
120 if (lhs->length() == 0) return true;
121 const unsigned char* l = lhs->raw_data();
122 const unsigned char* r = rhs->raw_data();
123 size_t length = rhs->length();
124 if (lhs->is_one_byte()) {
125 if (rhs->is_one_byte()) {
126 return CompareCharsEqualUnsigned(reinterpret_cast<const uint8_t*>(l),
127 reinterpret_cast<const uint8_t*>(r),
128 length);
129 } else {
130 return CompareCharsEqualUnsigned(reinterpret_cast<const uint8_t*>(l),
131 reinterpret_cast<const uint16_t*>(r),
132 length);
133 }
134 } else {
135 if (rhs->is_one_byte()) {
136 return CompareCharsEqualUnsigned(reinterpret_cast<const uint16_t*>(l),
137 reinterpret_cast<const uint8_t*>(r),
138 length);
139 } else {
140 return CompareCharsEqualUnsigned(reinterpret_cast<const uint16_t*>(l),
141 reinterpret_cast<const uint16_t*>(r),
142 length);
143 }
144 }
145}
146
148 // Fast path for equal pointers.
149 if (lhs == rhs) return 0;
150
151 const unsigned char* lhs_data = lhs->raw_data();
152 const unsigned char* rhs_data = rhs->raw_data();
153 size_t length = std::min(lhs->length(), rhs->length());
154
155 // Code point order by contents.
156 if (lhs->is_one_byte()) {
157 if (rhs->is_one_byte()) {
159 reinterpret_cast<const uint8_t*>(lhs_data),
160 reinterpret_cast<const uint8_t*>(rhs_data), length))
161 return result;
162 } else {
164 reinterpret_cast<const uint8_t*>(lhs_data),
165 reinterpret_cast<const uint16_t*>(rhs_data), length))
166 return result;
167 }
168 } else {
169 if (rhs->is_one_byte()) {
171 reinterpret_cast<const uint16_t*>(lhs_data),
172 reinterpret_cast<const uint8_t*>(rhs_data), length))
173 return result;
174 } else {
176 reinterpret_cast<const uint16_t*>(lhs_data),
177 reinterpret_cast<const uint16_t*>(rhs_data), length))
178 return result;
179 }
180 }
181
182 return lhs->byte_length() - rhs->byte_length();
183}
184
185#ifdef OBJECT_PRINT
186void AstRawString::Print() const { printf("%.*s", byte_length(), raw_data()); }
187#endif // OBJECT_PRINT
188
189template <typename IsolateT>
190Handle<String> AstConsString::Allocate(IsolateT* isolate) const {
191 DCHECK(string_.is_null());
192
193 if (IsEmpty()) {
194 return isolate->factory()->empty_string();
195 }
196 // AstRawStrings are internalized before AstConsStrings are allocated, so
197 // AstRawString::string() will just work.
198 Handle<String> tmp = segment_.string->string();
199 for (AstConsString::Segment* current = segment_.next; current != nullptr;
200 current = current->next) {
201 tmp = isolate->factory()
202 ->NewConsString(current->string->string(), tmp,
204 .ToHandleChecked();
205 }
206 return tmp;
207}
212 LocalIsolate* isolate) const;
213
214template <typename IsolateT>
215Handle<String> AstConsString::AllocateFlat(IsolateT* isolate) const {
216 if (IsEmpty()) {
217 return isolate->factory()->empty_string();
218 }
219 if (!segment_.next) {
220 return segment_.string->string();
221 }
222
223 int result_length = 0;
224 bool is_one_byte = true;
225 for (const AstConsString::Segment* current = &segment_; current != nullptr;
226 current = current->next) {
227 result_length += current->string->length();
228 is_one_byte = is_one_byte && current->string->is_one_byte();
229 }
230
231 if (is_one_byte) {
233 isolate->factory()
234 ->NewRawOneByteString(result_length, AllocationType::kOld)
235 .ToHandleChecked();
237 uint8_t* dest =
239 result_length;
240 for (const AstConsString::Segment* current = &segment_; current != nullptr;
241 current = current->next) {
242 int length = current->string->length();
243 dest -= length;
244 CopyChars(dest, current->string->raw_data(), length);
245 }
246 DCHECK_EQ(dest, result->GetChars(
248 return result;
249 }
250
252 isolate->factory()
253 ->NewRawTwoByteString(result_length, AllocationType::kOld)
254 .ToHandleChecked();
256 uint16_t* dest =
258 result_length;
259 for (const AstConsString::Segment* current = &segment_; current != nullptr;
260 current = current->next) {
261 int length = current->string->length();
262 dest -= length;
263 if (current->string->is_one_byte()) {
264 CopyChars(dest, current->string->raw_data(), length);
265 } else {
266 CopyChars(dest,
267 reinterpret_cast<const uint16_t*>(current->string->raw_data()),
268 length);
269 }
270 }
271 DCHECK_EQ(dest, result->GetChars(
273 return result;
274}
276 Handle<String> AstConsString::AllocateFlat<Isolate>(Isolate* isolate) const;
279 LocalIsolate* isolate) const;
280
281std::forward_list<const AstRawString*> AstConsString::ToRawStrings() const {
282 std::forward_list<const AstRawString*> result;
283 if (IsEmpty()) {
284 return result;
285 }
286
287 result.emplace_front(segment_.string);
288 for (AstConsString::Segment* current = segment_.next; current != nullptr;
289 current = current->next) {
290 result.emplace_front(current->string);
291 }
292 return result;
293}
294
296 : zone_(isolate->allocator(), ZONE_NAME),
297 string_table_(),
298 hash_seed_(hash_seed) {
299 DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
300#define F(name, str) \
301 { \
302 static const char data[] = str; \
303 base::Vector<const uint8_t> literal( \
304 reinterpret_cast<const uint8_t*>(data), \
305 static_cast<int>(arraysize(data) - 1)); \
306 IndirectHandle<String> handle = isolate->factory()->name(); \
307 uint32_t raw_hash_field = handle->raw_hash_field(); \
308 DCHECK_EQ(raw_hash_field, \
309 StringHasher::HashSequentialString<uint8_t>( \
310 literal.begin(), literal.length(), hash_seed_)); \
311 DCHECK_EQ(literal.length(), handle->length()); \
312 name##_ = zone_.New<AstRawString>(true, literal, raw_hash_field); \
313 /* The Handle returned by the factory is located on the roots */ \
314 /* array, not on the temporary HandleScope, so this is safe. */ \
315 name##_->set_string(handle); \
316 string_table_.InsertNew(name##_, name##_->Hash()); \
317 }
319#undef F
320}
321
324 if (literal.length() == 1) {
325 uint8_t key = literal[0];
327 return string_constants_->one_character_string(key);
328 }
329 }
330 uint32_t raw_hash_field = StringHasher::HashSequentialString<uint8_t>(
331 literal.begin(), literal.length(), hash_seed_);
332 return GetString(raw_hash_field, true, literal);
333}
334
342
345 const SharedStringAccessGuardIfNeeded& access_guard) {
346 const AstRawString* result = nullptr;
348 String::FlatContent content = literal->GetFlatContent(no_gc, access_guard);
349 if (content.IsOneByte()) {
351 } else {
352 DCHECK(content.IsTwoByte());
354 }
355 return result;
356}
357
361
365
367 const AstRawString* str2) {
368 return NewConsString()
370 ->AddString(single_parse_zone(), str2);
371}
372
373template <typename IsolateT>
374void AstValueFactory::Internalize(IsolateT* isolate) {
375 // Strings need to be internalized before values, because values refer to
376 // strings.
377 for (AstRawString* current = strings_; current != nullptr;) {
378 AstRawString* next = current->next();
379 current->Internalize(isolate);
380 current = next;
381 }
382
383 ResetStrings();
384}
389
391 uint32_t raw_hash_field, bool is_one_byte,
392 base::Vector<const uint8_t> literal_bytes) {
393 // literal_bytes here points to whatever the user passed, and this is OK
394 // because we use vector_compare (which checks the contents) to compare
395 // against the AstRawStrings which are in the string_table_. We should not
396 // return this AstRawString.
397 AstRawString key(is_one_byte, literal_bytes, raw_hash_field);
399 &key, key.Hash(),
400 [&]() {
401 // Copy literal contents for later comparison.
402 int length = literal_bytes.length();
403 uint8_t* new_literal_bytes =
404 ast_raw_string_zone()->AllocateArray<uint8_t>(length);
405 memcpy(new_literal_bytes, literal_bytes.begin(), length);
406 AstRawString* new_string = ast_raw_string_zone()->New<AstRawString>(
407 is_one_byte, base::Vector<const uint8_t>(new_literal_bytes, length),
408 raw_hash_field);
409 CHECK_NOT_NULL(new_string);
410 AddString(new_string);
411 return new_string;
412 },
413 [&]() { return base::NoHashMapValue(); });
414 return entry->key;
415}
416
417} // namespace internal
418} // namespace v8
int pos_
base::Vector< const uint8_t > literal_bytes_
#define AST_STRING_CONSTANTS(F)
static constexpr T decode(U value)
Definition bit-field.h:66
Entry * LookupOrInsert(const Key &key, uint32_t hash)
Definition hashmap.h:223
constexpr bool empty() const
Definition vector.h:73
constexpr size_t size() const
Definition vector.h:70
constexpr T * begin() const
Definition vector.h:96
Handle< String > Allocate(IsolateT *isolate) const
AstConsString * AddString(Zone *zone, const AstRawString *s)
Handle< String > AllocateFlat(IsolateT *isolate) const
IndirectHandle< String > string_
std::forward_list< const AstRawString * > ToRawStrings() const
V8_EXPORT_PRIVATE bool IsOneByteEqualTo(const char *data) const
base::Vector< const uint8_t > literal_bytes_
void Internalize(IsolateT *isolate)
const unsigned char * raw_data() const
static bool Equal(const AstRawString *lhs, const AstRawString *rhs)
bool AsArrayIndex(uint32_t *index) const
static int Compare(const AstRawString *lhs, const AstRawString *rhs)
void set_string(IndirectHandle< String > string)
static constexpr int kMaxOneCharStringValue
AstStringConstants(Isolate *isolate, uint64_t hash_seed)
V8_EXPORT_PRIVATE const AstRawString * GetOneByteStringInternal(base::Vector< const uint8_t > literal)
const AstStringConstants * string_constants_
const AstRawString * GetString(Tagged< String > literal, const SharedStringAccessGuardIfNeeded &)
void Internalize(IsolateT *isolate)
const AstRawString * GetTwoByteStringInternal(base::Vector< const uint16_t > literal)
V8_EXPORT_PRIVATE AstConsString * NewConsString()
static const int kMaxCachedArrayIndexLength
Definition name.h:150
static bool IsIntegerIndex(uint32_t raw_hash_field)
Definition name-inl.h:106
static SharedStringAccessGuardIfNeeded NotNeeded()
Definition string-inl.h:72
static uint32_t HashSequentialString(const char_t *chars, uint32_t length, uint64_t seed)
base::Vector< const uint8_t > ToOneByteVector() const
Definition string.h:139
base::Vector< const base::uc16 > ToUC16Vector() const
Definition string.h:145
static ThreadId Current()
Definition thread-id.h:32
T * New(Args &&... args)
Definition zone.h:114
Zone * zone_
#define EXPORT_TEMPLATE_DEFINE(export)
ZoneVector< RpoNumber > & result
Register tmp
FunctionLiteral * literal
Definition liveedit.cc:294
int r
Definition mul-fft.cc:298
unsigned short uint16_t
Definition unicode.cc:39
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
bool CompareCharsEqualUnsigned(const lchar *lhs, const rchar *rhs, size_t chars)
Definition utils.h:488
void CopyChars(DstType *dst, const SrcType *src, size_t count) V8_NONNULL(1
bool StringToIndex(Stream *stream, index_t *index)
Definition utils-inl.h:59
int CompareCharsUnsigned(const lchar *lhs, const rchar *rhs, size_t chars)
Definition utils.h:519
Local< T > Handle
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define ZONE_NAME
Definition zone.h:22