V8 Project
rewriter.cc
Go to the documentation of this file.
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
3 // found in the LICENSE file.
4 
5 #include "src/v8.h"
6 
7 #include "src/rewriter.h"
8 
9 #include "src/ast.h"
10 #include "src/compiler.h"
11 #include "src/scopes.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 class Processor: public AstVisitor {
17  public:
18  Processor(Variable* result, Zone* zone, AstNode::IdGen* ast_node_id_gen)
19  : result_(result),
21  is_set_(false),
22  in_try_(false),
23  // Passing a null AstValueFactory is fine, because Processor doesn't
24  // need to create strings or literals.
25  factory_(zone, NULL, ast_node_id_gen) {
26  InitializeAstVisitor(zone);
27  }
28 
29  virtual ~Processor() { }
30 
31  void Process(ZoneList<Statement*>* statements);
32  bool result_assigned() const { return result_assigned_; }
33 
35  return &factory_;
36  }
37 
38  private:
40 
41  // We are not tracking result usage via the result_'s use
42  // counts (we leave the accurate computation to the
43  // usage analyzer). Instead we simple remember if
44  // there was ever an assignment to result_.
46 
47  // To avoid storing to .result all the time, we eliminate some of
48  // the stores by keeping track of whether or not we're sure .result
49  // will be overwritten anyway. This is a bit more tricky than what I
50  // was hoping for
51  bool is_set_;
52  bool in_try_;
53 
55 
57  result_assigned_ = true;
58  VariableProxy* result_proxy = factory()->NewVariableProxy(result_);
59  return factory()->NewAssignment(
60  Token::ASSIGN, result_proxy, value, RelocInfo::kNoPosition);
61  }
62 
63  // Node visitors.
64 #define DEF_VISIT(type) \
65  virtual void Visit##type(type* node);
67 #undef DEF_VISIT
68 
70 
72 };
73 
74 
76  for (int i = statements->length() - 1; i >= 0; --i) {
77  Visit(statements->at(i));
78  }
79 }
80 
81 
82 void Processor::VisitBlock(Block* node) {
83  // An initializer block is the rewritten form of a variable declaration
84  // with initialization expressions. The initializer block contains the
85  // list of assignments corresponding to the initialization expressions.
86  // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of
87  // a variable declaration with initialization expression is 'undefined'
88  // with some JS VMs: For instance, using smjs, print(eval('var x = 7'))
89  // returns 'undefined'. To obtain the same behavior with v8, we need
90  // to prevent rewriting in that case.
91  if (!node->is_initializer_block()) Process(node->statements());
92 }
93 
94 
95 void Processor::VisitModuleStatement(ModuleStatement* node) {
96  bool set_after_body = is_set_;
97  Visit(node->body());
98  is_set_ = is_set_ && set_after_body;
99 }
100 
101 
102 void Processor::VisitExpressionStatement(ExpressionStatement* node) {
103  // Rewrite : <x>; -> .result = <x>;
104  if (!is_set_ && !node->expression()->IsThrow()) {
105  node->set_expression(SetResult(node->expression()));
106  if (!in_try_) is_set_ = true;
107  }
108 }
109 
110 
111 void Processor::VisitIfStatement(IfStatement* node) {
112  // Rewrite both then and else parts (reversed).
113  bool save = is_set_;
114  Visit(node->else_statement());
115  bool set_after_then = is_set_;
116  is_set_ = save;
117  Visit(node->then_statement());
118  is_set_ = is_set_ && set_after_then;
119 }
120 
121 
123  // Rewrite the body.
124  bool set_after_loop = is_set_;
125  Visit(node->body());
126  is_set_ = is_set_ && set_after_loop;
127 }
128 
129 
130 void Processor::VisitDoWhileStatement(DoWhileStatement* node) {
132 }
133 
134 
135 void Processor::VisitWhileStatement(WhileStatement* node) {
137 }
138 
139 
140 void Processor::VisitForStatement(ForStatement* node) {
142 }
143 
144 
145 void Processor::VisitForInStatement(ForInStatement* node) {
147 }
148 
149 
150 void Processor::VisitForOfStatement(ForOfStatement* node) {
152 }
153 
154 
155 void Processor::VisitTryCatchStatement(TryCatchStatement* node) {
156  // Rewrite both try and catch blocks (reversed order).
157  bool set_after_catch = is_set_;
158  Visit(node->catch_block());
159  is_set_ = is_set_ && set_after_catch;
160  bool save = in_try_;
161  in_try_ = true;
162  Visit(node->try_block());
163  in_try_ = save;
164 }
165 
166 
167 void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) {
168  // Rewrite both try and finally block (reversed order).
169  Visit(node->finally_block());
170  bool save = in_try_;
171  in_try_ = true;
172  Visit(node->try_block());
173  in_try_ = save;
174 }
175 
176 
177 void Processor::VisitSwitchStatement(SwitchStatement* node) {
178  // Rewrite statements in all case clauses in reversed order.
179  ZoneList<CaseClause*>* clauses = node->cases();
180  bool set_after_switch = is_set_;
181  for (int i = clauses->length() - 1; i >= 0; --i) {
182  CaseClause* clause = clauses->at(i);
183  Process(clause->statements());
184  }
185  is_set_ = is_set_ && set_after_switch;
186 }
187 
188 
189 void Processor::VisitContinueStatement(ContinueStatement* node) {
190  is_set_ = false;
191 }
192 
193 
194 void Processor::VisitBreakStatement(BreakStatement* node) {
195  is_set_ = false;
196 }
197 
198 
199 void Processor::VisitWithStatement(WithStatement* node) {
200  bool set_after_body = is_set_;
201  Visit(node->statement());
202  is_set_ = is_set_ && set_after_body;
203 }
204 
205 
206 // Do nothing:
207 void Processor::VisitVariableDeclaration(VariableDeclaration* node) {}
208 void Processor::VisitFunctionDeclaration(FunctionDeclaration* node) {}
209 void Processor::VisitModuleDeclaration(ModuleDeclaration* node) {}
210 void Processor::VisitImportDeclaration(ImportDeclaration* node) {}
211 void Processor::VisitExportDeclaration(ExportDeclaration* node) {}
212 void Processor::VisitModuleLiteral(ModuleLiteral* node) {}
213 void Processor::VisitModuleVariable(ModuleVariable* node) {}
214 void Processor::VisitModulePath(ModulePath* node) {}
215 void Processor::VisitModuleUrl(ModuleUrl* node) {}
216 void Processor::VisitEmptyStatement(EmptyStatement* node) {}
217 void Processor::VisitReturnStatement(ReturnStatement* node) {}
218 void Processor::VisitDebuggerStatement(DebuggerStatement* node) {}
219 
220 
221 // Expressions are never visited yet.
222 #define DEF_VISIT(type) \
223  void Processor::Visit##type(type* expr) { UNREACHABLE(); }
225 #undef DEF_VISIT
226 
227 
228 // Assumes code has been parsed. Mutates the AST, so the AST should not
229 // continue to be used in the case of failure.
231  FunctionLiteral* function = info->function();
232  DCHECK(function != NULL);
233  Scope* scope = function->scope();
234  DCHECK(scope != NULL);
235  if (!scope->is_global_scope() && !scope->is_eval_scope()) return true;
236 
237  ZoneList<Statement*>* body = function->body();
238  if (!body->is_empty()) {
239  Variable* result =
240  scope->NewTemporary(info->ast_value_factory()->dot_result_string());
241  // The name string must be internalized at this point.
242  DCHECK(!result->name().is_null());
243  Processor processor(result, info->zone(), info->ast_node_id_gen());
244  processor.Process(body);
245  if (processor.HasStackOverflow()) return false;
246 
247  if (processor.result_assigned()) {
248  DCHECK(function->end_position() != RelocInfo::kNoPosition);
249  // Set the position of the assignment statement one character past the
250  // source code, such that it definitely is not in the source code range
251  // of an immediate inner scope. For example in
252  // eval('with ({x:1}) x = 1');
253  // the end position of the function generated for executing the eval code
254  // coincides with the end of the with scope which is the position of '1'.
255  int pos = function->end_position();
256  VariableProxy* result_proxy = processor.factory()->NewVariableProxy(
257  result->raw_name(), false, result->interface(), pos);
258  result_proxy->BindTo(result);
259  Statement* result_statement =
260  processor.factory()->NewReturnStatement(result_proxy, pos);
261  body->Add(result_statement, info->zone());
262  }
263  }
264 
265  return true;
266 }
267 
268 
269 } } // namespace v8::internal
#define AST_NODE_LIST(V)
Definition: ast.h:102
#define EXPRESSION_NODE_LIST(V)
Definition: ast.h:77
AstNode::IdGen * ast_node_id_gen()
Definition: compiler.h:395
AstValueFactory * ast_value_factory() const
Definition: compiler.h:388
FunctionLiteral * function() const
Definition: compiler.h:107
Statement * body() const
Definition: ast.h:732
void Add(const T &element, AllocationPolicy allocator=AllocationPolicy())
Definition: list-inl.h:17
T & at(int i) const
Definition: list.h:69
Expression * SetResult(Expression *value)
Definition: rewriter.cc:56
Processor(Variable *result, Zone *zone, AstNode::IdGen *ast_node_id_gen)
Definition: rewriter.cc:18
void Process(ZoneList< Statement * > *statements)
Definition: rewriter.cc:75
void VisitIterationStatement(IterationStatement *stmt)
Definition: rewriter.cc:122
AstNodeFactory< AstNullVisitor > * factory()
Definition: rewriter.cc:34
bool result_assigned() const
Definition: rewriter.cc:32
AstNodeFactory< AstNullVisitor > factory_
Definition: rewriter.cc:54
static const int kNoPosition
Definition: assembler.h:317
static bool Rewrite(CompilationInfo *info)
Definition: rewriter.cc:230
bool is_global_scope() const
Definition: scopes.h:267
bool is_eval_scope() const
Definition: scopes.h:264
Variable * NewTemporary(const AstRawString *name)
Definition: scopes.cc:512
Handle< String > name() const
Definition: variables.h:71
Interface * interface() const
Definition: variables.h:129
const AstRawString * raw_name() const
Definition: variables.h:72
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define DCHECK(condition)
Definition: logging.h:205
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
#define DEF_VISIT(type)
Definition: rewriter.cc:222