summaryrefslogtreecommitdiff
path: root/deps/v8/src/ast/ast-value-factory.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/ast/ast-value-factory.cc')
-rw-r--r--deps/v8/src/ast/ast-value-factory.cc411
1 files changed, 411 insertions, 0 deletions
diff --git a/deps/v8/src/ast/ast-value-factory.cc b/deps/v8/src/ast/ast-value-factory.cc
new file mode 100644
index 0000000000..2e17fbcfaf
--- /dev/null
+++ b/deps/v8/src/ast/ast-value-factory.cc
@@ -0,0 +1,411 @@
+// 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.
+
+#include "src/ast/ast-value-factory.h"
+
+#include "src/api.h"
+#include "src/objects.h"
+#include "src/utils.h"
+
+namespace v8 {
+namespace internal {
+
+namespace {
+
+// For using StringToArrayIndex.
+class OneByteStringStream {
+ public:
+ explicit OneByteStringStream(Vector<const byte> lb) :
+ literal_bytes_(lb), pos_(0) {}
+
+ bool HasMore() { return pos_ < literal_bytes_.length(); }
+ uint16_t GetNext() { return literal_bytes_[pos_++]; }
+
+ private:
+ Vector<const byte> literal_bytes_;
+ int pos_;
+};
+
+} // namespace
+
+class AstRawStringInternalizationKey : public HashTableKey {
+ public:
+ explicit AstRawStringInternalizationKey(const AstRawString* string)
+ : string_(string) {}
+
+ bool IsMatch(Object* other) override {
+ if (string_->is_one_byte_)
+ return String::cast(other)->IsOneByteEqualTo(string_->literal_bytes_);
+ return String::cast(other)->IsTwoByteEqualTo(
+ Vector<const uint16_t>::cast(string_->literal_bytes_));
+ }
+
+ uint32_t Hash() override { return string_->hash() >> Name::kHashShift; }
+
+ uint32_t HashForObject(Object* key) override {
+ return String::cast(key)->Hash();
+ }
+
+ Handle<Object> AsHandle(Isolate* isolate) override {
+ if (string_->is_one_byte_)
+ return isolate->factory()->NewOneByteInternalizedString(
+ string_->literal_bytes_, string_->hash());
+ return isolate->factory()->NewTwoByteInternalizedString(
+ Vector<const uint16_t>::cast(string_->literal_bytes_), string_->hash());
+ }
+
+ private:
+ const AstRawString* string_;
+};
+
+
+void AstRawString::Internalize(Isolate* isolate) {
+ if (!string_.is_null()) return;
+ if (literal_bytes_.length() == 0) {
+ string_ = isolate->factory()->empty_string();
+ } else {
+ AstRawStringInternalizationKey key(this);
+ string_ = StringTable::LookupKey(isolate, &key);
+ }
+}
+
+
+bool AstRawString::AsArrayIndex(uint32_t* index) const {
+ if (!string_.is_null())
+ return string_->AsArrayIndex(index);
+ if (!is_one_byte_ || literal_bytes_.length() == 0 ||
+ literal_bytes_.length() > String::kMaxArrayIndexSize)
+ return false;
+ OneByteStringStream stream(literal_bytes_);
+ return StringToArrayIndex(&stream, index);
+}
+
+
+bool AstRawString::IsOneByteEqualTo(const char* data) const {
+ int length = static_cast<int>(strlen(data));
+ if (is_one_byte_ && literal_bytes_.length() == length) {
+ const char* token = reinterpret_cast<const char*>(literal_bytes_.start());
+ return !strncmp(token, data, length);
+ }
+ return false;
+}
+
+
+void AstConsString::Internalize(Isolate* isolate) {
+ // AstRawStrings are internalized before AstConsStrings so left and right are
+ // already internalized.
+ string_ = isolate->factory()
+ ->NewConsString(left_->string(), right_->string())
+ .ToHandleChecked();
+}
+
+
+bool AstValue::IsPropertyName() const {
+ if (type_ == STRING) {
+ uint32_t index;
+ return !string_->AsArrayIndex(&index);
+ }
+ return false;
+}
+
+
+bool AstValue::BooleanValue() const {
+ switch (type_) {
+ case STRING:
+ DCHECK(string_ != NULL);
+ return !string_->IsEmpty();
+ case SYMBOL:
+ UNREACHABLE();
+ break;
+ case NUMBER_WITH_DOT:
+ case NUMBER:
+ return DoubleToBoolean(number_);
+ case SMI:
+ return smi_ != 0;
+ case BOOLEAN:
+ return bool_;
+ case NULL_TYPE:
+ return false;
+ case THE_HOLE:
+ UNREACHABLE();
+ break;
+ case UNDEFINED:
+ return false;
+ }
+ UNREACHABLE();
+ return false;
+}
+
+
+void AstValue::Internalize(Isolate* isolate) {
+ switch (type_) {
+ case STRING:
+ DCHECK(string_ != NULL);
+ // Strings are already internalized.
+ DCHECK(!string_->string().is_null());
+ break;
+ case SYMBOL:
+ if (symbol_name_[0] == 'i') {
+ DCHECK_EQ(0, strcmp(symbol_name_, "iterator_symbol"));
+ value_ = isolate->factory()->iterator_symbol();
+ } else {
+ DCHECK_EQ(0, strcmp(symbol_name_, "home_object_symbol"));
+ value_ = isolate->factory()->home_object_symbol();
+ }
+ break;
+ case NUMBER_WITH_DOT:
+ case NUMBER:
+ value_ = isolate->factory()->NewNumber(number_, TENURED);
+ break;
+ case SMI:
+ value_ = handle(Smi::FromInt(smi_), isolate);
+ break;
+ case BOOLEAN:
+ if (bool_) {
+ value_ = isolate->factory()->true_value();
+ } else {
+ value_ = isolate->factory()->false_value();
+ }
+ break;
+ case NULL_TYPE:
+ value_ = isolate->factory()->null_value();
+ break;
+ case THE_HOLE:
+ value_ = isolate->factory()->the_hole_value();
+ break;
+ case UNDEFINED:
+ value_ = isolate->factory()->undefined_value();
+ break;
+ }
+}
+
+
+AstRawString* AstValueFactory::GetOneByteStringInternal(
+ Vector<const uint8_t> literal) {
+ uint32_t hash = StringHasher::HashSequentialString<uint8_t>(
+ literal.start(), literal.length(), hash_seed_);
+ return GetString(hash, true, literal);
+}
+
+
+AstRawString* AstValueFactory::GetTwoByteStringInternal(
+ Vector<const uint16_t> literal) {
+ uint32_t hash = StringHasher::HashSequentialString<uint16_t>(
+ literal.start(), literal.length(), hash_seed_);
+ return GetString(hash, false, Vector<const byte>::cast(literal));
+}
+
+
+const AstRawString* AstValueFactory::GetString(Handle<String> literal) {
+ // For the FlatContent to stay valid, we shouldn't do any heap
+ // allocation. Make sure we won't try to internalize the string in GetString.
+ AstRawString* result = NULL;
+ Isolate* saved_isolate = isolate_;
+ isolate_ = NULL;
+ {
+ DisallowHeapAllocation no_gc;
+ String::FlatContent content = literal->GetFlatContent();
+ if (content.IsOneByte()) {
+ result = GetOneByteStringInternal(content.ToOneByteVector());
+ } else {
+ DCHECK(content.IsTwoByte());
+ result = GetTwoByteStringInternal(content.ToUC16Vector());
+ }
+ }
+ isolate_ = saved_isolate;
+ if (isolate_) result->Internalize(isolate_);
+ return result;
+}
+
+
+const AstConsString* AstValueFactory::NewConsString(
+ const AstString* left, const AstString* right) {
+ // This Vector will be valid as long as the Collector is alive (meaning that
+ // the AstRawString will not be moved).
+ AstConsString* new_string = new (zone_) AstConsString(left, right);
+ strings_.Add(new_string);
+ if (isolate_) {
+ new_string->Internalize(isolate_);
+ }
+ return new_string;
+}
+
+
+void AstValueFactory::Internalize(Isolate* isolate) {
+ if (isolate_) {
+ // Everything is already internalized.
+ return;
+ }
+ // Strings need to be internalized before values, because values refer to
+ // strings.
+ for (int i = 0; i < strings_.length(); ++i) {
+ strings_[i]->Internalize(isolate);
+ }
+ for (int i = 0; i < values_.length(); ++i) {
+ values_[i]->Internalize(isolate);
+ }
+ isolate_ = isolate;
+}
+
+
+const AstValue* AstValueFactory::NewString(const AstRawString* string) {
+ AstValue* value = new (zone_) AstValue(string);
+ DCHECK(string != NULL);
+ if (isolate_) {
+ value->Internalize(isolate_);
+ }
+ values_.Add(value);
+ return value;
+}
+
+
+const AstValue* AstValueFactory::NewSymbol(const char* name) {
+ AstValue* value = new (zone_) AstValue(name);
+ if (isolate_) {
+ value->Internalize(isolate_);
+ }
+ values_.Add(value);
+ return value;
+}
+
+
+const AstValue* AstValueFactory::NewNumber(double number, bool with_dot) {
+ AstValue* value = new (zone_) AstValue(number, with_dot);
+ if (isolate_) {
+ value->Internalize(isolate_);
+ }
+ values_.Add(value);
+ return value;
+}
+
+
+const AstValue* AstValueFactory::NewSmi(int number) {
+ AstValue* value =
+ new (zone_) AstValue(AstValue::SMI, number);
+ if (isolate_) {
+ value->Internalize(isolate_);
+ }
+ values_.Add(value);
+ return value;
+}
+
+
+#define GENERATE_VALUE_GETTER(value, initializer) \
+ if (!value) { \
+ value = new (zone_) AstValue(initializer); \
+ if (isolate_) { \
+ value->Internalize(isolate_); \
+ } \
+ values_.Add(value); \
+ } \
+ return value;
+
+
+const AstValue* AstValueFactory::NewBoolean(bool b) {
+ if (b) {
+ GENERATE_VALUE_GETTER(true_value_, true);
+ } else {
+ GENERATE_VALUE_GETTER(false_value_, false);
+ }
+}
+
+
+const AstValue* AstValueFactory::NewNull() {
+ GENERATE_VALUE_GETTER(null_value_, AstValue::NULL_TYPE);
+}
+
+
+const AstValue* AstValueFactory::NewUndefined() {
+ GENERATE_VALUE_GETTER(undefined_value_, AstValue::UNDEFINED);
+}
+
+
+const AstValue* AstValueFactory::NewTheHole() {
+ GENERATE_VALUE_GETTER(the_hole_value_, AstValue::THE_HOLE);
+}
+
+
+#undef GENERATE_VALUE_GETTER
+
+AstRawString* AstValueFactory::GetString(uint32_t hash, bool is_one_byte,
+ Vector<const byte> literal_bytes) {
+ // 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.
+ AstRawString key(is_one_byte, literal_bytes, hash);
+ HashMap::Entry* entry = string_table_.LookupOrInsert(&key, hash);
+ if (entry->value == NULL) {
+ // Copy literal contents for later comparison.
+ int length = literal_bytes.length();
+ byte* new_literal_bytes = zone_->NewArray<byte>(length);
+ memcpy(new_literal_bytes, literal_bytes.start(), length);
+ AstRawString* new_string = new (zone_) AstRawString(
+ is_one_byte, Vector<const byte>(new_literal_bytes, length), hash);
+ entry->key = new_string;
+ strings_.Add(new_string);
+ if (isolate_) {
+ new_string->Internalize(isolate_);
+ }
+ entry->value = reinterpret_cast<void*>(1);
+ }
+ return reinterpret_cast<AstRawString*>(entry->key);
+}
+
+
+bool AstValueFactory::AstRawStringCompare(void* a, void* b) {
+ const AstRawString* lhs = static_cast<AstRawString*>(a);
+ const AstRawString* rhs = static_cast<AstRawString*>(b);
+ if (lhs->length() != rhs->length()) return false;
+ if (lhs->hash() != rhs->hash()) return false;
+ 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()) {
+ return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l),
+ reinterpret_cast<const uint8_t*>(r),
+ length) == 0;
+ } else {
+ return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l),
+ reinterpret_cast<const uint16_t*>(r),
+ length) == 0;
+ }
+ } else {
+ if (rhs->is_one_byte()) {
+ return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l),
+ reinterpret_cast<const uint8_t*>(r),
+ length) == 0;
+ } else {
+ return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l),
+ reinterpret_cast<const uint16_t*>(r),
+ length) == 0;
+ }
+ }
+}
+} // namespace internal
+} // namespace v8