The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / rewriter.cc @ f230a1cf

History | View | Annotate | Download (9.26 KB)

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->isolate(), zone) {
47
    InitializeAstVisitor(zone->isolate());
48
  }
49

    
50
  virtual ~Processor() { }
51

    
52
  void Process(ZoneList<Statement*>* statements);
53
  bool result_assigned() const { return result_assigned_; }
54

    
55
  AstNodeFactory<AstNullVisitor>* factory() {
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

    
75
  AstNodeFactory<AstNullVisitor> factory_;
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);
87
  AST_NODE_LIST(DEF_VISIT)
88
#undef DEF_VISIT
89

    
90
  void VisitIterationStatement(IterationStatement* stmt);
91

    
92
  DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
93
};
94

    
95

    
96
void Processor::Process(ZoneList<Statement*>* statements) {
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::VisitCaseClause(CaseClause* clause) {
211
  UNREACHABLE();
212
}
213

    
214

    
215
void Processor::VisitContinueStatement(ContinueStatement* node) {
216
  is_set_ = false;
217
}
218

    
219

    
220
void Processor::VisitBreakStatement(BreakStatement* node) {
221
  is_set_ = false;
222
}
223

    
224

    
225
void Processor::VisitWithStatement(WithStatement* node) {
226
  bool set_after_body = is_set_;
227
  Visit(node->statement());
228
  is_set_ = is_set_ && set_after_body;
229
}
230

    
231

    
232
// Do nothing:
233
void Processor::VisitVariableDeclaration(VariableDeclaration* node) {}
234
void Processor::VisitFunctionDeclaration(FunctionDeclaration* node) {}
235
void Processor::VisitModuleDeclaration(ModuleDeclaration* node) {}
236
void Processor::VisitImportDeclaration(ImportDeclaration* node) {}
237
void Processor::VisitExportDeclaration(ExportDeclaration* node) {}
238
void Processor::VisitModuleLiteral(ModuleLiteral* node) {}
239
void Processor::VisitModuleVariable(ModuleVariable* node) {}
240
void Processor::VisitModulePath(ModulePath* node) {}
241
void Processor::VisitModuleUrl(ModuleUrl* node) {}
242
void Processor::VisitEmptyStatement(EmptyStatement* node) {}
243
void Processor::VisitReturnStatement(ReturnStatement* node) {}
244
void Processor::VisitDebuggerStatement(DebuggerStatement* node) {}
245

    
246

    
247
// Expressions are never visited yet.
248
#define DEF_VISIT(type)                                         \
249
  void Processor::Visit##type(type* expr) { UNREACHABLE(); }
250
EXPRESSION_NODE_LIST(DEF_VISIT)
251
#undef DEF_VISIT
252

    
253

    
254
// Assumes code has been parsed.  Mutates the AST, so the AST should not
255
// continue to be used in the case of failure.
256
bool Rewriter::Rewrite(CompilationInfo* info) {
257
  FunctionLiteral* function = info->function();
258
  ASSERT(function != NULL);
259
  Scope* scope = function->scope();
260
  ASSERT(scope != NULL);
261
  if (!scope->is_global_scope() && !scope->is_eval_scope()) return true;
262

    
263
  ZoneList<Statement*>* body = function->body();
264
  if (!body->is_empty()) {
265
    Variable* result = scope->NewTemporary(
266
        info->isolate()->factory()->result_string());
267
    Processor processor(result, info->zone());
268
    processor.Process(body);
269
    if (processor.HasStackOverflow()) return false;
270

    
271
    if (processor.result_assigned()) {
272
      ASSERT(function->end_position() != RelocInfo::kNoPosition);
273
      // Set the position of the assignment statement one character past the
274
      // source code, such that it definitely is not in the source code range
275
      // of an immediate inner scope. For example in
276
      //   eval('with ({x:1}) x = 1');
277
      // the end position of the function generated for executing the eval code
278
      // coincides with the end of the with scope which is the position of '1'.
279
      int pos = function->end_position();
280
      VariableProxy* result_proxy = processor.factory()->NewVariableProxy(
281
          result->name(), false, result->interface(), pos);
282
      result_proxy->BindTo(result);
283
      Statement* result_statement =
284
          processor.factory()->NewReturnStatement(result_proxy, pos);
285
      body->Add(result_statement, info->zone());
286
    }
287
  }
288

    
289
  return true;
290
}
291

    
292

    
293
} }  // namespace v8::internal