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

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: Addressing review comments Created 5 years, 3 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 bool IsMatch(const char* key, const Object& b) {
11895 return String::Cast(b).Equals(key);
11896 }
11897 static uword Hash(const Object& obj) {
11898 return String::Cast(obj).Hash();
11899 }
11900 static uword Hash(const char* key) {
11901 return String::Hash(key, strlen(key));
11902 }
11903 };
11904 typedef UnorderedHashMap<ConstMapKeyEqualsTraits> ConstantsMap;
11905
11906
11907 void Parser::CacheConstantValue(intptr_t token_pos, const Instance& value) {
11908 String& key = String::Handle(Z, script_.url());
11909 String& suffix =
11910 String::Handle(Z, String::NewFormatted("_%" Pd "", token_pos));
11911 key = Symbols::FromConcat(key, suffix);
11912 if (isolate()->object_store()->compile_time_constants() == Array::null()) {
11913 const intptr_t kInitialConstMapSize = 16;
11914 isolate()->object_store()->set_compile_time_constants(
11915 Array::Handle(Z, HashTables::New<ConstantsMap>(kInitialConstMapSize)));
11916 }
11917 ConstantsMap constants(isolate()->object_store()->compile_time_constants());
11918 constants.UpdateOrInsert(key, value);
11919 if (FLAG_compiler_stats) {
11920 isolate_->compiler_stats()->num_cached_consts = constants.NumOccupied();
11921 }
11922 isolate()->object_store()->set_compile_time_constants(constants.Release());
11923 }
11924
11925
11926 bool Parser::GetCachedConstant(intptr_t token_pos, Instance* value) {
11927 if (isolate()->object_store()->compile_time_constants() == Array::null()) {
11928 return false;
11929 }
11930 // We don't want to allocate anything in the heap here since this code
11931 // is called from the optimizing compiler in the background thread. Allocate
11932 // the key value in the zone instead.
11933 const char* key = Z->PrintToString("%s_%" Pd "",
11934 String::Handle(Z, script_.url()).ToCString(),
11935 token_pos);
11936 ConstantsMap constants(isolate()->object_store()->compile_time_constants());
11937 bool is_present = false;
11938 *value ^= constants.GetOrNull<const char *>(key, &is_present);
11939 ASSERT(constants.Release().raw() ==
11940 isolate()->object_store()->compile_time_constants());
11941 if (FLAG_compiler_stats && is_present) {
11942 isolate_->compiler_stats()->num_const_cache_hits++;
11943 }
11944 return is_present;
11945 }
11946
11947
11888 RawInstance* Parser::TryCanonicalize(const Instance& instance, 11948 RawInstance* Parser::TryCanonicalize(const Instance& instance,
11889 intptr_t token_pos) { 11949 intptr_t token_pos) {
11890 if (instance.IsNull()) { 11950 if (instance.IsNull()) {
11891 return instance.raw(); 11951 return instance.raw();
11892 } 11952 }
11893 const char* error_str = NULL; 11953 const char* error_str = NULL;
11894 Instance& result = 11954 Instance& result =
11895 Instance::Handle(Z, instance.CheckAndCanonicalize(&error_str)); 11955 Instance::Handle(Z, instance.CheckAndCanonicalize(&error_str));
11896 if (result.IsNull()) { 11956 if (result.IsNull()) {
11897 ReportError(token_pos, "Invalid const object %s", error_str); 11957 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 12560 // Note: if the list literal is empty and the brackets have no whitespace
12501 // between them, the scanner recognizes the opening and closing bracket 12561 // between them, the scanner recognizes the opening and closing bracket
12502 // as one token of type Token::kINDEX. 12562 // as one token of type Token::kINDEX.
12503 AstNode* Parser::ParseListLiteral(intptr_t type_pos, 12563 AstNode* Parser::ParseListLiteral(intptr_t type_pos,
12504 bool is_const, 12564 bool is_const,
12505 const TypeArguments& type_arguments) { 12565 const TypeArguments& type_arguments) {
12506 TRACE_PARSER("ParseListLiteral"); 12566 TRACE_PARSER("ParseListLiteral");
12507 ASSERT(type_pos >= 0); 12567 ASSERT(type_pos >= 0);
12508 ASSERT(CurrentToken() == Token::kLBRACK || CurrentToken() == Token::kINDEX); 12568 ASSERT(CurrentToken() == Token::kLBRACK || CurrentToken() == Token::kINDEX);
12509 const intptr_t literal_pos = TokenPos(); 12569 const intptr_t literal_pos = TokenPos();
12570
12571 if (is_const) {
12572 Instance& existing_const = Instance::ZoneHandle(Z);
12573 if (GetCachedConstant(literal_pos, &existing_const)) {
12574 SkipListLiteral();
12575 return new(Z) LiteralNode(literal_pos, existing_const);
12576 }
12577 }
12578
12510 bool is_empty_literal = CurrentToken() == Token::kINDEX; 12579 bool is_empty_literal = CurrentToken() == Token::kINDEX;
12511 ConsumeToken(); 12580 ConsumeToken();
12512 12581
12513 AbstractType& element_type = Type::ZoneHandle(Z, Type::DynamicType()); 12582 AbstractType& element_type = Type::ZoneHandle(Z, Type::DynamicType());
12514 TypeArguments& list_type_arguments = 12583 TypeArguments& list_type_arguments =
12515 TypeArguments::ZoneHandle(Z, type_arguments.raw()); 12584 TypeArguments::ZoneHandle(Z, type_arguments.raw());
12516 // If no type argument vector is provided, leave it as null, which is 12585 // 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. 12586 // equivalent to using dynamic as the type argument for the element type.
12518 if (!list_type_arguments.IsNull()) { 12587 if (!list_type_arguments.IsNull()) {
12519 ASSERT(list_type_arguments.Length() > 0); 12588 ASSERT(list_type_arguments.Length() > 0);
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
12567 } else if (CurrentToken() != Token::kRBRACK) { 12636 } else if (CurrentToken() != Token::kRBRACK) {
12568 ReportError("comma or ']' expected"); 12637 ReportError("comma or ']' expected");
12569 } 12638 }
12570 } 12639 }
12571 ExpectToken(Token::kRBRACK); 12640 ExpectToken(Token::kRBRACK);
12572 SetAllowFunctionLiterals(saved_mode); 12641 SetAllowFunctionLiterals(saved_mode);
12573 } 12642 }
12574 12643
12575 if (is_const) { 12644 if (is_const) {
12576 // Allocate and initialize the const list at compile time. 12645 // Allocate and initialize the const list at compile time.
12577 Array& const_list = 12646 Array& const_list = Array::ZoneHandle(Z,
12578 Array::ZoneHandle(Z, Array::New(element_list.length(), Heap::kOld)); 12647 Array::New(element_list.length(), Heap::kOld));
12579 const_list.SetTypeArguments( 12648 const_list.SetTypeArguments(
12580 TypeArguments::Handle(Z, list_type_arguments.Canonicalize())); 12649 TypeArguments::Handle(Z, list_type_arguments.Canonicalize()));
12581 Error& malformed_error = Error::Handle(Z); 12650 Error& malformed_error = Error::Handle(Z);
12582 for (int i = 0; i < element_list.length(); i++) { 12651 for (int i = 0; i < element_list.length(); i++) {
12583 AstNode* elem = element_list[i]; 12652 AstNode* elem = element_list[i];
12584 // Arguments have been evaluated to a literal value already. 12653 // Arguments have been evaluated to a literal value already.
12585 ASSERT(elem->IsLiteralNode()); 12654 ASSERT(elem->IsLiteralNode());
12586 ASSERT(!is_top_level_); // We cannot check unresolved types. 12655 ASSERT(!is_top_level_); // We cannot check unresolved types.
12587 if (I->flags().type_checks() && 12656 if (I->flags().type_checks() &&
12588 !element_type.IsDynamicType() && 12657 !element_type.IsDynamicType() &&
(...skipping 11 matching lines...) Expand all
12600 "a constant of type '%s'", 12669 "a constant of type '%s'",
12601 i, 12670 i,
12602 String::Handle(Z, 12671 String::Handle(Z,
12603 element_type.UserVisibleName()).ToCString()); 12672 element_type.UserVisibleName()).ToCString());
12604 } 12673 }
12605 } 12674 }
12606 const_list.SetAt(i, elem->AsLiteralNode()->literal()); 12675 const_list.SetAt(i, elem->AsLiteralNode()->literal());
12607 } 12676 }
12608 const_list.MakeImmutable(); 12677 const_list.MakeImmutable();
12609 const_list ^= TryCanonicalize(const_list, literal_pos); 12678 const_list ^= TryCanonicalize(const_list, literal_pos);
12679 CacheConstantValue(literal_pos, const_list);
12610 return new(Z) LiteralNode(literal_pos, const_list); 12680 return new(Z) LiteralNode(literal_pos, const_list);
12611 } else { 12681 } else {
12612 // Factory call at runtime. 12682 // Factory call at runtime.
12613 const Class& factory_class = 12683 const Class& factory_class =
12614 Class::Handle(Z, Library::LookupCoreClass(Symbols::List())); 12684 Class::Handle(Z, Library::LookupCoreClass(Symbols::List()));
12615 ASSERT(!factory_class.IsNull()); 12685 ASSERT(!factory_class.IsNull());
12616 const Function& factory_method = Function::ZoneHandle(Z, 12686 const Function& factory_method = Function::ZoneHandle(Z,
12617 factory_class.LookupFactory( 12687 factory_class.LookupFactory(
12618 Library::PrivateCoreLibName(Symbols::ListLiteralFactory()))); 12688 Library::PrivateCoreLibName(Symbols::ListLiteralFactory())));
12619 ASSERT(!factory_method.IsNull()); 12689 ASSERT(!factory_method.IsNull());
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
12693 } 12763 }
12694 12764
12695 12765
12696 AstNode* Parser::ParseMapLiteral(intptr_t type_pos, 12766 AstNode* Parser::ParseMapLiteral(intptr_t type_pos,
12697 bool is_const, 12767 bool is_const,
12698 const TypeArguments& type_arguments) { 12768 const TypeArguments& type_arguments) {
12699 TRACE_PARSER("ParseMapLiteral"); 12769 TRACE_PARSER("ParseMapLiteral");
12700 ASSERT(type_pos >= 0); 12770 ASSERT(type_pos >= 0);
12701 ASSERT(CurrentToken() == Token::kLBRACE); 12771 ASSERT(CurrentToken() == Token::kLBRACE);
12702 const intptr_t literal_pos = TokenPos(); 12772 const intptr_t literal_pos = TokenPos();
12703 ConsumeToken();
12704 12773
12774 if (is_const) {
12775 Instance& existing_const = Instance::ZoneHandle(Z);
12776 if (GetCachedConstant(literal_pos, &existing_const)) {
12777 SkipMapLiteral();
12778 return new(Z) LiteralNode(literal_pos, existing_const);
12779 }
12780 }
12781
12782 ConsumeToken(); // Opening brace.
12705 AbstractType& key_type = Type::ZoneHandle(Z, Type::DynamicType()); 12783 AbstractType& key_type = Type::ZoneHandle(Z, Type::DynamicType());
12706 AbstractType& value_type = Type::ZoneHandle(Z, Type::DynamicType()); 12784 AbstractType& value_type = Type::ZoneHandle(Z, Type::DynamicType());
12707 TypeArguments& map_type_arguments = 12785 TypeArguments& map_type_arguments =
12708 TypeArguments::ZoneHandle(Z, type_arguments.raw()); 12786 TypeArguments::ZoneHandle(Z, type_arguments.raw());
12709 // If no type argument vector is provided, leave it as null, which is 12787 // 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 12788 // equivalent to using dynamic as the type argument for the both key and value
12711 // types. 12789 // types.
12712 if (!map_type_arguments.IsNull()) { 12790 if (!map_type_arguments.IsNull()) {
12713 ASSERT(map_type_arguments.Length() > 0); 12791 ASSERT(map_type_arguments.Length() > 0);
12714 // Map literals take two type arguments. 12792 // Map literals take two type arguments.
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
12851 EvaluateConstConstructorCall(immutable_map_class, 12929 EvaluateConstConstructorCall(immutable_map_class,
12852 map_type_arguments, 12930 map_type_arguments,
12853 map_constr, 12931 map_constr,
12854 constr_args)); 12932 constr_args));
12855 if (constructor_result.IsUnhandledException()) { 12933 if (constructor_result.IsUnhandledException()) {
12856 ReportErrors(Error::Cast(constructor_result), 12934 ReportErrors(Error::Cast(constructor_result),
12857 script_, literal_pos, 12935 script_, literal_pos,
12858 "error executing const Map constructor"); 12936 "error executing const Map constructor");
12859 } else { 12937 } else {
12860 const Instance& const_instance = Instance::Cast(constructor_result); 12938 const Instance& const_instance = Instance::Cast(constructor_result);
12939 CacheConstantValue(literal_pos, const_instance);
12861 return new(Z) LiteralNode( 12940 return new(Z) LiteralNode(
12862 literal_pos, Instance::ZoneHandle(Z, const_instance.raw())); 12941 literal_pos, Instance::ZoneHandle(Z, const_instance.raw()));
12863 } 12942 }
12864 } else { 12943 } else {
12865 // Factory call at runtime. 12944 // Factory call at runtime.
12866 const Class& factory_class = 12945 const Class& factory_class =
12867 Class::Handle(Z, Library::LookupCoreClass(Symbols::Map())); 12946 Class::Handle(Z, Library::LookupCoreClass(Symbols::Map()));
12868 ASSERT(!factory_class.IsNull()); 12947 ASSERT(!factory_class.IsNull());
12869 const Function& factory_method = Function::ZoneHandle(Z, 12948 const Function& factory_method = Function::ZoneHandle(Z,
12870 factory_class.LookupFactory( 12949 factory_class.LookupFactory(
(...skipping 523 matching lines...) Expand 10 before | Expand all | Expand 10 after
13394 // Make the constructor call. 13473 // Make the constructor call.
13395 AstNode* new_object = NULL; 13474 AstNode* new_object = NULL;
13396 if (is_const) { 13475 if (is_const) {
13397 if (!constructor.is_const()) { 13476 if (!constructor.is_const()) {
13398 const String& external_constructor_name = 13477 const String& external_constructor_name =
13399 (named_constructor ? constructor_name : type_class_name); 13478 (named_constructor ? constructor_name : type_class_name);
13400 ReportError("non-const constructor '%s' cannot be used in " 13479 ReportError("non-const constructor '%s' cannot be used in "
13401 "const object creation", 13480 "const object creation",
13402 external_constructor_name.ToCString()); 13481 external_constructor_name.ToCString());
13403 } 13482 }
13404 const Object& constructor_result = Object::Handle(Z, 13483
13405 EvaluateConstConstructorCall(type_class, 13484 Instance& const_instance = Instance::ZoneHandle(Z);
13406 type_arguments, 13485 if (GetCachedConstant(new_pos, &const_instance)) {
13407 constructor, 13486 // 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 { 13487 } else {
13416 // Const constructors can return null in the case where a const native 13488 Object& constructor_result = Object::Handle(Z,
13417 // factory returns a null value. Thus we cannot use a Instance::Cast here. 13489 EvaluateConstConstructorCall(type_class,
13418 Instance& const_instance = Instance::Handle(Z); 13490 type_arguments,
13491 constructor,
13492 arguments));
13493 if (constructor_result.IsUnhandledException()) {
13494 // It's a compile-time error if invocation of a const constructor
13495 // call fails.
13496 ReportErrors(Error::Cast(constructor_result),
13497 script_, new_pos,
13498 "error while evaluating const constructor");
13499 }
13419 const_instance ^= constructor_result.raw(); 13500 const_instance ^= constructor_result.raw();
13420 new_object = new(Z) LiteralNode( 13501 CacheConstantValue(new_pos, const_instance);
13421 new_pos, Instance::ZoneHandle(Z, const_instance.raw())); 13502 }
13422 if (!type_bound.IsNull()) { 13503 new_object = new(Z) LiteralNode(new_pos, const_instance);
13423 ASSERT(!type_bound.IsMalformed()); 13504 if (!type_bound.IsNull()) {
13424 Error& malformed_error = Error::Handle(Z); 13505 ASSERT(!type_bound.IsMalformed());
13425 ASSERT(!is_top_level_); // We cannot check unresolved types. 13506 Error& malformed_error = Error::Handle(Z);
13426 if (!const_instance.IsInstanceOf(type_bound, 13507 ASSERT(!is_top_level_); // We cannot check unresolved types.
13427 TypeArguments::Handle(Z), 13508 if (!const_instance.IsInstanceOf(type_bound,
13428 &malformed_error)) { 13509 TypeArguments::Handle(Z),
13429 type_bound = ClassFinalizer::NewFinalizedMalformedType( 13510 &malformed_error)) {
13430 malformed_error, 13511 type_bound = ClassFinalizer::NewFinalizedMalformedType(
13431 script_, 13512 malformed_error,
13432 new_pos, 13513 script_,
13433 "const factory result is not an instance of '%s'", 13514 new_pos,
13434 String::Handle(Z, type_bound.UserVisibleName()).ToCString()); 13515 "const factory result is not an instance of '%s'",
13435 new_object = ThrowTypeError(new_pos, type_bound); 13516 String::Handle(Z, type_bound.UserVisibleName()).ToCString());
13436 } 13517 new_object = ThrowTypeError(new_pos, type_bound);
13437 type_bound = AbstractType::null();
13438 } 13518 }
13519 type_bound = AbstractType::null();
13439 } 13520 }
13440 } else { 13521 } else {
13441 CheckConstructorCallTypeArguments(new_pos, constructor, type_arguments); 13522 CheckConstructorCallTypeArguments(new_pos, constructor, type_arguments);
13442 if (!type_arguments.IsNull() && 13523 if (!type_arguments.IsNull() &&
13443 !type_arguments.IsInstantiated() && 13524 !type_arguments.IsInstantiated() &&
13444 (current_block_->scope->function_level() > 0)) { 13525 (current_block_->scope->function_level() > 0)) {
13445 // Make sure that the instantiator is captured. 13526 // Make sure that the instantiator is captured.
13446 CaptureInstantiator(); 13527 CaptureInstantiator();
13447 } 13528 }
13448 // If the type argument vector is not instantiated, we verify in checked 13529 // 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() { 14268 void Parser::SkipQualIdent() {
14188 ASSERT(IsIdentifier()); 14269 ASSERT(IsIdentifier());
14189 ConsumeToken(); 14270 ConsumeToken();
14190 if (CurrentToken() == Token::kPERIOD) { 14271 if (CurrentToken() == Token::kPERIOD) {
14191 ConsumeToken(); // Consume the kPERIOD token. 14272 ConsumeToken(); // Consume the kPERIOD token.
14192 ExpectIdentifier("identifier expected after '.'"); 14273 ExpectIdentifier("identifier expected after '.'");
14193 } 14274 }
14194 } 14275 }
14195 14276
14196 } // namespace dart 14277 } // 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