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
33namespace v8 {
34namespace internal {
35
36namespace {
37
38// For using StringToArrayIndex.
39class OneByteStringStream {
40 public:
41  explicit OneByteStringStream(Vector<const byte> lb) :
42      literal_bytes_(lb), pos_(0) {}
43
44  bool HasMore() { return pos_ < literal_bytes_.length(); }
45  uint16_t GetNext() { return literal_bytes_[pos_++]; }
46
47 private:
48  Vector<const byte> literal_bytes_;
49  int pos_;
50};
51
52}
53
54class AstRawStringInternalizationKey : public HashTableKey {
55 public:
56  explicit AstRawStringInternalizationKey(const AstRawString* string)
57      : string_(string) {}
58
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
66  virtual uint32_t Hash() OVERRIDE {
67    return string_->hash() >> Name::kHashShift;
68  }
69
70  virtual uint32_t HashForObject(Object* key) OVERRIDE {
71    return String::cast(key)->Hash();
72  }
73
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
87void 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
98bool 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
109bool 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
119bool 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
131void 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
140bool AstValue::IsPropertyName() const {
141  if (type_ == STRING) {
142    uint32_t index;
143    return !string_->AsArrayIndex(&index);
144  }
145  return false;
146}
147
148
149bool 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
179void 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
233const 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
241const 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
249const 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
260const 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
273void 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
290const 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
301const 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
311const 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
321const 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
332const 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
342const 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
353const 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
363const 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
373const 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
383const 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