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