OLD | NEW |
| (Empty) |
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-value-factory.h" | |
29 | |
30 #include "src/api.h" | |
31 #include "src/objects.h" | |
32 #include "src/utils.h" | |
33 | |
34 namespace v8 { | |
35 namespace internal { | |
36 | |
37 namespace { | |
38 | |
39 // For using StringToArrayIndex. | |
40 class OneByteStringStream { | |
41 public: | |
42 explicit OneByteStringStream(Vector<const byte> lb) : | |
43 literal_bytes_(lb), pos_(0) {} | |
44 | |
45 bool HasMore() { return pos_ < literal_bytes_.length(); } | |
46 uint16_t GetNext() { return literal_bytes_[pos_++]; } | |
47 | |
48 private: | |
49 Vector<const byte> literal_bytes_; | |
50 int pos_; | |
51 }; | |
52 | |
53 } // namespace | |
54 | |
55 class AstRawStringInternalizationKey : public HashTableKey { | |
56 public: | |
57 explicit AstRawStringInternalizationKey(const AstRawString* string) | |
58 : string_(string) {} | |
59 | |
60 bool IsMatch(Object* other) override { | |
61 if (string_->is_one_byte_) | |
62 return String::cast(other)->IsOneByteEqualTo(string_->literal_bytes_); | |
63 return String::cast(other)->IsTwoByteEqualTo( | |
64 Vector<const uint16_t>::cast(string_->literal_bytes_)); | |
65 } | |
66 | |
67 uint32_t Hash() override { return string_->hash() >> Name::kHashShift; } | |
68 | |
69 uint32_t HashForObject(Object* key) override { | |
70 return String::cast(key)->Hash(); | |
71 } | |
72 | |
73 Handle<Object> AsHandle(Isolate* isolate) override { | |
74 if (string_->is_one_byte_) | |
75 return isolate->factory()->NewOneByteInternalizedString( | |
76 string_->literal_bytes_, string_->hash()); | |
77 return isolate->factory()->NewTwoByteInternalizedString( | |
78 Vector<const uint16_t>::cast(string_->literal_bytes_), string_->hash()); | |
79 } | |
80 | |
81 private: | |
82 const AstRawString* string_; | |
83 }; | |
84 | |
85 | |
86 void AstRawString::Internalize(Isolate* isolate) { | |
87 if (!string_.is_null()) return; | |
88 if (literal_bytes_.length() == 0) { | |
89 string_ = isolate->factory()->empty_string(); | |
90 } else { | |
91 AstRawStringInternalizationKey key(this); | |
92 string_ = StringTable::LookupKey(isolate, &key); | |
93 } | |
94 } | |
95 | |
96 | |
97 bool AstRawString::AsArrayIndex(uint32_t* index) const { | |
98 if (!string_.is_null()) | |
99 return string_->AsArrayIndex(index); | |
100 if (!is_one_byte_ || literal_bytes_.length() == 0 || | |
101 literal_bytes_.length() > String::kMaxArrayIndexSize) | |
102 return false; | |
103 OneByteStringStream stream(literal_bytes_); | |
104 return StringToArrayIndex(&stream, index); | |
105 } | |
106 | |
107 | |
108 bool AstRawString::IsOneByteEqualTo(const char* data) const { | |
109 int length = static_cast<int>(strlen(data)); | |
110 if (is_one_byte_ && literal_bytes_.length() == length) { | |
111 const char* token = reinterpret_cast<const char*>(literal_bytes_.start()); | |
112 return !strncmp(token, data, length); | |
113 } | |
114 return false; | |
115 } | |
116 | |
117 | |
118 void AstConsString::Internalize(Isolate* isolate) { | |
119 // AstRawStrings are internalized before AstConsStrings so left and right are | |
120 // already internalized. | |
121 string_ = isolate->factory() | |
122 ->NewConsString(left_->string(), right_->string()) | |
123 .ToHandleChecked(); | |
124 } | |
125 | |
126 | |
127 bool AstValue::IsPropertyName() const { | |
128 if (type_ == STRING) { | |
129 uint32_t index; | |
130 return !string_->AsArrayIndex(&index); | |
131 } | |
132 return false; | |
133 } | |
134 | |
135 | |
136 bool AstValue::BooleanValue() const { | |
137 switch (type_) { | |
138 case STRING: | |
139 DCHECK(string_ != NULL); | |
140 return !string_->IsEmpty(); | |
141 case SYMBOL: | |
142 UNREACHABLE(); | |
143 break; | |
144 case NUMBER_WITH_DOT: | |
145 case NUMBER: | |
146 return DoubleToBoolean(number_); | |
147 case SMI: | |
148 return smi_ != 0; | |
149 case BOOLEAN: | |
150 return bool_; | |
151 case NULL_TYPE: | |
152 return false; | |
153 case THE_HOLE: | |
154 UNREACHABLE(); | |
155 break; | |
156 case UNDEFINED: | |
157 return false; | |
158 } | |
159 UNREACHABLE(); | |
160 return false; | |
161 } | |
162 | |
163 | |
164 void AstValue::Internalize(Isolate* isolate) { | |
165 switch (type_) { | |
166 case STRING: | |
167 DCHECK(string_ != NULL); | |
168 // Strings are already internalized. | |
169 DCHECK(!string_->string().is_null()); | |
170 break; | |
171 case SYMBOL: | |
172 if (symbol_name_[0] == 'i') { | |
173 DCHECK_EQ(0, strcmp(symbol_name_, "iterator_symbol")); | |
174 value_ = isolate->factory()->iterator_symbol(); | |
175 } else { | |
176 DCHECK_EQ(0, strcmp(symbol_name_, "home_object_symbol")); | |
177 value_ = isolate->factory()->home_object_symbol(); | |
178 } | |
179 break; | |
180 case NUMBER_WITH_DOT: | |
181 case NUMBER: | |
182 value_ = isolate->factory()->NewNumber(number_, TENURED); | |
183 break; | |
184 case SMI: | |
185 value_ = handle(Smi::FromInt(smi_), isolate); | |
186 break; | |
187 case BOOLEAN: | |
188 if (bool_) { | |
189 value_ = isolate->factory()->true_value(); | |
190 } else { | |
191 value_ = isolate->factory()->false_value(); | |
192 } | |
193 break; | |
194 case NULL_TYPE: | |
195 value_ = isolate->factory()->null_value(); | |
196 break; | |
197 case THE_HOLE: | |
198 value_ = isolate->factory()->the_hole_value(); | |
199 break; | |
200 case UNDEFINED: | |
201 value_ = isolate->factory()->undefined_value(); | |
202 break; | |
203 } | |
204 } | |
205 | |
206 | |
207 AstRawString* AstValueFactory::GetOneByteStringInternal( | |
208 Vector<const uint8_t> literal) { | |
209 uint32_t hash = StringHasher::HashSequentialString<uint8_t>( | |
210 literal.start(), literal.length(), hash_seed_); | |
211 return GetString(hash, true, literal); | |
212 } | |
213 | |
214 | |
215 AstRawString* AstValueFactory::GetTwoByteStringInternal( | |
216 Vector<const uint16_t> literal) { | |
217 uint32_t hash = StringHasher::HashSequentialString<uint16_t>( | |
218 literal.start(), literal.length(), hash_seed_); | |
219 return GetString(hash, false, Vector<const byte>::cast(literal)); | |
220 } | |
221 | |
222 | |
223 const AstRawString* AstValueFactory::GetString(Handle<String> literal) { | |
224 // For the FlatContent to stay valid, we shouldn't do any heap | |
225 // allocation. Make sure we won't try to internalize the string in GetString. | |
226 AstRawString* result = NULL; | |
227 Isolate* saved_isolate = isolate_; | |
228 isolate_ = NULL; | |
229 { | |
230 DisallowHeapAllocation no_gc; | |
231 String::FlatContent content = literal->GetFlatContent(); | |
232 if (content.IsOneByte()) { | |
233 result = GetOneByteStringInternal(content.ToOneByteVector()); | |
234 } else { | |
235 DCHECK(content.IsTwoByte()); | |
236 result = GetTwoByteStringInternal(content.ToUC16Vector()); | |
237 } | |
238 } | |
239 isolate_ = saved_isolate; | |
240 if (isolate_) result->Internalize(isolate_); | |
241 return result; | |
242 } | |
243 | |
244 | |
245 const AstConsString* AstValueFactory::NewConsString( | |
246 const AstString* left, const AstString* right) { | |
247 // This Vector will be valid as long as the Collector is alive (meaning that | |
248 // the AstRawString will not be moved). | |
249 AstConsString* new_string = new (zone_) AstConsString(left, right); | |
250 strings_.Add(new_string); | |
251 if (isolate_) { | |
252 new_string->Internalize(isolate_); | |
253 } | |
254 return new_string; | |
255 } | |
256 | |
257 | |
258 void AstValueFactory::Internalize(Isolate* isolate) { | |
259 if (isolate_) { | |
260 // Everything is already internalized. | |
261 return; | |
262 } | |
263 // Strings need to be internalized before values, because values refer to | |
264 // strings. | |
265 for (int i = 0; i < strings_.length(); ++i) { | |
266 strings_[i]->Internalize(isolate); | |
267 } | |
268 for (int i = 0; i < values_.length(); ++i) { | |
269 values_[i]->Internalize(isolate); | |
270 } | |
271 isolate_ = isolate; | |
272 } | |
273 | |
274 | |
275 const AstValue* AstValueFactory::NewString(const AstRawString* string) { | |
276 AstValue* value = new (zone_) AstValue(string); | |
277 DCHECK(string != NULL); | |
278 if (isolate_) { | |
279 value->Internalize(isolate_); | |
280 } | |
281 values_.Add(value); | |
282 return value; | |
283 } | |
284 | |
285 | |
286 const AstValue* AstValueFactory::NewSymbol(const char* name) { | |
287 AstValue* value = new (zone_) AstValue(name); | |
288 if (isolate_) { | |
289 value->Internalize(isolate_); | |
290 } | |
291 values_.Add(value); | |
292 return value; | |
293 } | |
294 | |
295 | |
296 const AstValue* AstValueFactory::NewNumber(double number, bool with_dot) { | |
297 AstValue* value = new (zone_) AstValue(number, with_dot); | |
298 if (isolate_) { | |
299 value->Internalize(isolate_); | |
300 } | |
301 values_.Add(value); | |
302 return value; | |
303 } | |
304 | |
305 | |
306 const AstValue* AstValueFactory::NewSmi(int number) { | |
307 AstValue* value = | |
308 new (zone_) AstValue(AstValue::SMI, number); | |
309 if (isolate_) { | |
310 value->Internalize(isolate_); | |
311 } | |
312 values_.Add(value); | |
313 return value; | |
314 } | |
315 | |
316 | |
317 #define GENERATE_VALUE_GETTER(value, initializer) \ | |
318 if (!value) { \ | |
319 value = new (zone_) AstValue(initializer); \ | |
320 if (isolate_) { \ | |
321 value->Internalize(isolate_); \ | |
322 } \ | |
323 values_.Add(value); \ | |
324 } \ | |
325 return value; | |
326 | |
327 | |
328 const AstValue* AstValueFactory::NewBoolean(bool b) { | |
329 if (b) { | |
330 GENERATE_VALUE_GETTER(true_value_, true); | |
331 } else { | |
332 GENERATE_VALUE_GETTER(false_value_, false); | |
333 } | |
334 } | |
335 | |
336 | |
337 const AstValue* AstValueFactory::NewNull() { | |
338 GENERATE_VALUE_GETTER(null_value_, AstValue::NULL_TYPE); | |
339 } | |
340 | |
341 | |
342 const AstValue* AstValueFactory::NewUndefined() { | |
343 GENERATE_VALUE_GETTER(undefined_value_, AstValue::UNDEFINED); | |
344 } | |
345 | |
346 | |
347 const AstValue* AstValueFactory::NewTheHole() { | |
348 GENERATE_VALUE_GETTER(the_hole_value_, AstValue::THE_HOLE); | |
349 } | |
350 | |
351 | |
352 #undef GENERATE_VALUE_GETTER | |
353 | |
354 AstRawString* AstValueFactory::GetString(uint32_t hash, bool is_one_byte, | |
355 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); | |
361 HashMap::Entry* entry = string_table_.LookupOrInsert(&key, hash); | |
362 if (entry->value == NULL) { | |
363 // Copy literal contents for later comparison. | |
364 int length = literal_bytes.length(); | |
365 byte* new_literal_bytes = zone_->NewArray<byte>(length); | |
366 memcpy(new_literal_bytes, literal_bytes.start(), length); | |
367 AstRawString* new_string = new (zone_) AstRawString( | |
368 is_one_byte, Vector<const byte>(new_literal_bytes, length), hash); | |
369 entry->key = new_string; | |
370 strings_.Add(new_string); | |
371 if (isolate_) { | |
372 new_string->Internalize(isolate_); | |
373 } | |
374 entry->value = reinterpret_cast<void*>(1); | |
375 } | |
376 return reinterpret_cast<AstRawString*>(entry->key); | |
377 } | |
378 | |
379 | |
380 bool AstValueFactory::AstRawStringCompare(void* a, void* b) { | |
381 const AstRawString* lhs = static_cast<AstRawString*>(a); | |
382 const AstRawString* rhs = static_cast<AstRawString*>(b); | |
383 if (lhs->length() != rhs->length()) return false; | |
384 if (lhs->hash() != rhs->hash()) return false; | |
385 const unsigned char* l = lhs->raw_data(); | |
386 const unsigned char* r = rhs->raw_data(); | |
387 size_t length = rhs->length(); | |
388 if (lhs->is_one_byte()) { | |
389 if (rhs->is_one_byte()) { | |
390 return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l), | |
391 reinterpret_cast<const uint8_t*>(r), | |
392 length) == 0; | |
393 } else { | |
394 return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l), | |
395 reinterpret_cast<const uint16_t*>(r), | |
396 length) == 0; | |
397 } | |
398 } else { | |
399 if (rhs->is_one_byte()) { | |
400 return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l), | |
401 reinterpret_cast<const uint8_t*>(r), | |
402 length) == 0; | |
403 } else { | |
404 return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l), | |
405 reinterpret_cast<const uint16_t*>(r), | |
406 length) == 0; | |
407 } | |
408 } | |
409 } | |
410 } // namespace internal | |
411 } // namespace v8 | |
OLD | NEW |