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

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

Issue 10270028: Fix wrong order of execution in compound assignment nodes (located by Kevin). (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 7 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/language/compound_assignment_operator_test.dart » ('j') | 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 "vm/bigint_operations.h" 7 #include "vm/bigint_operations.h"
8 #include "vm/class_finalizer.h" 8 #include "vm/class_finalizer.h"
9 #include "vm/compiler.h" 9 #include "vm/compiler.h"
10 #include "vm/compiler_stats.h" 10 #include "vm/compiler_stats.h"
(...skipping 5901 matching lines...) Expand 10 before | Expand all | Expand 10 after
5912 intptr_t token_index = node->token_index(); 5912 intptr_t token_index = node->token_index();
5913 node = NULL; // Do not use it. 5913 node = NULL; // Do not use it.
5914 // The array object access may not have side effects. 5914 // The array object access may not have side effects.
5915 // First, evaluate the array object expression if it might have side 5915 // First, evaluate the array object expression if it might have side
5916 // effects. 5916 // effects.
5917 if (!IsLocalOrLiteralNode(load_indexed->array())) { 5917 if (!IsLocalOrLiteralNode(load_indexed->array())) {
5918 LocalVariable* temp = 5918 LocalVariable* temp =
5919 CreateTempConstVariable(token_index, token_id, "lia"); 5919 CreateTempConstVariable(token_index, token_id, "lia");
5920 AstNode* save = 5920 AstNode* save =
5921 new StoreLocalNode(token_index, *temp, load_indexed->array()); 5921 new StoreLocalNode(token_index, *temp, load_indexed->array());
5922 current_block_->statements->Add(save);
5923 AstNode* load = new LoadLocalNode(token_index, *temp);
5924 load_indexed = new LoadIndexedNode(token_index, 5922 load_indexed = new LoadIndexedNode(token_index,
5925 load, 5923 save,
5926 load_indexed->index_expr()); 5924 load_indexed->index_expr());
5927 } 5925 }
5928 // Second, evaluate the index expression and store in a temporary 5926 // Second, evaluate the index expression and store in a temporary
5929 // variable if it might have side effects. 5927 // variable if it might have side effects.
5930 if (!IsLocalOrLiteralNode(load_indexed->index_expr())) { 5928 if (!IsLocalOrLiteralNode(load_indexed->index_expr())) {
5931 LocalVariable* temp = 5929 LocalVariable* temp =
5932 CreateTempConstVariable(token_index, token_id, "lix"); 5930 CreateTempConstVariable(token_index, token_id, "lix");
5933 AstNode* save = 5931 AstNode* save =
5934 new StoreLocalNode(token_index, *temp, load_indexed->index_expr()); 5932 new StoreLocalNode(token_index, *temp, load_indexed->index_expr());
5935 current_block_->statements->Add(save);
5936 AstNode* load = new LoadLocalNode(token_index, *temp);
5937 load_indexed = new LoadIndexedNode(token_index, 5933 load_indexed = new LoadIndexedNode(token_index,
5938 load_indexed->array(), 5934 load_indexed->array(),
5939 load); 5935 save);
5940 } 5936 }
5941 return load_indexed; 5937 return load_indexed;
5942 } 5938 }
5943 if (node->IsInstanceGetterNode()) { 5939 if (node->IsInstanceGetterNode()) {
5944 InstanceGetterNode* getter = node->AsInstanceGetterNode(); 5940 InstanceGetterNode* getter = node->AsInstanceGetterNode();
5945 intptr_t token_index = node->token_index(); 5941 intptr_t token_index = node->token_index();
5946 intptr_t token_id = node->id(); 5942 intptr_t token_id = node->id();
5947 node = NULL; // Do not use it. 5943 node = NULL; // Do not use it.
5948 if (!IsLocalOrLiteralNode(getter->receiver())) { 5944 if (!IsLocalOrLiteralNode(getter->receiver())) {
5949 LocalVariable* temp = 5945 LocalVariable* temp =
5950 CreateTempConstVariable(token_index, token_id, "igr"); 5946 CreateTempConstVariable(token_index, token_id, "igr");
5951 AstNode* save = 5947 AstNode* save =
5952 new StoreLocalNode(token_index, *temp, getter->receiver()); 5948 new StoreLocalNode(token_index, *temp, getter->receiver());
5953 current_block_->statements->Add(save); 5949 getter = new InstanceGetterNode(token_index, save, getter->field_name());
5954 AstNode* load = new LoadLocalNode(token_index, *temp);
5955 getter = new InstanceGetterNode(token_index, load, getter->field_name());
5956 } 5950 }
5957 return getter; 5951 return getter;
5958 } 5952 }
5959 return node; 5953 return node;
5960 } 5954 }
5961 5955
5962 5956
5963 // TODO(srdjan): Implement other optimizations. 5957 // TODO(srdjan): Implement other optimizations.
5964 AstNode* Parser::OptimizeBinaryOpNode(intptr_t op_pos, 5958 AstNode* Parser::OptimizeBinaryOpNode(intptr_t op_pos,
5965 Token::Kind binary_op, 5959 Token::Kind binary_op,
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
6030 if (expr->IsLiteralNode()) { 6024 if (expr->IsLiteralNode()) {
6031 return expr; 6025 return expr;
6032 } 6026 }
6033 if (expr->EvalConstExpr() == NULL) { 6027 if (expr->EvalConstExpr() == NULL) {
6034 ErrorMsg(expr_pos, "expression must be a compile time constant"); 6028 ErrorMsg(expr_pos, "expression must be a compile time constant");
6035 } 6029 }
6036 return new LiteralNode(expr_pos, EvaluateConstExpr(expr)); 6030 return new LiteralNode(expr_pos, EvaluateConstExpr(expr));
6037 } 6031 }
6038 6032
6039 6033
6034 // A compound assignment consists of a store and a load part. In order
6035 // to control inputs with potential side effects, the store part stores any
6036 // side effect creating inputs into locals.
6037 // Here we convert the inputs if the load local from the StoreLocals to
6038 // LoadLocals.
6039 static AstNode* ModifyCompoundAssignmentLoad(AstNode* node) {
6040 if (node->IsLoadIndexedNode()) {
6041 LoadIndexedNode* load_indexed = node->AsLoadIndexedNode();
6042 if (load_indexed->array()->IsStoreLocalNode()) {
6043 StoreLocalNode* store = load_indexed->array()->AsStoreLocalNode();
6044 LoadLocalNode* load = new LoadLocalNode(store->token_index(),
6045 store->local());
6046 load_indexed = new LoadIndexedNode(load_indexed->token_index(),
6047 load,
6048 load_indexed->index_expr());
6049 }
6050 if (load_indexed->index_expr()->IsStoreLocalNode()) {
6051 StoreLocalNode* store = load_indexed->index_expr()->AsStoreLocalNode();
6052 LoadLocalNode* load = new LoadLocalNode(store->token_index(),
6053 store->local());
6054 load_indexed = new LoadIndexedNode(load_indexed->token_index(),
6055 load_indexed->array(),
6056 load);
6057 }
6058 return load_indexed;
6059 }
6060 if (node->IsInstanceGetterNode()) {
6061 InstanceGetterNode* getter = node->AsInstanceGetterNode();
6062 if (getter->receiver()->IsStoreLocalNode()) {
6063 StoreLocalNode* store = getter->receiver()->AsStoreLocalNode();
6064 LoadLocalNode* load = new LoadLocalNode(store->token_index(),
6065 store->local());
6066 getter = new InstanceGetterNode(getter->token_index(),
6067 load,
6068 getter->field_name());
6069 }
6070 return getter;
6071 }
6072 return node;
6073 }
6074
6075
6040 AstNode* Parser::ParseExpr(bool require_compiletime_const) { 6076 AstNode* Parser::ParseExpr(bool require_compiletime_const) {
6041 TRACE_PARSER("ParseExpr"); 6077 TRACE_PARSER("ParseExpr");
6042 const intptr_t expr_pos = token_index_; 6078 const intptr_t expr_pos = token_index_;
6043 AstNode* expr = ParseConditionalExpr(); 6079 AstNode* expr = ParseConditionalExpr();
6044 if (!Token::IsAssignmentOperator(CurrentToken())) { 6080 if (!Token::IsAssignmentOperator(CurrentToken())) {
6045 if (require_compiletime_const) { 6081 if (require_compiletime_const) {
6046 expr = FoldConstExpr(expr_pos, expr); 6082 expr = FoldConstExpr(expr_pos, expr);
6047 } 6083 }
6048 return expr; 6084 return expr;
6049 } 6085 }
6050 // Assignment expressions. 6086 // Assignment expressions.
6051 Token::Kind assignment_op = CurrentToken(); 6087 Token::Kind assignment_op = CurrentToken();
6052 const intptr_t assignment_pos = token_index_; 6088 const intptr_t assignment_pos = token_index_;
6053 ConsumeToken(); 6089 ConsumeToken();
6054 const intptr_t right_expr_pos = token_index_; 6090 const intptr_t right_expr_pos = token_index_;
6055 if (require_compiletime_const && (assignment_op != Token::kASSIGN)) { 6091 if (require_compiletime_const && (assignment_op != Token::kASSIGN)) {
6056 ErrorMsg(right_expr_pos, "expression must be a compile time constant"); 6092 ErrorMsg(right_expr_pos, "expression must be a compile time constant");
6057 } 6093 }
6058 AstNode* right_expr = ParseExpr(require_compiletime_const); 6094 AstNode* right_expr = ParseExpr(require_compiletime_const);
6095 AstNode* left_expr = expr;
6059 if (assignment_op != Token::kASSIGN) { 6096 if (assignment_op != Token::kASSIGN) {
6060 expr = AsSideEffectFreeNode(expr); 6097 // Compound assignment: store inputs with side effects into temp. locals.
6098 left_expr = AsSideEffectFreeNode(expr);
6099 expr = ModifyCompoundAssignmentLoad(left_expr);
Kevin Millikin (Google) 2012/05/01 08:40:13 Cute. ModifyCompoundAssignmentLoad is only safe i
srdjan 2012/05/01 16:27:55 Good point, will combine them.
6061 } 6100 }
6062 right_expr = 6101 right_expr =
6063 ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr); 6102 ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr);
6064 AstNode* assign_expr = expr->MakeAssignmentNode(right_expr); 6103 AstNode* assign_expr = left_expr->MakeAssignmentNode(right_expr);
6065 if (assign_expr == NULL) { 6104 if (assign_expr == NULL) {
6066 ErrorMsg(assignment_pos, 6105 ErrorMsg(assignment_pos,
6067 "left hand side of '%s' is not assignable", 6106 "left hand side of '%s' is not assignable",
6068 Token::Str(assignment_op)); 6107 Token::Str(assignment_op));
6069 } 6108 }
6070 return assign_expr; 6109 return assign_expr;
6071 } 6110 }
6072 6111
6073 6112
6074 LiteralNode* Parser::ParseConstExpr() { 6113 LiteralNode* Parser::ParseConstExpr() {
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
6284 const String& field_name) { 6323 const String& field_name) {
6285 TRACE_PARSER("ParseInstanceFieldAccess"); 6324 TRACE_PARSER("ParseInstanceFieldAccess");
6286 AstNode* access = NULL; 6325 AstNode* access = NULL;
6287 const intptr_t call_pos = token_index_; 6326 const intptr_t call_pos = token_index_;
6288 if (Token::IsAssignmentOperator(CurrentToken())) { 6327 if (Token::IsAssignmentOperator(CurrentToken())) {
6289 Token::Kind assignment_op = CurrentToken(); 6328 Token::Kind assignment_op = CurrentToken();
6290 ConsumeToken(); 6329 ConsumeToken();
6291 AstNode* value = ParseExpr(kAllowConst); 6330 AstNode* value = ParseExpr(kAllowConst);
6292 AstNode* load_access = 6331 AstNode* load_access =
6293 new InstanceGetterNode(call_pos, receiver, field_name); 6332 new InstanceGetterNode(call_pos, receiver, field_name);
6333 AstNode* left_load_access = load_access;
6294 if (assignment_op != Token::kASSIGN) { 6334 if (assignment_op != Token::kASSIGN) {
6295 load_access = AsSideEffectFreeNode(load_access); 6335 // Compound assignment: store inputs with side effects into temp. locals.
6336 left_load_access = AsSideEffectFreeNode(load_access);
6337 load_access = ModifyCompoundAssignmentLoad(left_load_access);
6296 } 6338 }
6297 value = ExpandAssignableOp(call_pos, assignment_op, load_access, value); 6339 value = ExpandAssignableOp(call_pos, assignment_op, load_access, value);
6298 access = load_access->MakeAssignmentNode(value); 6340 access = left_load_access->MakeAssignmentNode(value);
6299 } else { 6341 } else {
6300 access = CallGetter(call_pos, receiver, field_name); 6342 access = CallGetter(call_pos, receiver, field_name);
6301 } 6343 }
6302 return access; 6344 return access;
6303 } 6345 }
6304 6346
6305 6347
6306 AstNode* Parser::GenerateStaticFieldLookup(const Field& field, 6348 AstNode* Parser::GenerateStaticFieldLookup(const Field& field,
6307 intptr_t ident_pos) { 6349 intptr_t ident_pos) {
6308 // If the static field has an initializer, initialize the field at compile 6350 // If the static field has an initializer, initialize the field at compile
(...skipping 2104 matching lines...) Expand 10 before | Expand all | Expand 10 after
8413 void Parser::SkipQualIdent() { 8455 void Parser::SkipQualIdent() {
8414 ASSERT(IsIdentifier()); 8456 ASSERT(IsIdentifier());
8415 ConsumeToken(); 8457 ConsumeToken();
8416 if (CurrentToken() == Token::kPERIOD) { 8458 if (CurrentToken() == Token::kPERIOD) {
8417 ConsumeToken(); // Consume the kPERIOD token. 8459 ConsumeToken(); // Consume the kPERIOD token.
8418 ExpectIdentifier("identifier expected after '.'"); 8460 ExpectIdentifier("identifier expected after '.'");
8419 } 8461 }
8420 } 8462 }
8421 8463
8422 } // namespace dart 8464 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | tests/language/compound_assignment_operator_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698