V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
ast-value-factory.cc
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/char-predicates-inl.h"
31 #include "src/objects-inl.h"
32 #include "src/objects.h"
33 #include "src/string-hasher.h"
34 #include "src/utils-inl.h"
35 
36 namespace v8 {
37 namespace internal {
38 
39 namespace {
40 
41 // For using StringToArrayIndex.
42 class OneByteStringStream {
43  public:
44  explicit OneByteStringStream(Vector<const byte> lb) :
45  literal_bytes_(lb), pos_(0) {}
46 
47  bool HasMore() { return pos_ < literal_bytes_.length(); }
48  uint16_t GetNext() { return literal_bytes_[pos_++]; }
49 
50  private:
51  Vector<const byte> literal_bytes_;
52  int pos_;
53 };
54 
55 } // namespace
56 
58  public:
59  explicit AstRawStringInternalizationKey(const AstRawString* string)
60  : StringTableKey(string->hash_field()), string_(string) {}
61 
62  bool IsMatch(Object* other) override {
63  if (string_->is_one_byte())
64  return String::cast(other)->IsOneByteEqualTo(string_->literal_bytes_);
65  return String::cast(other)->IsTwoByteEqualTo(
66  Vector<const uint16_t>::cast(string_->literal_bytes_));
67  }
68 
69  Handle<String> AsHandle(Isolate* isolate) override {
70  if (string_->is_one_byte())
71  return isolate->factory()->NewOneByteInternalizedString(
72  string_->literal_bytes_, string_->hash_field());
73  return isolate->factory()->NewTwoByteInternalizedString(
74  Vector<const uint16_t>::cast(string_->literal_bytes_),
75  string_->hash_field());
76  }
77 
78  private:
79  const AstRawString* string_;
80 };
81 
82 void AstRawString::Internalize(Isolate* isolate) {
83  DCHECK(!has_string_);
84  if (literal_bytes_.length() == 0) {
85  set_string(isolate->factory()->empty_string());
86  } else {
87  AstRawStringInternalizationKey key(this);
88  set_string(StringTable::LookupKey(isolate, &key));
89  }
90 }
91 
92 bool AstRawString::AsArrayIndex(uint32_t* index) const {
93  // The StringHasher will set up the hash in such a way that we can use it to
94  // figure out whether the string is convertible to an array index.
95  if ((hash_field_ & Name::kIsNotArrayIndexMask) != 0) return false;
96  if (length() <= Name::kMaxCachedArrayIndexLength) {
97  *index = Name::ArrayIndexValueBits::decode(hash_field_);
98  } else {
99  OneByteStringStream stream(literal_bytes_);
100  CHECK(StringToArrayIndex(&stream, index));
101  }
102  return true;
103 }
104 
105 bool AstRawString::IsOneByteEqualTo(const char* data) const {
106  if (!is_one_byte()) return false;
107 
108  size_t length = static_cast<size_t>(literal_bytes_.length());
109  if (length != strlen(data)) return false;
110 
111  return 0 == strncmp(reinterpret_cast<const char*>(literal_bytes_.start()),
112  data, length);
113 }
114 
115 uint16_t AstRawString::FirstCharacter() const {
116  if (is_one_byte()) return literal_bytes_[0];
117  const uint16_t* c = reinterpret_cast<const uint16_t*>(literal_bytes_.start());
118  return *c;
119 }
120 
121 bool AstRawString::Compare(void* a, void* b) {
122  const AstRawString* lhs = static_cast<AstRawString*>(a);
123  const AstRawString* rhs = static_cast<AstRawString*>(b);
124  DCHECK_EQ(lhs->Hash(), rhs->Hash());
125 
126  if (lhs->length() != rhs->length()) return false;
127  const unsigned char* l = lhs->raw_data();
128  const unsigned char* r = rhs->raw_data();
129  size_t length = rhs->length();
130  if (lhs->is_one_byte()) {
131  if (rhs->is_one_byte()) {
132  return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l),
133  reinterpret_cast<const uint8_t*>(r),
134  length) == 0;
135  } else {
136  return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l),
137  reinterpret_cast<const uint16_t*>(r),
138  length) == 0;
139  }
140  } else {
141  if (rhs->is_one_byte()) {
142  return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l),
143  reinterpret_cast<const uint8_t*>(r),
144  length) == 0;
145  } else {
146  return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l),
147  reinterpret_cast<const uint16_t*>(r),
148  length) == 0;
149  }
150  }
151 }
152 
153 void AstConsString::Internalize(Isolate* isolate) {
154  if (IsEmpty()) {
155  set_string(isolate->factory()->empty_string());
156  return;
157  }
158  // AstRawStrings are internalized before AstConsStrings, so
159  // AstRawString::string() will just work.
160  Handle<String> tmp(segment_.string->string());
161  for (AstConsString::Segment* current = segment_.next; current != nullptr;
162  current = current->next) {
163  tmp = isolate->factory()
164  ->NewConsString(current->string->string(), tmp)
165  .ToHandleChecked();
166  }
167  set_string(tmp);
168 }
169 
170 std::forward_list<const AstRawString*> AstConsString::ToRawStrings() const {
171  std::forward_list<const AstRawString*> result;
172  if (IsEmpty()) {
173  return result;
174  }
175 
176  result.emplace_front(segment_.string);
177  for (AstConsString::Segment* current = segment_.next; current != nullptr;
178  current = current->next) {
179  result.emplace_front(current->string);
180  }
181  return result;
182 }
183 
184 AstStringConstants::AstStringConstants(Isolate* isolate, uint64_t hash_seed)
185  : zone_(isolate->allocator(), ZONE_NAME),
186  string_table_(AstRawString::Compare),
187  hash_seed_(hash_seed) {
188  DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
189 #define F(name, str) \
190  { \
191  const char* data = str; \
192  Vector<const uint8_t> literal(reinterpret_cast<const uint8_t*>(data), \
193  static_cast<int>(strlen(data))); \
194  uint32_t hash_field = StringHasher::HashSequentialString<uint8_t>( \
195  literal.start(), literal.length(), hash_seed_); \
196  name##_string_ = new (&zone_) AstRawString(true, literal, hash_field); \
197  /* The Handle returned by the factory is located on the roots */ \
198  /* array, not on the temporary HandleScope, so this is safe. */ \
199  name##_string_->set_string(isolate->factory()->name##_string()); \
200  base::HashMap::Entry* entry = \
201  string_table_.InsertNew(name##_string_, name##_string_->Hash()); \
202  DCHECK_NULL(entry->value); \
203  entry->value = reinterpret_cast<void*>(1); \
204  }
205  AST_STRING_CONSTANTS(F)
206 #undef F
207 }
208 
209 AstRawString* AstValueFactory::GetOneByteStringInternal(
210  Vector<const uint8_t> literal) {
211  if (literal.length() == 1 && literal[0] < kMaxOneCharStringValue) {
212  int key = literal[0];
213  if (V8_UNLIKELY(one_character_strings_[key] == nullptr)) {
214  uint32_t hash_field = StringHasher::HashSequentialString<uint8_t>(
215  literal.start(), literal.length(), hash_seed_);
216  one_character_strings_[key] = GetString(hash_field, true, literal);
217  }
218  return one_character_strings_[key];
219  }
220  uint32_t hash_field = StringHasher::HashSequentialString<uint8_t>(
221  literal.start(), literal.length(), hash_seed_);
222  return GetString(hash_field, true, literal);
223 }
224 
225 AstRawString* AstValueFactory::GetTwoByteStringInternal(
226  Vector<const uint16_t> literal) {
227  uint32_t hash_field = StringHasher::HashSequentialString<uint16_t>(
228  literal.start(), literal.length(), hash_seed_);
229  return GetString(hash_field, false, Vector<const byte>::cast(literal));
230 }
231 
232 const AstRawString* AstValueFactory::GetString(Handle<String> literal) {
233  AstRawString* result = nullptr;
234  DisallowHeapAllocation no_gc;
235  String::FlatContent content = literal->GetFlatContent();
236  if (content.IsOneByte()) {
237  result = GetOneByteStringInternal(content.ToOneByteVector());
238  } else {
239  DCHECK(content.IsTwoByte());
240  result = GetTwoByteStringInternal(content.ToUC16Vector());
241  }
242  return result;
243 }
244 
245 const AstRawString* AstValueFactory::CloneFromOtherFactory(
246  const AstRawString* raw_string) {
247  const AstRawString* result = GetString(
248  raw_string->hash_field(), raw_string->is_one_byte(),
249  Vector<const byte>(raw_string->raw_data(), raw_string->byte_length()));
250  return result;
251 }
252 
253 AstConsString* AstValueFactory::NewConsString() {
254  AstConsString* new_string = new (zone_) AstConsString;
255  DCHECK_NOT_NULL(new_string);
256  AddConsString(new_string);
257  return new_string;
258 }
259 
260 AstConsString* AstValueFactory::NewConsString(const AstRawString* str) {
261  return NewConsString()->AddString(zone_, str);
262 }
263 
264 AstConsString* AstValueFactory::NewConsString(const AstRawString* str1,
265  const AstRawString* str2) {
266  return NewConsString()->AddString(zone_, str1)->AddString(zone_, str2);
267 }
268 
269 void AstValueFactory::Internalize(Isolate* isolate) {
270  // Strings need to be internalized before values, because values refer to
271  // strings.
272  for (AstRawString* current = strings_; current != nullptr;) {
273  AstRawString* next = current->next();
274  current->Internalize(isolate);
275  current = next;
276  }
277 
278  // AstConsStrings refer to AstRawStrings.
279  for (AstConsString* current = cons_strings_; current != nullptr;) {
280  AstConsString* next = current->next();
281  current->Internalize(isolate);
282  current = next;
283  }
284 
285  ResetStrings();
286 }
287 
288 AstRawString* AstValueFactory::GetString(uint32_t hash_field, bool is_one_byte,
289  Vector<const byte> literal_bytes) {
290  // literal_bytes here points to whatever the user passed, and this is OK
291  // because we use vector_compare (which checks the contents) to compare
292  // against the AstRawStrings which are in the string_table_. We should not
293  // return this AstRawString.
294  AstRawString key(is_one_byte, literal_bytes, hash_field);
295  base::HashMap::Entry* entry = string_table_.LookupOrInsert(&key, key.Hash());
296  if (entry->value == nullptr) {
297  // Copy literal contents for later comparison.
298  int length = literal_bytes.length();
299  byte* new_literal_bytes = zone_->NewArray<byte>(length);
300  memcpy(new_literal_bytes, literal_bytes.start(), length);
301  AstRawString* new_string = new (zone_) AstRawString(
302  is_one_byte, Vector<const byte>(new_literal_bytes, length), hash_field);
303  CHECK_NOT_NULL(new_string);
304  AddString(new_string);
305  entry->key = new_string;
306  entry->value = reinterpret_cast<void*>(1);
307  }
308  return reinterpret_cast<AstRawString*>(entry->key);
309 }
310 
311 } // namespace internal
312 } // namespace v8
Definition: libplatform.h:13