• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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