ast-value-factory.cc 15.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
// Copyright 2014 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

28
#include "src/ast/ast-value-factory.h"
29

30
#include "src/base/hashmap-entry.h"
31
#include "src/base/logging.h"
32
#include "src/base/platform/wrappers.h"
33 34
#include "src/common/globals.h"
#include "src/heap/factory-inl.h"
35
#include "src/heap/local-factory-inl.h"
36 37
#include "src/objects/objects-inl.h"
#include "src/objects/objects.h"
38
#include "src/objects/string.h"
39 40
#include "src/strings/char-predicates-inl.h"
#include "src/strings/string-hasher.h"
41
#include "src/utils/utils-inl.h"
42 43 44 45 46 47

namespace v8 {
namespace internal {

namespace {

48
// For using StringToIndex.
49 50
class OneByteStringStream {
 public:
51
  explicit OneByteStringStream(base::Vector<const byte> lb)
52
      : literal_bytes_(lb), pos_(0) {}
53 54 55 56 57

  bool HasMore() { return pos_ < literal_bytes_.length(); }
  uint16_t GetNext() { return literal_bytes_[pos_++]; }

 private:
58
  base::Vector<const byte> literal_bytes_;
59 60 61
  int pos_;
};

62
}  // namespace
63

64 65
template <typename IsolateT>
void AstRawString::Internalize(IsolateT* isolate) {
66
  DCHECK(!has_string_);
67
  if (literal_bytes_.length() == 0) {
68
    set_string(isolate->factory()->empty_string());
69
  } else if (is_one_byte()) {
70
    OneByteStringKey key(raw_hash_field_, literal_bytes_);
71
    set_string(isolate->factory()->InternalizeStringWithKey(&key));
72
  } else {
73
    TwoByteStringKey key(raw_hash_field_,
74
                         base::Vector<const uint16_t>::cast(literal_bytes_));
75
    set_string(isolate->factory()->InternalizeStringWithKey(&key));
76 77 78
  }
}

79 80 81 82
template EXPORT_TEMPLATE_DEFINE(
    V8_EXPORT_PRIVATE) void AstRawString::Internalize(Isolate* isolate);
template EXPORT_TEMPLATE_DEFINE(
    V8_EXPORT_PRIVATE) void AstRawString::Internalize(LocalIsolate* isolate);
83

84
bool AstRawString::AsArrayIndex(uint32_t* index) const {
85 86
  // The StringHasher will set up the hash. Bail out early if we know it
  // can't be convertible to an array index.
Patrick Thier's avatar
Patrick Thier committed
87
  if (!IsIntegerIndex()) return false;
88
  if (length() <= Name::kMaxCachedArrayIndexLength) {
89
    *index = Name::ArrayIndexValueBits::decode(raw_hash_field_);
90
    return true;
91
  }
92 93 94 95 96
  // Might be an index, but too big to cache it. Do the slow conversion. This
  // might fail if the string is outside uint32_t (but within "safe integer")
  // range.
  OneByteStringStream stream(literal_bytes_);
  return StringToIndex(&stream, index);
97 98
}

99
bool AstRawString::IsIntegerIndex() const {
Patrick Thier's avatar
Patrick Thier committed
100
  return Name::IsIntegerIndex(raw_hash_field_);
101 102
}

103
bool AstRawString::IsOneByteEqualTo(const char* data) const {
104 105 106 107 108
  if (!is_one_byte()) return false;

  size_t length = static_cast<size_t>(literal_bytes_.length());
  if (length != strlen(data)) return false;

109
  return 0 == strncmp(reinterpret_cast<const char*>(literal_bytes_.begin()),
110 111 112 113 114
                      data, length);
}

uint16_t AstRawString::FirstCharacter() const {
  if (is_one_byte()) return literal_bytes_[0];
115
  const uint16_t* c = reinterpret_cast<const uint16_t*>(literal_bytes_.begin());
116
  return *c;
117 118
}

119
bool AstRawString::Equal(const AstRawString* lhs, const AstRawString* rhs) {
120
  DCHECK_EQ(lhs->Hash(), rhs->Hash());
121

122
  if (lhs->length() != rhs->length()) return false;
123
  if (lhs->length() == 0) return true;
124 125 126 127 128
  const unsigned char* l = lhs->raw_data();
  const unsigned char* r = rhs->raw_data();
  size_t length = rhs->length();
  if (lhs->is_one_byte()) {
    if (rhs->is_one_byte()) {
129 130 131
      return CompareCharsEqualUnsigned(reinterpret_cast<const uint8_t*>(l),
                                       reinterpret_cast<const uint8_t*>(r),
                                       length);
132
    } else {
133 134 135
      return CompareCharsEqualUnsigned(reinterpret_cast<const uint8_t*>(l),
                                       reinterpret_cast<const uint16_t*>(r),
                                       length);
136 137 138
    }
  } else {
    if (rhs->is_one_byte()) {
139 140 141
      return CompareCharsEqualUnsigned(reinterpret_cast<const uint16_t*>(l),
                                       reinterpret_cast<const uint8_t*>(r),
                                       length);
142
    } else {
143 144 145
      return CompareCharsEqualUnsigned(reinterpret_cast<const uint16_t*>(l),
                                       reinterpret_cast<const uint16_t*>(r),
                                       length);
146 147 148
    }
  }
}
149

150 151 152 153 154 155
int AstRawString::Compare(const AstRawString* lhs, const AstRawString* rhs) {
  // Fast path for equal pointers.
  if (lhs == rhs) return 0;

  const unsigned char* lhs_data = lhs->raw_data();
  const unsigned char* rhs_data = rhs->raw_data();
156
  size_t length = std::min(lhs->length(), rhs->length());
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

  // Code point order by contents.
  if (lhs->is_one_byte()) {
    if (rhs->is_one_byte()) {
      if (int result = CompareCharsUnsigned(
              reinterpret_cast<const uint8_t*>(lhs_data),
              reinterpret_cast<const uint8_t*>(rhs_data), length))
        return result;
    } else {
      if (int result = CompareCharsUnsigned(
              reinterpret_cast<const uint8_t*>(lhs_data),
              reinterpret_cast<const uint16_t*>(rhs_data), length))
        return result;
    }
  } else {
    if (rhs->is_one_byte()) {
      if (int result = CompareCharsUnsigned(
              reinterpret_cast<const uint16_t*>(lhs_data),
              reinterpret_cast<const uint8_t*>(rhs_data), length))
        return result;
    } else {
      if (int result = CompareCharsUnsigned(
              reinterpret_cast<const uint16_t*>(lhs_data),
              reinterpret_cast<const uint16_t*>(rhs_data), length))
        return result;
    }
  }

  return lhs->byte_length() - rhs->byte_length();
}

188 189
template <typename IsolateT>
Handle<String> AstConsString::Allocate(IsolateT* isolate) const {
190 191
  DCHECK(string_.is_null());

192
  if (IsEmpty()) {
193
    return isolate->factory()->empty_string();
194
  }
195
  // AstRawStrings are internalized before AstConsStrings are allocated, so
196
  // AstRawString::string() will just work.
197
  Handle<String> tmp = segment_.string->string();
198 199
  for (AstConsString::Segment* current = segment_.next; current != nullptr;
       current = current->next) {
200
    tmp = isolate->factory()
201
              ->NewConsString(current->string->string(), tmp,
202 203 204 205 206 207
                              AllocationType::kOld)
              .ToHandleChecked();
  }
  return tmp;
}
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
208
    Handle<String> AstConsString::Allocate<Isolate>(Isolate* isolate) const;
209
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
210 211
    Handle<String> AstConsString::Allocate<LocalIsolate>(
        LocalIsolate* isolate) const;
212

213 214
template <typename IsolateT>
Handle<String> AstConsString::AllocateFlat(IsolateT* isolate) const {
215
  if (IsEmpty()) {
216
    return isolate->factory()->empty_string();
217 218
  }
  if (!segment_.next) {
219
    return segment_.string->string();
220 221 222 223 224 225 226 227 228 229 230
  }

  int result_length = 0;
  bool is_one_byte = true;
  for (const AstConsString::Segment* current = &segment_; current != nullptr;
       current = current->next) {
    result_length += current->string->length();
    is_one_byte = is_one_byte && current->string->is_one_byte();
  }

  if (is_one_byte) {
231
    Handle<SeqOneByteString> result =
232 233
        isolate->factory()
            ->NewRawOneByteString(result_length, AllocationType::kOld)
234
            .ToHandleChecked();
235
    DisallowGarbageCollection no_gc;
236 237 238
    uint8_t* dest =
        result->GetChars(no_gc, SharedStringAccessGuardIfNeeded::NotNeeded()) +
        result_length;
239 240 241 242 243 244
    for (const AstConsString::Segment* current = &segment_; current != nullptr;
         current = current->next) {
      int length = current->string->length();
      dest -= length;
      CopyChars(dest, current->string->raw_data(), length);
    }
245 246
    DCHECK_EQ(dest, result->GetChars(
                        no_gc, SharedStringAccessGuardIfNeeded::NotNeeded()));
247 248 249
    return result;
  }

250
  Handle<SeqTwoByteString> result =
251 252
      isolate->factory()
          ->NewRawTwoByteString(result_length, AllocationType::kOld)
253
          .ToHandleChecked();
254
  DisallowGarbageCollection no_gc;
255 256 257
  uint16_t* dest =
      result->GetChars(no_gc, SharedStringAccessGuardIfNeeded::NotNeeded()) +
      result_length;
258 259 260 261 262 263 264 265 266 267 268
  for (const AstConsString::Segment* current = &segment_; current != nullptr;
       current = current->next) {
    int length = current->string->length();
    dest -= length;
    if (current->string->is_one_byte()) {
      CopyChars(dest, current->string->raw_data(), length);
    } else {
      CopyChars(dest,
                reinterpret_cast<const uint16_t*>(current->string->raw_data()),
                length);
    }
269
  }
270 271
  DCHECK_EQ(dest, result->GetChars(
                      no_gc, SharedStringAccessGuardIfNeeded::NotNeeded()));
272
  return result;
273
}
274
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
275
    Handle<String> AstConsString::AllocateFlat<Isolate>(Isolate* isolate) const;
276
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
277 278
    Handle<String> AstConsString::AllocateFlat<LocalIsolate>(
        LocalIsolate* isolate) const;
279

280 281 282 283 284 285 286 287 288 289 290 291 292 293
std::forward_list<const AstRawString*> AstConsString::ToRawStrings() const {
  std::forward_list<const AstRawString*> result;
  if (IsEmpty()) {
    return result;
  }

  result.emplace_front(segment_.string);
  for (AstConsString::Segment* current = segment_.next; current != nullptr;
       current = current->next) {
    result.emplace_front(current->string);
  }
  return result;
}

Yang Guo's avatar
Yang Guo committed
294
AstStringConstants::AstStringConstants(Isolate* isolate, uint64_t hash_seed)
295
    : zone_(isolate->allocator(), ZONE_NAME),
296
      string_table_(),
297
      hash_seed_(hash_seed) {
Clemens Hammacher's avatar
Clemens Hammacher committed
298
  DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
299 300 301
#define F(name, str)                                                         \
  {                                                                          \
    const char* data = str;                                                  \
302 303 304
    base::Vector<const uint8_t> literal(                                     \
        reinterpret_cast<const uint8_t*>(data),                              \
        static_cast<int>(strlen(data)));                                     \
305 306 307 308 309 310 311
    uint32_t raw_hash_field = StringHasher::HashSequentialString<uint8_t>(   \
        literal.begin(), literal.length(), hash_seed_);                      \
    name##_string_ = zone_.New<AstRawString>(true, literal, raw_hash_field); \
    /* The Handle returned by the factory is located on the roots */         \
    /* array, not on the temporary HandleScope, so this is safe.  */         \
    name##_string_->set_string(isolate->factory()->name##_string());         \
    string_table_.InsertNew(name##_string_, name##_string_->Hash());         \
312 313 314 315 316
  }
  AST_STRING_CONSTANTS(F)
#undef F
}

317
const AstRawString* AstValueFactory::GetOneByteStringInternal(
318
    base::Vector<const uint8_t> literal) {
319 320 321
  if (literal.length() == 1 && literal[0] < kMaxOneCharStringValue) {
    int key = literal[0];
    if (V8_UNLIKELY(one_character_strings_[key] == nullptr)) {
322
      uint32_t raw_hash_field = StringHasher::HashSequentialString<uint8_t>(
323
          literal.begin(), literal.length(), hash_seed_);
324
      one_character_strings_[key] = GetString(raw_hash_field, true, literal);
325 326 327
    }
    return one_character_strings_[key];
  }
328
  uint32_t raw_hash_field = StringHasher::HashSequentialString<uint8_t>(
329
      literal.begin(), literal.length(), hash_seed_);
330
  return GetString(raw_hash_field, true, literal);
331 332
}

333
const AstRawString* AstValueFactory::GetTwoByteStringInternal(
334
    base::Vector<const uint16_t> literal) {
335
  uint32_t raw_hash_field = StringHasher::HashSequentialString<uint16_t>(
336
      literal.begin(), literal.length(), hash_seed_);
337 338
  return GetString(raw_hash_field, false,
                   base::Vector<const byte>::cast(literal));
339 340
}

341 342
const AstRawString* AstValueFactory::GetString(
    String literal, const SharedStringAccessGuardIfNeeded& access_guard) {
343
  const AstRawString* result = nullptr;
344
  DisallowGarbageCollection no_gc;
345
  String::FlatContent content = literal.GetFlatContent(no_gc, access_guard);
346
  if (content.IsOneByte()) {
347
    result = GetOneByteStringInternal(content.ToOneByteVector());
348 349
  } else {
    DCHECK(content.IsTwoByte());
350
    result = GetTwoByteStringInternal(content.ToUC16Vector());
351
  }
352
  return result;
353 354
}

355
AstConsString* AstValueFactory::NewConsString() {
356
  return single_parse_zone()->New<AstConsString>();
357 358
}

359
AstConsString* AstValueFactory::NewConsString(const AstRawString* str) {
360
  return NewConsString()->AddString(single_parse_zone(), str);
361 362 363 364
}

AstConsString* AstValueFactory::NewConsString(const AstRawString* str1,
                                              const AstRawString* str2) {
365 366 367
  return NewConsString()
      ->AddString(single_parse_zone(), str1)
      ->AddString(single_parse_zone(), str2);
368 369
}

370 371
template <typename IsolateT>
void AstValueFactory::Internalize(IsolateT* isolate) {
372
  // Strings need to be internalized before values, because values refer to
373
  // strings.
374 375
  for (AstRawString* current = strings_; current != nullptr;) {
    AstRawString* next = current->next();
376
    current->Internalize(isolate);
377 378 379
    current = next;
  }

380
  ResetStrings();
381
}
382
template EXPORT_TEMPLATE_DEFINE(
383 384 385
    V8_EXPORT_PRIVATE) void AstValueFactory::Internalize(Isolate* isolate);
template EXPORT_TEMPLATE_DEFINE(
    V8_EXPORT_PRIVATE) void AstValueFactory::Internalize(LocalIsolate* isolate);
386

387
const AstRawString* AstValueFactory::GetString(
388
    uint32_t raw_hash_field, bool is_one_byte,
389
    base::Vector<const byte> literal_bytes) {
390 391 392 393
  // literal_bytes here points to whatever the user passed, and this is OK
  // because we use vector_compare (which checks the contents) to compare
  // against the AstRawStrings which are in the string_table_. We should not
  // return this AstRawString.
394
  AstRawString key(is_one_byte, literal_bytes, raw_hash_field);
395 396 397 398 399
  AstRawStringMap::Entry* entry = string_table_.LookupOrInsert(
      &key, key.Hash(),
      [&]() {
        // Copy literal contents for later comparison.
        int length = literal_bytes.length();
400
        byte* new_literal_bytes = ast_raw_string_zone()->NewArray<byte>(length);
401
        memcpy(new_literal_bytes, literal_bytes.begin(), length);
402
        AstRawString* new_string = ast_raw_string_zone()->New<AstRawString>(
403
            is_one_byte, base::Vector<const byte>(new_literal_bytes, length),
404
            raw_hash_field);
405 406 407 408 409 410
        CHECK_NOT_NULL(new_string);
        AddString(new_string);
        return new_string;
      },
      [&]() { return base::NoHashMapValue(); });
  return entry->key;
411 412
}

413 414
}  // namespace internal
}  // namespace v8