Commit da3e2225 authored by heimbuef's avatar heimbuef Committed by Commit bot

[Parser] Added SMI cache

With the very same SMIs making up a big chunk
of the parser zone (especially for asm.js) it
makes sense to cache the AstValues for them.
This is not ideal yet, but already saves
hundreds (sic!) MBs of memory for Unity games.

Review-Url: https://codereview.chromium.org/2485423002
Cr-Commit-Position: refs/heads/master@{#40866}
parent d91bed67
...@@ -330,10 +330,12 @@ const AstValue* AstValueFactory::NewNumber(double number, bool with_dot) { ...@@ -330,10 +330,12 @@ const AstValue* AstValueFactory::NewNumber(double number, bool with_dot) {
return AddValue(value); return AddValue(value);
} }
const AstValue* AstValueFactory::NewSmi(uint32_t number) {
bool cacheable_smi = number <= kMaxCachedSmi;
if (cacheable_smi && smis_[number] != nullptr) return smis_[number];
const AstValue* AstValueFactory::NewSmi(int number) { AstValue* value = new (zone_) AstValue(AstValue::SMI, number);
AstValue* value = if (cacheable_smi) smis_[number] = value;
new (zone_) AstValue(AstValue::SMI, number);
return AddValue(value); return AddValue(value);
} }
......
...@@ -332,6 +332,7 @@ class AstValueFactory { ...@@ -332,6 +332,7 @@ class AstValueFactory {
AstValueFactory(Zone* zone, uint32_t hash_seed) AstValueFactory(Zone* zone, uint32_t hash_seed)
: string_table_(AstRawStringCompare), : string_table_(AstRawStringCompare),
values_(nullptr), values_(nullptr),
smis_(),
strings_(nullptr), strings_(nullptr),
strings_end_(&strings_), strings_end_(&strings_),
zone_(zone), zone_(zone),
...@@ -342,6 +343,7 @@ class AstValueFactory { ...@@ -342,6 +343,7 @@ class AstValueFactory {
#define F(name) name##_ = NULL; #define F(name) name##_ = NULL;
OTHER_CONSTANTS(F) OTHER_CONSTANTS(F)
#undef F #undef F
std::fill(smis_, smis_ + arraysize(smis_), nullptr);
} }
Zone* zone() const { return zone_; } Zone* zone() const { return zone_; }
...@@ -381,7 +383,7 @@ class AstValueFactory { ...@@ -381,7 +383,7 @@ class AstValueFactory {
// A JavaScript symbol (ECMA-262 edition 6). // A JavaScript symbol (ECMA-262 edition 6).
const AstValue* NewSymbol(const char* name); const AstValue* NewSymbol(const char* name);
const AstValue* NewNumber(double number, bool with_dot = false); const AstValue* NewNumber(double number, bool with_dot = false);
const AstValue* NewSmi(int number); const AstValue* NewSmi(uint32_t number);
const AstValue* NewBoolean(bool b); const AstValue* NewBoolean(bool b);
const AstValue* NewStringList(ZoneList<const AstRawString*>* strings); const AstValue* NewStringList(ZoneList<const AstRawString*>* strings);
const AstValue* NewNull(); const AstValue* NewNull();
...@@ -389,6 +391,10 @@ class AstValueFactory { ...@@ -389,6 +391,10 @@ class AstValueFactory {
const AstValue* NewTheHole(); const AstValue* NewTheHole();
private: private:
static const uint32_t kMaxCachedSmi = 1 << 10;
STATIC_ASSERT(kMaxCachedSmi <= Smi::kMaxValue);
AstValue* AddValue(AstValue* value) { AstValue* AddValue(AstValue* value) {
value->set_next(values_); value->set_next(values_);
values_ = value; values_ = value;
...@@ -416,6 +422,8 @@ class AstValueFactory { ...@@ -416,6 +422,8 @@ class AstValueFactory {
// For keeping track of all AstValues and AstRawStrings we've created (so that // For keeping track of all AstValues and AstRawStrings we've created (so that
// they can be internalized later). // they can be internalized later).
AstValue* values_; AstValue* values_;
AstValue* smis_[kMaxCachedSmi + 1];
// 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.
AstString* strings_; AstString* strings_;
......
...@@ -3283,7 +3283,7 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3283,7 +3283,7 @@ class AstNodeFactory final BASE_EMBEDDED {
Literal(ast_value_factory_->NewNumber(number, with_dot), pos); Literal(ast_value_factory_->NewNumber(number, with_dot), pos);
} }
Literal* NewSmiLiteral(int number, int pos) { Literal* NewSmiLiteral(uint32_t number, int pos) {
return new (zone_) Literal(ast_value_factory_->NewSmi(number), pos); return new (zone_) Literal(ast_value_factory_->NewSmi(number), pos);
} }
......
...@@ -503,7 +503,7 @@ Literal* Parser::ExpressionFromLiteral(Token::Value token, int pos) { ...@@ -503,7 +503,7 @@ Literal* Parser::ExpressionFromLiteral(Token::Value token, int pos) {
case Token::FALSE_LITERAL: case Token::FALSE_LITERAL:
return factory()->NewBooleanLiteral(false, pos); return factory()->NewBooleanLiteral(false, pos);
case Token::SMI: { case Token::SMI: {
int value = scanner()->smi_value(); uint32_t value = scanner()->smi_value();
return factory()->NewSmiLiteral(value, pos); return factory()->NewSmiLiteral(value, pos);
} }
case Token::NUMBER: { case Token::NUMBER: {
...@@ -3923,9 +3923,9 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start, ...@@ -3923,9 +3923,9 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start,
const_cast<ZoneList<Expression*>*>(raw_strings), raw_idx, pos), const_cast<ZoneList<Expression*>*>(raw_strings), raw_idx, pos),
zone()); zone());
// Ensure hash is suitable as a Smi value // Truncate hash to Smi-range.
Smi* hash_obj = Smi::cast(Internals::IntToSmi(static_cast<int>(hash))); Smi* hash_obj = Smi::cast(Internals::IntToSmi(static_cast<int>(hash)));
args->Add(factory()->NewSmiLiteral(hash_obj->value(), pos), zone()); args->Add(factory()->NewNumberLiteral(hash_obj->value(), pos), zone());
Expression* call_site = factory()->NewCallRuntime( Expression* call_site = factory()->NewCallRuntime(
Context::GET_TEMPLATE_CALL_SITE_INDEX, args, start); Context::GET_TEMPLATE_CALL_SITE_INDEX, args, start);
......
...@@ -1153,7 +1153,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) { ...@@ -1153,7 +1153,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
if (next_.literal_chars->one_byte_literal().length() <= 10 && if (next_.literal_chars->one_byte_literal().length() <= 10 &&
value <= Smi::kMaxValue && c0_ != '.' && c0_ != 'e' && c0_ != 'E') { value <= Smi::kMaxValue && c0_ != '.' && c0_ != 'e' && c0_ != 'E') {
next_.smi_value_ = static_cast<int>(value); next_.smi_value_ = static_cast<uint32_t>(value);
literal.Complete(); literal.Complete();
HandleLeadSurrogate(); HandleLeadSurrogate();
......
...@@ -284,7 +284,7 @@ class Scanner { ...@@ -284,7 +284,7 @@ class Scanner {
} }
// Returns the value of the last smi that was scanned. // Returns the value of the last smi that was scanned.
int smi_value() const { return current_.smi_value_; } uint32_t smi_value() const { return current_.smi_value_; }
// Seek forward to the given position. This operation does not // Seek forward to the given position. This operation does not
// work in general, for instance when there are pushed back // work in general, for instance when there are pushed back
...@@ -487,7 +487,7 @@ class Scanner { ...@@ -487,7 +487,7 @@ class Scanner {
Location location; Location location;
LiteralBuffer* literal_chars; LiteralBuffer* literal_chars;
LiteralBuffer* raw_literal_chars; LiteralBuffer* raw_literal_chars;
int smi_value_; uint32_t smi_value_;
Token::Value token; Token::Value token;
}; };
......
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