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/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:
OneByteStringStream(Vector<const byte> lb)42   explicit OneByteStringStream(Vector<const byte> lb) :
43       literal_bytes_(lb), pos_(0) {}
44 
HasMore()45   bool HasMore() { return pos_ < literal_bytes_.length(); }
GetNext()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:
AstRawStringInternalizationKey(const AstRawString * string)57   explicit AstRawStringInternalizationKey(const AstRawString* string)
58       : string_(string) {}
59 
IsMatch(Object * other)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 
Hash()67   uint32_t Hash() override { return string_->hash() >> Name::kHashShift; }
68 
HashForObject(Object * key)69   uint32_t HashForObject(Object* key) override {
70     return String::cast(key)->Hash();
71   }
72 
AsHandle(Isolate * isolate)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 
Internalize(Isolate * isolate)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 
AsArrayIndex(uint32_t * index) const97 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 
IsOneByteEqualTo(const char * data) const108 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 
Internalize(Isolate * isolate)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 
IsPropertyName() const127 bool AstValue::IsPropertyName() const {
128   if (type_ == STRING) {
129     uint32_t index;
130     return !string_->AsArrayIndex(&index);
131   }
132   return false;
133 }
134 
135 
BooleanValue() const136 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 
Internalize(Isolate * isolate)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 
GetOneByteStringInternal(Vector<const uint8_t> literal)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 
GetTwoByteStringInternal(Vector<const uint16_t> literal)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 
GetString(Handle<String> literal)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 
NewConsString(const AstString * left,const AstString * right)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 
Internalize(Isolate * isolate)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 
NewString(const AstRawString * string)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 
NewSymbol(const char * name)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 
NewNumber(double number,bool with_dot)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 
NewSmi(int number)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 
NewBoolean(bool b)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 
NewNull()337 const AstValue* AstValueFactory::NewNull() {
338   GENERATE_VALUE_GETTER(null_value_, AstValue::NULL_TYPE);
339 }
340 
341 
NewUndefined()342 const AstValue* AstValueFactory::NewUndefined() {
343   GENERATE_VALUE_GETTER(undefined_value_, AstValue::UNDEFINED);
344 }
345 
346 
NewTheHole()347 const AstValue* AstValueFactory::NewTheHole() {
348   GENERATE_VALUE_GETTER(the_hole_value_, AstValue::THE_HOLE);
349 }
350 
351 
352 #undef GENERATE_VALUE_GETTER
353 
GetString(uint32_t hash,bool is_one_byte,Vector<const byte> literal_bytes)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 
AstRawStringCompare(void * a,void * b)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
412