diff --git a/include/v8.h b/include/v8.h index 1db14733a6..2739e070b6 100644 --- a/include/v8.h +++ b/include/v8.h @@ -5543,7 +5543,7 @@ class Internals { static const int kNullValueRootIndex = 7; static const int kTrueValueRootIndex = 8; static const int kFalseValueRootIndex = 9; - static const int kEmptyStringRootIndex = 163; + static const int kEmptyStringRootIndex = 160; // The external allocation limit should be below 256 MB on all architectures // to avoid that resource-constrained embedders run low on memory. diff --git a/src/ast-value-factory.cc b/src/ast-value-factory.cc new file mode 100644 index 0000000000..a430dcd308 --- /dev/null +++ b/src/ast-value-factory.cc @@ -0,0 +1,368 @@ +// 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-value-factory.h" + +#include "src/api.h" +#include "src/objects.h" + +namespace v8 { +namespace internal { + +namespace { + +template +int vector_hash(Vector string) { + int hash = 0; + for (int i = 0; i < string.length(); i++) { + int c = static_cast(string[i]); + hash += c; + hash += (hash << 10); + hash ^= (hash >> 6); + } + return hash; +} + + +// For using StringToArrayIndex. +class OneByteStringStream { + public: + explicit OneByteStringStream(Vector lb) : + literal_bytes_(lb), pos_(0) {} + + bool HasMore() { return pos_ < literal_bytes_.length(); } + uint16_t GetNext() { return literal_bytes_[pos_++]; } + + private: + Vector literal_bytes_; + int pos_; +}; + +} + + +bool AstString::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 AstString::IsOneByteEqualTo(const char* data) const { + int length = strlen(data); + if (is_one_byte_ && literal_bytes_.length() == length) { + const char* token = reinterpret_cast(literal_bytes_.start()); + return !strncmp(token, data, length); + } + return false; +} + + +void AstString::Internalize(Isolate* isolate) { + if (!string_.is_null()) return; + if (literal_bytes_.length() == 0) { + string_ = isolate->factory()->empty_string(); + } else if (is_one_byte_) { + string_ = isolate->factory()->InternalizeOneByteString(literal_bytes_); + } else { + string_ = isolate->factory()->InternalizeTwoByteString( + Vector::cast(literal_bytes_)); + } +} + + +bool AstString::Compare(void* a, void* b) { + AstString* string1 = reinterpret_cast(a); + AstString* string2 = reinterpret_cast(b); + if (string1->is_one_byte_ != string2->is_one_byte_) return false; + if (string1->hash_ != string2->hash_) return false; + int length = string1->literal_bytes_.length(); + if (string2->literal_bytes_.length() != length) return false; + return memcmp(string1->literal_bytes_.start(), + string2->literal_bytes_.start(), length) == 0; +} + + +bool AstValue::IsPropertyName() const { + if (type_ == STRING) { + uint32_t index; + return !string_->AsArrayIndex(&index); + } + return false; +} + + +bool AstValue::BooleanValue() const { + switch (type_) { + case STRING: + ASSERT(string_ != NULL); + return !string_->IsEmpty(); + case SYMBOL: + UNREACHABLE(); + break; + case NUMBER: + return DoubleToBoolean(number_); + case SMI: + return smi_ != 0; + case STRING_ARRAY: + UNREACHABLE(); + break; + 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: + ASSERT(string_ != NULL); + // Strings are already internalized. + ASSERT(!string_->string().is_null()); + break; + case SYMBOL: + value_ = Object::GetProperty( + isolate, handle(isolate->native_context()->builtins()), + symbol_name_).ToHandleChecked(); + break; + 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 STRING_ARRAY: { + ASSERT(strings_ != NULL); + Factory* factory = isolate->factory(); + int len = strings_->length(); + Handle elements = factory->NewFixedArray(len, TENURED); + for (int i = 0; i < len; i++) { + const AstString* string = (*strings_)[i]; + Handle element = string->string(); + // Strings are already internalized. + ASSERT(!element.is_null()); + elements->set(i, *element); + } + value_ = + factory->NewJSArrayWithElements(elements, FAST_ELEMENTS, TENURED); + 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; + } +} + + +const AstString* AstValueFactory::GetOneByteString( + Vector literal) { + return GetString(vector_hash(literal), true, literal); +} + + +const AstString* AstValueFactory::GetTwoByteString( + Vector literal) { + return GetString(vector_hash(literal), false, + Vector::cast(literal)); +} + + +const AstString* AstValueFactory::GetString(Handle literal) { + DisallowHeapAllocation no_gc; + String::FlatContent content = literal->GetFlatContent(); + if (content.IsAscii()) { + return GetOneByteString(content.ToOneByteVector()); + } + ASSERT(content.IsTwoByte()); + return GetTwoByteString(content.ToUC16Vector()); +} + + +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 (HashMap::Entry* p = string_table_.Start(); p != NULL; + p = string_table_.Next(p)) { + AstString* string = reinterpret_cast(p->key); + string->Internalize(isolate); + } + for (int i = 0; i < values_.length(); ++i) { + values_[i]->Internalize(isolate); + } + isolate_ = isolate; +} + + +const AstValue* AstValueFactory::NewString(const AstString* string) { + AstValue* value = new (zone_) AstValue(string); + ASSERT(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) { + AstValue* value = new (zone_) AstValue(number); + 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; +} + + +const AstValue* AstValueFactory::NewBoolean(bool b) { + AstValue* value = new (zone_) AstValue(b); + if (isolate_) { + value->Internalize(isolate_); + } + values_.Add(value); + return value; +} + + +const AstValue* AstValueFactory::NewStringList( + ZoneList* strings) { + AstValue* value = new (zone_) AstValue(strings); + if (isolate_) { + value->Internalize(isolate_); + } + values_.Add(value); + return value; +} + + +const AstValue* AstValueFactory::NewNull() { + AstValue* value = new (zone_) AstValue(AstValue::NULL_TYPE); + if (isolate_) { + value->Internalize(isolate_); + } + values_.Add(value); + return value; +} + + +const AstValue* AstValueFactory::NewUndefined() { + AstValue* value = new (zone_) AstValue(AstValue::UNDEFINED); + if (isolate_) { + value->Internalize(isolate_); + } + values_.Add(value); + return value; +} + + +const AstValue* AstValueFactory::NewTheHole() { + AstValue* value = new (zone_) AstValue(AstValue::THE_HOLE); + if (isolate_) { + value->Internalize(isolate_); + } + values_.Add(value); + return value; +} + + +const AstString* AstValueFactory::GetString(int hash, bool is_one_byte, + Vector 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 AstStrings which are in the string_table_. We should not return + // this AstString. + AstString key(is_one_byte, literal_bytes, hash); + HashMap::Entry* entry = string_table_.Lookup(&key, hash, true); + if (entry->value == NULL) { + // Copy literal contents for later comparison. + key.literal_bytes_ = + Vector::cast(literal_chars_.AddBlock(literal_bytes)); + // This Vector will be valid as long as the Collector is alive (meaning that + // the AstString will not be moved). + Vector new_string = string_table_keys_.AddBlock(1, key); + entry->key = &new_string[0]; + if (isolate_) { + new_string[0].Internalize(isolate_); + } + entry->value = reinterpret_cast(1); + } + return reinterpret_cast(entry->key); +} + + +} } // namespace v8::internal diff --git a/src/ast-value-factory.h b/src/ast-value-factory.h new file mode 100644 index 0000000000..8b3a7c3f18 --- /dev/null +++ b/src/ast-value-factory.h @@ -0,0 +1,294 @@ +// 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. + +#ifndef V8_AST_VALUE_FACTORY_H_ +#define V8_AST_VALUE_FACTORY_H_ + +#include "src/api.h" +#include "src/hashmap.h" +#include "src/utils.h" + +// AstString, AstValue and AstValueFactory are for storing strings and values +// independent of the V8 heap and internalizing them later. During parsing, +// AstStrings and AstValues are created and stored outside the heap, in +// AstValueFactory. After parsing, the strings and values are internalized +// (moved into the V8 heap). +namespace v8 { +namespace internal { + +class AstString { + public: + AstString(bool i, Vector lb, int h) + : is_one_byte_(i), + literal_bytes_(lb), + hash_(h) {} + + AstString() + : is_one_byte_(true), + hash_(0) {} + + bool AsArrayIndex(uint32_t* index) const; + + // The string is not null-terminated, use length() to find out the length. + const unsigned char* raw_data() const { return literal_bytes_.start(); } + int length() const { + if (is_one_byte_) + return literal_bytes_.length(); + return literal_bytes_.length() / 2; + } + bool is_one_byte() const { return is_one_byte_; } + bool IsEmpty() const { return literal_bytes_.length() == 0; } + bool IsOneByteEqualTo(const char* data) const; + uint16_t FirstCharacter() const { + if (is_one_byte_) + return literal_bytes_[0]; + const uint16_t* c = + reinterpret_cast(literal_bytes_.start()); + return *c; + } + + // Puts the string into the V8 heap. + void Internalize(Isolate* isolate); + + // This function can be called after internalizing. + V8_INLINE Handle string() const { + ASSERT(!string_.is_null()); + return string_; + } + + // For storing AstStrings in a hash map. + int hash() const { return hash_; } + static bool Compare(void* a, void* b); + + private: + friend class AstValueFactory; + + bool is_one_byte_; + // Weak. Points to memory owned by AstValueFactory. + Vector literal_bytes_; + int hash_; + + // This is null until the string is internalized. + Handle string_; +}; + + +// AstValue is either a string, a number, a string array, a boolean, or a +// special value (null, undefined, the hole). +class AstValue : public ZoneObject { + public: + bool IsString() const { + return type_ == STRING; + } + + bool IsNumber() const { + return type_ == NUMBER || type_ == SMI; + } + + const AstString* AsString() const { + if (type_ == STRING) + return string_; + UNREACHABLE(); + return 0; + } + + double AsNumber() const { + if (type_ == NUMBER) + return number_; + if (type_ == SMI) + return smi_; + UNREACHABLE(); + return 0; + } + + bool EqualsString(const AstString* string) const { + return type_ == STRING && string_ == string; + } + + bool IsPropertyName() const; + + bool BooleanValue() const; + + void Internalize(Isolate* isolate); + + // Can be called after Internalize has been called. + V8_INLINE Handle value() const { + if (type_ == STRING) { + return string_->string(); + } + ASSERT(!value_.is_null()); + return value_; + } + + private: + friend class AstValueFactory; + + enum Type { + STRING, + SYMBOL, + NUMBER, + SMI, + BOOLEAN, + STRING_ARRAY, + NULL_TYPE, + UNDEFINED, + THE_HOLE + }; + + explicit AstValue(const AstString* s) : type_(STRING) { string_ = s; } + + explicit AstValue(const char* name) : type_(SYMBOL) { symbol_name_ = name; } + + explicit AstValue(double n) : type_(NUMBER) { number_ = n; } + + AstValue(Type t, int i) : type_(t) { + ASSERT(type_ == SMI); + smi_ = i; + } + + explicit AstValue(bool b) : type_(BOOLEAN) { bool_ = b; } + + explicit AstValue(ZoneList* s) : type_(STRING_ARRAY) { + strings_ = s; + } + + explicit AstValue(Type t) : type_(t) { + ASSERT(t == NULL_TYPE || t == UNDEFINED || t == THE_HOLE); + } + + Type type_; + + // Uninternalized value. + union { + const AstString* string_; + double number_; + int smi_; + bool bool_; + ZoneList* strings_; + const char* symbol_name_; + }; + + // Internalized value (empty before internalized). + Handle value_; +}; + + +// For generating string constants. +#define STRING_CONSTANTS(F) \ + F(anonymous_function, "(anonymous function)") \ + F(arguments, "arguments") \ + F(done, "done") \ + F(dot_for, ".for") \ + F(dot_generator, ".generator") \ + F(dot_generator_object, ".generator_object") \ + F(dot_iterable, ".iterable") \ + F(dot_iterator, ".iterator") \ + F(dot_module, ".module") \ + F(dot_result, ".result") \ + F(empty, "") \ + F(eval, "eval") \ + F(initialize_const_global, "initializeConstGlobal") \ + F(initialize_var_global, "initializeVarGlobal") \ + F(make_reference_error, "MakeReferenceError") \ + F(make_syntax_error, "MakeSyntaxError") \ + F(make_type_error, "MakeTypeError") \ + F(module, "module") \ + F(native, "native") \ + F(next, "next") \ + F(proto, "__proto__") \ + F(prototype, "prototype") \ + F(this, "this") \ + F(use_strict, "use strict") \ + F(value, "value") + +class AstValueFactory { + public: + explicit AstValueFactory(Zone* zone) + : literal_chars_(0), + string_table_keys_(0), + string_table_(AstString::Compare), + zone_(zone), + isolate_(NULL) { +#define F(name, str) { \ + const char* data = str; \ + name##_string_ = GetOneByteString( \ + Vector(reinterpret_cast(data), \ + strlen(data))); \ + } + STRING_CONSTANTS(F) +#undef F + } + + const AstString* GetOneByteString(Vector literal); + const AstString* GetTwoByteString(Vector literal); + const AstString* GetString(Handle literal); + + void Internalize(Isolate* isolate); + +#define F(name, str) \ + const AstString* name##_string() const { return name##_string_; } + STRING_CONSTANTS(F) +#undef F + + const AstValue* NewString(const AstString* string); + // A JavaScript symbol (ECMA-262 edition 6). + const AstValue* NewSymbol(const char* name); + const AstValue* NewNumber(double number); + const AstValue* NewSmi(int number); + const AstValue* NewBoolean(bool b); + const AstValue* NewStringList(ZoneList* strings); + const AstValue* NewNull(); + const AstValue* NewUndefined(); + const AstValue* NewTheHole(); + + private: + const AstString* GetString(int hash, bool is_one_byte, + Vector literal_bytes); + + // All strings are copied here, one after another (no NULLs inbetween). + Collector literal_chars_; + // List of all AstStrings we have created; keys of string_table_ are pointers + // into AstStrings in string_table_keys_. + Collector string_table_keys_; + HashMap string_table_; + // For keeping track of all AstValues we've created (so that they can be + // internalized later). + List values_; + Zone* zone_; + Isolate* isolate_; + +#define F(name, str) \ + const AstString* name##_string_; + STRING_CONSTANTS(F) +#undef F +}; + +} } // namespace v8::internal + +#undef STRING_CONSTANTS + +#endif // V8_AST_VALUE_FACTORY_H_ diff --git a/src/ast.cc b/src/ast.cc index 8b1d94176f..59415c9e86 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -55,14 +55,13 @@ bool Expression::IsUndefinedLiteral(Isolate* isolate) const { // The global identifier "undefined" is immutable. Everything // else could be reassigned. return var != NULL && var->location() == Variable::UNALLOCATED && - String::Equals(var_proxy->name(), - isolate->factory()->undefined_string()); + var_proxy->raw_name()->IsOneByteEqualTo("undefined"); } VariableProxy::VariableProxy(Zone* zone, Variable* var, int position) : Expression(zone, position), - name_(var->name()), + name_(var->raw_name()), var_(NULL), // Will be set by the call to BindTo. is_this_(var->is_this()), is_trivial_(false), @@ -73,7 +72,7 @@ VariableProxy::VariableProxy(Zone* zone, Variable* var, int position) VariableProxy::VariableProxy(Zone* zone, - Handle name, + const AstString* name, bool is_this, Interface* interface, int position) @@ -84,8 +83,6 @@ VariableProxy::VariableProxy(Zone* zone, is_trivial_(false), is_lvalue_(false), interface_(interface) { - // Names must be canonicalized for fast equality checks. - ASSERT(name->IsInternalizedString()); } @@ -93,7 +90,7 @@ void VariableProxy::BindTo(Variable* var) { ASSERT(var_ == NULL); // must be bound only once ASSERT(var != NULL); // must bind ASSERT(!FLAG_harmony_modules || interface_->IsUnified(var->interface())); - ASSERT((is_this() && var->is_this()) || name_.is_identical_to(var->name())); + ASSERT((is_this() && var->is_this()) || name_ == var->raw_name()); // Ideally CONST-ness should match. However, this is very hard to achieve // because we don't know the exact semantics of conflicting (const and // non-const) multiple variable declarations, const vars introduced via @@ -180,15 +177,13 @@ void FunctionLiteral::InitializeSharedInfo( } -ObjectLiteralProperty::ObjectLiteralProperty( - Zone* zone, Literal* key, Expression* value) { +ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, + AstValueFactory* ast_value_factory, + Literal* key, Expression* value) { emit_store_ = true; key_ = key; value_ = value; - Handle k = key->value(); - if (k->IsInternalizedString() && - String::Equals(Handle::cast(k), - zone->isolate()->factory()->proto_string())) { + if (key->raw_value()->EqualsString(ast_value_factory->proto_string())) { kind_ = PROTOTYPE; } else if (value_->AsMaterializedLiteral() != NULL) { kind_ = MATERIALIZED_LITERAL; @@ -1122,9 +1117,8 @@ void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) { // optimize them. add_flag(kDontInline); } else if (node->function()->intrinsic_type == Runtime::INLINE && - (node->name()->IsOneByteEqualTo( - STATIC_ASCII_VECTOR("_ArgumentsLength")) || - node->name()->IsOneByteEqualTo(STATIC_ASCII_VECTOR("_Arguments")))) { + (node->raw_name()->IsOneByteEqualTo("_ArgumentsLength") || + node->raw_name()->IsOneByteEqualTo("_Arguments"))) { // Don't inline the %_ArgumentsLength or %_Arguments because their // implementation will not work. There is no stack frame to get them // from. @@ -1139,17 +1133,17 @@ void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) { Handle Literal::ToString() { - if (value_->IsString()) return Handle::cast(value_); + if (value_->IsString()) return value_->AsString()->string(); ASSERT(value_->IsNumber()); char arr[100]; Vector buffer(arr, ARRAY_SIZE(arr)); const char* str; - if (value_->IsSmi()) { + if (value()->IsSmi()) { // Optimization only, the heap number case would subsume this. - OS::SNPrintF(buffer, "%d", Smi::cast(*value_)->value()); + OS::SNPrintF(buffer, "%d", Smi::cast(*value())->value()); str = arr; } else { - str = DoubleToCString(value_->Number(), buffer); + str = DoubleToCString(value()->Number(), buffer); } return isolate_->factory()->NewStringFromAsciiChecked(str); } diff --git a/src/ast.h b/src/ast.h index f79c2d2b2b..196b4e77ec 100644 --- a/src/ast.h +++ b/src/ast.h @@ -8,6 +8,7 @@ #include "src/v8.h" #include "src/assembler.h" +#include "src/ast-value-factory.h" #include "src/factory.h" #include "src/feedback-slots.h" #include "src/isolate.h" @@ -367,11 +368,14 @@ class Expression : public AstNode { protected: Expression(Zone* zone, int pos) : AstNode(pos), + zone_(zone), bounds_(Bounds::Unbounded(zone)), id_(GetNextId(zone)), test_id_(GetNextId(zone)) {} void set_to_boolean_types(byte types) { to_boolean_types_ = types; } + Zone* zone_; + private: Bounds bounds_; byte to_boolean_types_; @@ -390,7 +394,7 @@ class BreakableStatement : public Statement { // The labels associated with this statement. May be NULL; // if it is != NULL, guaranteed to contain at least one entry. - ZoneStringList* labels() const { return labels_; } + ZoneList* labels() const { return labels_; } // Type testing & conversion. virtual BreakableStatement* AsBreakableStatement() V8_FINAL V8_OVERRIDE { @@ -410,7 +414,7 @@ class BreakableStatement : public Statement { protected: BreakableStatement( - Zone* zone, ZoneStringList* labels, + Zone* zone, ZoneList* labels, BreakableType breakable_type, int position) : Statement(zone, position), labels_(labels), @@ -422,7 +426,7 @@ class BreakableStatement : public Statement { private: - ZoneStringList* labels_; + ZoneList* labels_; BreakableType breakable_type_; Label break_target_; const BailoutId entry_id_; @@ -453,7 +457,7 @@ class Block V8_FINAL : public BreakableStatement { protected: Block(Zone* zone, - ZoneStringList* labels, + ZoneList* labels, int capacity, bool is_initializer_block, int pos) @@ -662,18 +666,15 @@ class ModulePath V8_FINAL : public Module { DECLARE_NODE_TYPE(ModulePath) Module* module() const { return module_; } - Handle name() const { return name_; } + Handle name() const { return name_->string(); } protected: - ModulePath(Zone* zone, Module* module, Handle name, int pos) - : Module(zone, pos), - module_(module), - name_(name) { - } + ModulePath(Zone* zone, Module* module, const AstString* name, int pos) + : Module(zone, pos), module_(module), name_(name) {} private: Module* module_; - Handle name_; + const AstString* name_; }; @@ -730,7 +731,7 @@ class IterationStatement : public BreakableStatement { Label* continue_target() { return &continue_target_; } protected: - IterationStatement(Zone* zone, ZoneStringList* labels, int pos) + IterationStatement(Zone* zone, ZoneList* labels, int pos) : BreakableStatement(zone, labels, TARGET_FOR_ANONYMOUS, pos), body_(NULL), osr_entry_id_(GetNextId(zone)) { @@ -764,7 +765,7 @@ class DoWhileStatement V8_FINAL : public IterationStatement { BailoutId BackEdgeId() const { return back_edge_id_; } protected: - DoWhileStatement(Zone* zone, ZoneStringList* labels, int pos) + DoWhileStatement(Zone* zone, ZoneList* labels, int pos) : IterationStatement(zone, labels, pos), cond_(NULL), continue_id_(GetNextId(zone)), @@ -801,7 +802,7 @@ class WhileStatement V8_FINAL : public IterationStatement { BailoutId BodyId() const { return body_id_; } protected: - WhileStatement(Zone* zone, ZoneStringList* labels, int pos) + WhileStatement(Zone* zone, ZoneList* labels, int pos) : IterationStatement(zone, labels, pos), cond_(NULL), may_have_function_literal_(true), @@ -852,7 +853,7 @@ class ForStatement V8_FINAL : public IterationStatement { void set_loop_variable(Variable* var) { loop_variable_ = var; } protected: - ForStatement(Zone* zone, ZoneStringList* labels, int pos) + ForStatement(Zone* zone, ZoneList* labels, int pos) : IterationStatement(zone, labels, pos), init_(NULL), cond_(NULL), @@ -894,11 +895,8 @@ class ForEachStatement : public IterationStatement { Expression* subject() const { return subject_; } protected: - ForEachStatement(Zone* zone, ZoneStringList* labels, int pos) - : IterationStatement(zone, labels, pos), - each_(NULL), - subject_(NULL) { - } + ForEachStatement(Zone* zone, ZoneList* labels, int pos) + : IterationStatement(zone, labels, pos), each_(NULL), subject_(NULL) {} private: Expression* each_; @@ -934,7 +932,7 @@ class ForInStatement V8_FINAL : public ForEachStatement, virtual BailoutId StackCheckId() const V8_OVERRIDE { return body_id_; } protected: - ForInStatement(Zone* zone, ZoneStringList* labels, int pos) + ForInStatement(Zone* zone, ZoneList* labels, int pos) : ForEachStatement(zone, labels, pos), for_in_type_(SLOW_FOR_IN), for_in_feedback_slot_(kInvalidFeedbackSlot), @@ -1004,7 +1002,7 @@ class ForOfStatement V8_FINAL : public ForEachStatement { BailoutId BackEdgeId() const { return back_edge_id_; } protected: - ForOfStatement(Zone* zone, ZoneStringList* labels, int pos) + ForOfStatement(Zone* zone, ZoneList* labels, int pos) : ForEachStatement(zone, labels, pos), assign_iterator_(NULL), next_result_(NULL), @@ -1165,7 +1163,7 @@ class SwitchStatement V8_FINAL : public BreakableStatement { ZoneList* cases() const { return cases_; } protected: - SwitchStatement(Zone* zone, ZoneStringList* labels, int pos) + SwitchStatement(Zone* zone, ZoneList* labels, int pos) : BreakableStatement(zone, labels, TARGET_FOR_ANONYMOUS, pos), tag_(NULL), cases_(NULL) { } @@ -1345,26 +1343,28 @@ class Literal V8_FINAL : public Expression { DECLARE_NODE_TYPE(Literal) virtual bool IsPropertyName() const V8_OVERRIDE { - if (value_->IsInternalizedString()) { - uint32_t ignored; - return !String::cast(*value_)->AsArrayIndex(&ignored); - } - return false; + return value_->IsPropertyName(); } Handle AsPropertyName() { ASSERT(IsPropertyName()); - return Handle::cast(value_); + return Handle::cast(value()); + } + + const AstString* AsRawPropertyName() { + ASSERT(IsPropertyName()); + return value_->AsString(); } virtual bool ToBooleanIsTrue() const V8_OVERRIDE { - return value_->BooleanValue(); + return value()->BooleanValue(); } virtual bool ToBooleanIsFalse() const V8_OVERRIDE { - return !value_->BooleanValue(); + return !value()->BooleanValue(); } - Handle value() const { return value_; } + Handle value() const { return value_->value(); } + const AstValue* raw_value() const { return value_; } // Support for using Literal as a HashMap key. NOTE: Currently, this works // only for string and number literals! @@ -1379,7 +1379,7 @@ class Literal V8_FINAL : public Expression { TypeFeedbackId LiteralFeedbackId() const { return reuse(id()); } protected: - Literal(Zone* zone, Handle value, int position) + Literal(Zone* zone, const AstValue* value, int position) : Expression(zone, position), value_(value), isolate_(zone->isolate()) { } @@ -1387,7 +1387,7 @@ class Literal V8_FINAL : public Expression { private: Handle ToString(); - Handle value_; + const AstValue* value_; // TODO(dcarney): remove. this is only needed for Match and Hash. Isolate* isolate_; }; @@ -1458,7 +1458,8 @@ class ObjectLiteralProperty V8_FINAL : public ZoneObject { PROTOTYPE // Property is __proto__. }; - ObjectLiteralProperty(Zone* zone, Literal* key, Expression* value); + ObjectLiteralProperty(Zone* zone, AstValueFactory* ast_value_factory, + Literal* key, Expression* value); Literal* key() { return key_; } Expression* value() { return value_; } @@ -1557,13 +1558,13 @@ class RegExpLiteral V8_FINAL : public MaterializedLiteral { public: DECLARE_NODE_TYPE(RegExpLiteral) - Handle pattern() const { return pattern_; } - Handle flags() const { return flags_; } + Handle pattern() const { return pattern_->string(); } + Handle flags() const { return flags_->string(); } protected: RegExpLiteral(Zone* zone, - Handle pattern, - Handle flags, + const AstString* pattern, + const AstString* flags, int literal_index, int pos) : MaterializedLiteral(zone, literal_index, pos), @@ -1573,8 +1574,8 @@ class RegExpLiteral V8_FINAL : public MaterializedLiteral { } private: - Handle pattern_; - Handle flags_; + const AstString* pattern_; + const AstString* flags_; }; @@ -1625,15 +1626,12 @@ class VariableProxy V8_FINAL : public Expression { return var_ == NULL ? true : var_->IsValidReference(); } - bool IsVariable(Handle n) const { - return !is_this() && name().is_identical_to(n); - } - bool IsArguments() const { return var_ != NULL && var_->is_arguments(); } bool IsLValue() const { return is_lvalue_; } - Handle name() const { return name_; } + Handle name() const { return name_->string(); } + const AstString* raw_name() const { return name_; } Variable* var() const { return var_; } bool is_this() const { return is_this_; } Interface* interface() const { return interface_; } @@ -1649,12 +1647,12 @@ class VariableProxy V8_FINAL : public Expression { VariableProxy(Zone* zone, Variable* var, int position); VariableProxy(Zone* zone, - Handle name, + const AstString* name, bool is_this, Interface* interface, int position); - Handle name_; + const AstString* name_; Variable* var_; // resolved variable, or NULL bool is_this_; bool is_trivial_; @@ -1900,7 +1898,8 @@ class CallRuntime V8_FINAL : public Expression { public: DECLARE_NODE_TYPE(CallRuntime) - Handle name() const { return name_; } + Handle name() const { return raw_name_->string(); } + const AstString* raw_name() const { return raw_name_; } const Runtime::Function* function() const { return function_; } ZoneList* arguments() const { return arguments_; } bool is_jsruntime() const { return function_ == NULL; } @@ -1909,17 +1908,17 @@ class CallRuntime V8_FINAL : public Expression { protected: CallRuntime(Zone* zone, - Handle name, + const AstString* name, const Runtime::Function* function, ZoneList* arguments, int pos) : Expression(zone, pos), - name_(name), + raw_name_(name), function_(function), arguments_(arguments) { } private: - Handle name_; + const AstString* raw_name_; const Runtime::Function* function_; ZoneList* arguments_; }; @@ -2307,7 +2306,8 @@ class FunctionLiteral V8_FINAL : public Expression { DECLARE_NODE_TYPE(FunctionLiteral) - Handle name() const { return name_; } + Handle name() const { return raw_name_->string(); } + const AstString* raw_name() const { return raw_name_; } Scope* scope() const { return scope_; } ZoneList* body() const { return body_; } void set_function_token_position(int pos) { function_token_position_ = pos; } @@ -2330,13 +2330,35 @@ class FunctionLiteral V8_FINAL : public Expression { void InitializeSharedInfo(Handle code); Handle debug_name() const { - if (name_->length() > 0) return name_; + if (raw_name_ != NULL && !raw_name_->IsEmpty()) { + return raw_name_->string(); + } return inferred_name(); } - Handle inferred_name() const { return inferred_name_; } + Handle inferred_name() const { + if (!inferred_name_.is_null()) { + ASSERT(raw_inferred_name_ == NULL); + return inferred_name_; + } + if (raw_inferred_name_ != NULL) { + return raw_inferred_name_->string(); + } + UNREACHABLE(); + return Handle(); + } + + // Only one of {set_inferred_name, set_raw_inferred_name} should be called. void set_inferred_name(Handle inferred_name) { inferred_name_ = inferred_name; + ASSERT(raw_inferred_name_== NULL || raw_inferred_name_->IsEmpty()); + raw_inferred_name_ = NULL; + } + + void set_raw_inferred_name(const AstString* raw_inferred_name) { + raw_inferred_name_ = raw_inferred_name; + ASSERT(inferred_name_.is_null()); + inferred_name_ = Handle(); } // shared_info may be null if it's not cached in full code. @@ -2383,7 +2405,8 @@ class FunctionLiteral V8_FINAL : public Expression { protected: FunctionLiteral(Zone* zone, - Handle name, + const AstString* name, + AstValueFactory* ast_value_factory, Scope* scope, ZoneList* body, int materialized_literal_count, @@ -2397,10 +2420,10 @@ class FunctionLiteral V8_FINAL : public Expression { IsGeneratorFlag is_generator, int position) : Expression(zone, position), - name_(name), + raw_name_(name), scope_(scope), body_(body), - inferred_name_(zone->isolate()->factory()->empty_string()), + raw_inferred_name_(ast_value_factory->empty_string()), dont_optimize_reason_(kNoReason), materialized_literal_count_(materialized_literal_count), expected_property_count_(expected_property_count), @@ -2418,10 +2441,12 @@ class FunctionLiteral V8_FINAL : public Expression { } private: + const AstString* raw_name_; Handle name_; Handle shared_info_; Scope* scope_; ZoneList* body_; + const AstString* raw_inferred_name_; Handle inferred_name_; AstProperties ast_properties_; BailoutReason dont_optimize_reason_; @@ -2447,16 +2472,16 @@ class NativeFunctionLiteral V8_FINAL : public Expression { public: DECLARE_NODE_TYPE(NativeFunctionLiteral) - Handle name() const { return name_; } + Handle name() const { return name_->string(); } v8::Extension* extension() const { return extension_; } protected: - NativeFunctionLiteral( - Zone* zone, Handle name, v8::Extension* extension, int pos) + NativeFunctionLiteral(Zone* zone, const AstString* name, + v8::Extension* extension, int pos) : Expression(zone, pos), name_(name), extension_(extension) {} private: - Handle name_; + const AstString* name_; v8::Extension* extension_; }; @@ -2948,7 +2973,8 @@ class AstNullVisitor BASE_EMBEDDED { template class AstNodeFactory V8_FINAL BASE_EMBEDDED { public: - explicit AstNodeFactory(Zone* zone) : zone_(zone) { } + explicit AstNodeFactory(Zone* zone, AstValueFactory* ast_value_factory) + : zone_(zone), ast_value_factory_(ast_value_factory) {} Visitor* visitor() { return &visitor_; } @@ -3012,8 +3038,8 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED { VISIT_AND_RETURN(ModuleVariable, module) } - ModulePath* NewModulePath(Module* origin, Handle name, int pos) { - ModulePath* module = new(zone_) ModulePath(zone_, origin, name, pos); + ModulePath* NewModulePath(Module* origin, const AstString* name, int pos) { + ModulePath* module = new (zone_) ModulePath(zone_, origin, name, pos); VISIT_AND_RETURN(ModulePath, module) } @@ -3022,7 +3048,7 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED { VISIT_AND_RETURN(ModuleUrl, module) } - Block* NewBlock(ZoneStringList* labels, + Block* NewBlock(ZoneList* labels, int capacity, bool is_initializer_block, int pos) { @@ -3032,7 +3058,7 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED { } #define STATEMENT_WITH_LABELS(NodeType) \ - NodeType* New##NodeType(ZoneStringList* labels, int pos) { \ + NodeType* New##NodeType(ZoneList* labels, int pos) { \ NodeType* stmt = new(zone_) NodeType(zone_, labels, pos); \ VISIT_AND_RETURN(NodeType, stmt); \ } @@ -3043,7 +3069,7 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED { #undef STATEMENT_WITH_LABELS ForEachStatement* NewForEachStatement(ForEachStatement::VisitMode visit_mode, - ZoneStringList* labels, + ZoneList* labels, int pos) { switch (visit_mode) { case ForEachStatement::ENUMERATE: { @@ -3140,14 +3166,59 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED { VISIT_AND_RETURN(CaseClause, clause) } - Literal* NewLiteral(Handle handle, int pos) { - Literal* lit = new(zone_) Literal(zone_, handle, pos); + Literal* NewStringLiteral(const AstString* string, int pos) { + Literal* lit = + new (zone_) Literal(zone_, ast_value_factory_->NewString(string), pos); + VISIT_AND_RETURN(Literal, lit) + } + + // A JavaScript symbol (ECMA-262 edition 6). + Literal* NewSymbolLiteral(const char* name, int pos) { + Literal* lit = + new (zone_) Literal(zone_, ast_value_factory_->NewSymbol(name), pos); VISIT_AND_RETURN(Literal, lit) } Literal* NewNumberLiteral(double number, int pos) { - return NewLiteral( - zone_->isolate()->factory()->NewNumber(number, TENURED), pos); + Literal* lit = new (zone_) + Literal(zone_, ast_value_factory_->NewNumber(number), pos); + VISIT_AND_RETURN(Literal, lit) + } + + Literal* NewSmiLiteral(int number, int pos) { + Literal* lit = + new (zone_) Literal(zone_, ast_value_factory_->NewSmi(number), pos); + VISIT_AND_RETURN(Literal, lit) + } + + Literal* NewBooleanLiteral(bool b, int pos) { + Literal* lit = + new (zone_) Literal(zone_, ast_value_factory_->NewBoolean(b), pos); + VISIT_AND_RETURN(Literal, lit) + } + + Literal* NewStringListLiteral(ZoneList* strings, int pos) { + Literal* lit = new (zone_) + Literal(zone_, ast_value_factory_->NewStringList(strings), pos); + VISIT_AND_RETURN(Literal, lit) + } + + Literal* NewNullLiteral(int pos) { + Literal* lit = + new (zone_) Literal(zone_, ast_value_factory_->NewNull(), pos); + VISIT_AND_RETURN(Literal, lit) + } + + Literal* NewUndefinedLiteral(int pos) { + Literal* lit = + new (zone_) Literal(zone_, ast_value_factory_->NewUndefined(), pos); + VISIT_AND_RETURN(Literal, lit) + } + + Literal* NewTheHoleLiteral(int pos) { + Literal* lit = + new (zone_) Literal(zone_, ast_value_factory_->NewTheHole(), pos); + VISIT_AND_RETURN(Literal, lit) } ObjectLiteral* NewObjectLiteral( @@ -3164,7 +3235,8 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED { ObjectLiteral::Property* NewObjectLiteralProperty(Literal* key, Expression* value) { - return new(zone_) ObjectLiteral::Property(zone_, key, value); + return new (zone_) + ObjectLiteral::Property(zone_, ast_value_factory_, key, value); } ObjectLiteral::Property* NewObjectLiteralProperty(bool is_getter, @@ -3172,12 +3244,12 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED { int pos) { ObjectLiteral::Property* prop = new(zone_) ObjectLiteral::Property(zone_, is_getter, value); - prop->set_key(NewLiteral(value->name(), pos)); + prop->set_key(NewStringLiteral(value->raw_name(), pos)); return prop; // Not an AST node, will not be visited. } - RegExpLiteral* NewRegExpLiteral(Handle pattern, - Handle flags, + RegExpLiteral* NewRegExpLiteral(const AstString* pattern, + const AstString* flags, int literal_index, int pos) { RegExpLiteral* lit = @@ -3199,7 +3271,7 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED { VISIT_AND_RETURN(VariableProxy, proxy) } - VariableProxy* NewVariableProxy(Handle name, + VariableProxy* NewVariableProxy(const AstString* name, bool is_this, Interface* interface = Interface::NewValue(), int position = RelocInfo::kNoPosition) { @@ -3227,7 +3299,7 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED { VISIT_AND_RETURN(CallNew, call) } - CallRuntime* NewCallRuntime(Handle name, + CallRuntime* NewCallRuntime(const AstString* name, const Runtime::Function* function, ZoneList* arguments, int pos) { @@ -3305,7 +3377,8 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED { } FunctionLiteral* NewFunctionLiteral( - Handle name, + const AstString* name, + AstValueFactory* ast_value_factory, Scope* scope, ZoneList* body, int materialized_literal_count, @@ -3319,7 +3392,7 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED { FunctionLiteral::IsGeneratorFlag is_generator, int position) { FunctionLiteral* lit = new(zone_) FunctionLiteral( - zone_, name, scope, body, + zone_, name, ast_value_factory, scope, body, materialized_literal_count, expected_property_count, handler_count, parameter_count, function_type, has_duplicate_parameters, is_function, is_parenthesized, is_generator, position); @@ -3331,7 +3404,8 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED { } NativeFunctionLiteral* NewNativeFunctionLiteral( - Handle name, v8::Extension* extension, int pos) { + const AstString* name, v8::Extension* extension, + int pos) { NativeFunctionLiteral* lit = new(zone_) NativeFunctionLiteral(zone_, name, extension, pos); VISIT_AND_RETURN(NativeFunctionLiteral, lit) @@ -3347,6 +3421,7 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED { private: Zone* zone_; Visitor visitor_; + AstValueFactory* ast_value_factory_; }; diff --git a/src/compiler.cc b/src/compiler.cc index 42fcc78406..cbd9be649a 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -38,7 +38,8 @@ CompilationInfo::CompilationInfo(Handle