v8  3.25.30(node0.11.13)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
rewriter.cc
Go to the documentation of this file.
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "v8.h"
29 
30 #include "rewriter.h"
31 
32 #include "ast.h"
33 #include "compiler.h"
34 #include "scopes.h"
35 
36 namespace v8 {
37 namespace internal {
38 
39 class Processor: public AstVisitor {
40  public:
41  Processor(Variable* result, Zone* zone)
42  : result_(result),
43  result_assigned_(false),
44  is_set_(false),
45  in_try_(false),
46  factory_(zone) {
47  InitializeAstVisitor(zone);
48  }
49 
50  virtual ~Processor() { }
51 
52  void Process(ZoneList<Statement*>* statements);
53  bool result_assigned() const { return result_assigned_; }
54 
56  return &factory_;
57  }
58 
59  private:
60  Variable* result_;
61 
62  // We are not tracking result usage via the result_'s use
63  // counts (we leave the accurate computation to the
64  // usage analyzer). Instead we simple remember if
65  // there was ever an assignment to result_.
66  bool result_assigned_;
67 
68  // To avoid storing to .result all the time, we eliminate some of
69  // the stores by keeping track of whether or not we're sure .result
70  // will be overwritten anyway. This is a bit more tricky than what I
71  // was hoping for
72  bool is_set_;
73  bool in_try_;
74 
76 
77  Expression* SetResult(Expression* value) {
78  result_assigned_ = true;
79  VariableProxy* result_proxy = factory()->NewVariableProxy(result_);
80  return factory()->NewAssignment(
81  Token::ASSIGN, result_proxy, value, RelocInfo::kNoPosition);
82  }
83 
84  // Node visitors.
85 #define DEF_VISIT(type) \
86  virtual void Visit##type(type* node);
88 #undef DEF_VISIT
89 
90  void VisitIterationStatement(IterationStatement* stmt);
91 
92  DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
93 };
94 
95 
97  for (int i = statements->length() - 1; i >= 0; --i) {
98  Visit(statements->at(i));
99  }
100 }
101 
102 
103 void Processor::VisitBlock(Block* node) {
104  // An initializer block is the rewritten form of a variable declaration
105  // with initialization expressions. The initializer block contains the
106  // list of assignments corresponding to the initialization expressions.
107  // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of
108  // a variable declaration with initialization expression is 'undefined'
109  // with some JS VMs: For instance, using smjs, print(eval('var x = 7'))
110  // returns 'undefined'. To obtain the same behavior with v8, we need
111  // to prevent rewriting in that case.
112  if (!node->is_initializer_block()) Process(node->statements());
113 }
114 
115 
116 void Processor::VisitModuleStatement(ModuleStatement* node) {
117  bool set_after_body = is_set_;
118  Visit(node->body());
119  is_set_ = is_set_ && set_after_body;
120 }
121 
122 
123 void Processor::VisitExpressionStatement(ExpressionStatement* node) {
124  // Rewrite : <x>; -> .result = <x>;
125  if (!is_set_ && !node->expression()->IsThrow()) {
126  node->set_expression(SetResult(node->expression()));
127  if (!in_try_) is_set_ = true;
128  }
129 }
130 
131 
132 void Processor::VisitIfStatement(IfStatement* node) {
133  // Rewrite both then and else parts (reversed).
134  bool save = is_set_;
135  Visit(node->else_statement());
136  bool set_after_then = is_set_;
137  is_set_ = save;
138  Visit(node->then_statement());
139  is_set_ = is_set_ && set_after_then;
140 }
141 
142 
143 void Processor::VisitIterationStatement(IterationStatement* node) {
144  // Rewrite the body.
145  bool set_after_loop = is_set_;
146  Visit(node->body());
147  is_set_ = is_set_ && set_after_loop;
148 }
149 
150 
151 void Processor::VisitDoWhileStatement(DoWhileStatement* node) {
152  VisitIterationStatement(node);
153 }
154 
155 
156 void Processor::VisitWhileStatement(WhileStatement* node) {
157  VisitIterationStatement(node);
158 }
159 
160 
161 void Processor::VisitForStatement(ForStatement* node) {
162  VisitIterationStatement(node);
163 }
164 
165 
166 void Processor::VisitForInStatement(ForInStatement* node) {
167  VisitIterationStatement(node);
168 }
169 
170 
171 void Processor::VisitForOfStatement(ForOfStatement* node) {
172  VisitIterationStatement(node);
173 }
174 
175 
176 void Processor::VisitTryCatchStatement(TryCatchStatement* node) {
177  // Rewrite both try and catch blocks (reversed order).
178  bool set_after_catch = is_set_;
179  Visit(node->catch_block());
180  is_set_ = is_set_ && set_after_catch;
181  bool save = in_try_;
182  in_try_ = true;
183  Visit(node->try_block());
184  in_try_ = save;
185 }
186 
187 
188 void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) {
189  // Rewrite both try and finally block (reversed order).
190  Visit(node->finally_block());
191  bool save = in_try_;
192  in_try_ = true;
193  Visit(node->try_block());
194  in_try_ = save;
195 }
196 
197 
198 void Processor::VisitSwitchStatement(SwitchStatement* node) {
199  // Rewrite statements in all case clauses in reversed order.
200  ZoneList<CaseClause*>* clauses = node->cases();
201  bool set_after_switch = is_set_;
202  for (int i = clauses->length() - 1; i >= 0; --i) {
203  CaseClause* clause = clauses->at(i);
204  Process(clause->statements());
205  }
206  is_set_ = is_set_ && set_after_switch;
207 }
208 
209 
210 void Processor::VisitContinueStatement(ContinueStatement* node) {
211  is_set_ = false;
212 }
213 
214 
215 void Processor::VisitBreakStatement(BreakStatement* node) {
216  is_set_ = false;
217 }
218 
219 
220 void Processor::VisitWithStatement(WithStatement* node) {
221  bool set_after_body = is_set_;
222  Visit(node->statement());
223  is_set_ = is_set_ && set_after_body;
224 }
225 
226 
227 // Do nothing:
228 void Processor::VisitVariableDeclaration(VariableDeclaration* node) {}
229 void Processor::VisitFunctionDeclaration(FunctionDeclaration* node) {}
230 void Processor::VisitModuleDeclaration(ModuleDeclaration* node) {}
231 void Processor::VisitImportDeclaration(ImportDeclaration* node) {}
232 void Processor::VisitExportDeclaration(ExportDeclaration* node) {}
233 void Processor::VisitModuleLiteral(ModuleLiteral* node) {}
234 void Processor::VisitModuleVariable(ModuleVariable* node) {}
235 void Processor::VisitModulePath(ModulePath* node) {}
236 void Processor::VisitModuleUrl(ModuleUrl* node) {}
237 void Processor::VisitEmptyStatement(EmptyStatement* node) {}
238 void Processor::VisitReturnStatement(ReturnStatement* node) {}
239 void Processor::VisitDebuggerStatement(DebuggerStatement* node) {}
240 
241 
242 // Expressions are never visited yet.
243 #define DEF_VISIT(type) \
244  void Processor::Visit##type(type* expr) { UNREACHABLE(); }
246 #undef DEF_VISIT
247 
248 
249 // Assumes code has been parsed. Mutates the AST, so the AST should not
250 // continue to be used in the case of failure.
252  FunctionLiteral* function = info->function();
253  ASSERT(function != NULL);
254  Scope* scope = function->scope();
255  ASSERT(scope != NULL);
256  if (!scope->is_global_scope() && !scope->is_eval_scope()) return true;
257 
258  ZoneList<Statement*>* body = function->body();
259  if (!body->is_empty()) {
260  Variable* result = scope->NewTemporary(
261  info->isolate()->factory()->dot_result_string());
262  Processor processor(result, info->zone());
263  processor.Process(body);
264  if (processor.HasStackOverflow()) return false;
265 
266  if (processor.result_assigned()) {
267  ASSERT(function->end_position() != RelocInfo::kNoPosition);
268  // Set the position of the assignment statement one character past the
269  // source code, such that it definitely is not in the source code range
270  // of an immediate inner scope. For example in
271  // eval('with ({x:1}) x = 1');
272  // the end position of the function generated for executing the eval code
273  // coincides with the end of the with scope which is the position of '1'.
274  int pos = function->end_position();
275  VariableProxy* result_proxy = processor.factory()->NewVariableProxy(
276  result->name(), false, result->interface(), pos);
277  result_proxy->BindTo(result);
278  Statement* result_statement =
279  processor.factory()->NewReturnStatement(result_proxy, pos);
280  body->Add(result_statement, info->zone());
281  }
282  }
283 
284  return true;
285 }
286 
287 
288 } } // namespace v8::internal
bool is_global_scope() const
Definition: scopes.h:286
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter NULL
Definition: flags.cc:269
#define DEF_VISIT(type)
Definition: rewriter.cc:243
AstNodeFactory< AstNullVisitor > * factory()
Definition: rewriter.cc:55
Processor(Variable *result, Zone *zone)
Definition: rewriter.cc:41
Isolate * isolate() const
Definition: compiler.h:67
bool result_assigned() const
Definition: rewriter.cc:53
#define ASSERT(condition)
Definition: checks.h:329
Variable * NewTemporary(Handle< String > name)
Definition: scopes.cc:518
Interface * interface() const
Definition: variables.h:151
void Process(ZoneList< Statement * > *statements)
Definition: rewriter.cc:96
Factory * factory()
Definition: isolate.h:995
Handle< String > name() const
Definition: variables.h:96
bool is_eval_scope() const
Definition: scopes.h:283
FunctionLiteral * function() const
Definition: compiler.h:77
#define AST_NODE_LIST(V)
Definition: ast.h:121
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function info
Definition: flags.cc:317
void Add(const T &element, AllocationPolicy allocator=AllocationPolicy())
#define EXPRESSION_NODE_LIST(V)
Definition: ast.h:98
static bool Rewrite(CompilationInfo *info)
Definition: rewriter.cc:251