| OLD | NEW | 
|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "src/rewriter.h" | 5 #include "src/rewriter.h" | 
| 6 | 6 | 
| 7 #include "src/ast.h" | 7 #include "src/ast.h" | 
| 8 #include "src/parser.h" | 8 #include "src/parser.h" | 
| 9 #include "src/scopes.h" | 9 #include "src/scopes.h" | 
| 10 | 10 | 
| 11 namespace v8 { | 11 namespace v8 { | 
| 12 namespace internal { | 12 namespace internal { | 
| 13 | 13 | 
| 14 class Processor: public AstVisitor { | 14 class Processor: public AstVisitor { | 
| 15  public: | 15  public: | 
| 16   Processor(Isolate* isolate, Variable* result, | 16   Processor(Isolate* isolate, Scope* scope, Variable* result, | 
| 17             AstValueFactory* ast_value_factory) | 17             AstValueFactory* ast_value_factory) | 
| 18       : result_(result), | 18       : result_(result), | 
| 19         result_assigned_(false), | 19         result_assigned_(false), | 
| 20         replacement_(nullptr), | 20         replacement_(nullptr), | 
| 21         is_set_(false), | 21         is_set_(false), | 
|  | 22         scope_(scope), | 
| 22         factory_(ast_value_factory) { | 23         factory_(ast_value_factory) { | 
| 23     InitializeAstVisitor(isolate, ast_value_factory->zone()); | 24     InitializeAstVisitor(isolate, ast_value_factory->zone()); | 
| 24   } | 25   } | 
| 25 | 26 | 
| 26   virtual ~Processor() { } | 27   virtual ~Processor() { } | 
| 27 | 28 | 
| 28   void Process(ZoneList<Statement*>* statements); | 29   void Process(ZoneList<Statement*>* statements); | 
| 29   bool result_assigned() const { return result_assigned_; } | 30   bool result_assigned() const { return result_assigned_; } | 
| 30 | 31 | 
|  | 32   Scope* scope() { return scope_; } | 
| 31   AstNodeFactory* factory() { return &factory_; } | 33   AstNodeFactory* factory() { return &factory_; } | 
| 32 | 34 | 
| 33  private: | 35  private: | 
| 34   Variable* result_; | 36   Variable* result_; | 
| 35 | 37 | 
| 36   // We are not tracking result usage via the result_'s use | 38   // We are not tracking result usage via the result_'s use | 
| 37   // counts (we leave the accurate computation to the | 39   // counts (we leave the accurate computation to the | 
| 38   // usage analyzer). Instead we simple remember if | 40   // usage analyzer). Instead we simple remember if | 
| 39   // there was ever an assignment to result_. | 41   // there was ever an assignment to result_. | 
| 40   bool result_assigned_; | 42   bool result_assigned_; | 
| 41 | 43 | 
| 42   // When visiting a node, we "return" a replacement for that node in | 44   // When visiting a node, we "return" a replacement for that node in | 
| 43   // [replacement_].  In many cases this will just be the original node. | 45   // [replacement_].  In many cases this will just be the original node. | 
| 44   Statement* replacement_; | 46   Statement* replacement_; | 
| 45 | 47 | 
| 46   // To avoid storing to .result all the time, we eliminate some of | 48   // To avoid storing to .result all the time, we eliminate some of | 
| 47   // the stores by keeping track of whether or not we're sure .result | 49   // the stores by keeping track of whether or not we're sure .result | 
| 48   // will be overwritten anyway. This is a bit more tricky than what I | 50   // will be overwritten anyway. This is a bit more tricky than what I | 
| 49   // was hoping for. | 51   // was hoping for. | 
| 50   bool is_set_; | 52   bool is_set_; | 
| 51 | 53 | 
|  | 54   Scope* scope_; | 
| 52   AstNodeFactory factory_; | 55   AstNodeFactory factory_; | 
| 53 | 56 | 
|  | 57   // Returns ".result = value" | 
| 54   Expression* SetResult(Expression* value) { | 58   Expression* SetResult(Expression* value) { | 
| 55     result_assigned_ = true; | 59     result_assigned_ = true; | 
| 56     VariableProxy* result_proxy = factory()->NewVariableProxy(result_); | 60     VariableProxy* result_proxy = factory()->NewVariableProxy(result_); | 
| 57     return factory()->NewAssignment( | 61     return factory()->NewAssignment( | 
| 58         Token::ASSIGN, result_proxy, value, RelocInfo::kNoPosition); | 62         Token::ASSIGN, result_proxy, value, RelocInfo::kNoPosition); | 
| 59   } | 63   } | 
| 60 | 64 | 
| 61   // Node visitors. | 65   // Node visitors. | 
| 62 #define DEF_VISIT(type) virtual void Visit##type(type* node) override; | 66 #define DEF_VISIT(type) virtual void Visit##type(type* node) override; | 
| 63   AST_NODE_LIST(DEF_VISIT) | 67   AST_NODE_LIST(DEF_VISIT) | 
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 160   is_set_ = set_after; | 164   is_set_ = set_after; | 
| 161   Visit(node->catch_block()); | 165   Visit(node->catch_block()); | 
| 162   node->set_catch_block(static_cast<Block*>(replacement_)); | 166   node->set_catch_block(static_cast<Block*>(replacement_)); | 
| 163   is_set_ = is_set_ && set_in_try; | 167   is_set_ = is_set_ && set_in_try; | 
| 164   replacement_ = node; | 168   replacement_ = node; | 
| 165 } | 169 } | 
| 166 | 170 | 
| 167 | 171 | 
| 168 void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) { | 172 void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) { | 
| 169   // Rewrite both try and finally block (in reverse order). | 173   // Rewrite both try and finally block (in reverse order). | 
|  | 174   bool set_after = is_set_; | 
|  | 175   is_set_ = true;  // Don't normally need to assign in finally block. | 
| 170   Visit(node->finally_block()); | 176   Visit(node->finally_block()); | 
| 171   node->set_finally_block(replacement_->AsBlock()); | 177   node->set_finally_block(replacement_->AsBlock()); | 
| 172   Visit(node->try_block());  // Exception will not be caught. | 178   {  // Save .result value at the beginning of the finally block and restore it | 
|  | 179      // at the end again: ".backup = .result; ...; .result = .backup" | 
|  | 180      // This is necessary because the finally block does not normally contribute | 
|  | 181      // to the completion value. | 
|  | 182     Variable* backup = scope()->NewTemporary( | 
|  | 183         factory()->ast_value_factory()->dot_result_string()); | 
|  | 184     Expression* backup_proxy = factory()->NewVariableProxy(backup); | 
|  | 185     Expression* result_proxy = factory()->NewVariableProxy(result_); | 
|  | 186     Expression* save = factory()->NewAssignment( | 
|  | 187         Token::ASSIGN, backup_proxy, result_proxy, RelocInfo::kNoPosition); | 
|  | 188     Expression* restore = factory()->NewAssignment( | 
|  | 189         Token::ASSIGN, result_proxy, backup_proxy, RelocInfo::kNoPosition); | 
|  | 190     node->finally_block()->statements()->InsertAt( | 
|  | 191         0, factory()->NewExpressionStatement(save, RelocInfo::kNoPosition), | 
|  | 192         zone()); | 
|  | 193     node->finally_block()->statements()->Add( | 
|  | 194         factory()->NewExpressionStatement(restore, RelocInfo::kNoPosition), | 
|  | 195         zone()); | 
|  | 196   } | 
|  | 197   is_set_ = set_after; | 
|  | 198   Visit(node->try_block()); | 
| 173   node->set_try_block(replacement_->AsBlock()); | 199   node->set_try_block(replacement_->AsBlock()); | 
| 174   replacement_ = node; | 200   replacement_ = node; | 
| 175 } | 201 } | 
| 176 | 202 | 
| 177 | 203 | 
| 178 void Processor::VisitSwitchStatement(SwitchStatement* node) { | 204 void Processor::VisitSwitchStatement(SwitchStatement* node) { | 
| 179   // Rewrite statements in all case clauses (in reverse order). | 205   // Rewrite statements in all case clauses (in reverse order). | 
| 180   ZoneList<CaseClause*>* clauses = node->cases(); | 206   ZoneList<CaseClause*>* clauses = node->cases(); | 
| 181   bool set_after = is_set_; | 207   bool set_after = is_set_; | 
| 182   for (int i = clauses->length() - 1; i >= 0; --i) { | 208   for (int i = clauses->length() - 1; i >= 0; --i) { | 
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 253   Scope* scope = function->scope(); | 279   Scope* scope = function->scope(); | 
| 254   DCHECK(scope != NULL); | 280   DCHECK(scope != NULL); | 
| 255   if (!scope->is_script_scope() && !scope->is_eval_scope()) return true; | 281   if (!scope->is_script_scope() && !scope->is_eval_scope()) return true; | 
| 256 | 282 | 
| 257   ZoneList<Statement*>* body = function->body(); | 283   ZoneList<Statement*>* body = function->body(); | 
| 258   if (!body->is_empty()) { | 284   if (!body->is_empty()) { | 
| 259     Variable* result = | 285     Variable* result = | 
| 260         scope->NewTemporary(info->ast_value_factory()->dot_result_string()); | 286         scope->NewTemporary(info->ast_value_factory()->dot_result_string()); | 
| 261     // The name string must be internalized at this point. | 287     // The name string must be internalized at this point. | 
| 262     DCHECK(!result->name().is_null()); | 288     DCHECK(!result->name().is_null()); | 
| 263     Processor processor(info->isolate(), result, info->ast_value_factory()); | 289     Processor processor(info->isolate(), scope, result, | 
|  | 290                         info->ast_value_factory()); | 
| 264     processor.Process(body); | 291     processor.Process(body); | 
| 265     if (processor.HasStackOverflow()) return false; | 292     if (processor.HasStackOverflow()) return false; | 
| 266 | 293 | 
| 267     if (processor.result_assigned()) { | 294     if (processor.result_assigned()) { | 
| 268       DCHECK(function->end_position() != RelocInfo::kNoPosition); | 295       DCHECK(function->end_position() != RelocInfo::kNoPosition); | 
| 269       // Set the position of the assignment statement one character past the | 296       // Set the position of the assignment statement one character past the | 
| 270       // source code, such that it definitely is not in the source code range | 297       // source code, such that it definitely is not in the source code range | 
| 271       // of an immediate inner scope. For example in | 298       // of an immediate inner scope. For example in | 
| 272       //   eval('with ({x:1}) x = 1'); | 299       //   eval('with ({x:1}) x = 1'); | 
| 273       // the end position of the function generated for executing the eval code | 300       // the end position of the function generated for executing the eval code | 
| 274       // coincides with the end of the with scope which is the position of '1'. | 301       // coincides with the end of the with scope which is the position of '1'. | 
| 275       int pos = function->end_position(); | 302       int pos = function->end_position(); | 
| 276       VariableProxy* result_proxy = | 303       VariableProxy* result_proxy = | 
| 277           processor.factory()->NewVariableProxy(result, pos); | 304           processor.factory()->NewVariableProxy(result, pos); | 
| 278       Statement* result_statement = | 305       Statement* result_statement = | 
| 279           processor.factory()->NewReturnStatement(result_proxy, pos); | 306           processor.factory()->NewReturnStatement(result_proxy, pos); | 
| 280       body->Add(result_statement, info->zone()); | 307       body->Add(result_statement, info->zone()); | 
| 281     } | 308     } | 
| 282   } | 309   } | 
| 283 | 310 | 
| 284   return true; | 311   return true; | 
| 285 } | 312 } | 
| 286 | 313 | 
| 287 | 314 | 
| 288 }  // namespace internal | 315 }  // namespace internal | 
| 289 }  // namespace v8 | 316 }  // namespace v8 | 
| OLD | NEW | 
|---|