Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1114)

Unified Diff: runtime/vm/parser.cc

Issue 1308073005: Introduce per-isolate cache for compile time constants (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Addressing review comments Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/parser.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/parser.cc
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 286fbe7c97da52bdfd5ff7d32fafc8f6d5d81e9f..0881cddd6fa00d84779ccd5039e5f7b5b5eaa890 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -16,6 +16,7 @@
#include "vm/flags.h"
#include "vm/growable_array.h"
#include "vm/handles.h"
+#include "vm/hash_table.h"
#include "vm/heap.h"
#include "vm/isolate.h"
#include "vm/longjump.h"
@@ -11885,6 +11886,65 @@ bool Parser::IsInstantiatorRequired() const {
}
+class ConstMapKeyEqualsTraits {
+ public:
+ static bool IsMatch(const Object& a, const Object& b) {
+ return String::Cast(a).Equals(String::Cast(b));
+ }
+ static bool IsMatch(const char* key, const Object& b) {
+ return String::Cast(b).Equals(key);
+ }
+ static uword Hash(const Object& obj) {
+ return String::Cast(obj).Hash();
+ }
+ static uword Hash(const char* key) {
+ return String::Hash(key, strlen(key));
+ }
+};
+typedef UnorderedHashMap<ConstMapKeyEqualsTraits> ConstantsMap;
+
+
+void Parser::CacheConstantValue(intptr_t token_pos, const Instance& value) {
+ String& key = String::Handle(Z, script_.url());
+ String& suffix =
+ String::Handle(Z, String::NewFormatted("_%" Pd "", token_pos));
+ key = Symbols::FromConcat(key, suffix);
+ if (isolate()->object_store()->compile_time_constants() == Array::null()) {
+ const intptr_t kInitialConstMapSize = 16;
+ isolate()->object_store()->set_compile_time_constants(
+ Array::Handle(Z, HashTables::New<ConstantsMap>(kInitialConstMapSize)));
+ }
+ ConstantsMap constants(isolate()->object_store()->compile_time_constants());
+ constants.UpdateOrInsert(key, value);
+ if (FLAG_compiler_stats) {
+ isolate_->compiler_stats()->num_cached_consts = constants.NumOccupied();
+ }
+ isolate()->object_store()->set_compile_time_constants(constants.Release());
+}
+
+
+bool Parser::GetCachedConstant(intptr_t token_pos, Instance* value) {
+ if (isolate()->object_store()->compile_time_constants() == Array::null()) {
+ return false;
+ }
+ // We don't want to allocate anything in the heap here since this code
+ // is called from the optimizing compiler in the background thread. Allocate
+ // the key value in the zone instead.
+ const char* key = Z->PrintToString("%s_%" Pd "",
+ String::Handle(Z, script_.url()).ToCString(),
+ token_pos);
+ ConstantsMap constants(isolate()->object_store()->compile_time_constants());
+ bool is_present = false;
+ *value ^= constants.GetOrNull<const char *>(key, &is_present);
+ ASSERT(constants.Release().raw() ==
+ isolate()->object_store()->compile_time_constants());
+ if (FLAG_compiler_stats && is_present) {
+ isolate_->compiler_stats()->num_const_cache_hits++;
+ }
+ return is_present;
+}
+
+
RawInstance* Parser::TryCanonicalize(const Instance& instance,
intptr_t token_pos) {
if (instance.IsNull()) {
@@ -12507,6 +12567,15 @@ AstNode* Parser::ParseListLiteral(intptr_t type_pos,
ASSERT(type_pos >= 0);
ASSERT(CurrentToken() == Token::kLBRACK || CurrentToken() == Token::kINDEX);
const intptr_t literal_pos = TokenPos();
+
+ if (is_const) {
+ Instance& existing_const = Instance::ZoneHandle(Z);
+ if (GetCachedConstant(literal_pos, &existing_const)) {
+ SkipListLiteral();
+ return new(Z) LiteralNode(literal_pos, existing_const);
+ }
+ }
+
bool is_empty_literal = CurrentToken() == Token::kINDEX;
ConsumeToken();
@@ -12574,8 +12643,8 @@ AstNode* Parser::ParseListLiteral(intptr_t type_pos,
if (is_const) {
// Allocate and initialize the const list at compile time.
- Array& const_list =
- Array::ZoneHandle(Z, Array::New(element_list.length(), Heap::kOld));
+ Array& const_list = Array::ZoneHandle(Z,
+ Array::New(element_list.length(), Heap::kOld));
const_list.SetTypeArguments(
TypeArguments::Handle(Z, list_type_arguments.Canonicalize()));
Error& malformed_error = Error::Handle(Z);
@@ -12607,6 +12676,7 @@ AstNode* Parser::ParseListLiteral(intptr_t type_pos,
}
const_list.MakeImmutable();
const_list ^= TryCanonicalize(const_list, literal_pos);
+ CacheConstantValue(literal_pos, const_list);
return new(Z) LiteralNode(literal_pos, const_list);
} else {
// Factory call at runtime.
@@ -12700,8 +12770,16 @@ AstNode* Parser::ParseMapLiteral(intptr_t type_pos,
ASSERT(type_pos >= 0);
ASSERT(CurrentToken() == Token::kLBRACE);
const intptr_t literal_pos = TokenPos();
- ConsumeToken();
+ if (is_const) {
+ Instance& existing_const = Instance::ZoneHandle(Z);
+ if (GetCachedConstant(literal_pos, &existing_const)) {
+ SkipMapLiteral();
+ return new(Z) LiteralNode(literal_pos, existing_const);
+ }
+ }
+
+ ConsumeToken(); // Opening brace.
AbstractType& key_type = Type::ZoneHandle(Z, Type::DynamicType());
AbstractType& value_type = Type::ZoneHandle(Z, Type::DynamicType());
TypeArguments& map_type_arguments =
@@ -12858,6 +12936,7 @@ AstNode* Parser::ParseMapLiteral(intptr_t type_pos,
"error executing const Map constructor");
} else {
const Instance& const_instance = Instance::Cast(constructor_result);
+ CacheConstantValue(literal_pos, const_instance);
return new(Z) LiteralNode(
literal_pos, Instance::ZoneHandle(Z, const_instance.raw()));
}
@@ -13401,41 +13480,43 @@ AstNode* Parser::ParseNewOperator(Token::Kind op_kind) {
"const object creation",
external_constructor_name.ToCString());
}
- const Object& constructor_result = Object::Handle(Z,
- EvaluateConstConstructorCall(type_class,
- type_arguments,
- constructor,
- arguments));
- if (constructor_result.IsUnhandledException()) {
- // It's a compile-time error if invocation of a const constructor
- // call fails.
- ReportErrors(Error::Cast(constructor_result),
- script_, new_pos,
- "error while evaluating const constructor");
+
+ Instance& const_instance = Instance::ZoneHandle(Z);
+ if (GetCachedConstant(new_pos, &const_instance)) {
+ // Cache hit, nothing else to do.
} else {
- // Const constructors can return null in the case where a const native
- // factory returns a null value. Thus we cannot use a Instance::Cast here.
- Instance& const_instance = Instance::Handle(Z);
+ Object& constructor_result = Object::Handle(Z,
+ EvaluateConstConstructorCall(type_class,
+ type_arguments,
+ constructor,
+ arguments));
+ if (constructor_result.IsUnhandledException()) {
+ // It's a compile-time error if invocation of a const constructor
+ // call fails.
+ ReportErrors(Error::Cast(constructor_result),
+ script_, new_pos,
+ "error while evaluating const constructor");
+ }
const_instance ^= constructor_result.raw();
- new_object = new(Z) LiteralNode(
- new_pos, Instance::ZoneHandle(Z, const_instance.raw()));
- if (!type_bound.IsNull()) {
- ASSERT(!type_bound.IsMalformed());
- Error& malformed_error = Error::Handle(Z);
- ASSERT(!is_top_level_); // We cannot check unresolved types.
- if (!const_instance.IsInstanceOf(type_bound,
- TypeArguments::Handle(Z),
- &malformed_error)) {
- type_bound = ClassFinalizer::NewFinalizedMalformedType(
- malformed_error,
- script_,
- new_pos,
- "const factory result is not an instance of '%s'",
- String::Handle(Z, type_bound.UserVisibleName()).ToCString());
- new_object = ThrowTypeError(new_pos, type_bound);
- }
- type_bound = AbstractType::null();
+ CacheConstantValue(new_pos, const_instance);
+ }
+ new_object = new(Z) LiteralNode(new_pos, const_instance);
+ if (!type_bound.IsNull()) {
+ ASSERT(!type_bound.IsMalformed());
+ Error& malformed_error = Error::Handle(Z);
+ ASSERT(!is_top_level_); // We cannot check unresolved types.
+ if (!const_instance.IsInstanceOf(type_bound,
+ TypeArguments::Handle(Z),
+ &malformed_error)) {
+ type_bound = ClassFinalizer::NewFinalizedMalformedType(
+ malformed_error,
+ script_,
+ new_pos,
+ "const factory result is not an instance of '%s'",
+ String::Handle(Z, type_bound.UserVisibleName()).ToCString());
+ new_object = ThrowTypeError(new_pos, type_bound);
}
+ type_bound = AbstractType::null();
}
} else {
CheckConstructorCallTypeArguments(new_pos, constructor, type_arguments);
« no previous file with comments | « runtime/vm/parser.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698