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) {
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)
: zone_(isolate->allocator(), ZONE_NAME),
string_table_(AstRawString::Compare),
......@@ -364,77 +263,9 @@ void AstValueFactory::Internalize(Isolate* isolate) {
current = next;
}
for (AstValue* current = values_; current != nullptr;) {
AstValue* next = current->next();
current->Internalize(isolate);
current = next;
}
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,
Vector<const byte> literal_bytes) {
......
......@@ -35,7 +35,7 @@
#include "src/isolate.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
// parsing, they are created and stored outside the heap, in AstValueFactory.
// After parsing, the strings and values are internalized (moved into the V8
......@@ -176,124 +176,17 @@ class AstConsString final : public ZoneObject {
enum class AstSymbol : uint8_t { kHomeObjectSymbol };
// AstValue is either a string, a symbol, a number, a string array, a boolean,
// or a special value (null, undefined, the hole).
class AstValue : public ZoneObject {
class AstBigInt {
public:
bool IsString() const {
return type_ == STRING;
}
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;
// |bigint| must be a NUL-terminated string of ASCII characters
// representing a BigInt (suitable for passing to BigIntLiteral()
// from conversions.h).
explicit AstBigInt(const char* bigint) : bigint_(bigint) {}
V8_EXPORT_PRIVATE bool BooleanValue() const;
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; }
const char* c_str() const { return bigint_; }
private:
void set_value(Handle<Object> object) { value_ = object.location(); }
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_;
};
const char* bigint_;
};
// For generating constants.
......@@ -371,7 +264,6 @@ class AstValueFactory {
AstValueFactory(Zone* zone, const AstStringConstants* string_constants,
uint32_t hash_seed)
: string_table_(string_constants->string_table()),
values_(nullptr),
strings_(nullptr),
strings_end_(&strings_),
cons_strings_(nullptr),
......@@ -381,7 +273,6 @@ class AstValueFactory {
zone_(zone),
hash_seed_(hash_seed) {
DCHECK_EQ(hash_seed, string_constants->hash_seed());
std::fill(smis_, smis_ + arraysize(smis_), nullptr);
std::fill(one_character_strings_,
one_character_strings_ + arraysize(one_character_strings_),
nullptr);
......@@ -416,27 +307,7 @@ class AstValueFactory {
#undef F
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:
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) {
*strings_end_ = string;
strings_end_ = string->next_location();
......@@ -461,9 +332,6 @@ class AstValueFactory {
// All strings are copied here, one after another (no zeroes inbetween).
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
// members to be internalized first.
......@@ -476,20 +344,12 @@ class AstValueFactory {
const AstStringConstants* string_constants_;
const AstConsString* empty_cons_string_;
// Caches for faster access: small numbers, one character lowercase strings
// (for minified code).
AstValue* smis_[kMaxCachedSmi + 1];
// Caches one character lowercase strings (for minified code).
AstRawString* one_character_strings_[26];
Zone* zone_;
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 v8
......
......@@ -14,7 +14,7 @@
#include "src/builtins/builtins.h"
#include "src/code-stubs.h"
#include "src/contexts.h"
#include "src/conversions.h"
#include "src/conversions-inl.h"
#include "src/double.h"
#include "src/elements.h"
#include "src/objects-inl.h"
......@@ -421,11 +421,11 @@ void ObjectLiteral::BuildConstantProperties(Isolate* isolate) {
continue;
}
Handle<Object> key = property->key()->AsLiteral()->value();
Literal* key = property->key()->AsLiteral();
uint32_t element_index = 0;
if (key->ToArrayIndex(&element_index) ||
(key->IsString() && String::cast(*key)->AsArrayIndex(&element_index))) {
(key->IsString() && key->AsRawString()->AsArrayIndex(&element_index))) {
index_keys++;
}
}
......@@ -454,7 +454,7 @@ void ObjectLiteral::BuildConstantProperties(Isolate* isolate) {
// Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
// value for COMPUTED properties, the real value is filled in at
// 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);
uint32_t element_index = 0;
......@@ -603,7 +603,7 @@ bool MaterializedLiteral::IsSimple() const {
Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression,
Isolate* isolate) {
if (expression->IsLiteral()) {
return expression->AsLiteral()->value();
return expression->AsLiteral()->BuildValue(isolate);
}
if (CompileTimeValue::IsCompileTimeValue(expression)) {
return CompileTimeValue::GetValue(isolate, expression);
......@@ -792,23 +792,90 @@ Call::CallType Call::GetCallType() const {
CaseClause::CaseClause(Expression* label, ZoneList<Statement*>* 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 {
if (IsSmi()) {
int num = AsSmiLiteral()->value();
if (num < 0) return false;
*value = static_cast<uint32_t>(num);
return true;
}
if (IsNumber()) {
return DoubleToUint32IfEqualToSelf(AsNumber(), value);
switch (type()) {
case kSmi:
if (smi_ < 0) return false;
*value = static_cast<uint32_t>(smi_);
return true;
case kHeapNumber:
return DoubleToUint32IfEqualToSelf(AsNumber(), value);
default:
return false;
}
return false;
}
bool Literal::ToArrayIndex(uint32_t* value) const {
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() {
return IsString() ? AsRawString()->Hash()
: ComputeLongHash(double_to_uint64(AsNumber()));
......@@ -816,13 +883,22 @@ uint32_t Literal::Hash() {
// static
bool Literal::Match(void* literal1, void* literal2) {
const AstValue* x = static_cast<Literal*>(literal1)->value_;
const AstValue* y = static_cast<Literal*>(literal2)->value_;
return (x->IsString() && y->IsString() && x->AsString() == y->AsString()) ||
bool Literal::Match(void* a, void* b) {
Literal* x = static_cast<Literal*>(a);
Literal* y = static_cast<Literal*>(b);
return (x->IsString() && y->IsString() &&
x->AsRawString() == y->AsRawString()) ||
(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() {
#ifdef DEBUG
return is_jsruntime() ? NameForNativeContextIntrinsicIndex(context_index_)
......
......@@ -989,46 +989,65 @@ class Literal final : public Expression {
public:
// Returns true if literal represents a property name (i.e. cannot be parsed
// as array indices).
bool IsPropertyName() const { return value_->IsPropertyName(); }
bool IsPropertyName() const;
const AstRawString* AsRawPropertyName() {
DCHECK(IsPropertyName());
return value_->AsString();
return string_;
}
bool IsSmi() const { return value_->IsSmi(); }
bool IsSmi() const { return type() == kSmi; }
Smi* AsSmiLiteral() const {
DCHECK(IsSmi());
return value_->AsSmi();
DCHECK_EQ(kSmi, type());
return Smi::FromInt(smi_);
}
bool IsNumber() const { return value_->IsNumber(); }
bool IsNumber() const { return type() == kHeapNumber || type() == kSmi; }
double AsNumber() const {
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() {
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 IsUndefined() const { return value_->IsUndefined(); }
bool IsTheHole() const { return value_->IsTheHole(); }
bool IsNull() const { return type() == kNull; }
bool IsUndefined() const { return type() == kUndefined; }
bool IsTheHole() const { return type() == kTheHole; }
bool IsTrue() const { return value_->IsTrue(); }
bool IsFalse() const { return value_->IsFalse(); }
bool IsTrue() const { return type() == kTrue; }
bool IsFalse() const { return type() == kFalse; }
bool ToBooleanIsTrue() const { return value_->BooleanValue(); }
bool ToBooleanIsFalse() const { return !value_->BooleanValue(); }
V8_EXPORT_PRIVATE bool ToBooleanIsTrue() const;
bool ToBooleanIsFalse() const { return !ToBooleanIsTrue(); }
bool ToUint32(uint32_t* value) const;
bool ToArrayIndex(uint32_t* value) const;
Handle<Object> value() const { return value_->value(); }
const AstValue* raw_value() const { return value_; }
// Returns an appropriate Object representing this Literal, allocating
// a heap object if needed.
Handle<Object> BuildValue(Isolate* isolate) const;
// Support for using Literal as a HashMap key. NOTE: Currently, this works
// only for string and number literals!
......@@ -1038,10 +1057,60 @@ class Literal final : public Expression {
private:
friend class AstNodeFactory;
Literal(const AstValue* value, int position)
: Expression(position, kLiteral), value_(value) {}
enum Type {
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.
......@@ -2943,41 +3012,41 @@ class AstNodeFactory final BASE_EMBEDDED {
}
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).
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) {
return new (zone_) Literal(ast_value_factory_->NewNumber(number), pos);
}
Literal* NewNumberLiteral(double number, int pos);
Literal* NewSmiLiteral(uint32_t number, int pos) {
return new (zone_) Literal(ast_value_factory_->NewSmi(number), pos);
Literal* NewSmiLiteral(int number, int pos) {
return new (zone_) Literal(number, pos);
}
Literal* NewBigIntLiteral(const char* buffer, int pos) {
return new (zone_) Literal(ast_value_factory_->NewBigInt(buffer), pos);
Literal* NewBigIntLiteral(AstBigInt bigint, int pos) {
return new (zone_) Literal(bigint, 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) {
return new (zone_) Literal(ast_value_factory_->NewNull(), pos);
return new (zone_) Literal(Literal::kNull, pos);
}
Literal* NewUndefinedLiteral(int pos) {
return new (zone_) Literal(ast_value_factory_->NewUndefined(), pos);
return new (zone_) Literal(Literal::kUndefined, pos);
}
Literal* NewTheHoleLiteral() {
return new (zone_)
Literal(ast_value_factory_->NewTheHole(), kNoSourcePosition);
return new (zone_) Literal(Literal::kTheHole, kNoSourcePosition);
}
ObjectLiteral* NewObjectLiteral(
......
......@@ -219,7 +219,9 @@ void CallPrinter::VisitConditional(Conditional* 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()); }
void CallPrinter::VisitProperty(Property* node) {
Expression* key = node->key();
Literal* literal = key->AsLiteral();
if (literal != nullptr && literal->value()->IsInternalizedString()) {
if (literal != nullptr &&
literal->BuildValue(isolate_)->IsInternalizedString()) {
Find(node->obj(), true);
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 {
Find(node->obj(), true);
Print("[");
......@@ -1023,9 +1028,10 @@ void AstPrinter::VisitConditional(Conditional* node) {
}
// TODO(svenpanne) Start with IndentedScope.
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) {
Visit(node->obj());
Literal* literal = node->key()->AsLiteral();
if (literal != nullptr && literal->value()->IsInternalizedString()) {
PrintLiteralIndented("NAME", literal->value(), false);
if (literal != nullptr &&
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 {
PrintIndentedVisit("KEY", node->key());
}
......
......@@ -571,6 +571,12 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(double value) {
size_t entry = GetConstantPoolEntry(value);
OutputLdaConstant(entry);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
const AstRawString* raw_string) {
size_t entry = GetConstantPoolEntry(raw_string);
......@@ -584,27 +590,22 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(const Scope* scope) {
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
const AstValue* ast_value) {
DCHECK(ast_value->IsHeapNumber() || ast_value->IsBigInt() ||
ast_value->IsSymbol());
if (ast_value->IsHeapNumber() || ast_value->IsBigInt()) {
size_t entry = GetConstantPoolEntry(ast_value);
OutputLdaConstant(entry);
return *this;
} else {
// This should be the only ast value type left.
DCHECK(ast_value->IsSymbol());
size_t entry;
switch (ast_value->AsSymbol()) {
case AstSymbol::kHomeObjectSymbol:
entry = HomeObjectSymbolConstantPoolEntry();
break;
// No default case so that we get a warning if AstSymbol changes
}
OutputLdaConstant(entry);
return *this;
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(AstBigInt bigint) {
size_t entry = GetConstantPoolEntry(bigint);
OutputLdaConstant(entry);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(AstSymbol symbol) {
size_t entry;
switch (symbol) {
case AstSymbol::kHomeObjectSymbol:
entry = HomeObjectSymbolConstantPoolEntry();
break;
// No default case so that we get a warning if AstSymbol changes
}
OutputLdaConstant(entry);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() {
......@@ -1416,15 +1417,18 @@ size_t BytecodeArrayBuilder::GetConstantPoolEntry(
return constant_array_builder()->Insert(raw_string);
}
size_t BytecodeArrayBuilder::GetConstantPoolEntry(const AstValue* heap_number) {
DCHECK(heap_number->IsHeapNumber() || heap_number->IsBigInt());
return constant_array_builder()->Insert(heap_number);
size_t BytecodeArrayBuilder::GetConstantPoolEntry(AstBigInt bigint) {
return constant_array_builder()->Insert(bigint);
}
size_t BytecodeArrayBuilder::GetConstantPoolEntry(const Scope* scope) {
return constant_array_builder()->Insert(scope);
}
size_t BytecodeArrayBuilder::GetConstantPoolEntry(double number) {
return constant_array_builder()->Insert(number);
}
#define ENTRY_GETTER(NAME, ...) \
size_t BytecodeArrayBuilder::NAME##ConstantPoolEntry() { \
return constant_array_builder()->Insert##NAME(); \
......
......@@ -71,9 +71,11 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
// Constant loads to accumulator.
BytecodeArrayBuilder& LoadConstantPoolEntry(size_t entry);
BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value);
BytecodeArrayBuilder& LoadLiteral(double value);
BytecodeArrayBuilder& LoadLiteral(const AstRawString* raw_string);
BytecodeArrayBuilder& LoadLiteral(const Scope* scope);
BytecodeArrayBuilder& LoadLiteral(const AstValue* ast_value);
BytecodeArrayBuilder& LoadLiteral(AstBigInt bigint);
BytecodeArrayBuilder& LoadLiteral(AstSymbol symbol);
BytecodeArrayBuilder& LoadUndefined();
BytecodeArrayBuilder& LoadNull();
BytecodeArrayBuilder& LoadTheHole();
......@@ -440,8 +442,9 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
// Gets a constant pool entry.
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(double number);
#define ENTRY_GETTER(NAME, ...) size_t NAME##ConstantPoolEntry();
SINGLETON_CONSTANT_ENTRY_TYPES(ENTRY_GETTER)
#undef ENTRY_GETTER
......
......@@ -1977,8 +1977,11 @@ void BytecodeGenerator::VisitConditional(Conditional* expr) {
void BytecodeGenerator::VisitLiteral(Literal* expr) {
if (!execution_result()->IsEffect()) {
// TODO(adamk): Make this a switch statement.
if (expr->IsSmi()) {
builder()->LoadLiteral(expr->AsSmiLiteral());
} else if (expr->IsNumber()) {
builder()->LoadLiteral(expr->AsNumber());
} else if (expr->IsUndefined()) {
builder()->LoadUndefined();
} else if (expr->IsTrue()) {
......@@ -1991,9 +1994,10 @@ void BytecodeGenerator::VisitLiteral(Literal* expr) {
builder()->LoadTheHole();
} else if (expr->IsString()) {
builder()->LoadLiteral(expr->AsRawString());
} else {
// TODO(adamk): Get rid of this case.
builder()->LoadLiteral(expr->raw_value());
} else if (expr->IsSymbol()) {
builder()->LoadLiteral(expr->AsSymbol());
} else if (expr->IsBigInt()) {
builder()->LoadLiteral(expr->AsBigInt());
}
if (expr->IsTrue() || expr->IsFalse()) {
execution_result()->SetResultIsBoolean();
......
......@@ -4,6 +4,7 @@
#include "src/interpreter/constant-array-builder.h"
#include <cmath>
#include <functional>
#include <set>
......@@ -65,17 +66,50 @@ const ConstantArrayBuilder::Entry& ConstantArrayBuilder::ConstantArraySlice::At(
#if DEBUG
void ConstantArrayBuilder::ConstantArraySlice::CheckAllElementsAreUnique(
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_) {
// TODO(leszeks): Ignore jump tables because they have to be contiguous,
// so they can contain duplicates.
if (entry.IsJumpTableEntry()) continue;
Handle<Object> handle = entry.ToHandle(isolate);
if (elements.find(*handle) != elements.end()) {
bool duplicate = false;
switch (entry.tag_) {
case Entry::Tag::kSmi:
duplicate = !smis.insert(entry.smi_).second;
break;
case Entry::Tag::kHeapNumber:
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;
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.
size_t i = start_index();
for (const Entry& prev_entry : constants_) {
......@@ -83,7 +117,6 @@ void ConstantArrayBuilder::ConstantArraySlice::CheckAllElementsAreUnique(
}
FATAL(os.str().c_str());
}
elements.insert(*handle);
}
}
#endif
......@@ -99,6 +132,7 @@ ConstantArrayBuilder::ConstantArrayBuilder(Zone* zone)
ZoneAllocationPolicy(zone)),
smi_map_(zone),
smi_pairs_(zone),
heap_number_map_(zone),
#define INIT_SINGLETON_ENTRY_FIELD(NAME, LOWER_NAME) LOWER_NAME##_(-1),
SINGLETON_CONSTANT_ENTRY_TYPES(INIT_SINGLETON_ENTRY_FIELD)
#undef INIT_SINGLETON_ENTRY_FIELD
......@@ -153,14 +187,14 @@ Handle<FixedArray> ConstantArrayBuilder::ToFixedArray(Isolate* isolate) {
base::bits::IsPowerOfTwo(static_cast<uint32_t>(array_index)));
#if DEBUG
// Different slices might contain the same element due to reservations, but
// all elements within a slice should be unique. If this DCHECK fails, then
// the AST nodes are not being internalized within a CanonicalHandleScope.
// all elements within a slice should be unique.
slice->CheckAllElementsAreUnique(isolate);
#endif
// Copy objects from slice into array.
for (size_t i = 0; i < slice->size(); ++i) {
fixed_array->set(array_index++,
*slice->At(slice->start_index() + i).ToHandle(isolate));
Handle<Object> value =
slice->At(slice->start_index() + i).ToHandle(isolate);
fixed_array->set(array_index++, *value);
}
// Leave holes where reservations led to unused slots.
size_t padding = slice->capacity() - slice->size();
......@@ -181,6 +215,17 @@ size_t ConstantArrayBuilder::Insert(Smi* smi) {
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) {
return constants_map_
.LookupOrInsert(reinterpret_cast<intptr_t>(raw_string),
......@@ -190,17 +235,11 @@ size_t ConstantArrayBuilder::Insert(const AstRawString* raw_string) {
->value;
}
size_t ConstantArrayBuilder::Insert(const AstValue* heap_number) {
// 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());
size_t ConstantArrayBuilder::Insert(AstBigInt bigint) {
return constants_map_
.LookupOrInsert(reinterpret_cast<intptr_t>(heap_number),
static_cast<uint32_t>(base::hash_value(heap_number)),
[&]() { return AllocateIndex(Entry(heap_number)); },
.LookupOrInsert(reinterpret_cast<intptr_t>(bigint.c_str()),
static_cast<uint32_t>(base::hash_value(bigint.c_str())),
[&]() { return AllocateIndex(Entry(bigint)); },
ZoneAllocationPolicy(zone_))
->value;
}
......@@ -340,8 +379,11 @@ Handle<Object> ConstantArrayBuilder::Entry::ToHandle(Isolate* isolate) const {
case Tag::kRawString:
return raw_string_->string();
case Tag::kHeapNumber:
DCHECK(heap_number_->IsHeapNumber() || heap_number_->IsBigInt());
return heap_number_->value();
return isolate->factory()->NewNumber(heap_number_);
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:
return scope_->scope_info();
#define ENTRY_LOOKUP(Name, name) \
......
......@@ -5,6 +5,7 @@
#ifndef 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/identity-map.h"
#include "src/interpreter/bytecodes.h"
......@@ -21,6 +22,7 @@ namespace interpreter {
// Constant array entries that represent singletons.
#define SINGLETON_CONSTANT_ENTRY_TYPES(V) \
V(NaN, nan_value) \
V(IteratorSymbol, iterator_symbol) \
V(AsyncIteratorSymbol, async_iterator_symbol) \
V(HomeObjectSymbol, home_object_symbol) \
......@@ -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.
// Returns the array index associated with the object.
size_t Insert(Smi* smi);
size_t Insert(double number);
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);
#define INSERT_ENTRY(NAME, ...) size_t Insert##NAME();
SINGLETON_CONSTANT_ENTRY_TYPES(INSERT_ENTRY)
......@@ -97,16 +100,19 @@ class V8_EXPORT_PRIVATE ConstantArrayBuilder final BASE_EMBEDDED {
private:
typedef uint32_t index_t;
struct ConstantArraySlice;
class Entry {
private:
enum class Tag : uint8_t;
public:
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)
: raw_string_(raw_string), tag_(Tag::kRawString) {}
explicit Entry(const AstValue* heap_number)
: heap_number_(heap_number), tag_(Tag::kHeapNumber) {}
explicit Entry(AstBigInt bigint) : bigint_(bigint), tag_(Tag::kBigInt) {}
explicit Entry(const Scope* scope) : scope_(scope), tag_(Tag::kScope) {}
#define CONSTRUCT_ENTRY(NAME, LOWER_NAME) \
......@@ -147,8 +153,9 @@ class V8_EXPORT_PRIVATE ConstantArrayBuilder final BASE_EMBEDDED {
union {
Handle<Object> handle_;
Smi* smi_;
double heap_number_;
const AstRawString* raw_string_;
const AstValue* heap_number_;
AstBigInt bigint_;
const Scope* scope_;
};
......@@ -158,6 +165,7 @@ class V8_EXPORT_PRIVATE ConstantArrayBuilder final BASE_EMBEDDED {
kSmi,
kRawString,
kHeapNumber,
kBigInt,
kScope,
kUninitializedJumpTableSmi,
kJumpTableSmi,
......@@ -165,6 +173,11 @@ class V8_EXPORT_PRIVATE ConstantArrayBuilder final BASE_EMBEDDED {
SINGLETON_CONSTANT_ENTRY_TYPES(ENTRY_TAG)
#undef ENTRY_TAG
} tag_;
#if DEBUG
// Required by CheckAllElementsAreUnique().
friend struct ConstantArraySlice;
#endif
};
index_t AllocateIndex(Entry constant_entry);
......@@ -212,6 +225,7 @@ class V8_EXPORT_PRIVATE ConstantArrayBuilder final BASE_EMBEDDED {
constants_map_;
ZoneMap<Smi*, index_t> smi_map_;
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##_;
SINGLETON_CONSTANT_ENTRY_TYPES(SINGLETON_ENTRY_FIELD)
......
......@@ -437,7 +437,7 @@ Literal* Parser::ExpressionFromLiteral(Token::Value token, int pos) {
}
case Token::BIGINT:
return factory()->NewBigIntLiteral(
scanner()->CurrentLiteralAsCString(zone()), pos);
AstBigInt(scanner()->CurrentLiteralAsCString(zone())), pos);
default:
DCHECK(false);
}
......
......@@ -331,10 +331,6 @@ TEST(HeapNumberConstants) {
"var a = 1.2; return 2.6;\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),
......@@ -950,25 +946,6 @@ TEST(BasicLoops) {
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) {
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
......@@ -1197,20 +1174,6 @@ TEST(RegExpLiterals) {
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) {
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
......@@ -1229,20 +1192,6 @@ TEST(ArrayLiterals) {
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) {
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
......@@ -1283,19 +1232,6 @@ TEST(ObjectLiterals) {
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) {
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
......@@ -2016,41 +1952,6 @@ TEST(LookupSlotInEval) {
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) {
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
......
This diff is collapsed.
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <limits>
#include "src/v8.h"
#include "src/ast/scopes.h"
......@@ -339,7 +341,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
// Wide constant pool loads
for (int i = 0; i < 256; i++) {
// 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));
const AstRawString* wide_name = ast_factory.GetOneByteString("var_wide_name");
......@@ -514,9 +516,9 @@ TEST_F(BytecodeArrayBuilderTest, Constants) {
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed());
const AstValue* heap_num_1 = ast_factory.NewNumber(3.14);
const AstValue* heap_num_2 = ast_factory.NewNumber(5.2);
const AstValue* heap_num_2_copy = ast_factory.NewNumber(5.2);
double heap_num_1 = 3.14;
double heap_num_2 = 5.2;
double nan = std::numeric_limits<double>::quiet_NaN();
const AstRawString* string = ast_factory.GetOneByteString("foo");
const AstRawString* string_copy = ast_factory.GetOneByteString("foo");
......@@ -525,13 +527,15 @@ TEST_F(BytecodeArrayBuilderTest, Constants) {
.LoadLiteral(string)
.LoadLiteral(heap_num_1)
.LoadLiteral(heap_num_1)
.LoadLiteral(nan)
.LoadLiteral(string_copy)
.LoadLiteral(heap_num_2_copy)
.LoadLiteral(heap_num_2)
.LoadLiteral(nan)
.Return();
ast_factory.Internalize(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());
}
......
......@@ -26,8 +26,8 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) {
BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec);
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed());
const AstValue* heap_num_0 = ast_factory.NewNumber(2.718);
const AstValue* heap_num_1 = ast_factory.NewNumber(2.0 * Smi::kMaxValue);
double heap_num_0 = 2.718;
double heap_num_1 = 2.0 * Smi::kMaxValue;
Smi* zero = Smi::kZero;
Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536);
......@@ -78,8 +78,7 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) {
EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant);
EXPECT_EQ(iterator.current_offset(), offset);
EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
CHECK(iterator.GetConstantForIndexOperand(0).is_identical_to(
heap_num_0->value()));
EXPECT_EQ(iterator.GetConstantForIndexOperand(0)->Number(), heap_num_0);
CHECK(!iterator.done());
offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle);
iterator.Advance();
......@@ -96,8 +95,7 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) {
EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant);
EXPECT_EQ(iterator.current_offset(), offset);
EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
CHECK(iterator.GetConstantForIndexOperand(0).is_identical_to(
heap_num_1->value()));
EXPECT_EQ(iterator.GetConstantForIndexOperand(0)->Number(), heap_num_1);
CHECK(!iterator.done());
offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle);
iterator.Advance();
......
......@@ -26,8 +26,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, InvalidBeforeStart) {
BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec);
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed());
const AstValue* heap_num_0 = ast_factory.NewNumber(2.718);
const AstValue* heap_num_1 = ast_factory.NewNumber(2.0 * Smi::kMaxValue);
double heap_num_0 = 2.718;
double heap_num_1 = 2.0 * Smi::kMaxValue;
Smi* zero = Smi::kZero;
Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536);
......@@ -80,8 +80,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, InvalidAfterEnd) {
BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec);
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed());
const AstValue* heap_num_0 = ast_factory.NewNumber(2.718);
const AstValue* heap_num_1 = ast_factory.NewNumber(2.0 * Smi::kMaxValue);
double heap_num_0 = 2.718;
double heap_num_1 = 2.0 * Smi::kMaxValue;
Smi* zero = Smi::kZero;
Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536);
......@@ -134,8 +134,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, AccessesFirst) {
BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec);
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed());
const AstValue* heap_num_0 = ast_factory.NewNumber(2.718);
const AstValue* heap_num_1 = ast_factory.NewNumber(2.0 * Smi::kMaxValue);
double heap_num_0 = 2.718;
double heap_num_1 = 2.0 * Smi::kMaxValue;
Smi* zero = Smi::kZero;
Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536);
......@@ -181,8 +181,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, AccessesFirst) {
EXPECT_EQ(iterator.current_index(), 0);
EXPECT_EQ(iterator.current_offset(), 0);
EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
EXPECT_TRUE(iterator.GetConstantForIndexOperand(0).is_identical_to(
heap_num_0->value()));
EXPECT_EQ(iterator.GetConstantForIndexOperand(0)->Number(), heap_num_0);
ASSERT_TRUE(iterator.IsValid());
}
......@@ -193,8 +192,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, AccessesLast) {
BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec);
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed());
const AstValue* heap_num_0 = ast_factory.NewNumber(2.718);
const AstValue* heap_num_1 = ast_factory.NewNumber(2.0 * Smi::kMaxValue);
double heap_num_0 = 2.718;
double heap_num_1 = 2.0 * Smi::kMaxValue;
Smi* zero = Smi::kZero;
Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536);
......@@ -252,8 +251,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, RandomAccessValid) {
BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec);
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed());
const AstValue* heap_num_0 = ast_factory.NewNumber(2.718);
const AstValue* heap_num_1 = ast_factory.NewNumber(2.0 * Smi::kMaxValue);
double heap_num_0 = 2.718;
double heap_num_1 = 2.0 * Smi::kMaxValue;
Smi* zero = Smi::kZero;
Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536);
......@@ -329,8 +328,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, RandomAccessValid) {
EXPECT_EQ(iterator.current_index(), 2);
EXPECT_EQ(iterator.current_offset(), offset);
EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
EXPECT_TRUE(iterator.GetConstantForIndexOperand(0).is_identical_to(
heap_num_1->value()));
EXPECT_EQ(iterator.GetConstantForIndexOperand(0)->Number(), heap_num_1);
ASSERT_TRUE(iterator.IsValid());
iterator.GoToIndex(18);
......@@ -438,8 +436,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArray) {
BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec);
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed());
const AstValue* heap_num_0 = ast_factory.NewNumber(2.718);
const AstValue* heap_num_1 = ast_factory.NewNumber(2.0 * Smi::kMaxValue);
double heap_num_0 = 2.718;
double heap_num_1 = 2.0 * Smi::kMaxValue;
Smi* zero = Smi::kZero;
Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536);
......@@ -487,8 +485,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArray) {
EXPECT_EQ(iterator.current_index(), 0);
EXPECT_EQ(iterator.current_offset(), offset);
EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
EXPECT_TRUE(iterator.GetConstantForIndexOperand(0).is_identical_to(
heap_num_0->value()));
EXPECT_EQ(iterator.GetConstantForIndexOperand(0)->Number(), heap_num_0);
ASSERT_TRUE(iterator.IsValid());
offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle);
++iterator;
......@@ -507,8 +504,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArray) {
EXPECT_EQ(iterator.current_index(), 2);
EXPECT_EQ(iterator.current_offset(), offset);
EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
EXPECT_TRUE(iterator.GetConstantForIndexOperand(0).is_identical_to(
heap_num_1->value()));
EXPECT_EQ(iterator.GetConstantForIndexOperand(0)->Number(), heap_num_1);
ASSERT_TRUE(iterator.IsValid());
offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle);
++iterator;
......@@ -719,8 +715,8 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArrayBackwards) {
BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, &feedback_spec);
AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
isolate()->heap()->HashSeed());
const AstValue* heap_num_0 = ast_factory.NewNumber(2.718);
const AstValue* heap_num_1 = ast_factory.NewNumber(2.0 * Smi::kMaxValue);
double heap_num_0 = 2.718;
double heap_num_1 = 2.0 * Smi::kMaxValue;
Smi* zero = Smi::kZero;
Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536);
......@@ -969,8 +965,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArrayBackwards) {
EXPECT_EQ(iterator.current_index(), 2);
EXPECT_EQ(iterator.current_offset(), offset);
EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
EXPECT_TRUE(iterator.GetConstantForIndexOperand(0).is_identical_to(
heap_num_1->value()));
EXPECT_EQ(iterator.GetConstantForIndexOperand(0)->Number(), heap_num_1);
ASSERT_TRUE(iterator.IsValid());
--iterator;
......@@ -989,8 +984,7 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArrayBackwards) {
EXPECT_EQ(iterator.current_index(), 0);
EXPECT_EQ(iterator.current_offset(), offset);
EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
EXPECT_TRUE(iterator.GetConstantForIndexOperand(0).is_identical_to(
heap_num_0->value()));
EXPECT_EQ(iterator.GetConstantForIndexOperand(0)->Number(), heap_num_0);
ASSERT_TRUE(iterator.IsValid());
--iterator;
ASSERT_FALSE(iterator.IsValid());
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "src/ast/ast-value-factory.h"
#include "src/ast/ast.h"
#include "src/heap/heap-inl.h"
#include "src/isolate-inl.h"
#include "src/zone/zone.h"
......@@ -16,27 +17,34 @@ class AstValueTest : public TestWithIsolateAndZone {
protected:
AstValueTest()
: 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_;
AstNodeFactory ast_node_factory_;
};
TEST_F(AstValueTest, BigIntBooleanValue) {
EXPECT_FALSE(ast_value_factory_.NewBigInt("0")->BooleanValue());
EXPECT_FALSE(ast_value_factory_.NewBigInt("0b0")->BooleanValue());
EXPECT_FALSE(ast_value_factory_.NewBigInt("0o0")->BooleanValue());
EXPECT_FALSE(ast_value_factory_.NewBigInt("0x0")->BooleanValue());
EXPECT_FALSE(ast_value_factory_.NewBigInt("0b000")->BooleanValue());
EXPECT_FALSE(ast_value_factory_.NewBigInt("0o00000")->BooleanValue());
EXPECT_FALSE(ast_value_factory_.NewBigInt("0x000000000")->BooleanValue());
EXPECT_TRUE(ast_value_factory_.NewBigInt("3")->BooleanValue());
EXPECT_TRUE(ast_value_factory_.NewBigInt("0b1")->BooleanValue());
EXPECT_TRUE(ast_value_factory_.NewBigInt("0o6")->BooleanValue());
EXPECT_TRUE(ast_value_factory_.NewBigInt("0xa")->BooleanValue());
EXPECT_TRUE(ast_value_factory_.NewBigInt("0b0000001")->BooleanValue());
EXPECT_TRUE(ast_value_factory_.NewBigInt("0o00005000")->BooleanValue());
EXPECT_TRUE(ast_value_factory_.NewBigInt("0x0000d00c0")->BooleanValue());
TEST_F(AstValueTest, BigIntToBooleanIsTrue) {
EXPECT_FALSE(NewBigInt("0")->ToBooleanIsTrue());
EXPECT_FALSE(NewBigInt("0b0")->ToBooleanIsTrue());
EXPECT_FALSE(NewBigInt("0o0")->ToBooleanIsTrue());
EXPECT_FALSE(NewBigInt("0x0")->ToBooleanIsTrue());
EXPECT_FALSE(NewBigInt("0b000")->ToBooleanIsTrue());
EXPECT_FALSE(NewBigInt("0o00000")->ToBooleanIsTrue());
EXPECT_FALSE(NewBigInt("0x000000000")->ToBooleanIsTrue());
EXPECT_TRUE(NewBigInt("3")->ToBooleanIsTrue());
EXPECT_TRUE(NewBigInt("0b1")->ToBooleanIsTrue());
EXPECT_TRUE(NewBigInt("0o6")->ToBooleanIsTrue());
EXPECT_TRUE(NewBigInt("0xa")->ToBooleanIsTrue());
EXPECT_TRUE(NewBigInt("0b0000001")->ToBooleanIsTrue());
EXPECT_TRUE(NewBigInt("0o00005000")->ToBooleanIsTrue());
EXPECT_TRUE(NewBigInt("0x0000d00c0")->ToBooleanIsTrue());
}
} // 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