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
28 #include "src/ast/ast-value-factory.h"
29
30 #include "src/base/hashmap-entry.h"
31 #include "src/base/logging.h"
32 #include "src/common/globals.h"
33 #include "src/heap/factory-inl.h"
34 #include "src/heap/local-factory-inl.h"
35 #include "src/objects/objects-inl.h"
36 #include "src/objects/objects.h"
37 #include "src/objects/string.h"
38 #include "src/strings/char-predicates-inl.h"
39 #include "src/strings/string-hasher.h"
40 #include "src/utils/utils-inl.h"
41
42 namespace v8 {
43 namespace internal {
44
45 namespace {
46
47 // For using StringToIndex.
48 class OneByteStringStream {
49 public:
OneByteStringStream(Vector<const byte> lb)50 explicit OneByteStringStream(Vector<const byte> lb)
51 : literal_bytes_(lb), pos_(0) {}
52
HasMore()53 bool HasMore() { return pos_ < literal_bytes_.length(); }
GetNext()54 uint16_t GetNext() { return literal_bytes_[pos_++]; }
55
56 private:
57 Vector<const byte> literal_bytes_;
58 int pos_;
59 };
60
61 } // namespace
62
63 template <typename LocalIsolate>
Internalize(LocalIsolate * isolate)64 void AstRawString::Internalize(LocalIsolate* isolate) {
65 DCHECK(!has_string_);
66 if (literal_bytes_.length() == 0) {
67 set_string(isolate->factory()->empty_string());
68 } else if (is_one_byte()) {
69 OneByteStringKey key(hash_field_, literal_bytes_);
70 set_string(isolate->factory()->InternalizeStringWithKey(&key));
71 } else {
72 TwoByteStringKey key(hash_field_,
73 Vector<const uint16_t>::cast(literal_bytes_));
74 set_string(isolate->factory()->InternalizeStringWithKey(&key));
75 }
76 }
77
78 template EXPORT_TEMPLATE_DEFINE(
79 V8_EXPORT_PRIVATE) void AstRawString::Internalize(Isolate* isolate);
80 template EXPORT_TEMPLATE_DEFINE(
81 V8_EXPORT_PRIVATE) void AstRawString::Internalize(LocalIsolate* isolate);
82
AsArrayIndex(uint32_t * index) const83 bool AstRawString::AsArrayIndex(uint32_t* index) const {
84 // The StringHasher will set up the hash. Bail out early if we know it
85 // can't be convertible to an array index.
86 if ((hash_field_ & Name::kIsNotIntegerIndexMask) != 0) return false;
87 if (length() <= Name::kMaxCachedArrayIndexLength) {
88 *index = Name::ArrayIndexValueBits::decode(hash_field_);
89 return true;
90 }
91 // Might be an index, but too big to cache it. Do the slow conversion. This
92 // might fail if the string is outside uint32_t (but within "safe integer")
93 // range.
94 OneByteStringStream stream(literal_bytes_);
95 return StringToIndex(&stream, index);
96 }
97
IsIntegerIndex() const98 bool AstRawString::IsIntegerIndex() const {
99 return (hash_field_ & Name::kIsNotIntegerIndexMask) == 0;
100 }
101
IsOneByteEqualTo(const char * data) const102 bool AstRawString::IsOneByteEqualTo(const char* data) const {
103 if (!is_one_byte()) return false;
104
105 size_t length = static_cast<size_t>(literal_bytes_.length());
106 if (length != strlen(data)) return false;
107
108 return 0 == strncmp(reinterpret_cast<const char*>(literal_bytes_.begin()),
109 data, length);
110 }
111
FirstCharacter() const112 uint16_t AstRawString::FirstCharacter() const {
113 if (is_one_byte()) return literal_bytes_[0];
114 const uint16_t* c = reinterpret_cast<const uint16_t*>(literal_bytes_.begin());
115 return *c;
116 }
117
Compare(const AstRawString * lhs,const AstRawString * rhs)118 bool AstRawString::Compare(const AstRawString* lhs, const AstRawString* rhs) {
119 DCHECK_EQ(lhs->Hash(), rhs->Hash());
120
121 if (lhs->length() != rhs->length()) return false;
122 if (lhs->length() == 0) return true;
123 const unsigned char* l = lhs->raw_data();
124 const unsigned char* r = rhs->raw_data();
125 size_t length = rhs->length();
126 if (lhs->is_one_byte()) {
127 if (rhs->is_one_byte()) {
128 return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l),
129 reinterpret_cast<const uint8_t*>(r),
130 length) == 0;
131 } else {
132 return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l),
133 reinterpret_cast<const uint16_t*>(r),
134 length) == 0;
135 }
136 } else {
137 if (rhs->is_one_byte()) {
138 return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l),
139 reinterpret_cast<const uint8_t*>(r),
140 length) == 0;
141 } else {
142 return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l),
143 reinterpret_cast<const uint16_t*>(r),
144 length) == 0;
145 }
146 }
147 }
148
149 template <typename LocalIsolate>
Allocate(LocalIsolate * isolate) const150 Handle<String> AstConsString::Allocate(LocalIsolate* isolate) const {
151 DCHECK(string_.is_null());
152
153 if (IsEmpty()) {
154 return isolate->factory()->empty_string();
155 }
156 // AstRawStrings are internalized before AstConsStrings are allocated, so
157 // AstRawString::string() will just work.
158 Handle<String> tmp = segment_.string->string();
159 for (AstConsString::Segment* current = segment_.next; current != nullptr;
160 current = current->next) {
161 tmp = isolate->factory()
162 ->NewConsString(current->string->string(), tmp,
163 AllocationType::kOld)
164 .ToHandleChecked();
165 }
166 return tmp;
167 }
168 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
169 Handle<String> AstConsString::Allocate<Isolate>(Isolate* isolate) const;
170 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
171 Handle<String> AstConsString::Allocate<LocalIsolate>(
172 LocalIsolate* isolate) const;
173
174 template <typename LocalIsolate>
AllocateFlat(LocalIsolate * isolate) const175 Handle<String> AstConsString::AllocateFlat(LocalIsolate* isolate) const {
176 if (IsEmpty()) {
177 return isolate->factory()->empty_string();
178 }
179 if (!segment_.next) {
180 return segment_.string->string();
181 }
182
183 int result_length = 0;
184 bool is_one_byte = true;
185 for (const AstConsString::Segment* current = &segment_; current != nullptr;
186 current = current->next) {
187 result_length += current->string->length();
188 is_one_byte = is_one_byte && current->string->is_one_byte();
189 }
190
191 if (is_one_byte) {
192 Handle<SeqOneByteString> result =
193 isolate->factory()
194 ->NewRawOneByteString(result_length, AllocationType::kOld)
195 .ToHandleChecked();
196 DisallowHeapAllocation no_gc;
197 uint8_t* dest =
198 result->GetChars(no_gc, SharedStringAccessGuardIfNeeded::NotNeeded()) +
199 result_length;
200 for (const AstConsString::Segment* current = &segment_; current != nullptr;
201 current = current->next) {
202 int length = current->string->length();
203 dest -= length;
204 CopyChars(dest, current->string->raw_data(), length);
205 }
206 DCHECK_EQ(dest, result->GetChars(
207 no_gc, SharedStringAccessGuardIfNeeded::NotNeeded()));
208 return result;
209 }
210
211 Handle<SeqTwoByteString> result =
212 isolate->factory()
213 ->NewRawTwoByteString(result_length, AllocationType::kOld)
214 .ToHandleChecked();
215 DisallowHeapAllocation no_gc;
216 uint16_t* dest =
217 result->GetChars(no_gc, SharedStringAccessGuardIfNeeded::NotNeeded()) +
218 result_length;
219 for (const AstConsString::Segment* current = &segment_; current != nullptr;
220 current = current->next) {
221 int length = current->string->length();
222 dest -= length;
223 if (current->string->is_one_byte()) {
224 CopyChars(dest, current->string->raw_data(), length);
225 } else {
226 CopyChars(dest,
227 reinterpret_cast<const uint16_t*>(current->string->raw_data()),
228 length);
229 }
230 }
231 DCHECK_EQ(dest, result->GetChars(
232 no_gc, SharedStringAccessGuardIfNeeded::NotNeeded()));
233 return result;
234 }
235 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
236 Handle<String> AstConsString::AllocateFlat<Isolate>(Isolate* isolate) const;
237 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
238 Handle<String> AstConsString::AllocateFlat<LocalIsolate>(
239 LocalIsolate* isolate) const;
240
ToRawStrings() const241 std::forward_list<const AstRawString*> AstConsString::ToRawStrings() const {
242 std::forward_list<const AstRawString*> result;
243 if (IsEmpty()) {
244 return result;
245 }
246
247 result.emplace_front(segment_.string);
248 for (AstConsString::Segment* current = segment_.next; current != nullptr;
249 current = current->next) {
250 result.emplace_front(current->string);
251 }
252 return result;
253 }
254
AstStringConstants(Isolate * isolate,uint64_t hash_seed)255 AstStringConstants::AstStringConstants(Isolate* isolate, uint64_t hash_seed)
256 : zone_(isolate->allocator(), ZONE_NAME),
257 string_table_(),
258 hash_seed_(hash_seed) {
259 DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
260 #define F(name, str) \
261 { \
262 const char* data = str; \
263 Vector<const uint8_t> literal(reinterpret_cast<const uint8_t*>(data), \
264 static_cast<int>(strlen(data))); \
265 uint32_t hash_field = StringHasher::HashSequentialString<uint8_t>( \
266 literal.begin(), literal.length(), hash_seed_); \
267 name##_string_ = zone_.New<AstRawString>(true, literal, hash_field); \
268 /* The Handle returned by the factory is located on the roots */ \
269 /* array, not on the temporary HandleScope, so this is safe. */ \
270 name##_string_->set_string(isolate->factory()->name##_string()); \
271 string_table_.InsertNew(name##_string_, name##_string_->Hash()); \
272 }
273 AST_STRING_CONSTANTS(F)
274 #undef F
275 }
276
GetOneByteStringInternal(Vector<const uint8_t> literal)277 const AstRawString* AstValueFactory::GetOneByteStringInternal(
278 Vector<const uint8_t> literal) {
279 if (literal.length() == 1 && literal[0] < kMaxOneCharStringValue) {
280 int key = literal[0];
281 if (V8_UNLIKELY(one_character_strings_[key] == nullptr)) {
282 uint32_t hash_field = StringHasher::HashSequentialString<uint8_t>(
283 literal.begin(), literal.length(), hash_seed_);
284 one_character_strings_[key] = GetString(hash_field, true, literal);
285 }
286 return one_character_strings_[key];
287 }
288 uint32_t hash_field = StringHasher::HashSequentialString<uint8_t>(
289 literal.begin(), literal.length(), hash_seed_);
290 return GetString(hash_field, true, literal);
291 }
292
GetTwoByteStringInternal(Vector<const uint16_t> literal)293 const AstRawString* AstValueFactory::GetTwoByteStringInternal(
294 Vector<const uint16_t> literal) {
295 uint32_t hash_field = StringHasher::HashSequentialString<uint16_t>(
296 literal.begin(), literal.length(), hash_seed_);
297 return GetString(hash_field, false, Vector<const byte>::cast(literal));
298 }
299
GetString(Handle<String> literal)300 const AstRawString* AstValueFactory::GetString(Handle<String> literal) {
301 const AstRawString* result = nullptr;
302 DisallowHeapAllocation no_gc;
303 String::FlatContent content = literal->GetFlatContent(no_gc);
304 if (content.IsOneByte()) {
305 result = GetOneByteStringInternal(content.ToOneByteVector());
306 } else {
307 DCHECK(content.IsTwoByte());
308 result = GetTwoByteStringInternal(content.ToUC16Vector());
309 }
310 return result;
311 }
312
CloneFromOtherFactory(const AstRawString * raw_string)313 const AstRawString* AstValueFactory::CloneFromOtherFactory(
314 const AstRawString* raw_string) {
315 const AstRawString* result = GetString(
316 raw_string->hash_field(), raw_string->is_one_byte(),
317 Vector<const byte>(raw_string->raw_data(), raw_string->byte_length()));
318 return result;
319 }
320
NewConsString()321 AstConsString* AstValueFactory::NewConsString() {
322 return zone()->New<AstConsString>();
323 }
324
NewConsString(const AstRawString * str)325 AstConsString* AstValueFactory::NewConsString(const AstRawString* str) {
326 return NewConsString()->AddString(zone(), str);
327 }
328
NewConsString(const AstRawString * str1,const AstRawString * str2)329 AstConsString* AstValueFactory::NewConsString(const AstRawString* str1,
330 const AstRawString* str2) {
331 return NewConsString()->AddString(zone(), str1)->AddString(zone(), str2);
332 }
333
334 template <typename LocalIsolate>
Internalize(LocalIsolate * isolate)335 void AstValueFactory::Internalize(LocalIsolate* isolate) {
336 if (!zone_) return;
337
338 // Strings need to be internalized before values, because values refer to
339 // strings.
340 for (AstRawString* current = strings_; current != nullptr;) {
341 AstRawString* next = current->next();
342 current->Internalize(isolate);
343 current = next;
344 }
345
346 ResetStrings();
347 zone_ = nullptr;
348 }
349 template EXPORT_TEMPLATE_DEFINE(
350 V8_EXPORT_PRIVATE) void AstValueFactory::Internalize(Isolate* isolate);
351 template EXPORT_TEMPLATE_DEFINE(
352 V8_EXPORT_PRIVATE) void AstValueFactory::Internalize(LocalIsolate* isolate);
353
GetString(uint32_t hash_field,bool is_one_byte,Vector<const byte> literal_bytes)354 const AstRawString* AstValueFactory::GetString(
355 uint32_t hash_field, bool is_one_byte, Vector<const byte> literal_bytes) {
356 // literal_bytes here points to whatever the user passed, and this is OK
357 // because we use vector_compare (which checks the contents) to compare
358 // against the AstRawStrings which are in the string_table_. We should not
359 // return this AstRawString.
360 AstRawString key(is_one_byte, literal_bytes, hash_field);
361 AstRawStringMap::Entry* entry = string_table_.LookupOrInsert(
362 &key, key.Hash(),
363 [&]() {
364 // Copy literal contents for later comparison.
365 int length = literal_bytes.length();
366 byte* new_literal_bytes = zone()->NewArray<byte>(length);
367 memcpy(new_literal_bytes, literal_bytes.begin(), length);
368 AstRawString* new_string = zone()->New<AstRawString>(
369 is_one_byte, Vector<const byte>(new_literal_bytes, length),
370 hash_field);
371 CHECK_NOT_NULL(new_string);
372 AddString(new_string);
373 return new_string;
374 },
375 [&]() { return base::NoHashMapValue(); });
376 return entry->key;
377 }
378
379 } // namespace internal
380 } // namespace v8
381