| OLD | NEW |
| 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 5884 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5895 LocalVariable* temp = | 5895 LocalVariable* temp = |
| 5896 new LocalVariable(token_index, | 5896 new LocalVariable(token_index, |
| 5897 String::ZoneHandle(String::NewSymbol(name)), | 5897 String::ZoneHandle(String::NewSymbol(name)), |
| 5898 Type::ZoneHandle(Type::DynamicType())); | 5898 Type::ZoneHandle(Type::DynamicType())); |
| 5899 temp->set_is_final(); | 5899 temp->set_is_final(); |
| 5900 current_block_->scope->AddVariable(temp); | 5900 current_block_->scope->AddVariable(temp); |
| 5901 return temp; | 5901 return temp; |
| 5902 } | 5902 } |
| 5903 | 5903 |
| 5904 | 5904 |
| 5905 // If 'node' can create side effects, store its result in a temporary variable | |
| 5906 // and return a LoadLocalNode instead. | |
| 5907 // Side effect free nodes are LoadLocalNode and LiteralNode. | |
| 5908 AstNode* Parser::AsSideEffectFreeNode(AstNode* node) { | |
| 5909 if (node->IsLoadIndexedNode()) { | |
| 5910 LoadIndexedNode* load_indexed = node->AsLoadIndexedNode(); | |
| 5911 intptr_t token_id = node->id(); | |
| 5912 intptr_t token_index = node->token_index(); | |
| 5913 node = NULL; // Do not use it. | |
| 5914 // The array object access may not have side effects. | |
| 5915 // First, evaluate the array object expression if it might have side | |
| 5916 // effects. | |
| 5917 if (!IsLocalOrLiteralNode(load_indexed->array())) { | |
| 5918 LocalVariable* temp = | |
| 5919 CreateTempConstVariable(token_index, token_id, "lia"); | |
| 5920 AstNode* save = | |
| 5921 new StoreLocalNode(token_index, *temp, load_indexed->array()); | |
| 5922 load_indexed = new LoadIndexedNode(token_index, | |
| 5923 save, | |
| 5924 load_indexed->index_expr()); | |
| 5925 } | |
| 5926 // Second, evaluate the index expression and store in a temporary | |
| 5927 // variable if it might have side effects. | |
| 5928 if (!IsLocalOrLiteralNode(load_indexed->index_expr())) { | |
| 5929 LocalVariable* temp = | |
| 5930 CreateTempConstVariable(token_index, token_id, "lix"); | |
| 5931 AstNode* save = | |
| 5932 new StoreLocalNode(token_index, *temp, load_indexed->index_expr()); | |
| 5933 load_indexed = new LoadIndexedNode(token_index, | |
| 5934 load_indexed->array(), | |
| 5935 save); | |
| 5936 } | |
| 5937 return load_indexed; | |
| 5938 } | |
| 5939 if (node->IsInstanceGetterNode()) { | |
| 5940 InstanceGetterNode* getter = node->AsInstanceGetterNode(); | |
| 5941 intptr_t token_index = node->token_index(); | |
| 5942 intptr_t token_id = node->id(); | |
| 5943 node = NULL; // Do not use it. | |
| 5944 if (!IsLocalOrLiteralNode(getter->receiver())) { | |
| 5945 LocalVariable* temp = | |
| 5946 CreateTempConstVariable(token_index, token_id, "igr"); | |
| 5947 AstNode* save = | |
| 5948 new StoreLocalNode(token_index, *temp, getter->receiver()); | |
| 5949 getter = new InstanceGetterNode(token_index, save, getter->field_name()); | |
| 5950 } | |
| 5951 return getter; | |
| 5952 } | |
| 5953 return node; | |
| 5954 } | |
| 5955 | |
| 5956 | |
| 5957 // TODO(srdjan): Implement other optimizations. | 5905 // TODO(srdjan): Implement other optimizations. |
| 5958 AstNode* Parser::OptimizeBinaryOpNode(intptr_t op_pos, | 5906 AstNode* Parser::OptimizeBinaryOpNode(intptr_t op_pos, |
| 5959 Token::Kind binary_op, | 5907 Token::Kind binary_op, |
| 5960 AstNode* lhs, | 5908 AstNode* lhs, |
| 5961 AstNode* rhs) { | 5909 AstNode* rhs) { |
| 5962 LiteralNode* lhs_literal = lhs->AsLiteralNode(); | 5910 LiteralNode* lhs_literal = lhs->AsLiteralNode(); |
| 5963 LiteralNode* rhs_literal = rhs->AsLiteralNode(); | 5911 LiteralNode* rhs_literal = rhs->AsLiteralNode(); |
| 5964 if ((lhs_literal != NULL) && (rhs_literal != NULL)) { | 5912 if ((lhs_literal != NULL) && (rhs_literal != NULL)) { |
| 5965 if (lhs_literal->literal().IsDouble() && | 5913 if (lhs_literal->literal().IsDouble() && |
| 5966 rhs_literal->literal().IsDouble()) { | 5914 rhs_literal->literal().IsDouble()) { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6026 } | 5974 } |
| 6027 if (expr->EvalConstExpr() == NULL) { | 5975 if (expr->EvalConstExpr() == NULL) { |
| 6028 ErrorMsg(expr_pos, "expression must be a compile time constant"); | 5976 ErrorMsg(expr_pos, "expression must be a compile time constant"); |
| 6029 } | 5977 } |
| 6030 return new LiteralNode(expr_pos, EvaluateConstExpr(expr)); | 5978 return new LiteralNode(expr_pos, EvaluateConstExpr(expr)); |
| 6031 } | 5979 } |
| 6032 | 5980 |
| 6033 | 5981 |
| 6034 // A compound assignment consists of a store and a load part. In order | 5982 // 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 | 5983 // to control inputs with potential side effects, the store part stores any |
| 6036 // side effect creating inputs into locals. | 5984 // side effect creating inputs into locals. The load part reads then from |
| 6037 // Here we convert the inputs if the load local from the StoreLocals to | 5985 // those locals. If expr may have side effects, it will be split into two new |
| 6038 // LoadLocals. | 5986 // left and right nodes. 'expr' becomes the right node, left node is returned as |
| 6039 static AstNode* ModifyCompoundAssignmentLoad(AstNode* node) { | 5987 // result. |
| 5988 AstNode* Parser::PrepareCompoundAssignmentNodes(AstNode** expr) { |
| 5989 AstNode* node = *expr; |
| 6040 if (node->IsLoadIndexedNode()) { | 5990 if (node->IsLoadIndexedNode()) { |
| 6041 LoadIndexedNode* load_indexed = node->AsLoadIndexedNode(); | 5991 LoadIndexedNode* left_node = node->AsLoadIndexedNode(); |
| 6042 if (load_indexed->array()->IsStoreLocalNode()) { | 5992 LoadIndexedNode* right_node = left_node; |
| 6043 StoreLocalNode* store = load_indexed->array()->AsStoreLocalNode(); | 5993 intptr_t node_id = node->id(); |
| 6044 LoadLocalNode* load = new LoadLocalNode(store->token_index(), | 5994 intptr_t token_index = node->token_index(); |
| 6045 store->local()); | 5995 node = NULL; // Do not use it. |
| 6046 load_indexed = new LoadIndexedNode(load_indexed->token_index(), | 5996 if (!IsLocalOrLiteralNode(left_node->array())) { |
| 6047 load, | 5997 LocalVariable* temp = |
| 6048 load_indexed->index_expr()); | 5998 CreateTempConstVariable(token_index, node_id, "lia"); |
| 5999 StoreLocalNode* save = |
| 6000 new StoreLocalNode(token_index, *temp, left_node->array()); |
| 6001 left_node = |
| 6002 new LoadIndexedNode(token_index, save, left_node->index_expr()); |
| 6003 right_node = new LoadIndexedNode(token_index, |
| 6004 new LoadLocalNode(token_index, *temp), |
| 6005 right_node->index_expr()); |
| 6049 } | 6006 } |
| 6050 if (load_indexed->index_expr()->IsStoreLocalNode()) { | 6007 if (!IsLocalOrLiteralNode(left_node->index_expr())) { |
| 6051 StoreLocalNode* store = load_indexed->index_expr()->AsStoreLocalNode(); | 6008 LocalVariable* temp = |
| 6052 LoadLocalNode* load = new LoadLocalNode(store->token_index(), | 6009 CreateTempConstVariable(token_index, node_id, "lix"); |
| 6053 store->local()); | 6010 StoreLocalNode* save = |
| 6054 load_indexed = new LoadIndexedNode(load_indexed->token_index(), | 6011 new StoreLocalNode(token_index, *temp, left_node->index_expr()); |
| 6055 load_indexed->array(), | 6012 left_node = new LoadIndexedNode(token_index, |
| 6056 load); | 6013 left_node->array(), |
| 6014 save); |
| 6015 right_node = new LoadIndexedNode(token_index, |
| 6016 right_node->array(), |
| 6017 new LoadLocalNode(token_index, *temp)); |
| 6057 } | 6018 } |
| 6058 return load_indexed; | 6019 *expr = right_node; |
| 6020 return left_node; |
| 6059 } | 6021 } |
| 6060 if (node->IsInstanceGetterNode()) { | 6022 if (node->IsInstanceGetterNode()) { |
| 6061 InstanceGetterNode* getter = node->AsInstanceGetterNode(); | 6023 InstanceGetterNode* left_node = node->AsInstanceGetterNode(); |
| 6062 if (getter->receiver()->IsStoreLocalNode()) { | 6024 InstanceGetterNode* right_node = left_node; |
| 6063 StoreLocalNode* store = getter->receiver()->AsStoreLocalNode(); | 6025 intptr_t node_id = node->id(); |
| 6064 LoadLocalNode* load = new LoadLocalNode(store->token_index(), | 6026 intptr_t token_index = node->token_index(); |
| 6065 store->local()); | 6027 node = NULL; // Do not use it. |
| 6066 getter = new InstanceGetterNode(getter->token_index(), | 6028 if (!IsLocalOrLiteralNode(left_node->receiver())) { |
| 6067 load, | 6029 LocalVariable* temp = |
| 6068 getter->field_name()); | 6030 CreateTempConstVariable(token_index, node_id, "igr"); |
| 6031 StoreLocalNode* save = |
| 6032 new StoreLocalNode(token_index, *temp, left_node->receiver()); |
| 6033 left_node = new InstanceGetterNode(token_index, |
| 6034 save, |
| 6035 left_node->field_name()); |
| 6036 right_node = new InstanceGetterNode(token_index, |
| 6037 new LoadLocalNode(token_index, *temp), |
| 6038 right_node->field_name()); |
| 6069 } | 6039 } |
| 6070 return getter; | 6040 *expr = right_node; |
| 6041 return left_node; |
| 6071 } | 6042 } |
| 6072 return node; | 6043 return *expr; |
| 6073 } | 6044 } |
| 6074 | 6045 |
| 6075 | 6046 |
| 6076 AstNode* Parser::ParseExpr(bool require_compiletime_const) { | 6047 AstNode* Parser::ParseExpr(bool require_compiletime_const) { |
| 6077 TRACE_PARSER("ParseExpr"); | 6048 TRACE_PARSER("ParseExpr"); |
| 6078 const intptr_t expr_pos = token_index_; | 6049 const intptr_t expr_pos = token_index_; |
| 6079 AstNode* expr = ParseConditionalExpr(); | 6050 AstNode* expr = ParseConditionalExpr(); |
| 6080 if (!Token::IsAssignmentOperator(CurrentToken())) { | 6051 if (!Token::IsAssignmentOperator(CurrentToken())) { |
| 6081 if (require_compiletime_const) { | 6052 if (require_compiletime_const) { |
| 6082 expr = FoldConstExpr(expr_pos, expr); | 6053 expr = FoldConstExpr(expr_pos, expr); |
| 6083 } | 6054 } |
| 6084 return expr; | 6055 return expr; |
| 6085 } | 6056 } |
| 6086 // Assignment expressions. | 6057 // Assignment expressions. |
| 6087 Token::Kind assignment_op = CurrentToken(); | 6058 Token::Kind assignment_op = CurrentToken(); |
| 6088 const intptr_t assignment_pos = token_index_; | 6059 const intptr_t assignment_pos = token_index_; |
| 6089 ConsumeToken(); | 6060 ConsumeToken(); |
| 6090 const intptr_t right_expr_pos = token_index_; | 6061 const intptr_t right_expr_pos = token_index_; |
| 6091 if (require_compiletime_const && (assignment_op != Token::kASSIGN)) { | 6062 if (require_compiletime_const && (assignment_op != Token::kASSIGN)) { |
| 6092 ErrorMsg(right_expr_pos, "expression must be a compile time constant"); | 6063 ErrorMsg(right_expr_pos, "expression must be a compile time constant"); |
| 6093 } | 6064 } |
| 6094 AstNode* right_expr = ParseExpr(require_compiletime_const); | 6065 AstNode* right_expr = ParseExpr(require_compiletime_const); |
| 6095 AstNode* left_expr = expr; | 6066 AstNode* left_expr = expr; |
| 6096 if (assignment_op != Token::kASSIGN) { | 6067 if (assignment_op != Token::kASSIGN) { |
| 6097 // Compound assignment: store inputs with side effects into temp. locals. | 6068 // Compound assignment: store inputs with side effects into temp. locals. |
| 6098 left_expr = AsSideEffectFreeNode(expr); | 6069 left_expr = PrepareCompoundAssignmentNodes(&expr); |
| 6099 expr = ModifyCompoundAssignmentLoad(left_expr); | |
| 6100 } | 6070 } |
| 6101 right_expr = | 6071 right_expr = |
| 6102 ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr); | 6072 ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr); |
| 6103 AstNode* assign_expr = left_expr->MakeAssignmentNode(right_expr); | 6073 AstNode* assign_expr = left_expr->MakeAssignmentNode(right_expr); |
| 6104 if (assign_expr == NULL) { | 6074 if (assign_expr == NULL) { |
| 6105 ErrorMsg(assignment_pos, | 6075 ErrorMsg(assignment_pos, |
| 6106 "left hand side of '%s' is not assignable", | 6076 "left hand side of '%s' is not assignable", |
| 6107 Token::Str(assignment_op)); | 6077 Token::Str(assignment_op)); |
| 6108 } | 6078 } |
| 6109 return assign_expr; | 6079 return assign_expr; |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6326 const intptr_t call_pos = token_index_; | 6296 const intptr_t call_pos = token_index_; |
| 6327 if (Token::IsAssignmentOperator(CurrentToken())) { | 6297 if (Token::IsAssignmentOperator(CurrentToken())) { |
| 6328 Token::Kind assignment_op = CurrentToken(); | 6298 Token::Kind assignment_op = CurrentToken(); |
| 6329 ConsumeToken(); | 6299 ConsumeToken(); |
| 6330 AstNode* value = ParseExpr(kAllowConst); | 6300 AstNode* value = ParseExpr(kAllowConst); |
| 6331 AstNode* load_access = | 6301 AstNode* load_access = |
| 6332 new InstanceGetterNode(call_pos, receiver, field_name); | 6302 new InstanceGetterNode(call_pos, receiver, field_name); |
| 6333 AstNode* left_load_access = load_access; | 6303 AstNode* left_load_access = load_access; |
| 6334 if (assignment_op != Token::kASSIGN) { | 6304 if (assignment_op != Token::kASSIGN) { |
| 6335 // Compound assignment: store inputs with side effects into temp. locals. | 6305 // Compound assignment: store inputs with side effects into temp. locals. |
| 6336 left_load_access = AsSideEffectFreeNode(load_access); | 6306 left_load_access = PrepareCompoundAssignmentNodes(&load_access); |
| 6337 load_access = ModifyCompoundAssignmentLoad(left_load_access); | |
| 6338 } | 6307 } |
| 6339 value = ExpandAssignableOp(call_pos, assignment_op, load_access, value); | 6308 value = ExpandAssignableOp(call_pos, assignment_op, load_access, value); |
| 6340 access = left_load_access->MakeAssignmentNode(value); | 6309 access = left_load_access->MakeAssignmentNode(value); |
| 6341 } else { | 6310 } else { |
| 6342 access = CallGetter(call_pos, receiver, field_name); | 6311 access = CallGetter(call_pos, receiver, field_name); |
| 6343 } | 6312 } |
| 6344 return access; | 6313 return access; |
| 6345 } | 6314 } |
| 6346 | 6315 |
| 6347 | 6316 |
| (...skipping 2107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8455 void Parser::SkipQualIdent() { | 8424 void Parser::SkipQualIdent() { |
| 8456 ASSERT(IsIdentifier()); | 8425 ASSERT(IsIdentifier()); |
| 8457 ConsumeToken(); | 8426 ConsumeToken(); |
| 8458 if (CurrentToken() == Token::kPERIOD) { | 8427 if (CurrentToken() == Token::kPERIOD) { |
| 8459 ConsumeToken(); // Consume the kPERIOD token. | 8428 ConsumeToken(); // Consume the kPERIOD token. |
| 8460 ExpectIdentifier("identifier expected after '.'"); | 8429 ExpectIdentifier("identifier expected after '.'"); |
| 8461 } | 8430 } |
| 8462 } | 8431 } |
| 8463 | 8432 |
| 8464 } // namespace dart | 8433 } // namespace dart |
| OLD | NEW |