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

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: 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..f83dd78df2da91c2ff65dbfc575d935f66be2849 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,62 @@ 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 uword Hash(const Object& obj) {
+ return String::Cast(obj).Hash();
+ }
+};
+typedef UnorderedHashMap<ConstMapKeyEqualsTraits> ConstantsMap;
+
+
+static void BuildConstMapKey(const Script& script,
+ intptr_t token_pos,
+ String* key) {
+ *key = script.url();
+ String& suffix = String::Handle(String::NewFormatted("_%" Pd "", token_pos));
koda 2015/08/25 18:27:12 Add TODO: avoid allocations for lookup by introduc
koda 2015/08/25 18:27:12 Make private method and then: Handle(Z, ...)
hausner 2015/08/25 19:48:51 We discussed offline, but for those following alon
hausner 2015/08/25 19:48:51 Done.
srdjan 2015/08/25 22:16:19 String::NewFormatted is allocating a string in new
+ *key = Symbols::FromConcat(*key, suffix);
+}
+
+
+void Parser::CacheConstantValue(intptr_t token_pos, const Instance& value) {
+ String& key = String::Handle();
koda 2015/08/25 18:27:12 Handle(Z)
hausner 2015/08/25 19:48:51 Done.
+ BuildConstMapKey(script_, token_pos, &key);
+ 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)));
srdjan 2015/08/25 22:16:19 It does not matter for optimizing compiler (since
+ }
+ 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;
+ }
+ String& key = String::Handle();
koda 2015/08/25 18:27:12 Handle(Z)
hausner 2015/08/25 19:48:52 Done.
+ BuildConstMapKey(script_, token_pos, &key);
+ ConstantsMap constants(isolate()->object_store()->compile_time_constants());
+ bool is_present = false;
+ *value ^= constants.GetOrNull(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 +12564,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 +12640,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 +12673,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 +12767,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 +12933,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);
Florian Schneider 2015/08/26 08:58:09 Are cached constants ever GCed? What if the code t
hausner 2015/08/26 17:46:14 No, they are not GCed. But we hold on to these con
return new(Z) LiteralNode(
literal_pos, Instance::ZoneHandle(Z, const_instance.raw()));
}
@@ -13401,41 +13477,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