Home | History | Annotate | Download | only in ast
      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 
     57 class AstRawStringInternalizationKey : public StringTableKey {
     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 && IsInRange(literal[0], 'a', 'z')) {
    212     int key = literal[0] - 'a';
    213     if (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 AstConsString* AstValueFactory::NewConsString() {
    246   AstConsString* new_string = new (zone_) AstConsString;
    247   DCHECK_NOT_NULL(new_string);
    248   AddConsString(new_string);
    249   return new_string;
    250 }
    251 
    252 AstConsString* AstValueFactory::NewConsString(const AstRawString* str) {
    253   return NewConsString()->AddString(zone_, str);
    254 }
    255 
    256 AstConsString* AstValueFactory::NewConsString(const AstRawString* str1,
    257                                               const AstRawString* str2) {
    258   return NewConsString()->AddString(zone_, str1)->AddString(zone_, str2);
    259 }
    260 
    261 void AstValueFactory::Internalize(Isolate* isolate) {
    262   // Strings need to be internalized before values, because values refer to
    263   // strings.
    264   for (AstRawString* current = strings_; current != nullptr;) {
    265     AstRawString* next = current->next();
    266     current->Internalize(isolate);
    267     current = next;
    268   }
    269 
    270   // AstConsStrings refer to AstRawStrings.
    271   for (AstConsString* current = cons_strings_; current != nullptr;) {
    272     AstConsString* next = current->next();
    273     current->Internalize(isolate);
    274     current = next;
    275   }
    276 
    277   ResetStrings();
    278 }
    279 
    280 AstRawString* AstValueFactory::GetString(uint32_t hash_field, bool is_one_byte,
    281                                          Vector<const byte> literal_bytes) {
    282   // literal_bytes here points to whatever the user passed, and this is OK
    283   // because we use vector_compare (which checks the contents) to compare
    284   // against the AstRawStrings which are in the string_table_. We should not
    285   // return this AstRawString.
    286   AstRawString key(is_one_byte, literal_bytes, hash_field);
    287   base::HashMap::Entry* entry = string_table_.LookupOrInsert(&key, key.Hash());
    288   if (entry->value == nullptr) {
    289     // Copy literal contents for later comparison.
    290     int length = literal_bytes.length();
    291     byte* new_literal_bytes = zone_->NewArray<byte>(length);
    292     memcpy(new_literal_bytes, literal_bytes.start(), length);
    293     AstRawString* new_string = new (zone_) AstRawString(
    294         is_one_byte, Vector<const byte>(new_literal_bytes, length), hash_field);
    295     CHECK_NOT_NULL(new_string);
    296     AddString(new_string);
    297     entry->key = new_string;
    298     entry->value = reinterpret_cast<void*>(1);
    299   }
    300   return reinterpret_cast<AstRawString*>(entry->key);
    301 }
    302 
    303 }  // namespace internal
    304 }  // namespace v8
    305