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

Side by Side Diff: runtime/vm/parser.cc

Issue 2338463003: Improve compile time constant evaluation (Closed)
Patch Set: Merge branch 'master' into ponly Created 4 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/compiler_stats.cc ('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 #include "vm/flags.h" 6 #include "vm/flags.h"
7 7
8 #ifndef DART_PRECOMPILED_RUNTIME 8 #ifndef DART_PRECOMPILED_RUNTIME
9 9
10 #include "lib/invocation_mirror.h" 10 #include "lib/invocation_mirror.h"
(...skipping 2712 matching lines...) Expand 10 before | Expand all | Expand 10 after
2723 receiver->set_invisible(false); 2723 receiver->set_invisible(false);
2724 SetAllowFunctionLiterals(saved_mode); 2724 SetAllowFunctionLiterals(saved_mode);
2725 if (current_function().is_const()) { 2725 if (current_function().is_const()) {
2726 if (!init_expr->IsPotentiallyConst()) { 2726 if (!init_expr->IsPotentiallyConst()) {
2727 ReportError(expr_pos, 2727 ReportError(expr_pos,
2728 "initializer expression must be compile time constant."); 2728 "initializer expression must be compile time constant.");
2729 } 2729 }
2730 if (init_expr->EvalConstExpr() != NULL) { 2730 if (init_expr->EvalConstExpr() != NULL) {
2731 // If the expression is a compile-time constant, ensure that it 2731 // If the expression is a compile-time constant, ensure that it
2732 // is evaluated and canonicalized. See issue 27164. 2732 // is evaluated and canonicalized. See issue 27164.
2733 Instance& const_instance = Instance::ZoneHandle(Z); 2733 init_expr = FoldConstExpr(expr_pos, init_expr);
2734 if (!GetCachedConstant(expr_pos, &const_instance)) {
2735 const_instance = EvaluateConstExpr(expr_pos, init_expr).raw();
2736 CacheConstantValue(expr_pos, const_instance);
2737 }
2738 init_expr = new(Z) LiteralNode(expr_pos, const_instance);
2739 } 2734 }
2740 } 2735 }
2741 Field& field = Field::ZoneHandle(Z, cls.LookupInstanceField(field_name)); 2736 Field& field = Field::ZoneHandle(Z, cls.LookupInstanceField(field_name));
2742 if (field.IsNull()) { 2737 if (field.IsNull()) {
2743 ReportError(field_pos, "unresolved reference to instance field '%s'", 2738 ReportError(field_pos, "unresolved reference to instance field '%s'",
2744 field_name.ToCString()); 2739 field_name.ToCString());
2745 } 2740 }
2746 EnsureExpressionTemp(); 2741 EnsureExpressionTemp();
2747 AstNode* instance = new(Z) LoadLocalNode(field_pos, receiver); 2742 AstNode* instance = new(Z) LoadLocalNode(field_pos, receiver);
2748 AstNode* initializer = CheckDuplicateFieldInit(field_pos, 2743 AstNode* initializer = CheckDuplicateFieldInit(field_pos,
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
2805 ASSERT(IsIdentifier()); 2800 ASSERT(IsIdentifier());
2806 ConsumeToken(); 2801 ConsumeToken();
2807 ExpectToken(Token::kASSIGN); 2802 ExpectToken(Token::kASSIGN);
2808 AstNode* init_expr = NULL; 2803 AstNode* init_expr = NULL;
2809 TokenPosition expr_pos = TokenPos(); 2804 TokenPosition expr_pos = TokenPos();
2810 if (field.is_const()) { 2805 if (field.is_const()) {
2811 init_expr = ParseConstExpr(); 2806 init_expr = ParseConstExpr();
2812 } else { 2807 } else {
2813 init_expr = ParseExpr(kAllowConst, kConsumeCascades); 2808 init_expr = ParseExpr(kAllowConst, kConsumeCascades);
2814 if (init_expr->EvalConstExpr() != NULL) { 2809 if (init_expr->EvalConstExpr() != NULL) {
2815 Instance& expr_value = Instance::ZoneHandle(Z); 2810 init_expr = FoldConstExpr(expr_pos, init_expr);
2816 if (!GetCachedConstant(expr_pos, &expr_value)) {
2817 expr_value = EvaluateConstExpr(expr_pos, init_expr).raw();
2818 CacheConstantValue(expr_pos, expr_value);
2819 }
2820 init_expr = new(Z) LiteralNode(field.token_pos(), expr_value);
2821 } 2811 }
2822 } 2812 }
2823 set_library(saved_library); 2813 set_library(saved_library);
2824 SetScript(saved_script, saved_token_pos); 2814 SetScript(saved_script, saved_token_pos);
2825 return init_expr; 2815 return init_expr;
2826 } 2816 }
2827 2817
2828 2818
2829 void Parser::ParseInitializedInstanceFields(const Class& cls, 2819 void Parser::ParseInitializedInstanceFields(const Class& cls,
2830 LocalVariable* receiver, 2820 LocalVariable* receiver,
(...skipping 22 matching lines...) Expand all
2853 ConsumeToken(); 2843 ConsumeToken();
2854 ExpectToken(Token::kASSIGN); 2844 ExpectToken(Token::kASSIGN);
2855 if (current_class().is_const()) { 2845 if (current_class().is_const()) {
2856 // If the class has a const contructor, the initializer 2846 // If the class has a const contructor, the initializer
2857 // expression must be a compile-time constant. 2847 // expression must be a compile-time constant.
2858 init_expr = ParseConstExpr(); 2848 init_expr = ParseConstExpr();
2859 } else { 2849 } else {
2860 TokenPosition expr_pos = TokenPos(); 2850 TokenPosition expr_pos = TokenPos();
2861 init_expr = ParseExpr(kAllowConst, kConsumeCascades); 2851 init_expr = ParseExpr(kAllowConst, kConsumeCascades);
2862 if (init_expr->EvalConstExpr() != NULL) { 2852 if (init_expr->EvalConstExpr() != NULL) {
2863 Instance& expr_value = Instance::ZoneHandle(Z); 2853 init_expr = FoldConstExpr(expr_pos, init_expr);
2864 if (!GetCachedConstant(expr_pos, &expr_value)) {
2865 expr_value = EvaluateConstExpr(expr_pos, init_expr).raw();
2866 CacheConstantValue(expr_pos, expr_value);
2867 }
2868 init_expr = new(Z) LiteralNode(field.token_pos(), expr_value);
2869 } 2854 }
2870 } 2855 }
2871 } 2856 }
2872 ASSERT(init_expr != NULL); 2857 ASSERT(init_expr != NULL);
2873 AstNode* instance = new LoadLocalNode(field.token_pos(), receiver); 2858 AstNode* instance = new LoadLocalNode(field.token_pos(), receiver);
2874 EnsureExpressionTemp(); 2859 EnsureExpressionTemp();
2875 AstNode* field_init = 2860 AstNode* field_init =
2876 new StoreInstanceFieldNode(field.token_pos(), 2861 new StoreInstanceFieldNode(field.token_pos(),
2877 instance, 2862 instance,
2878 field, 2863 field,
(...skipping 8147 matching lines...) Expand 10 before | Expand all | Expand 10 after
11026 if ((rhs_literal == NULL) && (lhs_literal != NULL)) { 11011 if ((rhs_literal == NULL) && (lhs_literal != NULL)) {
11027 // Swap. 11012 // Swap.
11028 LiteralNode* temp = rhs_literal; 11013 LiteralNode* temp = rhs_literal;
11029 rhs_literal = lhs_literal; 11014 rhs_literal = lhs_literal;
11030 lhs_literal = temp; 11015 lhs_literal = temp;
11031 } 11016 }
11032 } 11017 }
11033 if (binary_op == Token::kIFNULL) { 11018 if (binary_op == Token::kIFNULL) {
11034 // Handle a ?? b. 11019 // Handle a ?? b.
11035 if ((lhs->EvalConstExpr() != NULL) && (rhs->EvalConstExpr() != NULL)) { 11020 if ((lhs->EvalConstExpr() != NULL) && (rhs->EvalConstExpr() != NULL)) {
11036 Instance& expr_value = Instance::ZoneHandle(Z); 11021 Instance& expr_value = Instance::ZoneHandle(Z,
11037 if (!GetCachedConstant(op_pos, &expr_value)) { 11022 EvaluateConstExpr(lhs->token_pos(), lhs).raw());
11038 expr_value = EvaluateConstExpr(lhs->token_pos(), lhs).raw(); 11023 if (expr_value.IsNull()) {
11039 if (expr_value.IsNull()) { 11024 expr_value = EvaluateConstExpr(rhs->token_pos(), rhs).raw();
11040 expr_value = EvaluateConstExpr(rhs->token_pos(), rhs).raw();
11041 }
11042 CacheConstantValue(op_pos, expr_value);
11043 } 11025 }
11044 return new(Z) LiteralNode(op_pos, expr_value); 11026 return new(Z) LiteralNode(op_pos, expr_value);
11045 } 11027 }
11046 11028
11047 LetNode* result = new(Z) LetNode(op_pos); 11029 LetNode* result = new(Z) LetNode(op_pos);
11048 LocalVariable* left_temp = result->AddInitializer(lhs); 11030 LocalVariable* left_temp = result->AddInitializer(lhs);
11049 left_temp->set_is_final(); 11031 left_temp->set_is_final();
11050 const TokenPosition no_pos = TokenPosition::kNoSource; 11032 const TokenPosition no_pos = TokenPosition::kNoSource;
11051 LiteralNode* null_operand = 11033 LiteralNode* null_operand =
11052 new(Z) LiteralNode(no_pos, Object::null_instance()); 11034 new(Z) LiteralNode(no_pos, Object::null_instance());
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
11110 11092
11111 // Evaluates the value of the compile time constant expression 11093 // Evaluates the value of the compile time constant expression
11112 // and returns a literal node for the value. 11094 // and returns a literal node for the value.
11113 LiteralNode* Parser::FoldConstExpr(TokenPosition expr_pos, AstNode* expr) { 11095 LiteralNode* Parser::FoldConstExpr(TokenPosition expr_pos, AstNode* expr) {
11114 if (expr->IsLiteralNode()) { 11096 if (expr->IsLiteralNode()) {
11115 return expr->AsLiteralNode(); 11097 return expr->AsLiteralNode();
11116 } 11098 }
11117 if (expr->EvalConstExpr() == NULL) { 11099 if (expr->EvalConstExpr() == NULL) {
11118 ReportError(expr_pos, "expression is not a valid compile-time constant"); 11100 ReportError(expr_pos, "expression is not a valid compile-time constant");
11119 } 11101 }
11120 return new(Z) LiteralNode( 11102 return new(Z) LiteralNode(expr_pos, EvaluateConstExpr(expr_pos, expr));
11121 expr_pos, EvaluateConstExpr(expr_pos, expr));
11122 } 11103 }
11123 11104
11124 11105
11125 LetNode* Parser::PrepareCompoundAssignmentNodes(AstNode** expr) { 11106 LetNode* Parser::PrepareCompoundAssignmentNodes(AstNode** expr) {
11126 AstNode* node = *expr; 11107 AstNode* node = *expr;
11127 TokenPosition token_pos = node->token_pos(); 11108 TokenPosition token_pos = node->token_pos();
11128 LetNode* result = new(Z) LetNode(token_pos); 11109 LetNode* result = new(Z) LetNode(token_pos);
11129 if (node->IsLoadIndexedNode()) { 11110 if (node->IsLoadIndexedNode()) {
11130 LoadIndexedNode* load_indexed = node->AsLoadIndexedNode(); 11111 LoadIndexedNode* load_indexed = node->AsLoadIndexedNode();
11131 AstNode* array = load_indexed->array(); 11112 AstNode* array = load_indexed->array();
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after
11372 return new(Z) LiteralNode(expr_pos, existing_const); 11353 return new(Z) LiteralNode(expr_pos, existing_const);
11373 } 11354 }
11374 } 11355 }
11375 11356
11376 AstNode* expr = ParseConditionalExpr(); 11357 AstNode* expr = ParseConditionalExpr();
11377 if (!Token::IsAssignmentOperator(CurrentToken())) { 11358 if (!Token::IsAssignmentOperator(CurrentToken())) {
11378 if ((CurrentToken() == Token::kCASCADE) && consume_cascades) { 11359 if ((CurrentToken() == Token::kCASCADE) && consume_cascades) {
11379 return ParseCascades(expr); 11360 return ParseCascades(expr);
11380 } 11361 }
11381 if (require_compiletime_const) { 11362 if (require_compiletime_const) {
11382 const bool use_cache = !expr->IsLiteralNode(); 11363 expr = FoldConstExpr(expr_pos, expr);
11383 LiteralNode* const_value = FoldConstExpr(expr_pos, expr);
11384 if (use_cache) CacheConstantValue(expr_pos, const_value->literal());
11385 expr = const_value;
11386 } else { 11364 } else {
11387 expr = LiteralIfStaticConst(Z, expr); 11365 expr = LiteralIfStaticConst(Z, expr);
11388 } 11366 }
11389 return expr; 11367 return expr;
11390 } 11368 }
11391 // Assignment expressions. 11369 // Assignment expressions.
11392 if (!IsLegalAssignableSyntax(expr, TokenPos())) { 11370 if (!IsLegalAssignableSyntax(expr, TokenPos())) {
11393 ReportError(expr_pos, "expression is not assignable"); 11371 ReportError(expr_pos, "expression is not assignable");
11394 } 11372 }
11395 const Token::Kind assignment_op = CurrentToken(); 11373 const Token::Kind assignment_op = CurrentToken();
(...skipping 1074 matching lines...) Expand 10 before | Expand all | Expand 10 after
12470 12448
12471 12449
12472 void Parser::CacheConstantValue(TokenPosition token_pos, 12450 void Parser::CacheConstantValue(TokenPosition token_pos,
12473 const Instance& value) { 12451 const Instance& value) {
12474 if (current_function().kind() == RawFunction::kImplicitStaticFinalGetter) { 12452 if (current_function().kind() == RawFunction::kImplicitStaticFinalGetter) {
12475 // Don't cache constants in initializer expressions. They get 12453 // Don't cache constants in initializer expressions. They get
12476 // evaluated only once. 12454 // evaluated only once.
12477 return; 12455 return;
12478 } 12456 }
12479 InsertCachedConstantValue(script_, token_pos, value); 12457 InsertCachedConstantValue(script_, token_pos, value);
12458 INC_STAT(thread_, num_cached_consts, 1);
12480 } 12459 }
12481 12460
12482 12461
12483 bool Parser::GetCachedConstant(TokenPosition token_pos, Instance* value) { 12462 bool Parser::GetCachedConstant(TokenPosition token_pos, Instance* value) {
12484 bool is_present = false; 12463 bool is_present = false;
12485 ASSERT(!script_.InVMHeap()); 12464 ASSERT(!script_.InVMHeap());
12486 if (script_.compile_time_constants() == Array::null()) { 12465 if (script_.compile_time_constants() == Array::null()) {
12487 return false; 12466 return false;
12488 } 12467 }
12489 ConstantsMap constants(script_.compile_time_constants()); 12468 ConstantsMap constants(script_.compile_time_constants());
(...skipping 1983 matching lines...) Expand 10 before | Expand all | Expand 10 after
14473 expr->AsLoadLocalNode()->local().IsConst()) { 14452 expr->AsLoadLocalNode()->local().IsConst()) {
14474 return *expr->AsLoadLocalNode()->local().ConstValue(); 14453 return *expr->AsLoadLocalNode()->local().ConstValue();
14475 } else if (expr->IsLoadStaticFieldNode()) { 14454 } else if (expr->IsLoadStaticFieldNode()) {
14476 const Field& field = expr->AsLoadStaticFieldNode()->field(); 14455 const Field& field = expr->AsLoadStaticFieldNode()->field();
14477 // We already checked that this field is const and has been 14456 // We already checked that this field is const and has been
14478 // initialized. 14457 // initialized.
14479 ASSERT(field.is_const()); 14458 ASSERT(field.is_const());
14480 ASSERT(field.StaticValue() != Object::sentinel().raw()); 14459 ASSERT(field.StaticValue() != Object::sentinel().raw());
14481 ASSERT(field.StaticValue() != Object::transition_sentinel().raw()); 14460 ASSERT(field.StaticValue() != Object::transition_sentinel().raw());
14482 return Instance::ZoneHandle(Z, field.StaticValue()); 14461 return Instance::ZoneHandle(Z, field.StaticValue());
14462 } else if (expr->IsTypeNode()) {
14463 AbstractType& type =
14464 AbstractType::ZoneHandle(Z, expr->AsTypeNode()->type().raw());
14465 ASSERT(type.IsInstantiated() && !type.IsMalformedOrMalbounded());
14466 return type;
14467 } else if (expr->IsClosureNode()) {
14468 const Function& func = expr->AsClosureNode()->function();
14469 ASSERT((func.IsImplicitStaticClosureFunction()));
14470 Instance& closure = Instance::ZoneHandle(Z, func.ImplicitStaticClosure());
14471 closure = TryCanonicalize(closure, expr_pos);
14472 return closure;
14483 } else { 14473 } else {
14484 ASSERT(expr->EvalConstExpr() != NULL); 14474 ASSERT(expr->EvalConstExpr() != NULL);
14485 ReturnNode* ret = new(Z) ReturnNode(expr->token_pos(), expr); 14475 Instance& value = Instance::ZoneHandle(Z);
14476 if (GetCachedConstant(expr_pos, &value)) {
14477 return value;
14478 }
14479 ReturnNode* ret = new(Z) ReturnNode(expr_pos, expr);
14486 // Compile time constant expressions cannot reference anything from a 14480 // Compile time constant expressions cannot reference anything from a
14487 // local scope. 14481 // local scope.
14488 LocalScope* empty_scope = new(Z) LocalScope(NULL, 0, 0); 14482 LocalScope* empty_scope = new(Z) LocalScope(NULL, 0, 0);
14489 SequenceNode* seq = new(Z) SequenceNode(expr->token_pos(), empty_scope); 14483 SequenceNode* seq = new(Z) SequenceNode(expr_pos, empty_scope);
14490 seq->Add(ret); 14484 seq->Add(ret);
14491 14485
14486 INC_STAT(thread_, num_execute_const, 1);
14492 Object& result = Object::Handle(Z, Compiler::ExecuteOnce(seq)); 14487 Object& result = Object::Handle(Z, Compiler::ExecuteOnce(seq));
14493 if (result.IsError()) { 14488 if (result.IsError()) {
14494 ReportErrors(Error::Cast(result), 14489 ReportErrors(Error::Cast(result),
14495 script_, expr_pos, 14490 script_, expr_pos,
14496 "error evaluating constant expression"); 14491 "error evaluating constant expression");
14497 } 14492 }
14498 ASSERT(result.IsInstance() || result.IsNull()); 14493 ASSERT(result.IsInstance() || result.IsNull());
14499 Instance& value = Instance::ZoneHandle(Z);
14500 value ^= result.raw(); 14494 value ^= result.raw();
14501 value = TryCanonicalize(value, TokenPos()); 14495 value = TryCanonicalize(value, expr_pos);
14496 CacheConstantValue(expr_pos, value);
14502 return value; 14497 return value;
14503 } 14498 }
14504 } 14499 }
14505 14500
14506 14501
14507 void Parser::SkipFunctionLiteral() { 14502 void Parser::SkipFunctionLiteral() {
14508 if (IsIdentifier()) { 14503 if (IsIdentifier()) {
14509 if (LookaheadToken(1) != Token::kLPAREN) { 14504 if (LookaheadToken(1) != Token::kLPAREN) {
14510 SkipType(true); 14505 SkipType(true);
14511 } 14506 }
(...skipping 446 matching lines...) Expand 10 before | Expand all | Expand 10 after
14958 const ArgumentListNode& function_args, 14953 const ArgumentListNode& function_args,
14959 const LocalVariable* temp_for_last_arg, 14954 const LocalVariable* temp_for_last_arg,
14960 bool is_super_invocation) { 14955 bool is_super_invocation) {
14961 UNREACHABLE(); 14956 UNREACHABLE();
14962 return NULL; 14957 return NULL;
14963 } 14958 }
14964 14959
14965 } // namespace dart 14960 } // namespace dart
14966 14961
14967 #endif // DART_PRECOMPILED_RUNTIME 14962 #endif // DART_PRECOMPILED_RUNTIME
OLDNEW
« no previous file with comments | « runtime/vm/compiler_stats.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698