1// Copyright 2011 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
36namespace v8 {
37namespace internal {
38
39class Processor: public AstVisitor {
40 public:
41  explicit Processor(Variable* result)
42      : result_(result),
43        result_assigned_(false),
44        is_set_(false),
45        in_try_(false) {
46  }
47
48  void Process(ZoneList<Statement*>* statements);
49  bool result_assigned() const { return result_assigned_; }
50
51 private:
52  Variable* result_;
53
54  // We are not tracking result usage via the result_'s use
55  // counts (we leave the accurate computation to the
56  // usage analyzer). Instead we simple remember if
57  // there was ever an assignment to result_.
58  bool result_assigned_;
59
60  // To avoid storing to .result all the time, we eliminate some of
61  // the stores by keeping track of whether or not we're sure .result
62  // will be overwritten anyway. This is a bit more tricky than what I
63  // was hoping for
64  bool is_set_;
65  bool in_try_;
66
67  Expression* SetResult(Expression* value) {
68    result_assigned_ = true;
69    VariableProxy* result_proxy = new VariableProxy(result_);
70    return new Assignment(Token::ASSIGN, result_proxy, value,
71                          RelocInfo::kNoPosition);
72  }
73
74  // Node visitors.
75#define DEF_VISIT(type) \
76  virtual void Visit##type(type* node);
77  AST_NODE_LIST(DEF_VISIT)
78#undef DEF_VISIT
79
80  void VisitIterationStatement(IterationStatement* stmt);
81};
82
83
84void Processor::Process(ZoneList<Statement*>* statements) {
85  for (int i = statements->length() - 1; i >= 0; --i) {
86    Visit(statements->at(i));
87  }
88}
89
90
91void Processor::VisitBlock(Block* node) {
92  // An initializer block is the rewritten form of a variable declaration
93  // with initialization expressions. The initializer block contains the
94  // list of assignments corresponding to the initialization expressions.
95  // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of
96  // a variable declaration with initialization expression is 'undefined'
97  // with some JS VMs: For instance, using smjs, print(eval('var x = 7'))
98  // returns 'undefined'. To obtain the same behavior with v8, we need
99  // to prevent rewriting in that case.
100  if (!node->is_initializer_block()) Process(node->statements());
101}
102
103
104void Processor::VisitExpressionStatement(ExpressionStatement* node) {
105  // Rewrite : <x>; -> .result = <x>;
106  if (!is_set_) {
107    node->set_expression(SetResult(node->expression()));
108    if (!in_try_) is_set_ = true;
109  }
110}
111
112
113void Processor::VisitIfStatement(IfStatement* node) {
114  // Rewrite both then and else parts (reversed).
115  bool save = is_set_;
116  Visit(node->else_statement());
117  bool set_after_then = is_set_;
118  is_set_ = save;
119  Visit(node->then_statement());
120  is_set_ = is_set_ && set_after_then;
121}
122
123
124void Processor::VisitIterationStatement(IterationStatement* node) {
125  // Rewrite the body.
126  bool set_after_loop = is_set_;
127  Visit(node->body());
128  is_set_ = is_set_ && set_after_loop;
129}
130
131
132void Processor::VisitDoWhileStatement(DoWhileStatement* node) {
133  VisitIterationStatement(node);
134}
135
136
137void Processor::VisitWhileStatement(WhileStatement* node) {
138  VisitIterationStatement(node);
139}
140
141
142void Processor::VisitForStatement(ForStatement* node) {
143  VisitIterationStatement(node);
144}
145
146
147void Processor::VisitForInStatement(ForInStatement* node) {
148  VisitIterationStatement(node);
149}
150
151
152void Processor::VisitTryCatchStatement(TryCatchStatement* node) {
153  // Rewrite both try and catch blocks (reversed order).
154  bool set_after_catch = is_set_;
155  Visit(node->catch_block());
156  is_set_ = is_set_ && set_after_catch;
157  bool save = in_try_;
158  in_try_ = true;
159  Visit(node->try_block());
160  in_try_ = save;
161}
162
163
164void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) {
165  // Rewrite both try and finally block (reversed order).
166  Visit(node->finally_block());
167  bool save = in_try_;
168  in_try_ = true;
169  Visit(node->try_block());
170  in_try_ = save;
171}
172
173
174void Processor::VisitSwitchStatement(SwitchStatement* node) {
175  // Rewrite statements in all case clauses in reversed order.
176  ZoneList<CaseClause*>* clauses = node->cases();
177  bool set_after_switch = is_set_;
178  for (int i = clauses->length() - 1; i >= 0; --i) {
179    CaseClause* clause = clauses->at(i);
180    Process(clause->statements());
181  }
182  is_set_ = is_set_ && set_after_switch;
183}
184
185
186void Processor::VisitContinueStatement(ContinueStatement* node) {
187  is_set_ = false;
188}
189
190
191void Processor::VisitBreakStatement(BreakStatement* node) {
192  is_set_ = false;
193}
194
195
196// Do nothing:
197void Processor::VisitDeclaration(Declaration* node) {}
198void Processor::VisitEmptyStatement(EmptyStatement* node) {}
199void Processor::VisitReturnStatement(ReturnStatement* node) {}
200void Processor::VisitWithEnterStatement(WithEnterStatement* node) {}
201void Processor::VisitWithExitStatement(WithExitStatement* node) {}
202void Processor::VisitDebuggerStatement(DebuggerStatement* node) {}
203
204
205// Expressions are never visited yet.
206void Processor::VisitFunctionLiteral(FunctionLiteral* node) {
207  USE(node);
208  UNREACHABLE();
209}
210
211
212void Processor::VisitSharedFunctionInfoLiteral(
213    SharedFunctionInfoLiteral* node) {
214  USE(node);
215  UNREACHABLE();
216}
217
218
219void Processor::VisitConditional(Conditional* node) {
220  USE(node);
221  UNREACHABLE();
222}
223
224
225void Processor::VisitVariableProxy(VariableProxy* node) {
226  USE(node);
227  UNREACHABLE();
228}
229
230
231void Processor::VisitLiteral(Literal* node) {
232  USE(node);
233  UNREACHABLE();
234}
235
236
237void Processor::VisitRegExpLiteral(RegExpLiteral* node) {
238  USE(node);
239  UNREACHABLE();
240}
241
242
243void Processor::VisitArrayLiteral(ArrayLiteral* node) {
244  USE(node);
245  UNREACHABLE();
246}
247
248
249void Processor::VisitObjectLiteral(ObjectLiteral* node) {
250  USE(node);
251  UNREACHABLE();
252}
253
254
255void Processor::VisitCatchExtensionObject(CatchExtensionObject* node) {
256  USE(node);
257  UNREACHABLE();
258}
259
260
261void Processor::VisitAssignment(Assignment* node) {
262  USE(node);
263  UNREACHABLE();
264}
265
266
267void Processor::VisitThrow(Throw* node) {
268  USE(node);
269  UNREACHABLE();
270}
271
272
273void Processor::VisitProperty(Property* node) {
274  USE(node);
275  UNREACHABLE();
276}
277
278
279void Processor::VisitCall(Call* node) {
280  USE(node);
281  UNREACHABLE();
282}
283
284
285void Processor::VisitCallNew(CallNew* node) {
286  USE(node);
287  UNREACHABLE();
288}
289
290
291void Processor::VisitCallRuntime(CallRuntime* node) {
292  USE(node);
293  UNREACHABLE();
294}
295
296
297void Processor::VisitUnaryOperation(UnaryOperation* node) {
298  USE(node);
299  UNREACHABLE();
300}
301
302
303void Processor::VisitCountOperation(CountOperation* node) {
304  USE(node);
305  UNREACHABLE();
306}
307
308
309void Processor::VisitBinaryOperation(BinaryOperation* node) {
310  USE(node);
311  UNREACHABLE();
312}
313
314
315void Processor::VisitCompareOperation(CompareOperation* node) {
316  USE(node);
317  UNREACHABLE();
318}
319
320
321void Processor::VisitCompareToNull(CompareToNull* node) {
322  USE(node);
323  UNREACHABLE();
324}
325
326
327void Processor::VisitThisFunction(ThisFunction* node) {
328  USE(node);
329  UNREACHABLE();
330}
331
332
333// Assumes code has been parsed and scopes have been analyzed.  Mutates the
334// AST, so the AST should not continue to be used in the case of failure.
335bool Rewriter::Rewrite(CompilationInfo* info) {
336  FunctionLiteral* function = info->function();
337  ASSERT(function != NULL);
338  Scope* scope = function->scope();
339  ASSERT(scope != NULL);
340  if (scope->is_function_scope()) return true;
341
342  ZoneList<Statement*>* body = function->body();
343  if (!body->is_empty()) {
344    Variable* result = scope->NewTemporary(
345        info->isolate()->factory()->result_symbol());
346    Processor processor(result);
347    processor.Process(body);
348    if (processor.HasStackOverflow()) return false;
349
350    if (processor.result_assigned()) {
351      VariableProxy* result_proxy = new VariableProxy(result);
352      body->Add(new ReturnStatement(result_proxy));
353    }
354  }
355
356  return true;
357}
358
359
360} }  // namespace v8::internal
361