Commit 317cf321 authored by Adam Klein's avatar Adam Klein Committed by Commit Bot

[ast] Move AstValue implementation into Literal

This eliminates the AstValue class, effectively moving its
implementation into the Literal AstNode. This should cause
no difference in behavior, but it does signal some shifts
in the underlying system. Biggest changes include:

  - Reduction in AST memory usage
  - No duplicate HeapNumbers in Ignition constant pools
  - Non-String values are allocated either at constant pool
    creation time (or at boilerplate creation time for literals),
    rather than at AstValueFactory::Internalize() time.

There are a variety of test-only/debug-only changes due to these
switches as well.

Bug: v8:6984
Change-Id: I5f178040ce2796d4e7370c24d1063419e1c843a1
Reviewed-on: https://chromium-review.googlesource.com/731111
Commit-Queue: Adam Klein <adamk@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49013}
parent 419924a2
...@@ -168,107 +168,6 @@ void AstConsString::Internalize(Isolate* isolate) { ...@@ -168,107 +168,6 @@ void AstConsString::Internalize(Isolate* isolate) {
set_string(tmp); set_string(tmp);
} }
AstValue::AstValue(double n) : next_(nullptr) {
int int_value;
if (DoubleToSmiInteger(n, &int_value)) {
type_ = SMI;
smi_ = int_value;
} else {
type_ = NUMBER;
number_ = n;
}
}
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_NOT_NULL(string_);
return !string_->IsEmpty();
case SYMBOL:
UNREACHABLE();
break;
case NUMBER:
return DoubleToBoolean(number_);
case SMI:
return smi_ != 0;
case BIGINT: {
size_t length = strlen(bigint_buffer_);
DCHECK_GT(length, 0);
if (length == 1 && bigint_buffer_[0] == '0') return false;
// Skip over any radix prefix; BigInts with length > 1 only
// begin with zero if they include a radix.
for (size_t i = (bigint_buffer_[0] == '0') ? 2 : 0; i < length; ++i) {
if (bigint_buffer_[i] != '0') return true;
}
return false;
}
case BOOLEAN:
return bool_;
case NULL_TYPE:
return false;
case THE_HOLE:
UNREACHABLE();
break;
case UNDEFINED:
return false;
}
UNREACHABLE();
}
void AstValue::Internalize(Isolate* isolate) {
switch (type_) {
case STRING:
DCHECK_NOT_NULL(string_);
// Strings are already internalized.
DCHECK(!string_->string().is_null());
break;
case SYMBOL:
switch (symbol_) {
case AstSymbol::kHomeObjectSymbol:
set_value(isolate->factory()->home_object_symbol());
break;
}
break;
case NUMBER:
set_value(isolate->factory()->NewNumber(number_, TENURED));
break;
case SMI:
set_value(handle(Smi::FromInt(smi_), isolate));
break;
case BIGINT:
// TODO(adamk): Don't check-fail on conversion failure; instead
// check for errors during parsing and throw at that point.
set_value(BigIntLiteral(isolate, bigint_buffer_).ToHandleChecked());
break;
case BOOLEAN:
if (bool_) {
set_value(isolate->factory()->true_value());
} else {
set_value(isolate->factory()->false_value());
}
break;
case NULL_TYPE:
set_value(isolate->factory()->null_value());
break;
case THE_HOLE:
set_value(isolate->factory()->the_hole_value());
break;
case UNDEFINED:
set_value(isolate->factory()->undefined_value());
break;
}
}
AstStringConstants::AstStringConstants(Isolate* isolate, uint32_t hash_seed) AstStringConstants::AstStringConstants(Isolate* isolate, uint32_t hash_seed)
: zone_(isolate->allocator(), ZONE_NAME), : zone_(isolate->allocator(), ZONE_NAME),
string_table_(AstRawString::Compare), string_table_(AstRawString::Compare),
...@@ -364,77 +263,9 @@ void AstValueFactory::Internalize(Isolate* isolate) { ...@@ -364,77 +263,9 @@ void AstValueFactory::Internalize(Isolate* isolate) {
current = next; current = next;
} }
for (AstValue* current = values_; current != nullptr;) {
AstValue* next = current->next();
current->Internalize(isolate);
current = next;
}
ResetStrings(); ResetStrings();
values_ = nullptr;
}
const AstValue* AstValueFactory::NewString(const AstRawString* string) {
AstValue* value = new (zone_) AstValue(string);
CHECK_NOT_NULL(string);
return AddValue(value);
}
const AstValue* AstValueFactory::NewSymbol(AstSymbol symbol) {
AstValue* value = new (zone_) AstValue(symbol);
return AddValue(value);
}
const AstValue* AstValueFactory::NewNumber(double number) {
AstValue* value = new (zone_) AstValue(number);
return AddValue(value);
}
const AstValue* AstValueFactory::NewSmi(uint32_t number) {
bool cacheable_smi = number <= kMaxCachedSmi;
if (cacheable_smi && smis_[number] != nullptr) return smis_[number];
AstValue* value = new (zone_) AstValue(AstValue::SMI, number);
if (cacheable_smi) smis_[number] = value;
return AddValue(value);
} }
const AstValue* AstValueFactory::NewBigInt(const char* number) {
AstValue* value = new (zone_) AstValue(number);
return AddValue(value);
}
#define GENERATE_VALUE_GETTER(value, initializer) \
if (!value) { \
value = AddValue(new (zone_) AstValue(initializer)); \
} \
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_field, bool is_one_byte, AstRawString* AstValueFactory::GetString(uint32_t hash_field, bool is_one_byte,
Vector<const byte> literal_bytes) { Vector<const byte> literal_bytes) {
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
#include "src/isolate.h" #include "src/isolate.h"
#include "src/utils.h" #include "src/utils.h"
// Ast(Raw|Cons)String, AstValue and AstValueFactory are for storing strings and // Ast(Raw|Cons)String and AstValueFactory are for storing strings and
// values independent of the V8 heap and internalizing them later. During // values independent of the V8 heap and internalizing them later. During
// parsing, they are created and stored outside the heap, in AstValueFactory. // parsing, they are created and stored outside the heap, in AstValueFactory.
// After parsing, the strings and values are internalized (moved into the V8 // After parsing, the strings and values are internalized (moved into the V8
...@@ -176,124 +176,17 @@ class AstConsString final : public ZoneObject { ...@@ -176,124 +176,17 @@ class AstConsString final : public ZoneObject {
enum class AstSymbol : uint8_t { kHomeObjectSymbol }; enum class AstSymbol : uint8_t { kHomeObjectSymbol };
// AstValue is either a string, a symbol, a number, a string array, a boolean, class AstBigInt {
// or a special value (null, undefined, the hole).
class AstValue : public ZoneObject {
public: public:
bool IsString() const { // |bigint| must be a NUL-terminated string of ASCII characters
return type_ == STRING; // representing a BigInt (suitable for passing to BigIntLiteral()
} // from conversions.h).
explicit AstBigInt(const char* bigint) : bigint_(bigint) {}
bool IsSymbol() const { return type_ == SYMBOL; }
bool IsNumber() const { return IsSmi() || IsHeapNumber(); }
const AstRawString* AsString() const {
CHECK_EQ(STRING, type_);
return string_;
}
AstSymbol AsSymbol() const {
CHECK_EQ(SYMBOL, type_);
return symbol_;
}
double AsNumber() const {
if (IsHeapNumber()) return number_;
if (IsSmi()) return smi_;
UNREACHABLE();
}
Smi* AsSmi() const {
CHECK(IsSmi());
return Smi::FromInt(smi_);
}
bool IsPropertyName() const;
V8_EXPORT_PRIVATE bool BooleanValue() const; const char* c_str() const { return bigint_; }
bool IsSmi() const { return type_ == SMI; }
bool IsHeapNumber() const { return type_ == NUMBER; }
bool IsBigInt() const { return type_ == BIGINT; }
bool IsFalse() const { return type_ == BOOLEAN && !bool_; }
bool IsTrue() const { return type_ == BOOLEAN && bool_; }
bool IsUndefined() const { return type_ == UNDEFINED; }
bool IsTheHole() const { return type_ == THE_HOLE; }
bool IsNull() const { return type_ == NULL_TYPE; }
void Internalize(Isolate* isolate);
// Can be called after Internalize has been called.
V8_INLINE Handle<Object> value() const {
if (type_ == STRING) {
return string_->string();
}
DCHECK_NOT_NULL(value_);
return Handle<Object>(value_);
}
AstValue* next() const { return next_; }
void set_next(AstValue* next) { next_ = next; }
private: private:
void set_value(Handle<Object> object) { value_ = object.location(); } const char* bigint_;
friend class AstValueFactory;
enum Type {
STRING,
SYMBOL,
NUMBER,
SMI,
BIGINT,
BOOLEAN,
NULL_TYPE,
UNDEFINED,
THE_HOLE
};
explicit AstValue(const AstRawString* s) : type_(STRING), next_(nullptr) {
string_ = s;
}
explicit AstValue(AstSymbol symbol) : type_(SYMBOL), next_(nullptr) {
symbol_ = symbol;
}
explicit AstValue(double n);
AstValue(Type t, int i) : type_(t), next_(nullptr) {
DCHECK(type_ == SMI);
smi_ = i;
}
explicit AstValue(const char* n) : type_(BIGINT), next_(nullptr) {
bigint_buffer_ = n;
}
explicit AstValue(bool b) : type_(BOOLEAN), next_(nullptr) { bool_ = b; }
explicit AstValue(Type t) : type_(t), next_(nullptr) {
DCHECK(t == NULL_TYPE || t == UNDEFINED || t == THE_HOLE);
}
Type type_;
// {value_} is stored as Object** instead of a Handle<Object> so it can be
// stored in a union with {next_}.
union {
Object** value_; // if internalized
AstValue* next_; // if !internalized
};
// Uninternalized value.
union {
const AstRawString* string_;
double number_;
int smi_;
bool bool_;
AstSymbol symbol_;
const char* bigint_buffer_;
};
}; };
// For generating constants. // For generating constants.
...@@ -371,7 +264,6 @@ class AstValueFactory { ...@@ -371,7 +264,6 @@ class AstValueFactory {
AstValueFactory(Zone* zone, const AstStringConstants* string_constants, AstValueFactory(Zone* zone, const AstStringConstants* string_constants,
uint32_t hash_seed) uint32_t hash_seed)
: string_table_(string_constants->string_table()), : string_table_(string_constants->string_table()),
values_(nullptr),
strings_(nullptr), strings_(nullptr),
strings_end_(&strings_), strings_end_(&strings_),
cons_strings_(nullptr), cons_strings_(nullptr),
...@@ -381,7 +273,6 @@ class AstValueFactory { ...@@ -381,7 +273,6 @@ class AstValueFactory {
zone_(zone), zone_(zone),
hash_seed_(hash_seed) { hash_seed_(hash_seed) {
DCHECK_EQ(hash_seed, string_constants->hash_seed()); DCHECK_EQ(hash_seed, string_constants->hash_seed());
std::fill(smis_, smis_ + arraysize(smis_), nullptr);
std::fill(one_character_strings_, std::fill(one_character_strings_,
one_character_strings_ + arraysize(one_character_strings_), one_character_strings_ + arraysize(one_character_strings_),
nullptr); nullptr);
...@@ -416,27 +307,7 @@ class AstValueFactory { ...@@ -416,27 +307,7 @@ class AstValueFactory {
#undef F #undef F
const AstConsString* empty_cons_string() const { return empty_cons_string_; } const AstConsString* empty_cons_string() const { return empty_cons_string_; }
V8_EXPORT_PRIVATE const AstValue* NewString(const AstRawString* string);
// A JavaScript symbol (ECMA-262 edition 6).
const AstValue* NewSymbol(AstSymbol symbol);
V8_EXPORT_PRIVATE const AstValue* NewNumber(double number);
const AstValue* NewSmi(uint32_t number);
V8_EXPORT_PRIVATE const AstValue* NewBigInt(const char* number);
const AstValue* NewBoolean(bool b);
const AstValue* NewNull();
const AstValue* NewUndefined();
const AstValue* NewTheHole();
private: private:
static const uint32_t kMaxCachedSmi = 1 << 10;
STATIC_ASSERT(kMaxCachedSmi <= Smi::kMaxValue);
AstValue* AddValue(AstValue* value) {
value->set_next(values_);
values_ = value;
return value;
}
AstRawString* AddString(AstRawString* string) { AstRawString* AddString(AstRawString* string) {
*strings_end_ = string; *strings_end_ = string;
strings_end_ = string->next_location(); strings_end_ = string->next_location();
...@@ -461,9 +332,6 @@ class AstValueFactory { ...@@ -461,9 +332,6 @@ class AstValueFactory {
// All strings are copied here, one after another (no zeroes inbetween). // All strings are copied here, one after another (no zeroes inbetween).
base::CustomMatcherHashMap string_table_; base::CustomMatcherHashMap string_table_;
// For keeping track of all AstValues and AstRawStrings we've created (so that
// they can be internalized later).
AstValue* values_;
// We need to keep track of strings_ in order since cons strings require their // We need to keep track of strings_ in order since cons strings require their
// members to be internalized first. // members to be internalized first.
...@@ -476,20 +344,12 @@ class AstValueFactory { ...@@ -476,20 +344,12 @@ class AstValueFactory {
const AstStringConstants* string_constants_; const AstStringConstants* string_constants_;
const AstConsString* empty_cons_string_; const AstConsString* empty_cons_string_;
// Caches for faster access: small numbers, one character lowercase strings // Caches one character lowercase strings (for minified code).
// (for minified code).
AstValue* smis_[kMaxCachedSmi + 1];
AstRawString* one_character_strings_[26]; AstRawString* one_character_strings_[26];
Zone* zone_; Zone* zone_;
uint32_t hash_seed_; uint32_t hash_seed_;
AstValue* true_value_ = nullptr;
AstValue* false_value_ = nullptr;
AstValue* null_value_ = nullptr;
AstValue* undefined_value_ = nullptr;
AstValue* the_hole_value_ = nullptr;
}; };
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include "src/builtins/builtins.h" #include "src/builtins/builtins.h"
#include "src/code-stubs.h" #include "src/code-stubs.h"
#include "src/contexts.h" #include "src/contexts.h"
#include "src/conversions.h" #include "src/conversions-inl.h"
#include "src/double.h" #include "src/double.h"
#include "src/elements.h" #include "src/elements.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
...@@ -421,11 +421,11 @@ void ObjectLiteral::BuildConstantProperties(Isolate* isolate) { ...@@ -421,11 +421,11 @@ void ObjectLiteral::BuildConstantProperties(Isolate* isolate) {
continue; continue;
} }
Handle<Object> key = property->key()->AsLiteral()->value(); Literal* key = property->key()->AsLiteral();
uint32_t element_index = 0; uint32_t element_index = 0;
if (key->ToArrayIndex(&element_index) || if (key->ToArrayIndex(&element_index) ||
(key->IsString() && String::cast(*key)->AsArrayIndex(&element_index))) { (key->IsString() && key->AsRawString()->AsArrayIndex(&element_index))) {
index_keys++; index_keys++;
} }
} }
...@@ -454,7 +454,7 @@ void ObjectLiteral::BuildConstantProperties(Isolate* isolate) { ...@@ -454,7 +454,7 @@ void ObjectLiteral::BuildConstantProperties(Isolate* isolate) {
// Add CONSTANT and COMPUTED properties to boilerplate. Use undefined // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
// value for COMPUTED properties, the real value is filled in at // value for COMPUTED properties, the real value is filled in at
// runtime. The enumeration order is maintained. // runtime. The enumeration order is maintained.
Handle<Object> key = property->key()->AsLiteral()->value(); Handle<Object> key = property->key()->AsLiteral()->BuildValue(isolate);
Handle<Object> value = GetBoilerplateValue(property->value(), isolate); Handle<Object> value = GetBoilerplateValue(property->value(), isolate);
uint32_t element_index = 0; uint32_t element_index = 0;
...@@ -603,7 +603,7 @@ bool MaterializedLiteral::IsSimple() const { ...@@ -603,7 +603,7 @@ bool MaterializedLiteral::IsSimple() const {
Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression, Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression,
Isolate* isolate) { Isolate* isolate) {
if (expression->IsLiteral()) { if (expression->IsLiteral()) {
return expression->AsLiteral()->value(); return expression->AsLiteral()->BuildValue(isolate);
} }
if (CompileTimeValue::IsCompileTimeValue(expression)) { if (CompileTimeValue::IsCompileTimeValue(expression)) {
return CompileTimeValue::GetValue(isolate, expression); return CompileTimeValue::GetValue(isolate, expression);
...@@ -792,23 +792,90 @@ Call::CallType Call::GetCallType() const { ...@@ -792,23 +792,90 @@ Call::CallType Call::GetCallType() const {
CaseClause::CaseClause(Expression* label, ZoneList<Statement*>* statements) CaseClause::CaseClause(Expression* label, ZoneList<Statement*>* statements)
: label_(label), statements_(statements) {} : label_(label), statements_(statements) {}
bool Literal::IsPropertyName() const {
if (type() != kString) return false;
uint32_t index;
return !string_->AsArrayIndex(&index);
}
bool Literal::ToUint32(uint32_t* value) const { bool Literal::ToUint32(uint32_t* value) const {
if (IsSmi()) { switch (type()) {
int num = AsSmiLiteral()->value(); case kSmi:
if (num < 0) return false; if (smi_ < 0) return false;
*value = static_cast<uint32_t>(num); *value = static_cast<uint32_t>(smi_);
return true; return true;
} case kHeapNumber:
if (IsNumber()) { return DoubleToUint32IfEqualToSelf(AsNumber(), value);
return DoubleToUint32IfEqualToSelf(AsNumber(), value); default:
return false;
} }
return false;
} }
bool Literal::ToArrayIndex(uint32_t* value) const { bool Literal::ToArrayIndex(uint32_t* value) const {
return ToUint32(value) && *value != kMaxUInt32; return ToUint32(value) && *value != kMaxUInt32;
} }
Handle<Object> Literal::BuildValue(Isolate* isolate) const {
switch (type()) {
case kSmi:
return handle(Smi::FromInt(smi_), isolate);
case kHeapNumber:
return isolate->factory()->NewNumber(number_);
case kString:
return string_->string();
case kSymbol:
return isolate->factory()->home_object_symbol();
case kTrue:
return isolate->factory()->true_value();
case kFalse:
return isolate->factory()->false_value();
case kNull:
return isolate->factory()->null_value();
case kUndefined:
return isolate->factory()->undefined_value();
case kTheHole:
return isolate->factory()->the_hole_value();
case kBigInt:
return BigIntLiteral(isolate, bigint_.c_str()).ToHandleChecked();
}
UNREACHABLE();
}
bool Literal::ToBooleanIsTrue() const {
switch (type()) {
case kSmi:
return smi_ != 0;
case kHeapNumber:
return DoubleToBoolean(number_);
case kString:
return !string_->IsEmpty();
case kNull:
case kUndefined:
return false;
case kTrue:
return true;
case kFalse:
return false;
case kBigInt: {
const char* bigint_str = bigint_.c_str();
size_t length = strlen(bigint_str);
DCHECK_GT(length, 0);
if (length == 1 && bigint_str[0] == '0') return false;
// Skip over any radix prefix; BigInts with length > 1 only
// begin with zero if they include a radix.
for (size_t i = (bigint_str[0] == '0') ? 2 : 0; i < length; ++i) {
if (bigint_str[i] != '0') return true;
}
return false;
}
case kSymbol:
return true;
case kTheHole:
UNREACHABLE();
}
UNREACHABLE();
}
uint32_t Literal::Hash() { uint32_t Literal::Hash() {
return IsString() ? AsRawString()->Hash() return IsString() ? AsRawString()->Hash()
: ComputeLongHash(double_to_uint64(AsNumber())); : ComputeLongHash(double_to_uint64(AsNumber()));
...@@ -816,13 +883,22 @@ uint32_t Literal::Hash() { ...@@ -816,13 +883,22 @@ uint32_t Literal::Hash() {
// static // static
bool Literal::Match(void* literal1, void* literal2) { bool Literal::Match(void* a, void* b) {
const AstValue* x = static_cast<Literal*>(literal1)->value_; Literal* x = static_cast<Literal*>(a);
const AstValue* y = static_cast<Literal*>(literal2)->value_; Literal* y = static_cast<Literal*>(b);
return (x->IsString() && y->IsString() && x->AsString() == y->AsString()) || return (x->IsString() && y->IsString() &&
x->AsRawString() == y->AsRawString()) ||
(x->IsNumber() && y->IsNumber() && x->AsNumber() == y->AsNumber()); (x->IsNumber() && y->IsNumber() && x->AsNumber() == y->AsNumber());
} }
Literal* AstNodeFactory::NewNumberLiteral(double number, int pos) {
int int_value;
if (DoubleToSmiInteger(number, &int_value)) {
return NewSmiLiteral(int_value, pos);
}
return new (zone_) Literal(number, pos);
}
const char* CallRuntime::debug_name() { const char* CallRuntime::debug_name() {
#ifdef DEBUG #ifdef DEBUG
return is_jsruntime() ? NameForNativeContextIntrinsicIndex(context_index_) return is_jsruntime() ? NameForNativeContextIntrinsicIndex(context_index_)
......
...@@ -989,46 +989,65 @@ class Literal final : public Expression { ...@@ -989,46 +989,65 @@ class Literal final : public Expression {
public: public:
// Returns true if literal represents a property name (i.e. cannot be parsed // Returns true if literal represents a property name (i.e. cannot be parsed
// as array indices). // as array indices).
bool IsPropertyName() const { return value_->IsPropertyName(); } bool IsPropertyName() const;
const AstRawString* AsRawPropertyName() { const AstRawString* AsRawPropertyName() {
DCHECK(IsPropertyName()); DCHECK(IsPropertyName());
return value_->AsString(); return string_;
} }
bool IsSmi() const { return value_->IsSmi(); } bool IsSmi() const { return type() == kSmi; }
Smi* AsSmiLiteral() const { Smi* AsSmiLiteral() const {
DCHECK(IsSmi()); DCHECK_EQ(kSmi, type());
return value_->AsSmi(); return Smi::FromInt(smi_);
} }
bool IsNumber() const { return value_->IsNumber(); } bool IsNumber() const { return type() == kHeapNumber || type() == kSmi; }
double AsNumber() const { double AsNumber() const {
DCHECK(IsNumber()); DCHECK(IsNumber());
return value_->AsNumber(); switch (type()) {
case kSmi:
return smi_;
case kHeapNumber:
return number_;
default:
UNREACHABLE();
}
} }
bool IsString() const { return value_->IsString(); } bool IsBigInt() const { return type() == kBigInt; }
AstBigInt AsBigInt() const {
DCHECK(IsBigInt());
return bigint_;
}
bool IsString() const { return type() == kString; }
const AstRawString* AsRawString() { const AstRawString* AsRawString() {
DCHECK(IsString()); DCHECK(IsString());
return value_->AsString(); return string_;
}
bool IsSymbol() const { return type() == kSymbol; }
AstSymbol AsSymbol() {
DCHECK(IsSymbol());
return symbol_;
} }
bool IsNull() const { return value_->IsNull(); } bool IsNull() const { return type() == kNull; }
bool IsUndefined() const { return value_->IsUndefined(); } bool IsUndefined() const { return type() == kUndefined; }
bool IsTheHole() const { return value_->IsTheHole(); } bool IsTheHole() const { return type() == kTheHole; }
bool IsTrue() const { return value_->IsTrue(); } bool IsTrue() const { return type() == kTrue; }
bool IsFalse() const { return value_->IsFalse(); } bool IsFalse() const { return type() == kFalse; }
bool ToBooleanIsTrue() const { return value_->BooleanValue(); } V8_EXPORT_PRIVATE bool ToBooleanIsTrue() const;
bool ToBooleanIsFalse() const { return !value_->BooleanValue(); } bool ToBooleanIsFalse() const { return !ToBooleanIsTrue(); }
bool ToUint32(uint32_t* value) const; bool ToUint32(uint32_t* value) const;
bool ToArrayIndex(uint32_t* value) const; bool ToArrayIndex(uint32_t* value) const;
Handle<Object> value() const { return value_->value(); } // Returns an appropriate Object representing this Literal, allocating
const AstValue* raw_value() const { return value_; } // a heap object if needed.
Handle<Object> BuildValue(Isolate* isolate) const;
// Support for using Literal as a HashMap key. NOTE: Currently, this works // Support for using Literal as a HashMap key. NOTE: Currently, this works
// only for string and number literals! // only for string and number literals!
...@@ -1038,10 +1057,60 @@ class Literal final : public Expression { ...@@ -1038,10 +1057,60 @@ class Literal final : public Expression {
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
Literal(const AstValue* value, int position) enum Type {
: Expression(position, kLiteral), value_(value) {} kSmi,
kHeapNumber,
kBigInt,
kString,
kSymbol,
kUndefined,
kNull,
kTheHole,
kTrue,
kFalse
};
class TypeField : public BitField<Type, Expression::kNextBitFieldIndex, 4> {};
Type type() const { return TypeField::decode(bit_field_); }
Literal(int smi, int position) : Expression(position, kLiteral), smi_(smi) {
bit_field_ = TypeField::update(bit_field_, kSmi);
}
Literal(double number, int position)
: Expression(position, kLiteral), number_(number) {
bit_field_ = TypeField::update(bit_field_, kHeapNumber);
}
Literal(AstBigInt bigint, int position)
: Expression(position, kLiteral), bigint_(bigint) {
bit_field_ = TypeField::update(bit_field_, kBigInt);
}
Literal(const AstRawString* string, int position)
: Expression(position, kLiteral), string_(string) {
bit_field_ = TypeField::update(bit_field_, kString);
}
Literal(AstSymbol symbol, int position)
: Expression(position, kLiteral), symbol_(symbol) {
bit_field_ = TypeField::update(bit_field_, kSymbol);
}
const AstValue* value_; Literal(Type type, int position) : Expression(position, kLiteral) {
DCHECK(type == kNull || type == kUndefined || type == kTheHole ||
type == kTrue || type == kFalse);
bit_field_ = TypeField::update(bit_field_, type);
}
union {
const AstRawString* string_;
int smi_;
double number_;
AstSymbol symbol_;
AstBigInt bigint_;
};
}; };
// Base class for literals that need space in the type feedback vector. // Base class for literals that need space in the type feedback vector.
...@@ -2943,41 +3012,41 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -2943,41 +3012,41 @@ class AstNodeFactory final BASE_EMBEDDED {
} }
Literal* NewStringLiteral(const AstRawString* string, int pos) { Literal* NewStringLiteral(const AstRawString* string, int pos) {
return new (zone_) Literal(ast_value_factory_->NewString(string), pos); return new (zone_) Literal(string, pos);
} }
// A JavaScript symbol (ECMA-262 edition 6). // A JavaScript symbol (ECMA-262 edition 6).
Literal* NewSymbolLiteral(AstSymbol symbol, int pos) { Literal* NewSymbolLiteral(AstSymbol symbol, int pos) {
return new (zone_) Literal(ast_value_factory_->NewSymbol(symbol), pos); return new (zone_) Literal(symbol, pos);
} }
Literal* NewNumberLiteral(double number, int pos) { Literal* NewNumberLiteral(double number, int pos);
return new (zone_) Literal(ast_value_factory_->NewNumber(number), pos);
}
Literal* NewSmiLiteral(uint32_t number, int pos) { Literal* NewSmiLiteral(int number, int pos) {
return new (zone_) Literal(ast_value_factory_->NewSmi(number), pos); return new (zone_) Literal(number, pos);
} }
Literal* NewBigIntLiteral(const char* buffer, int pos) { Literal* NewBigIntLiteral(AstBigInt bigint, int pos) {
return new (zone_) Literal(ast_value_factory_->NewBigInt(buffer), pos); return new (zone_) Literal(bigint, pos);
} }
Literal* NewBooleanLiteral(bool b, int pos) { Literal* NewBooleanLiteral(bool b, int pos) {
return new (zone_) Literal(ast_value_factory_->NewBoolean(b), pos); if (b) {
return new (zone_) Literal(Literal::kTrue, pos);
}
return new (zone_) Literal(Literal::kFalse, pos);
} }
Literal* NewNullLiteral(int pos) { Literal* NewNullLiteral(int pos) {
return new (zone_) Literal(ast_value_factory_->NewNull(), pos); return new (zone_) Literal(Literal::kNull, pos);
} }
Literal* NewUndefinedLiteral(int pos) { Literal* NewUndefinedLiteral(int pos) {
return new (zone_) Literal(ast_value_factory_->NewUndefined(), pos); return new (zone_) Literal(Literal::kUndefined, pos);
} }
Literal* NewTheHoleLiteral() { Literal* NewTheHoleLiteral() {
return new (zone_) return new (zone_) Literal(Literal::kTheHole, kNoSourcePosition);
Literal(ast_value_factory_->NewTheHole(), kNoSourcePosition);
} }
ObjectLiteral* NewObjectLiteral( ObjectLiteral* NewObjectLiteral(
......
...@@ -219,7 +219,9 @@ void CallPrinter::VisitConditional(Conditional* node) { ...@@ -219,7 +219,9 @@ void CallPrinter::VisitConditional(Conditional* node) {
void CallPrinter::VisitLiteral(Literal* node) { void CallPrinter::VisitLiteral(Literal* node) {
PrintLiteral(node->value(), true); // TODO(adamk): Teach Literal how to print its values without
// allocating on the heap.
PrintLiteral(node->BuildValue(isolate_), true);
} }
...@@ -285,10 +287,13 @@ void CallPrinter::VisitThrow(Throw* node) { Find(node->exception()); } ...@@ -285,10 +287,13 @@ void CallPrinter::VisitThrow(Throw* node) { Find(node->exception()); }
void CallPrinter::VisitProperty(Property* node) { void CallPrinter::VisitProperty(Property* node) {
Expression* key = node->key(); Expression* key = node->key();
Literal* literal = key->AsLiteral(); Literal* literal = key->AsLiteral();
if (literal != nullptr && literal->value()->IsInternalizedString()) { if (literal != nullptr &&
literal->BuildValue(isolate_)->IsInternalizedString()) {
Find(node->obj(), true); Find(node->obj(), true);
Print("."); Print(".");
PrintLiteral(literal->value(), false); // TODO(adamk): Teach Literal how to print its values without
// allocating on the heap.
PrintLiteral(literal->BuildValue(isolate_), false);
} else { } else {
Find(node->obj(), true); Find(node->obj(), true);
Print("["); Print("[");
...@@ -1023,9 +1028,10 @@ void AstPrinter::VisitConditional(Conditional* node) { ...@@ -1023,9 +1028,10 @@ void AstPrinter::VisitConditional(Conditional* node) {
} }
// TODO(svenpanne) Start with IndentedScope.
void AstPrinter::VisitLiteral(Literal* node) { void AstPrinter::VisitLiteral(Literal* node) {
PrintLiteralIndented("LITERAL", node->value(), true); // TODO(adamk): Teach Literal how to print its values without
// allocating on the heap.
PrintLiteralIndented("LITERAL", node->BuildValue(isolate_), true);
} }
...@@ -1177,8 +1183,11 @@ void AstPrinter::VisitProperty(Property* node) { ...@@ -1177,8 +1183,11 @@ void AstPrinter::VisitProperty(Property* node) {
Visit(node->obj()); Visit(node->obj());
Literal* literal = node->key()->AsLiteral(); Literal* literal = node->key()->AsLiteral();
if (literal != nullptr && literal->value()->IsInternalizedString()) { if (literal != nullptr &&
PrintLiteralIndented("NAME", literal->value(), false); literal->BuildValue(isolate_)->IsInternalizedString()) {
// TODO(adamk): Teach Literal how to print its values without
// allocating on the heap.
PrintLiteralIndented("NAME", literal->BuildValue(isolate_), false);
} else { } else {
PrintIndentedVisit("KEY", node->key()); PrintIndentedVisit("KEY", node->key());
} }
......
...@@ -571,6 +571,12 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral( ...@@ -571,6 +571,12 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(double value) {
size_t entry = GetConstantPoolEntry(value);
OutputLdaConstant(entry);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral( BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
const AstRawString* raw_string) { const AstRawString* raw_string) {
size_t entry = GetConstantPoolEntry(raw_string); size_t entry = GetConstantPoolEntry(raw_string);
...@@ -584,27 +590,22 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(const Scope* scope) { ...@@ -584,27 +590,22 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(const Scope* scope) {
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral( BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(AstBigInt bigint) {
const AstValue* ast_value) { size_t entry = GetConstantPoolEntry(bigint);
DCHECK(ast_value->IsHeapNumber() || ast_value->IsBigInt() || OutputLdaConstant(entry);
ast_value->IsSymbol()); return *this;
if (ast_value->IsHeapNumber() || ast_value->IsBigInt()) { }
size_t entry = GetConstantPoolEntry(ast_value);
OutputLdaConstant(entry); BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(AstSymbol symbol) {
return *this; size_t entry;
} else { switch (symbol) {
// This should be the only ast value type left. case AstSymbol::kHomeObjectSymbol:
DCHECK(ast_value->IsSymbol()); entry = HomeObjectSymbolConstantPoolEntry();
size_t entry; break;
switch (ast_value->AsSymbol()) { // No default case so that we get a warning if AstSymbol changes
case AstSymbol::kHomeObjectSymbol:
entry = HomeObjectSymbolConstantPoolEntry();
break;
// No default case so that we get a warning if AstSymbol changes
}
OutputLdaConstant(entry);
return *this;
} }
OutputLdaConstant(entry);
return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() { BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() {
...@@ -1416,15 +1417,18 @@ size_t BytecodeArrayBuilder::GetConstantPoolEntry( ...@@ -1416,15 +1417,18 @@ size_t BytecodeArrayBuilder::GetConstantPoolEntry(
return constant_array_builder()->Insert(raw_string); return constant_array_builder()->Insert(raw_string);
} }
size_t BytecodeArrayBuilder::GetConstantPoolEntry(const AstValue* heap_number) { size_t BytecodeArrayBuilder::GetConstantPoolEntry(AstBigInt bigint) {
DCHECK(heap_number->IsHeapNumber() || heap_number->IsBigInt()); return constant_array_builder()->Insert(bigint);
return constant_array_builder()->Insert(heap_number);
} }
size_t BytecodeArrayBuilder::GetConstantPoolEntry(const Scope* scope) { size_t BytecodeArrayBuilder::GetConstantPoolEntry(const Scope* scope) {
return constant_array_builder()->Insert(scope); return constant_array_builder()->Insert(scope);
} }
size_t BytecodeArrayBuilder::GetConstantPoolEntry(double number) {
return constant_array_builder()->Insert(number);
}
#define ENTRY_GETTER(NAME, ...) \ #define ENTRY_GETTER(NAME, ...) \
size_t BytecodeArrayBuilder::NAME##ConstantPoolEntry() { \ size_t BytecodeArrayBuilder::NAME##ConstantPoolEntry() { \
return constant_array_builder()->Insert##NAME(); \ return constant_array_builder()->Insert##NAME(); \
......
...@@ -71,9 +71,11 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final ...@@ -71,9 +71,11 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
// Constant loads to accumulator. // Constant loads to accumulator.
BytecodeArrayBuilder& LoadConstantPoolEntry(size_t entry); BytecodeArrayBuilder& LoadConstantPoolEntry(size_t entry);
BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value); BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value);
BytecodeArrayBuilder& LoadLiteral(double value);
BytecodeArrayBuilder& LoadLiteral(const AstRawString* raw_string); BytecodeArrayBuilder& LoadLiteral(const AstRawString* raw_string);
BytecodeArrayBuilder& LoadLiteral(const Scope* scope); BytecodeArrayBuilder& LoadLiteral(const Scope* scope);
BytecodeArrayBuilder& LoadLiteral(const AstValue* ast_value); BytecodeArrayBuilder& LoadLiteral(AstBigInt bigint);
BytecodeArrayBuilder& LoadLiteral(AstSymbol symbol);
BytecodeArrayBuilder& LoadUndefined(); BytecodeArrayBuilder& LoadUndefined();
BytecodeArrayBuilder& LoadNull(); BytecodeArrayBuilder& LoadNull();
BytecodeArrayBuilder& LoadTheHole(); BytecodeArrayBuilder& LoadTheHole();
...@@ -440,8 +442,9 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final ...@@ -440,8 +442,9 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
// Gets a constant pool entry. // Gets a constant pool entry.
size_t GetConstantPoolEntry(const AstRawString* raw_string); size_t GetConstantPoolEntry(const AstRawString* raw_string);
size_t GetConstantPoolEntry(const AstValue* heap_number); size_t GetConstantPoolEntry(AstBigInt bigint);
size_t GetConstantPoolEntry(const Scope* scope); size_t GetConstantPoolEntry(const Scope* scope);
size_t GetConstantPoolEntry(double number);
#define ENTRY_GETTER(NAME, ...) size_t NAME##ConstantPoolEntry(); #define ENTRY_GETTER(NAME, ...) size_t NAME##ConstantPoolEntry();
SINGLETON_CONSTANT_ENTRY_TYPES(ENTRY_GETTER) SINGLETON_CONSTANT_ENTRY_TYPES(ENTRY_GETTER)
#undef ENTRY_GETTER #undef ENTRY_GETTER
......
...@@ -1977,8 +1977,11 @@ void BytecodeGenerator::VisitConditional(Conditional* expr) { ...@@ -1977,8 +1977,11 @@ void BytecodeGenerator::VisitConditional(Conditional* expr) {
void BytecodeGenerator::VisitLiteral(Literal* expr) { void BytecodeGenerator::VisitLiteral(Literal* expr) {
if (!execution_result()->IsEffect()) { if (!execution_result()->IsEffect()) {
// TODO(adamk): Make this a switch statement.
if (expr->IsSmi()) { if (expr->IsSmi()) {
builder()->LoadLiteral(expr->AsSmiLiteral()); builder()->LoadLiteral(expr->AsSmiLiteral());
} else if (expr->IsNumber()) {
builder()->LoadLiteral(expr->AsNumber());
} else if (expr->IsUndefined()) { } else if (expr->IsUndefined()) {
builder()->LoadUndefined(); builder()->LoadUndefined();
} else if (expr->IsTrue()) { } else if (expr->IsTrue()) {
...@@ -1991,9 +1994,10 @@ void BytecodeGenerator::VisitLiteral(Literal* expr) { ...@@ -1991,9 +1994,10 @@ void BytecodeGenerator::VisitLiteral(Literal* expr) {
builder()->LoadTheHole(); builder()->LoadTheHole();
} else if (expr->IsString()) { } else if (expr->IsString()) {
builder()->LoadLiteral(expr->AsRawString()); builder()->LoadLiteral(expr->AsRawString());
} else { } else if (expr->IsSymbol()) {
// TODO(adamk): Get rid of this case. builder()->LoadLiteral(expr->AsSymbol());
builder()->LoadLiteral(expr->raw_value()); } else if (expr->IsBigInt()) {
builder()->LoadLiteral(expr->AsBigInt());
} }
if (expr->IsTrue() || expr->IsFalse()) { if (expr->IsTrue() || expr->IsFalse()) {
execution_result()->SetResultIsBoolean(); execution_result()->SetResultIsBoolean();
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "src/interpreter/constant-array-builder.h" #include "src/interpreter/constant-array-builder.h"
#include <cmath>
#include <functional> #include <functional>
#include <set> #include <set>
...@@ -65,17 +66,50 @@ const ConstantArrayBuilder::Entry& ConstantArrayBuilder::ConstantArraySlice::At( ...@@ -65,17 +66,50 @@ const ConstantArrayBuilder::Entry& ConstantArrayBuilder::ConstantArraySlice::At(
#if DEBUG #if DEBUG
void ConstantArrayBuilder::ConstantArraySlice::CheckAllElementsAreUnique( void ConstantArrayBuilder::ConstantArraySlice::CheckAllElementsAreUnique(
Isolate* isolate) const { Isolate* isolate) const {
std::set<Object*> elements; std::set<Smi*> smis;
std::set<double> heap_numbers;
std::set<const AstRawString*> strings;
std::set<const char*> bigints;
std::set<const Scope*> scopes;
std::set<Object*> deferred_objects;
for (const Entry& entry : constants_) { for (const Entry& entry : constants_) {
// TODO(leszeks): Ignore jump tables because they have to be contiguous, bool duplicate = false;
// so they can contain duplicates. switch (entry.tag_) {
if (entry.IsJumpTableEntry()) continue; case Entry::Tag::kSmi:
duplicate = !smis.insert(entry.smi_).second;
Handle<Object> handle = entry.ToHandle(isolate); break;
case Entry::Tag::kHeapNumber:
if (elements.find(*handle) != elements.end()) { duplicate = !heap_numbers.insert(entry.heap_number_).second;
break;
case Entry::Tag::kRawString:
duplicate = !strings.insert(entry.raw_string_).second;
break;
case Entry::Tag::kBigInt:
duplicate = !bigints.insert(entry.bigint_.c_str()).second;
break;
case Entry::Tag::kScope:
duplicate = !scopes.insert(entry.scope_).second;
break;
case Entry::Tag::kHandle:
duplicate = !deferred_objects.insert(*entry.handle_).second;
break;
case Entry::Tag::kDeferred:
UNREACHABLE(); // Should be kHandle at this point.
case Entry::Tag::kJumpTableSmi:
case Entry::Tag::kUninitializedJumpTableSmi:
// TODO(leszeks): Ignore jump tables because they have to be contiguous,
// so they can contain duplicates.
break;
#define CASE_TAG(NAME, ...) case Entry::Tag::k##NAME:
SINGLETON_CONSTANT_ENTRY_TYPES(CASE_TAG)
#undef CASE_TAG
// Singletons are non-duplicated by definition.
break;
}
if (duplicate) {
std::ostringstream os; std::ostringstream os;
os << "Duplicate constant found: " << Brief(*handle) << std::endl; os << "Duplicate constant found: " << Brief(*entry.ToHandle(isolate))
<< std::endl;
// Print all the entries in the slice to help debug duplicates. // Print all the entries in the slice to help debug duplicates.
size_t i = start_index(); size_t i = start_index();
for (const Entry& prev_entry : constants_) { for (const Entry& prev_entry : constants_) {
...@@ -83,7 +117,6 @@ void ConstantArrayBuilder::ConstantArraySlice::CheckAllElementsAreUnique( ...@@ -83,7 +117,6 @@ void ConstantArrayBuilder::ConstantArraySlice::CheckAllElementsAreUnique(
} }
FATAL(os.str().c_str()); FATAL(os.str().c_str());
} }
elements.insert(*handle);
} }
} }
#endif #endif
...@@ -99,6 +132,7 @@ ConstantArrayBuilder::ConstantArrayBuilder(Zone* zone) ...@@ -99,6 +132,7 @@ ConstantArrayBuilder::ConstantArrayBuilder(Zone* zone)
ZoneAllocationPolicy(zone)), ZoneAllocationPolicy(zone)),
smi_map_(zone), smi_map_(zone),
smi_pairs_(zone), smi_pairs_(zone),
heap_number_map_(zone),
#define INIT_SINGLETON_ENTRY_FIELD(NAME, LOWER_NAME) LOWER_NAME##_(-1), #define INIT_SINGLETON_ENTRY_FIELD(NAME, LOWER_NAME) LOWER_NAME##_(-1),
SINGLETON_CONSTANT_ENTRY_TYPES(INIT_SINGLETON_ENTRY_FIELD) SINGLETON_CONSTANT_ENTRY_TYPES(INIT_SINGLETON_ENTRY_FIELD)
#undef INIT_SINGLETON_ENTRY_FIELD #undef INIT_SINGLETON_ENTRY_FIELD
...@@ -153,14 +187,14 @@ Handle<FixedArray> ConstantArrayBuilder::ToFixedArray(Isolate* isolate) { ...@@ -153,14 +187,14 @@ Handle<FixedArray> ConstantArrayBuilder::ToFixedArray(Isolate* isolate) {
base::bits::IsPowerOfTwo(static_cast<uint32_t>(array_index))); base::bits::IsPowerOfTwo(static_cast<uint32_t>(array_index)));
#if DEBUG #if DEBUG
// Different slices might contain the same element due to reservations, but // Different slices might contain the same element due to reservations, but
// all elements within a slice should be unique. If this DCHECK fails, then // all elements within a slice should be unique.
// the AST nodes are not being internalized within a CanonicalHandleScope.
slice->CheckAllElementsAreUnique(isolate); slice->CheckAllElementsAreUnique(isolate);
#endif #endif
// Copy objects from slice into array. // Copy objects from slice into array.
for (size_t i = 0; i < slice->size(); ++i) { for (size_t i = 0; i < slice->size(); ++i) {
fixed_array->set(array_index++, Handle<Object> value =
*slice->At(slice->start_index() + i).ToHandle(isolate)); slice->At(slice->start_index() + i).ToHandle(isolate);
fixed_array->set(array_index++, *value);
} }
// Leave holes where reservations led to unused slots. // Leave holes where reservations led to unused slots.
size_t padding = slice->capacity() - slice->size(); size_t padding = slice->capacity() - slice->size();
...@@ -181,6 +215,17 @@ size_t ConstantArrayBuilder::Insert(Smi* smi) { ...@@ -181,6 +215,17 @@ size_t ConstantArrayBuilder::Insert(Smi* smi) {
return entry->second; return entry->second;
} }
size_t ConstantArrayBuilder::Insert(double number) {
if (std::isnan(number)) return InsertNaN();
auto entry = heap_number_map_.find(number);
if (entry == heap_number_map_.end()) {
index_t index = static_cast<index_t>(AllocateIndex(Entry(number)));
heap_number_map_[number] = index;
return index;
}
return entry->second;
}
size_t ConstantArrayBuilder::Insert(const AstRawString* raw_string) { size_t ConstantArrayBuilder::Insert(const AstRawString* raw_string) {
return constants_map_ return constants_map_
.LookupOrInsert(reinterpret_cast<intptr_t>(raw_string), .LookupOrInsert(reinterpret_cast<intptr_t>(raw_string),
...@@ -190,17 +235,11 @@ size_t ConstantArrayBuilder::Insert(const AstRawString* raw_string) { ...@@ -190,17 +235,11 @@ size_t ConstantArrayBuilder::Insert(const AstRawString* raw_string) {
->value; ->value;
} }
size_t ConstantArrayBuilder::Insert(const AstValue* heap_number) { size_t ConstantArrayBuilder::Insert(AstBigInt bigint) {
// This method only accepts heap numbers and BigInts. Other types of
// AstValue should either be passed through as raw values (in the
// case of strings), use the singleton Insert methods (in the case
// of symbols), or skip the constant pool entirely and use bytecodes
// with immediate values (Smis, booleans, undefined, etc.).
DCHECK(heap_number->IsHeapNumber() || heap_number->IsBigInt());
return constants_map_ return constants_map_
.LookupOrInsert(reinterpret_cast<intptr_t>(heap_number), .LookupOrInsert(reinterpret_cast<intptr_t>(bigint.c_str()),
static_cast<uint32_t>(base::hash_value(heap_number)), static_cast<uint32_t>(base::hash_value(bigint.c_str())),
[&]() { return AllocateIndex(Entry(heap_number)); }, [&]() { return AllocateIndex(Entry(bigint)); },
ZoneAllocationPolicy(zone_)) ZoneAllocationPolicy(zone_))
->value; ->value;
} }
...@@ -340,8 +379,11 @@ Handle<Object> ConstantArrayBuilder::Entry::ToHandle(Isolate* isolate) const { ...@@ -340,8 +379,11 @@ Handle<Object> ConstantArrayBuilder::Entry::ToHandle(Isolate* isolate) const {
case Tag::kRawString: case Tag::kRawString:
return raw_string_->string(); return raw_string_->string();
case Tag::kHeapNumber: case Tag::kHeapNumber:
DCHECK(heap_number_->IsHeapNumber() || heap_number_->IsBigInt()); return isolate->factory()->NewNumber(heap_number_);
return heap_number_->value(); case Tag::kBigInt:
// TODO(adamk): Don't check-fail on conversion failure; instead
// check for errors during parsing and throw at that point.
return BigIntLiteral(isolate, bigint_.c_str()).ToHandleChecked();
case Tag::kScope: case Tag::kScope:
return scope_->scope_info(); return scope_->scope_info();
#define ENTRY_LOOKUP(Name, name) \ #define ENTRY_LOOKUP(Name, name) \
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef V8_INTERPRETER_CONSTANT_ARRAY_BUILDER_H_ #ifndef V8_INTERPRETER_CONSTANT_ARRAY_BUILDER_H_
#define V8_INTERPRETER_CONSTANT_ARRAY_BUILDER_H_ #define V8_INTERPRETER_CONSTANT_ARRAY_BUILDER_H_
#include "src/ast/ast-value-factory.h"
#include "src/globals.h" #include "src/globals.h"
#include "src/identity-map.h" #include "src/identity-map.h"
#include "src/interpreter/bytecodes.h" #include "src/interpreter/bytecodes.h"
...@@ -21,6 +22,7 @@ namespace interpreter { ...@@ -21,6 +22,7 @@ namespace interpreter {
// Constant array entries that represent singletons. // Constant array entries that represent singletons.
#define SINGLETON_CONSTANT_ENTRY_TYPES(V) \ #define SINGLETON_CONSTANT_ENTRY_TYPES(V) \
V(NaN, nan_value) \
V(IteratorSymbol, iterator_symbol) \ V(IteratorSymbol, iterator_symbol) \
V(AsyncIteratorSymbol, async_iterator_symbol) \ V(AsyncIteratorSymbol, async_iterator_symbol) \
V(HomeObjectSymbol, home_object_symbol) \ V(HomeObjectSymbol, home_object_symbol) \
...@@ -58,8 +60,9 @@ class V8_EXPORT_PRIVATE ConstantArrayBuilder final BASE_EMBEDDED { ...@@ -58,8 +60,9 @@ class V8_EXPORT_PRIVATE ConstantArrayBuilder final BASE_EMBEDDED {
// Insert an object into the constants array if it is not already present. // Insert an object into the constants array if it is not already present.
// Returns the array index associated with the object. // Returns the array index associated with the object.
size_t Insert(Smi* smi); size_t Insert(Smi* smi);
size_t Insert(double number);
size_t Insert(const AstRawString* raw_string); size_t Insert(const AstRawString* raw_string);
size_t Insert(const AstValue* heap_number); size_t Insert(AstBigInt bigint);
size_t Insert(const Scope* scope); size_t Insert(const Scope* scope);
#define INSERT_ENTRY(NAME, ...) size_t Insert##NAME(); #define INSERT_ENTRY(NAME, ...) size_t Insert##NAME();
SINGLETON_CONSTANT_ENTRY_TYPES(INSERT_ENTRY) SINGLETON_CONSTANT_ENTRY_TYPES(INSERT_ENTRY)
...@@ -97,16 +100,19 @@ class V8_EXPORT_PRIVATE ConstantArrayBuilder final BASE_EMBEDDED { ...@@ -97,16 +100,19 @@ class V8_EXPORT_PRIVATE ConstantArrayBuilder final BASE_EMBEDDED {
private: private:
typedef uint32_t index_t; typedef uint32_t index_t;
struct ConstantArraySlice;
class Entry { class Entry {
private: private:
enum class Tag : uint8_t; enum class Tag : uint8_t;
public: public:
explicit Entry(Smi* smi) : smi_(smi), tag_(Tag::kSmi) {} explicit Entry(Smi* smi) : smi_(smi), tag_(Tag::kSmi) {}
explicit Entry(double heap_number)
: heap_number_(heap_number), tag_(Tag::kHeapNumber) {}
explicit Entry(const AstRawString* raw_string) explicit Entry(const AstRawString* raw_string)
: raw_string_(raw_string), tag_(Tag::kRawString) {} : raw_string_(raw_string), tag_(Tag::kRawString) {}
explicit Entry(const AstValue* heap_number) explicit Entry(AstBigInt bigint) : bigint_(bigint), tag_(Tag::kBigInt) {}
: heap_number_(heap_number), tag_(Tag::kHeapNumber) {}
explicit Entry(const Scope* scope) : scope_(scope), tag_(Tag::kScope) {} explicit Entry(const Scope* scope) : scope_(scope), tag_(Tag::kScope) {}
#define CONSTRUCT_ENTRY(NAME, LOWER_NAME) \ #define CONSTRUCT_ENTRY(NAME, LOWER_NAME) \
...@@ -147,8 +153,9 @@ class V8_EXPORT_PRIVATE ConstantArrayBuilder final BASE_EMBEDDED { ...@@ -147,8 +153,9 @@ class V8_EXPORT_PRIVATE ConstantArrayBuilder final BASE_EMBEDDED {
union { union {
Handle<Object> handle_; Handle<Object> handle_;
Smi* smi_; Smi* smi_;
double heap_number_;
const AstRawString* raw_string_; const AstRawString* raw_string_;
const AstValue* heap_number_; AstBigInt bigint_;
const Scope* scope_; const Scope* scope_;
}; };
...@@ -158,6 +165,7 @@ class V8_EXPORT_PRIVATE ConstantArrayBuilder final BASE_EMBEDDED { ...@@ -158,6 +165,7 @@ class V8_EXPORT_PRIVATE ConstantArrayBuilder final BASE_EMBEDDED {
kSmi, kSmi,
kRawString, kRawString,
kHeapNumber, kHeapNumber,
kBigInt,
kScope, kScope,
kUninitializedJumpTableSmi, kUninitializedJumpTableSmi,
kJumpTableSmi, kJumpTableSmi,
...@@ -165,6 +173,11 @@ class V8_EXPORT_PRIVATE ConstantArrayBuilder final BASE_EMBEDDED { ...@@ -165,6 +173,11 @@ class V8_EXPORT_PRIVATE ConstantArrayBuilder final BASE_EMBEDDED {
SINGLETON_CONSTANT_ENTRY_TYPES(ENTRY_TAG) SINGLETON_CONSTANT_ENTRY_TYPES(ENTRY_TAG)
#undef ENTRY_TAG #undef ENTRY_TAG
} tag_; } tag_;
#if DEBUG
// Required by CheckAllElementsAreUnique().
friend struct ConstantArraySlice;
#endif
}; };
index_t AllocateIndex(Entry constant_entry); index_t AllocateIndex(Entry constant_entry);
...@@ -212,6 +225,7 @@ class V8_EXPORT_PRIVATE ConstantArrayBuilder final BASE_EMBEDDED { ...@@ -212,6 +225,7 @@ class V8_EXPORT_PRIVATE ConstantArrayBuilder final BASE_EMBEDDED {
constants_map_; constants_map_;
ZoneMap<Smi*, index_t> smi_map_; ZoneMap<Smi*, index_t> smi_map_;
ZoneVector<std::pair<Smi*, index_t>> smi_pairs_; ZoneVector<std::pair<Smi*, index_t>> smi_pairs_;
ZoneMap<double, index_t> heap_number_map_;
#define SINGLETON_ENTRY_FIELD(NAME, LOWER_NAME) int LOWER_NAME##_; #define SINGLETON_ENTRY_FIELD(NAME, LOWER_NAME) int LOWER_NAME##_;
SINGLETON_CONSTANT_ENTRY_TYPES(SINGLETON_ENTRY_FIELD) SINGLETON_CONSTANT_ENTRY_TYPES(SINGLETON_ENTRY_FIELD)
......
...@@ -437,7 +437,7 @@ Literal* Parser::ExpressionFromLiteral(Token::Value token, int pos) { ...@@ -437,7 +437,7 @@ Literal* Parser::ExpressionFromLiteral(Token::Value token, int pos) {
} }
case Token::BIGINT: case Token::BIGINT:
return factory()->NewBigIntLiteral( return factory()->NewBigIntLiteral(
scanner()->CurrentLiteralAsCString(zone()), pos); AstBigInt(scanner()->CurrentLiteralAsCString(zone())), pos);
default: default:
DCHECK(false); DCHECK(false);
} }
......
...@@ -331,10 +331,6 @@ TEST(HeapNumberConstants) { ...@@ -331,10 +331,6 @@ TEST(HeapNumberConstants) {
"var a = 1.2; return 2.6;\n", "var a = 1.2; return 2.6;\n",
"var a = 3.14; return 3.14;\n", "var a = 3.14; return 3.14;\n",
"var a;" //
REPEAT_256("\na = 1.414;") //
" a = 3.14;\n",
}; };
CHECK(CompareTexts(BuildActual(printer, snippets), CHECK(CompareTexts(BuildActual(printer, snippets),
...@@ -950,25 +946,6 @@ TEST(BasicLoops) { ...@@ -950,25 +946,6 @@ TEST(BasicLoops) {
LoadGolden("BasicLoops.golden"))); LoadGolden("BasicLoops.golden")));
} }
TEST(JumpsRequiringConstantWideOperands) {
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
const char* snippets[] = {
REPEAT_256("var x = 0.1;\n")
REPEAT_32("var x = 0.2;\n")
REPEAT_16("var x = 0.3;\n")
REPEAT_8("var x = 0.4;\n")
"for (var i = 0; i < 3; i++) {\n"
" if (i == 1) continue;\n"
" if (i == 2) break;\n"
"}\n"
"return 3;\n",
};
CHECK(CompareTexts(BuildActual(printer, snippets),
LoadGolden("JumpsRequiringConstantWideOperands.golden")));
}
TEST(UnaryOperators) { TEST(UnaryOperators) {
InitializedIgnitionHandleScope scope; InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate()); BytecodeExpectationsPrinter printer(CcTest::isolate());
...@@ -1197,20 +1174,6 @@ TEST(RegExpLiterals) { ...@@ -1197,20 +1174,6 @@ TEST(RegExpLiterals) {
LoadGolden("RegExpLiterals.golden"))); LoadGolden("RegExpLiterals.golden")));
} }
TEST(RegExpLiteralsWide) {
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
const char* snippets[] = {
"var a;" //
REPEAT_256("\na = 1.23;") //
"\nreturn /ab+d/;\n",
};
CHECK(CompareTexts(BuildActual(printer, snippets),
LoadGolden("RegExpLiteralsWide.golden")));
}
TEST(ArrayLiterals) { TEST(ArrayLiterals) {
InitializedIgnitionHandleScope scope; InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate()); BytecodeExpectationsPrinter printer(CcTest::isolate());
...@@ -1229,20 +1192,6 @@ TEST(ArrayLiterals) { ...@@ -1229,20 +1192,6 @@ TEST(ArrayLiterals) {
LoadGolden("ArrayLiterals.golden"))); LoadGolden("ArrayLiterals.golden")));
} }
TEST(ArrayLiteralsWide) {
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
const char* snippets[] = {
"var a;" //
REPEAT_256("\na = 1.23;") //
"\nreturn [ 1 , 2 ];\n",
};
CHECK(CompareTexts(BuildActual(printer, snippets),
LoadGolden("ArrayLiteralsWide.golden")));
}
TEST(ObjectLiterals) { TEST(ObjectLiterals) {
InitializedIgnitionHandleScope scope; InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate()); BytecodeExpectationsPrinter printer(CcTest::isolate());
...@@ -1283,19 +1232,6 @@ TEST(ObjectLiterals) { ...@@ -1283,19 +1232,6 @@ TEST(ObjectLiterals) {
LoadGolden("ObjectLiterals.golden"))); LoadGolden("ObjectLiterals.golden")));
} }
TEST(ObjectLiteralsWide) {
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
const char* snippets[] = {
"var a;" //
REPEAT_256("\na = 1.23;") //
"\nreturn { name: 'string', val: 9.2 };\n",
};
CHECK(CompareTexts(BuildActual(printer, snippets),
LoadGolden("ObjectLiteralsWide.golden")));
}
TEST(TopLevelObjectLiterals) { TEST(TopLevelObjectLiterals) {
InitializedIgnitionHandleScope scope; InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate()); BytecodeExpectationsPrinter printer(CcTest::isolate());
...@@ -2016,41 +1952,6 @@ TEST(LookupSlotInEval) { ...@@ -2016,41 +1952,6 @@ TEST(LookupSlotInEval) {
CHECK(CompareTexts(actual, LoadGolden("LookupSlotInEval.golden"))); CHECK(CompareTexts(actual, LoadGolden("LookupSlotInEval.golden")));
} }
TEST(LookupSlotWideInEval) {
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
printer.set_wrap(false);
printer.set_test_function_name("f");
const char* snippets[] = {
REPEAT_256(" \"var y = 2.3;\" +\n") //
" \"return x;\" +\n",
REPEAT_256(" \"var y = 2.3;\" +\n") //
" \"return typeof x;\" +\n",
REPEAT_256(" \"var y = 2.3;\" +\n") //
" \"x = 10;\" +\n",
" \"'use strict';\" +\n" //
REPEAT_256(" \"var y = 2.3;\" +\n") //
" \"x = 10;\" +\n",
};
std::string actual = BuildActual(printer, snippets,
"var f;\n"
"var x = 1;\n"
"function f1() {\n"
" eval(\"function t() {\" +\n",
" \"};\" +\n"
" \"f = t; f();\"\n);\n"
"}\n"
"f1();");
CHECK(CompareTexts(actual, LoadGolden("LookupSlotWideInEval.golden")));
}
TEST(DeleteLookupSlotInEval) { TEST(DeleteLookupSlotInEval) {
InitializedIgnitionHandleScope scope; InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate()); BytecodeExpectationsPrinter printer(CcTest::isolate());
......
This diff is collapsed.
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include <limits>
#include "src/v8.h" #include "src/v8.h"
#include "src/ast/scopes.h" #include "src/ast/scopes.h"
...@@ -339,7 +341,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -339,7 +341,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
// Wide constant pool loads // Wide constant pool loads
for (int i = 0; i < 256; i++) { for (int i = 0; i < 256; i++) {
// Emit junk in constant pool to force wide constant pool index. // Emit junk in constant pool to force wide constant pool index.
builder.LoadLiteral(ast_factory.NewNumber(2.5321 + i)); builder.LoadLiteral(2.5321 + i);
} }
builder.LoadLiteral(Smi::FromInt(20000000)); builder.LoadLiteral(Smi::FromInt(20000000));
const AstRawString* wide_name = ast_factory.GetOneByteString("var_wide_name"); const AstRawString* wide_name = ast_factory.GetOneByteString("var_wide_name");
...@@ -514,9 +516,9 @@ TEST_F(BytecodeArrayBuilderTest, Constants) { ...@@ -514,9 +516,9 @@ TEST_F(BytecodeArrayBuilderTest, Constants) {
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(), AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed()); isolate()->heap()->HashSeed());
const AstValue* heap_num_1 = ast_factory.NewNumber(3.14); double heap_num_1 = 3.14;
const AstValue* heap_num_2 = ast_factory.NewNumber(5.2); double heap_num_2 = 5.2;
const AstValue* heap_num_2_copy = ast_factory.NewNumber(5.2); double nan = std::numeric_limits<double>::quiet_NaN();
const AstRawString* string = ast_factory.GetOneByteString("foo"); const AstRawString* string = ast_factory.GetOneByteString("foo");
const AstRawString* string_copy = ast_factory.GetOneByteString("foo"); const AstRawString* string_copy = ast_factory.GetOneByteString("foo");
...@@ -525,13 +527,15 @@ TEST_F(BytecodeArrayBuilderTest, Constants) { ...@@ -525,13 +527,15 @@ TEST_F(BytecodeArrayBuilderTest, Constants) {
.LoadLiteral(string) .LoadLiteral(string)
.LoadLiteral(heap_num_1) .LoadLiteral(heap_num_1)
.LoadLiteral(heap_num_1) .LoadLiteral(heap_num_1)
.LoadLiteral(nan)
.LoadLiteral(string_copy) .LoadLiteral(string_copy)
.LoadLiteral(heap_num_2_copy) .LoadLiteral(heap_num_2)
.LoadLiteral(nan)
.Return(); .Return();
ast_factory.Internalize(isolate()); ast_factory.Internalize(isolate());
Handle<BytecodeArray> array = builder.ToBytecodeArray(isolate()); Handle<BytecodeArray> array = builder.ToBytecodeArray(isolate());
// Should only have one entry for each identical string constant. // Should only have one entry for each identical constant.
EXPECT_EQ(4, array->constant_pool()->length()); EXPECT_EQ(4, array->constant_pool()->length());
} }
......
...@@ -26,8 +26,8 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) { ...@@ -26,8 +26,8 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) {
BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec); BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec);
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(), AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed()); isolate()->heap()->HashSeed());
const AstValue* heap_num_0 = ast_factory.NewNumber(2.718); double heap_num_0 = 2.718;
const AstValue* heap_num_1 = ast_factory.NewNumber(2.0 * Smi::kMaxValue); double heap_num_1 = 2.0 * Smi::kMaxValue;
Smi* zero = Smi::kZero; Smi* zero = Smi::kZero;
Smi* smi_0 = Smi::FromInt(64); Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536); Smi* smi_1 = Smi::FromInt(-65536);
...@@ -78,8 +78,7 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) { ...@@ -78,8 +78,7 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) {
EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant); EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant);
EXPECT_EQ(iterator.current_offset(), offset); EXPECT_EQ(iterator.current_offset(), offset);
EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
CHECK(iterator.GetConstantForIndexOperand(0).is_identical_to( EXPECT_EQ(iterator.GetConstantForIndexOperand(0)->Number(), heap_num_0);
heap_num_0->value()));
CHECK(!iterator.done()); CHECK(!iterator.done());
offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle); offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle);
iterator.Advance(); iterator.Advance();
...@@ -96,8 +95,7 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) { ...@@ -96,8 +95,7 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) {
EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant); EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant);
EXPECT_EQ(iterator.current_offset(), offset); EXPECT_EQ(iterator.current_offset(), offset);
EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
CHECK(iterator.GetConstantForIndexOperand(0).is_identical_to( EXPECT_EQ(iterator.GetConstantForIndexOperand(0)->Number(), heap_num_1);
heap_num_1->value()));
CHECK(!iterator.done()); CHECK(!iterator.done());
offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle); offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle);
iterator.Advance(); iterator.Advance();
......
...@@ -26,8 +26,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, InvalidBeforeStart) { ...@@ -26,8 +26,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, InvalidBeforeStart) {
BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec); BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec);
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(), AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed()); isolate()->heap()->HashSeed());
const AstValue* heap_num_0 = ast_factory.NewNumber(2.718); double heap_num_0 = 2.718;
const AstValue* heap_num_1 = ast_factory.NewNumber(2.0 * Smi::kMaxValue); double heap_num_1 = 2.0 * Smi::kMaxValue;
Smi* zero = Smi::kZero; Smi* zero = Smi::kZero;
Smi* smi_0 = Smi::FromInt(64); Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536); Smi* smi_1 = Smi::FromInt(-65536);
...@@ -80,8 +80,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, InvalidAfterEnd) { ...@@ -80,8 +80,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, InvalidAfterEnd) {
BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec); BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec);
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(), AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed()); isolate()->heap()->HashSeed());
const AstValue* heap_num_0 = ast_factory.NewNumber(2.718); double heap_num_0 = 2.718;
const AstValue* heap_num_1 = ast_factory.NewNumber(2.0 * Smi::kMaxValue); double heap_num_1 = 2.0 * Smi::kMaxValue;
Smi* zero = Smi::kZero; Smi* zero = Smi::kZero;
Smi* smi_0 = Smi::FromInt(64); Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536); Smi* smi_1 = Smi::FromInt(-65536);
...@@ -134,8 +134,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, AccessesFirst) { ...@@ -134,8 +134,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, AccessesFirst) {
BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec); BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec);
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(), AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed()); isolate()->heap()->HashSeed());
const AstValue* heap_num_0 = ast_factory.NewNumber(2.718); double heap_num_0 = 2.718;
const AstValue* heap_num_1 = ast_factory.NewNumber(2.0 * Smi::kMaxValue); double heap_num_1 = 2.0 * Smi::kMaxValue;
Smi* zero = Smi::kZero; Smi* zero = Smi::kZero;
Smi* smi_0 = Smi::FromInt(64); Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536); Smi* smi_1 = Smi::FromInt(-65536);
...@@ -181,8 +181,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, AccessesFirst) { ...@@ -181,8 +181,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, AccessesFirst) {
EXPECT_EQ(iterator.current_index(), 0); EXPECT_EQ(iterator.current_index(), 0);
EXPECT_EQ(iterator.current_offset(), 0); EXPECT_EQ(iterator.current_offset(), 0);
EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
EXPECT_TRUE(iterator.GetConstantForIndexOperand(0).is_identical_to( EXPECT_EQ(iterator.GetConstantForIndexOperand(0)->Number(), heap_num_0);
heap_num_0->value()));
ASSERT_TRUE(iterator.IsValid()); ASSERT_TRUE(iterator.IsValid());
} }
...@@ -193,8 +192,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, AccessesLast) { ...@@ -193,8 +192,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, AccessesLast) {
BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec); BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec);
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(), AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed()); isolate()->heap()->HashSeed());
const AstValue* heap_num_0 = ast_factory.NewNumber(2.718); double heap_num_0 = 2.718;
const AstValue* heap_num_1 = ast_factory.NewNumber(2.0 * Smi::kMaxValue); double heap_num_1 = 2.0 * Smi::kMaxValue;
Smi* zero = Smi::kZero; Smi* zero = Smi::kZero;
Smi* smi_0 = Smi::FromInt(64); Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536); Smi* smi_1 = Smi::FromInt(-65536);
...@@ -252,8 +251,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, RandomAccessValid) { ...@@ -252,8 +251,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, RandomAccessValid) {
BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec); BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec);
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(), AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed()); isolate()->heap()->HashSeed());
const AstValue* heap_num_0 = ast_factory.NewNumber(2.718); double heap_num_0 = 2.718;
const AstValue* heap_num_1 = ast_factory.NewNumber(2.0 * Smi::kMaxValue); double heap_num_1 = 2.0 * Smi::kMaxValue;
Smi* zero = Smi::kZero; Smi* zero = Smi::kZero;
Smi* smi_0 = Smi::FromInt(64); Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536); Smi* smi_1 = Smi::FromInt(-65536);
...@@ -329,8 +328,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, RandomAccessValid) { ...@@ -329,8 +328,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, RandomAccessValid) {
EXPECT_EQ(iterator.current_index(), 2); EXPECT_EQ(iterator.current_index(), 2);
EXPECT_EQ(iterator.current_offset(), offset); EXPECT_EQ(iterator.current_offset(), offset);
EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
EXPECT_TRUE(iterator.GetConstantForIndexOperand(0).is_identical_to( EXPECT_EQ(iterator.GetConstantForIndexOperand(0)->Number(), heap_num_1);
heap_num_1->value()));
ASSERT_TRUE(iterator.IsValid()); ASSERT_TRUE(iterator.IsValid());
iterator.GoToIndex(18); iterator.GoToIndex(18);
...@@ -438,8 +436,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArray) { ...@@ -438,8 +436,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArray) {
BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec); BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec);
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(), AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed()); isolate()->heap()->HashSeed());
const AstValue* heap_num_0 = ast_factory.NewNumber(2.718); double heap_num_0 = 2.718;
const AstValue* heap_num_1 = ast_factory.NewNumber(2.0 * Smi::kMaxValue); double heap_num_1 = 2.0 * Smi::kMaxValue;
Smi* zero = Smi::kZero; Smi* zero = Smi::kZero;
Smi* smi_0 = Smi::FromInt(64); Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536); Smi* smi_1 = Smi::FromInt(-65536);
...@@ -487,8 +485,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArray) { ...@@ -487,8 +485,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArray) {
EXPECT_EQ(iterator.current_index(), 0); EXPECT_EQ(iterator.current_index(), 0);
EXPECT_EQ(iterator.current_offset(), offset); EXPECT_EQ(iterator.current_offset(), offset);
EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
EXPECT_TRUE(iterator.GetConstantForIndexOperand(0).is_identical_to( EXPECT_EQ(iterator.GetConstantForIndexOperand(0)->Number(), heap_num_0);
heap_num_0->value()));
ASSERT_TRUE(iterator.IsValid()); ASSERT_TRUE(iterator.IsValid());
offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle); offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle);
++iterator; ++iterator;
...@@ -507,8 +504,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArray) { ...@@ -507,8 +504,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArray) {
EXPECT_EQ(iterator.current_index(), 2); EXPECT_EQ(iterator.current_index(), 2);
EXPECT_EQ(iterator.current_offset(), offset); EXPECT_EQ(iterator.current_offset(), offset);
EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
EXPECT_TRUE(iterator.GetConstantForIndexOperand(0).is_identical_to( EXPECT_EQ(iterator.GetConstantForIndexOperand(0)->Number(), heap_num_1);
heap_num_1->value()));
ASSERT_TRUE(iterator.IsValid()); ASSERT_TRUE(iterator.IsValid());
offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle); offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle);
++iterator; ++iterator;
...@@ -719,8 +715,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArrayBackwards) { ...@@ -719,8 +715,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArrayBackwards) {
BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec); BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec);
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(), AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed()); isolate()->heap()->HashSeed());
const AstValue* heap_num_0 = ast_factory.NewNumber(2.718); double heap_num_0 = 2.718;
const AstValue* heap_num_1 = ast_factory.NewNumber(2.0 * Smi::kMaxValue); double heap_num_1 = 2.0 * Smi::kMaxValue;
Smi* zero = Smi::kZero; Smi* zero = Smi::kZero;
Smi* smi_0 = Smi::FromInt(64); Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536); Smi* smi_1 = Smi::FromInt(-65536);
...@@ -969,8 +965,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArrayBackwards) { ...@@ -969,8 +965,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArrayBackwards) {
EXPECT_EQ(iterator.current_index(), 2); EXPECT_EQ(iterator.current_index(), 2);
EXPECT_EQ(iterator.current_offset(), offset); EXPECT_EQ(iterator.current_offset(), offset);
EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
EXPECT_TRUE(iterator.GetConstantForIndexOperand(0).is_identical_to( EXPECT_EQ(iterator.GetConstantForIndexOperand(0)->Number(), heap_num_1);
heap_num_1->value()));
ASSERT_TRUE(iterator.IsValid()); ASSERT_TRUE(iterator.IsValid());
--iterator; --iterator;
...@@ -989,8 +984,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArrayBackwards) { ...@@ -989,8 +984,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArrayBackwards) {
EXPECT_EQ(iterator.current_index(), 0); EXPECT_EQ(iterator.current_index(), 0);
EXPECT_EQ(iterator.current_offset(), offset); EXPECT_EQ(iterator.current_offset(), offset);
EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
EXPECT_TRUE(iterator.GetConstantForIndexOperand(0).is_identical_to( EXPECT_EQ(iterator.GetConstantForIndexOperand(0)->Number(), heap_num_0);
heap_num_0->value()));
ASSERT_TRUE(iterator.IsValid()); ASSERT_TRUE(iterator.IsValid());
--iterator; --iterator;
ASSERT_FALSE(iterator.IsValid()); ASSERT_FALSE(iterator.IsValid());
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "src/ast/ast-value-factory.h" #include "src/ast/ast-value-factory.h"
#include "src/ast/ast.h"
#include "src/heap/heap-inl.h" #include "src/heap/heap-inl.h"
#include "src/isolate-inl.h" #include "src/isolate-inl.h"
#include "src/zone/zone.h" #include "src/zone/zone.h"
...@@ -16,27 +17,34 @@ class AstValueTest : public TestWithIsolateAndZone { ...@@ -16,27 +17,34 @@ class AstValueTest : public TestWithIsolateAndZone {
protected: protected:
AstValueTest() AstValueTest()
: ast_value_factory_(zone(), i_isolate()->ast_string_constants(), : ast_value_factory_(zone(), i_isolate()->ast_string_constants(),
i_isolate()->heap()->HashSeed()) {} i_isolate()->heap()->HashSeed()),
ast_node_factory_(&ast_value_factory_, zone()) {}
Literal* NewBigInt(const char* str) {
return ast_node_factory_.NewBigIntLiteral(AstBigInt(str),
kNoSourcePosition);
}
AstValueFactory ast_value_factory_; AstValueFactory ast_value_factory_;
AstNodeFactory ast_node_factory_;
}; };
TEST_F(AstValueTest, BigIntBooleanValue) { TEST_F(AstValueTest, BigIntToBooleanIsTrue) {
EXPECT_FALSE(ast_value_factory_.NewBigInt("0")->BooleanValue()); EXPECT_FALSE(NewBigInt("0")->ToBooleanIsTrue());
EXPECT_FALSE(ast_value_factory_.NewBigInt("0b0")->BooleanValue()); EXPECT_FALSE(NewBigInt("0b0")->ToBooleanIsTrue());
EXPECT_FALSE(ast_value_factory_.NewBigInt("0o0")->BooleanValue()); EXPECT_FALSE(NewBigInt("0o0")->ToBooleanIsTrue());
EXPECT_FALSE(ast_value_factory_.NewBigInt("0x0")->BooleanValue()); EXPECT_FALSE(NewBigInt("0x0")->ToBooleanIsTrue());
EXPECT_FALSE(ast_value_factory_.NewBigInt("0b000")->BooleanValue()); EXPECT_FALSE(NewBigInt("0b000")->ToBooleanIsTrue());
EXPECT_FALSE(ast_value_factory_.NewBigInt("0o00000")->BooleanValue()); EXPECT_FALSE(NewBigInt("0o00000")->ToBooleanIsTrue());
EXPECT_FALSE(ast_value_factory_.NewBigInt("0x000000000")->BooleanValue()); EXPECT_FALSE(NewBigInt("0x000000000")->ToBooleanIsTrue());
EXPECT_TRUE(ast_value_factory_.NewBigInt("3")->BooleanValue()); EXPECT_TRUE(NewBigInt("3")->ToBooleanIsTrue());
EXPECT_TRUE(ast_value_factory_.NewBigInt("0b1")->BooleanValue()); EXPECT_TRUE(NewBigInt("0b1")->ToBooleanIsTrue());
EXPECT_TRUE(ast_value_factory_.NewBigInt("0o6")->BooleanValue()); EXPECT_TRUE(NewBigInt("0o6")->ToBooleanIsTrue());
EXPECT_TRUE(ast_value_factory_.NewBigInt("0xa")->BooleanValue()); EXPECT_TRUE(NewBigInt("0xa")->ToBooleanIsTrue());
EXPECT_TRUE(ast_value_factory_.NewBigInt("0b0000001")->BooleanValue()); EXPECT_TRUE(NewBigInt("0b0000001")->ToBooleanIsTrue());
EXPECT_TRUE(ast_value_factory_.NewBigInt("0o00005000")->BooleanValue()); EXPECT_TRUE(NewBigInt("0o00005000")->ToBooleanIsTrue());
EXPECT_TRUE(ast_value_factory_.NewBigInt("0x0000d00c0")->BooleanValue()); EXPECT_TRUE(NewBigInt("0x0000d00c0")->ToBooleanIsTrue());
} }
} // namespace internal } // namespace internal
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment