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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « runtime/vm/parser.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/parser.h" 5 #include "vm/parser.h"
6 6
7 #include "lib/invocation_mirror.h" 7 #include "lib/invocation_mirror.h"
8 #include "platform/utils.h" 8 #include "platform/utils.h"
9 #include "vm/ast_transformer.h" 9 #include "vm/ast_transformer.h"
10 #include "vm/bootstrap.h" 10 #include "vm/bootstrap.h"
11 #include "vm/class_finalizer.h" 11 #include "vm/class_finalizer.h"
12 #include "vm/compiler.h" 12 #include "vm/compiler.h"
13 #include "vm/compiler_stats.h" 13 #include "vm/compiler_stats.h"
14 #include "vm/dart_api_impl.h" 14 #include "vm/dart_api_impl.h"
15 #include "vm/dart_entry.h" 15 #include "vm/dart_entry.h"
16 #include "vm/flags.h" 16 #include "vm/flags.h"
17 #include "vm/growable_array.h" 17 #include "vm/growable_array.h"
18 #include "vm/handles.h" 18 #include "vm/handles.h"
19 #include "vm/hash_table.h"
19 #include "vm/heap.h" 20 #include "vm/heap.h"
20 #include "vm/isolate.h" 21 #include "vm/isolate.h"
21 #include "vm/longjump.h" 22 #include "vm/longjump.h"
22 #include "vm/native_arguments.h" 23 #include "vm/native_arguments.h"
23 #include "vm/native_entry.h" 24 #include "vm/native_entry.h"
24 #include "vm/object.h" 25 #include "vm/object.h"
25 #include "vm/object_store.h" 26 #include "vm/object_store.h"
26 #include "vm/os.h" 27 #include "vm/os.h"
27 #include "vm/regexp_assembler.h" 28 #include "vm/regexp_assembler.h"
28 #include "vm/report.h" 29 #include "vm/report.h"
(...skipping 11849 matching lines...) Expand 10 before | Expand all | Expand 10 after
11878 bool Parser::IsInstantiatorRequired() const { 11879 bool Parser::IsInstantiatorRequired() const {
11879 ASSERT(!current_function().IsNull()); 11880 ASSERT(!current_function().IsNull());
11880 if (current_function().is_static() && 11881 if (current_function().is_static() &&
11881 !current_function().IsInFactoryScope()) { 11882 !current_function().IsInFactoryScope()) {
11882 return false; 11883 return false;
11883 } 11884 }
11884 return current_class().NumTypeParameters() > 0; 11885 return current_class().NumTypeParameters() > 0;
11885 } 11886 }
11886 11887
11887 11888
11889 class ConstMapKeyEqualsTraits {
11890 public:
11891 static bool IsMatch(const Object& a, const Object& b) {
11892 return String::Cast(a).Equals(String::Cast(b));
11893 }
11894 static uword Hash(const Object& obj) {
11895 return String::Cast(obj).Hash();
11896 }
11897 };
11898 typedef UnorderedHashMap<ConstMapKeyEqualsTraits> ConstantsMap;
11899
11900
11901 static void BuildConstMapKey(const Script& script,
11902 intptr_t token_pos,
11903 String* key) {
11904 *key = script.url();
11905 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
11906 *key = Symbols::FromConcat(*key, suffix);
11907 }
11908
11909
11910 void Parser::CacheConstantValue(intptr_t token_pos, const Instance& value) {
11911 String& key = String::Handle();
koda 2015/08/25 18:27:12 Handle(Z)
hausner 2015/08/25 19:48:51 Done.
11912 BuildConstMapKey(script_, token_pos, &key);
11913 if (isolate()->object_store()->compile_time_constants() == Array::null()) {
11914 const intptr_t kInitialConstMapSize = 16;
11915 isolate()->object_store()->set_compile_time_constants(
11916 Array::Handle(Z, HashTables::New<ConstantsMap>(kInitialConstMapSize)));
srdjan 2015/08/25 22:16:19 It does not matter for optimizing compiler (since
11917 }
11918 ConstantsMap constants(isolate()->object_store()->compile_time_constants());
11919 constants.UpdateOrInsert(key, value);
11920 if (FLAG_compiler_stats) {
11921 isolate_->compiler_stats()->num_cached_consts = constants.NumOccupied();
11922 }
11923 isolate()->object_store()->set_compile_time_constants(constants.Release());
11924 }
11925
11926
11927 bool Parser::GetCachedConstant(intptr_t token_pos, Instance* value) {
11928 if (isolate()->object_store()->compile_time_constants() == Array::null()) {
11929 return false;
11930 }
11931 String& key = String::Handle();
koda 2015/08/25 18:27:12 Handle(Z)
hausner 2015/08/25 19:48:52 Done.
11932 BuildConstMapKey(script_, token_pos, &key);
11933 ConstantsMap constants(isolate()->object_store()->compile_time_constants());
11934 bool is_present = false;
11935 *value ^= constants.GetOrNull(key, &is_present);
11936 ASSERT(constants.Release().raw() ==
11937 isolate()->object_store()->compile_time_constants());
11938 if (FLAG_compiler_stats && is_present) {
11939 isolate_->compiler_stats()->num_const_cache_hits++;
11940 }
11941 return is_present;
11942 }
11943
11944
11888 RawInstance* Parser::TryCanonicalize(const Instance& instance, 11945 RawInstance* Parser::TryCanonicalize(const Instance& instance,
11889 intptr_t token_pos) { 11946 intptr_t token_pos) {
11890 if (instance.IsNull()) { 11947 if (instance.IsNull()) {
11891 return instance.raw(); 11948 return instance.raw();
11892 } 11949 }
11893 const char* error_str = NULL; 11950 const char* error_str = NULL;
11894 Instance& result = 11951 Instance& result =
11895 Instance::Handle(Z, instance.CheckAndCanonicalize(&error_str)); 11952 Instance::Handle(Z, instance.CheckAndCanonicalize(&error_str));
11896 if (result.IsNull()) { 11953 if (result.IsNull()) {
11897 ReportError(token_pos, "Invalid const object %s", error_str); 11954 ReportError(token_pos, "Invalid const object %s", error_str);
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after
12500 // Note: if the list literal is empty and the brackets have no whitespace 12557 // Note: if the list literal is empty and the brackets have no whitespace
12501 // between them, the scanner recognizes the opening and closing bracket 12558 // between them, the scanner recognizes the opening and closing bracket
12502 // as one token of type Token::kINDEX. 12559 // as one token of type Token::kINDEX.
12503 AstNode* Parser::ParseListLiteral(intptr_t type_pos, 12560 AstNode* Parser::ParseListLiteral(intptr_t type_pos,
12504 bool is_const, 12561 bool is_const,
12505 const TypeArguments& type_arguments) { 12562 const TypeArguments& type_arguments) {
12506 TRACE_PARSER("ParseListLiteral"); 12563 TRACE_PARSER("ParseListLiteral");
12507 ASSERT(type_pos >= 0); 12564 ASSERT(type_pos >= 0);
12508 ASSERT(CurrentToken() == Token::kLBRACK || CurrentToken() == Token::kINDEX); 12565 ASSERT(CurrentToken() == Token::kLBRACK || CurrentToken() == Token::kINDEX);
12509 const intptr_t literal_pos = TokenPos(); 12566 const intptr_t literal_pos = TokenPos();
12567
12568 if (is_const) {
12569 Instance& existing_const = Instance::ZoneHandle(Z);
12570 if (GetCachedConstant(literal_pos, &existing_const)) {
12571 SkipListLiteral();
12572 return new(Z) LiteralNode(literal_pos, existing_const);
12573 }
12574 }
12575
12510 bool is_empty_literal = CurrentToken() == Token::kINDEX; 12576 bool is_empty_literal = CurrentToken() == Token::kINDEX;
12511 ConsumeToken(); 12577 ConsumeToken();
12512 12578
12513 AbstractType& element_type = Type::ZoneHandle(Z, Type::DynamicType()); 12579 AbstractType& element_type = Type::ZoneHandle(Z, Type::DynamicType());
12514 TypeArguments& list_type_arguments = 12580 TypeArguments& list_type_arguments =
12515 TypeArguments::ZoneHandle(Z, type_arguments.raw()); 12581 TypeArguments::ZoneHandle(Z, type_arguments.raw());
12516 // If no type argument vector is provided, leave it as null, which is 12582 // If no type argument vector is provided, leave it as null, which is
12517 // equivalent to using dynamic as the type argument for the element type. 12583 // equivalent to using dynamic as the type argument for the element type.
12518 if (!list_type_arguments.IsNull()) { 12584 if (!list_type_arguments.IsNull()) {
12519 ASSERT(list_type_arguments.Length() > 0); 12585 ASSERT(list_type_arguments.Length() > 0);
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
12567 } else if (CurrentToken() != Token::kRBRACK) { 12633 } else if (CurrentToken() != Token::kRBRACK) {
12568 ReportError("comma or ']' expected"); 12634 ReportError("comma or ']' expected");
12569 } 12635 }
12570 } 12636 }
12571 ExpectToken(Token::kRBRACK); 12637 ExpectToken(Token::kRBRACK);
12572 SetAllowFunctionLiterals(saved_mode); 12638 SetAllowFunctionLiterals(saved_mode);
12573 } 12639 }
12574 12640
12575 if (is_const) { 12641 if (is_const) {
12576 // Allocate and initialize the const list at compile time. 12642 // Allocate and initialize the const list at compile time.
12577 Array& const_list = 12643 Array& const_list = Array::ZoneHandle(Z,
12578 Array::ZoneHandle(Z, Array::New(element_list.length(), Heap::kOld)); 12644 Array::New(element_list.length(), Heap::kOld));
12579 const_list.SetTypeArguments( 12645 const_list.SetTypeArguments(
12580 TypeArguments::Handle(Z, list_type_arguments.Canonicalize())); 12646 TypeArguments::Handle(Z, list_type_arguments.Canonicalize()));
12581 Error& malformed_error = Error::Handle(Z); 12647 Error& malformed_error = Error::Handle(Z);
12582 for (int i = 0; i < element_list.length(); i++) { 12648 for (int i = 0; i < element_list.length(); i++) {
12583 AstNode* elem = element_list[i]; 12649 AstNode* elem = element_list[i];
12584 // Arguments have been evaluated to a literal value already. 12650 // Arguments have been evaluated to a literal value already.
12585 ASSERT(elem->IsLiteralNode()); 12651 ASSERT(elem->IsLiteralNode());
12586 ASSERT(!is_top_level_); // We cannot check unresolved types. 12652 ASSERT(!is_top_level_); // We cannot check unresolved types.
12587 if (I->flags().type_checks() && 12653 if (I->flags().type_checks() &&
12588 !element_type.IsDynamicType() && 12654 !element_type.IsDynamicType() &&
(...skipping 11 matching lines...) Expand all
12600 "a constant of type '%s'", 12666 "a constant of type '%s'",
12601 i, 12667 i,
12602 String::Handle(Z, 12668 String::Handle(Z,
12603 element_type.UserVisibleName()).ToCString()); 12669 element_type.UserVisibleName()).ToCString());
12604 } 12670 }
12605 } 12671 }
12606 const_list.SetAt(i, elem->AsLiteralNode()->literal()); 12672 const_list.SetAt(i, elem->AsLiteralNode()->literal());
12607 } 12673 }
12608 const_list.MakeImmutable(); 12674 const_list.MakeImmutable();
12609 const_list ^= TryCanonicalize(const_list, literal_pos); 12675 const_list ^= TryCanonicalize(const_list, literal_pos);
12676 CacheConstantValue(literal_pos, const_list);
12610 return new(Z) LiteralNode(literal_pos, const_list); 12677 return new(Z) LiteralNode(literal_pos, const_list);
12611 } else { 12678 } else {
12612 // Factory call at runtime. 12679 // Factory call at runtime.
12613 const Class& factory_class = 12680 const Class& factory_class =
12614 Class::Handle(Z, Library::LookupCoreClass(Symbols::List())); 12681 Class::Handle(Z, Library::LookupCoreClass(Symbols::List()));
12615 ASSERT(!factory_class.IsNull()); 12682 ASSERT(!factory_class.IsNull());
12616 const Function& factory_method = Function::ZoneHandle(Z, 12683 const Function& factory_method = Function::ZoneHandle(Z,
12617 factory_class.LookupFactory( 12684 factory_class.LookupFactory(
12618 Library::PrivateCoreLibName(Symbols::ListLiteralFactory()))); 12685 Library::PrivateCoreLibName(Symbols::ListLiteralFactory())));
12619 ASSERT(!factory_method.IsNull()); 12686 ASSERT(!factory_method.IsNull());
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
12693 } 12760 }
12694 12761
12695 12762
12696 AstNode* Parser::ParseMapLiteral(intptr_t type_pos, 12763 AstNode* Parser::ParseMapLiteral(intptr_t type_pos,
12697 bool is_const, 12764 bool is_const,
12698 const TypeArguments& type_arguments) { 12765 const TypeArguments& type_arguments) {
12699 TRACE_PARSER("ParseMapLiteral"); 12766 TRACE_PARSER("ParseMapLiteral");
12700 ASSERT(type_pos >= 0); 12767 ASSERT(type_pos >= 0);
12701 ASSERT(CurrentToken() == Token::kLBRACE); 12768 ASSERT(CurrentToken() == Token::kLBRACE);
12702 const intptr_t literal_pos = TokenPos(); 12769 const intptr_t literal_pos = TokenPos();
12703 ConsumeToken();
12704 12770
12771 if (is_const) {
12772 Instance& existing_const = Instance::ZoneHandle(Z);
12773 if (GetCachedConstant(literal_pos, &existing_const)) {
12774 SkipMapLiteral();
12775 return new(Z) LiteralNode(literal_pos, existing_const);
12776 }
12777 }
12778
12779 ConsumeToken(); // Opening brace.
12705 AbstractType& key_type = Type::ZoneHandle(Z, Type::DynamicType()); 12780 AbstractType& key_type = Type::ZoneHandle(Z, Type::DynamicType());
12706 AbstractType& value_type = Type::ZoneHandle(Z, Type::DynamicType()); 12781 AbstractType& value_type = Type::ZoneHandle(Z, Type::DynamicType());
12707 TypeArguments& map_type_arguments = 12782 TypeArguments& map_type_arguments =
12708 TypeArguments::ZoneHandle(Z, type_arguments.raw()); 12783 TypeArguments::ZoneHandle(Z, type_arguments.raw());
12709 // If no type argument vector is provided, leave it as null, which is 12784 // If no type argument vector is provided, leave it as null, which is
12710 // equivalent to using dynamic as the type argument for the both key and value 12785 // equivalent to using dynamic as the type argument for the both key and value
12711 // types. 12786 // types.
12712 if (!map_type_arguments.IsNull()) { 12787 if (!map_type_arguments.IsNull()) {
12713 ASSERT(map_type_arguments.Length() > 0); 12788 ASSERT(map_type_arguments.Length() > 0);
12714 // Map literals take two type arguments. 12789 // Map literals take two type arguments.
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
12851 EvaluateConstConstructorCall(immutable_map_class, 12926 EvaluateConstConstructorCall(immutable_map_class,
12852 map_type_arguments, 12927 map_type_arguments,
12853 map_constr, 12928 map_constr,
12854 constr_args)); 12929 constr_args));
12855 if (constructor_result.IsUnhandledException()) { 12930 if (constructor_result.IsUnhandledException()) {
12856 ReportErrors(Error::Cast(constructor_result), 12931 ReportErrors(Error::Cast(constructor_result),
12857 script_, literal_pos, 12932 script_, literal_pos,
12858 "error executing const Map constructor"); 12933 "error executing const Map constructor");
12859 } else { 12934 } else {
12860 const Instance& const_instance = Instance::Cast(constructor_result); 12935 const Instance& const_instance = Instance::Cast(constructor_result);
12936 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
12861 return new(Z) LiteralNode( 12937 return new(Z) LiteralNode(
12862 literal_pos, Instance::ZoneHandle(Z, const_instance.raw())); 12938 literal_pos, Instance::ZoneHandle(Z, const_instance.raw()));
12863 } 12939 }
12864 } else { 12940 } else {
12865 // Factory call at runtime. 12941 // Factory call at runtime.
12866 const Class& factory_class = 12942 const Class& factory_class =
12867 Class::Handle(Z, Library::LookupCoreClass(Symbols::Map())); 12943 Class::Handle(Z, Library::LookupCoreClass(Symbols::Map()));
12868 ASSERT(!factory_class.IsNull()); 12944 ASSERT(!factory_class.IsNull());
12869 const Function& factory_method = Function::ZoneHandle(Z, 12945 const Function& factory_method = Function::ZoneHandle(Z,
12870 factory_class.LookupFactory( 12946 factory_class.LookupFactory(
(...skipping 523 matching lines...) Expand 10 before | Expand all | Expand 10 after
13394 // Make the constructor call. 13470 // Make the constructor call.
13395 AstNode* new_object = NULL; 13471 AstNode* new_object = NULL;
13396 if (is_const) { 13472 if (is_const) {
13397 if (!constructor.is_const()) { 13473 if (!constructor.is_const()) {
13398 const String& external_constructor_name = 13474 const String& external_constructor_name =
13399 (named_constructor ? constructor_name : type_class_name); 13475 (named_constructor ? constructor_name : type_class_name);
13400 ReportError("non-const constructor '%s' cannot be used in " 13476 ReportError("non-const constructor '%s' cannot be used in "
13401 "const object creation", 13477 "const object creation",
13402 external_constructor_name.ToCString()); 13478 external_constructor_name.ToCString());
13403 } 13479 }
13404 const Object& constructor_result = Object::Handle(Z, 13480
13405 EvaluateConstConstructorCall(type_class, 13481 Instance& const_instance = Instance::ZoneHandle(Z);
13406 type_arguments, 13482 if (GetCachedConstant(new_pos, &const_instance)) {
13407 constructor, 13483 // Cache hit, nothing else to do.
13408 arguments));
13409 if (constructor_result.IsUnhandledException()) {
13410 // It's a compile-time error if invocation of a const constructor
13411 // call fails.
13412 ReportErrors(Error::Cast(constructor_result),
13413 script_, new_pos,
13414 "error while evaluating const constructor");
13415 } else { 13484 } else {
13416 // Const constructors can return null in the case where a const native 13485 Object& constructor_result = Object::Handle(Z,
13417 // factory returns a null value. Thus we cannot use a Instance::Cast here. 13486 EvaluateConstConstructorCall(type_class,
13418 Instance& const_instance = Instance::Handle(Z); 13487 type_arguments,
13488 constructor,
13489 arguments));
13490 if (constructor_result.IsUnhandledException()) {
13491 // It's a compile-time error if invocation of a const constructor
13492 // call fails.
13493 ReportErrors(Error::Cast(constructor_result),
13494 script_, new_pos,
13495 "error while evaluating const constructor");
13496 }
13419 const_instance ^= constructor_result.raw(); 13497 const_instance ^= constructor_result.raw();
13420 new_object = new(Z) LiteralNode( 13498 CacheConstantValue(new_pos, const_instance);
13421 new_pos, Instance::ZoneHandle(Z, const_instance.raw())); 13499 }
13422 if (!type_bound.IsNull()) { 13500 new_object = new(Z) LiteralNode(new_pos, const_instance);
13423 ASSERT(!type_bound.IsMalformed()); 13501 if (!type_bound.IsNull()) {
13424 Error& malformed_error = Error::Handle(Z); 13502 ASSERT(!type_bound.IsMalformed());
13425 ASSERT(!is_top_level_); // We cannot check unresolved types. 13503 Error& malformed_error = Error::Handle(Z);
13426 if (!const_instance.IsInstanceOf(type_bound, 13504 ASSERT(!is_top_level_); // We cannot check unresolved types.
13427 TypeArguments::Handle(Z), 13505 if (!const_instance.IsInstanceOf(type_bound,
13428 &malformed_error)) { 13506 TypeArguments::Handle(Z),
13429 type_bound = ClassFinalizer::NewFinalizedMalformedType( 13507 &malformed_error)) {
13430 malformed_error, 13508 type_bound = ClassFinalizer::NewFinalizedMalformedType(
13431 script_, 13509 malformed_error,
13432 new_pos, 13510 script_,
13433 "const factory result is not an instance of '%s'", 13511 new_pos,
13434 String::Handle(Z, type_bound.UserVisibleName()).ToCString()); 13512 "const factory result is not an instance of '%s'",
13435 new_object = ThrowTypeError(new_pos, type_bound); 13513 String::Handle(Z, type_bound.UserVisibleName()).ToCString());
13436 } 13514 new_object = ThrowTypeError(new_pos, type_bound);
13437 type_bound = AbstractType::null();
13438 } 13515 }
13516 type_bound = AbstractType::null();
13439 } 13517 }
13440 } else { 13518 } else {
13441 CheckConstructorCallTypeArguments(new_pos, constructor, type_arguments); 13519 CheckConstructorCallTypeArguments(new_pos, constructor, type_arguments);
13442 if (!type_arguments.IsNull() && 13520 if (!type_arguments.IsNull() &&
13443 !type_arguments.IsInstantiated() && 13521 !type_arguments.IsInstantiated() &&
13444 (current_block_->scope->function_level() > 0)) { 13522 (current_block_->scope->function_level() > 0)) {
13445 // Make sure that the instantiator is captured. 13523 // Make sure that the instantiator is captured.
13446 CaptureInstantiator(); 13524 CaptureInstantiator();
13447 } 13525 }
13448 // If the type argument vector is not instantiated, we verify in checked 13526 // If the type argument vector is not instantiated, we verify in checked
(...skipping 738 matching lines...) Expand 10 before | Expand all | Expand 10 after
14187 void Parser::SkipQualIdent() { 14265 void Parser::SkipQualIdent() {
14188 ASSERT(IsIdentifier()); 14266 ASSERT(IsIdentifier());
14189 ConsumeToken(); 14267 ConsumeToken();
14190 if (CurrentToken() == Token::kPERIOD) { 14268 if (CurrentToken() == Token::kPERIOD) {
14191 ConsumeToken(); // Consume the kPERIOD token. 14269 ConsumeToken(); // Consume the kPERIOD token.
14192 ExpectIdentifier("identifier expected after '.'"); 14270 ExpectIdentifier("identifier expected after '.'");
14193 } 14271 }
14194 } 14272 }
14195 14273
14196 } // namespace dart 14274 } // namespace dart
OLDNEW
« 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