blob: 99225511c5c19c652413219f2779ccd749396114 [file] [log] [blame]
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001// Copyright 2011 the V8 project authors. All rights reserved.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002// 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#ifndef V8_HYDROGEN_H_
29#define V8_HYDROGEN_H_
30
31#include "v8.h"
32
lrn@chromium.org1c092762011-05-09 09:42:16 +000033#include "allocation.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000034#include "ast.h"
35#include "compiler.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "hydrogen-instructions.h"
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000037#include "type-info.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000038#include "zone.h"
39
40namespace v8 {
41namespace internal {
42
43// Forward declarations.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000044class BitVector;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000045class HEnvironment;
46class HGraph;
47class HLoopInformation;
48class HTracer;
49class LAllocator;
50class LChunk;
51class LiveRange;
52
53
54class HBasicBlock: public ZoneObject {
55 public:
56 explicit HBasicBlock(HGraph* graph);
57 virtual ~HBasicBlock() { }
58
59 // Simple accessors.
60 int block_id() const { return block_id_; }
61 void set_block_id(int id) { block_id_ = id; }
62 HGraph* graph() const { return graph_; }
63 const ZoneList<HPhi*>* phis() const { return &phis_; }
64 HInstruction* first() const { return first_; }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000065 HInstruction* last() const { return last_; }
66 void set_last(HInstruction* instr) { last_ = instr; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000067 HInstruction* GetLastInstruction();
68 HControlInstruction* end() const { return end_; }
69 HLoopInformation* loop_information() const { return loop_information_; }
70 const ZoneList<HBasicBlock*>* predecessors() const { return &predecessors_; }
71 bool HasPredecessor() const { return predecessors_.length() > 0; }
72 const ZoneList<HBasicBlock*>* dominated_blocks() const {
73 return &dominated_blocks_;
74 }
75 const ZoneList<int>* deleted_phis() const {
76 return &deleted_phis_;
77 }
78 void RecordDeletedPhi(int merge_index) {
79 deleted_phis_.Add(merge_index);
80 }
81 HBasicBlock* dominator() const { return dominator_; }
82 HEnvironment* last_environment() const { return last_environment_; }
83 int argument_count() const { return argument_count_; }
84 void set_argument_count(int count) { argument_count_ = count; }
85 int first_instruction_index() const { return first_instruction_index_; }
86 void set_first_instruction_index(int index) {
87 first_instruction_index_ = index;
88 }
89 int last_instruction_index() const { return last_instruction_index_; }
90 void set_last_instruction_index(int index) {
91 last_instruction_index_ = index;
92 }
93
94 void AttachLoopInformation();
95 void DetachLoopInformation();
96 bool IsLoopHeader() const { return loop_information() != NULL; }
97 bool IsStartBlock() const { return block_id() == 0; }
98 void PostProcessLoopHeader(IterationStatement* stmt);
99
100 bool IsFinished() const { return end_ != NULL; }
101 void AddPhi(HPhi* phi);
102 void RemovePhi(HPhi* phi);
103 void AddInstruction(HInstruction* instr);
104 bool Dominates(HBasicBlock* other) const;
105
106 void SetInitialEnvironment(HEnvironment* env);
107 void ClearEnvironment() { last_environment_ = NULL; }
108 bool HasEnvironment() const { return last_environment_ != NULL; }
109 void UpdateEnvironment(HEnvironment* env) { last_environment_ = env; }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000110 HBasicBlock* parent_loop_header() const { return parent_loop_header_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000111
112 void set_parent_loop_header(HBasicBlock* block) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000113 ASSERT(parent_loop_header_ == NULL);
114 parent_loop_header_ = block;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000115 }
116
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000117 bool HasParentLoopHeader() const { return parent_loop_header_ != NULL; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000118
ager@chromium.org04921a82011-06-27 13:21:41 +0000119 void SetJoinId(int ast_id);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000120
121 void Finish(HControlInstruction* last);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000122 void FinishExit(HControlInstruction* instruction);
ager@chromium.org04921a82011-06-27 13:21:41 +0000123 void Goto(HBasicBlock* block);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000124
125 int PredecessorIndexOf(HBasicBlock* predecessor) const;
ager@chromium.org04921a82011-06-27 13:21:41 +0000126 void AddSimulate(int ast_id) { AddInstruction(CreateSimulate(ast_id)); }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000127 void AssignCommonDominator(HBasicBlock* other);
128
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000129 void FinishExitWithDeoptimization(HDeoptimize::UseEnvironment has_uses) {
130 FinishExit(CreateDeoptimize(has_uses));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000131 }
132
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000133 // Add the inlined function exit sequence, adding an HLeaveInlined
134 // instruction and updating the bailout environment.
135 void AddLeaveInlined(HValue* return_value, HBasicBlock* target);
136
137 // If a target block is tagged as an inline function return, all
138 // predecessors should contain the inlined exit sequence:
139 //
140 // LeaveInlined
141 // Simulate (caller's environment)
142 // Goto (target block)
143 bool IsInlineReturnTarget() const { return is_inline_return_target_; }
144 void MarkAsInlineReturnTarget() { is_inline_return_target_ = true; }
145
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000146 bool IsDeoptimizing() const { return is_deoptimizing_; }
147 void MarkAsDeoptimizing() { is_deoptimizing_ = true; }
148
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000149 inline Zone* zone();
150
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000151#ifdef DEBUG
152 void Verify();
153#endif
154
155 private:
156 void RegisterPredecessor(HBasicBlock* pred);
157 void AddDominatedBlock(HBasicBlock* block);
158
ager@chromium.org04921a82011-06-27 13:21:41 +0000159 HSimulate* CreateSimulate(int ast_id);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000160 HDeoptimize* CreateDeoptimize(HDeoptimize::UseEnvironment has_uses);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000161
162 int block_id_;
163 HGraph* graph_;
164 ZoneList<HPhi*> phis_;
165 HInstruction* first_;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000166 HInstruction* last_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000167 HControlInstruction* end_;
168 HLoopInformation* loop_information_;
169 ZoneList<HBasicBlock*> predecessors_;
170 HBasicBlock* dominator_;
171 ZoneList<HBasicBlock*> dominated_blocks_;
172 HEnvironment* last_environment_;
173 // Outgoing parameter count at block exit, set during lithium translation.
174 int argument_count_;
175 // Instruction indices into the lithium code stream.
176 int first_instruction_index_;
177 int last_instruction_index_;
178 ZoneList<int> deleted_phis_;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000179 HBasicBlock* parent_loop_header_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000180 bool is_inline_return_target_;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000181 bool is_deoptimizing_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000182};
183
184
185class HLoopInformation: public ZoneObject {
186 public:
187 explicit HLoopInformation(HBasicBlock* loop_header)
ager@chromium.org04921a82011-06-27 13:21:41 +0000188 : back_edges_(4),
189 loop_header_(loop_header),
190 blocks_(8),
191 stack_check_(NULL) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000192 blocks_.Add(loop_header);
193 }
194 virtual ~HLoopInformation() {}
195
196 const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; }
197 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
198 HBasicBlock* loop_header() const { return loop_header_; }
199 HBasicBlock* GetLastBackEdge() const;
200 void RegisterBackEdge(HBasicBlock* block);
201
ager@chromium.org04921a82011-06-27 13:21:41 +0000202 HStackCheck* stack_check() const { return stack_check_; }
203 void set_stack_check(HStackCheck* stack_check) {
204 stack_check_ = stack_check;
205 }
206
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000207 private:
208 void AddBlock(HBasicBlock* block);
209
210 ZoneList<HBasicBlock*> back_edges_;
211 HBasicBlock* loop_header_;
212 ZoneList<HBasicBlock*> blocks_;
ager@chromium.org04921a82011-06-27 13:21:41 +0000213 HStackCheck* stack_check_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000214};
215
216
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000217class HGraph: public ZoneObject {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000218 public:
219 explicit HGraph(CompilationInfo* info);
220
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000221 Isolate* isolate() { return isolate_; }
222 Zone* zone() { return isolate_->zone(); }
223
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000224 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
225 const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000226 HBasicBlock* entry_block() const { return entry_block_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000227 HEnvironment* start_environment() const { return start_environment_; }
228
229 void InitializeInferredTypes();
230 void InsertTypeConversions();
231 void InsertRepresentationChanges();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000232 void MarkDeoptimizeOnUndefined();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000233 void ComputeMinusZeroChecks();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000234 bool ProcessArgumentsObject();
235 void EliminateRedundantPhis();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000236 void EliminateUnreachablePhis();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000237 void Canonicalize();
238 void OrderBlocks();
239 void AssignDominators();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000240 void ReplaceCheckedValues();
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000241 void PropagateDeoptimizingMark();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000242
243 // Returns false if there are phi-uses of the arguments-object
244 // which are not supported by the optimizing compiler.
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +0000245 bool CheckPhis();
246
247 // Returns false if there are phi-uses of hole values comming
248 // from uninitialized consts.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000249 bool CollectPhis();
250
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000251 Handle<Code> Compile(CompilationInfo* info);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000252
253 void set_undefined_constant(HConstant* constant) {
254 undefined_constant_.set(constant);
255 }
256 HConstant* GetConstantUndefined() const { return undefined_constant_.get(); }
257 HConstant* GetConstant1();
258 HConstant* GetConstantMinus1();
259 HConstant* GetConstantTrue();
260 HConstant* GetConstantFalse();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000261 HConstant* GetConstantHole();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000262
263 HBasicBlock* CreateBasicBlock();
264 HArgumentsObject* GetArgumentsObject() const {
265 return arguments_object_.get();
266 }
267 bool HasArgumentsObject() const { return arguments_object_.is_set(); }
268
269 void SetArgumentsObject(HArgumentsObject* object) {
270 arguments_object_.set(object);
271 }
272
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000273 int GetMaximumValueID() const { return values_.length(); }
274 int GetNextBlockID() { return next_block_id_++; }
275 int GetNextValueID(HValue* value) {
276 values_.Add(value);
277 return values_.length() - 1;
278 }
279 HValue* LookupValue(int id) const {
280 if (id >= 0 && id < values_.length()) return values_[id];
281 return NULL;
282 }
283
284#ifdef DEBUG
285 void Verify() const;
286#endif
287
288 private:
289 void Postorder(HBasicBlock* block,
290 BitVector* visited,
291 ZoneList<HBasicBlock*>* order,
292 HBasicBlock* loop_header);
293 void PostorderLoopBlocks(HLoopInformation* loop,
294 BitVector* visited,
295 ZoneList<HBasicBlock*>* order,
296 HBasicBlock* loop_header);
297 HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
298 Object* value);
299
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000300 void MarkAsDeoptimizingRecursively(HBasicBlock* block);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000301 void InsertTypeConversions(HInstruction* instr);
302 void PropagateMinusZeroChecks(HValue* value, BitVector* visited);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000303 void RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000304 void InsertRepresentationChangeForUse(HValue* value,
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000305 HValue* use_value,
306 int use_index,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000307 Representation to);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000308 void InsertRepresentationChangesForValue(HValue* value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000309 void InferTypes(ZoneList<HValue*>* worklist);
310 void InitializeInferredTypes(int from_inclusive, int to_inclusive);
311 void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
312
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000313 Isolate* isolate_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000314 int next_block_id_;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000315 HBasicBlock* entry_block_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000316 HEnvironment* start_environment_;
317 ZoneList<HBasicBlock*> blocks_;
318 ZoneList<HValue*> values_;
319 ZoneList<HPhi*>* phi_list_;
320 SetOncePointer<HConstant> undefined_constant_;
321 SetOncePointer<HConstant> constant_1_;
322 SetOncePointer<HConstant> constant_minus1_;
323 SetOncePointer<HConstant> constant_true_;
324 SetOncePointer<HConstant> constant_false_;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000325 SetOncePointer<HConstant> constant_hole_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000326 SetOncePointer<HArgumentsObject> arguments_object_;
327
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000328 DISALLOW_COPY_AND_ASSIGN(HGraph);
329};
330
331
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000332Zone* HBasicBlock::zone() { return graph_->zone(); }
333
334
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000335class HEnvironment: public ZoneObject {
336 public:
337 HEnvironment(HEnvironment* outer,
338 Scope* scope,
339 Handle<JSFunction> closure);
340
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000341 // Simple accessors.
342 Handle<JSFunction> closure() const { return closure_; }
343 const ZoneList<HValue*>* values() const { return &values_; }
344 const ZoneList<int>* assigned_variables() const {
345 return &assigned_variables_;
346 }
347 int parameter_count() const { return parameter_count_; }
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000348 int specials_count() const { return specials_count_; }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000349 int local_count() const { return local_count_; }
350 HEnvironment* outer() const { return outer_; }
351 int pop_count() const { return pop_count_; }
352 int push_count() const { return push_count_; }
353
354 int ast_id() const { return ast_id_; }
355 void set_ast_id(int id) { ast_id_ = id; }
356
357 int length() const { return values_.length(); }
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000358 bool is_special_index(int i) const {
359 return i >= parameter_count() && i < parameter_count() + specials_count();
360 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000361
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000362 void Bind(Variable* variable, HValue* value) {
363 Bind(IndexFor(variable), value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000364 }
365
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000366 void Bind(int index, HValue* value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000367
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000368 void BindContext(HValue* value) {
369 Bind(parameter_count(), value);
370 }
371
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000372 HValue* Lookup(Variable* variable) const {
373 return Lookup(IndexFor(variable));
374 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000375
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000376 HValue* Lookup(int index) const {
377 HValue* result = values_[index];
378 ASSERT(result != NULL);
379 return result;
380 }
381
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000382 HValue* LookupContext() const {
383 // Return first special.
384 return Lookup(parameter_count());
385 }
386
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000387 void Push(HValue* value) {
388 ASSERT(value != NULL);
389 ++push_count_;
390 values_.Add(value);
391 }
392
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000393 HValue* Pop() {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000394 ASSERT(!ExpressionStackIsEmpty());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000395 if (push_count_ > 0) {
396 --push_count_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000397 } else {
398 ++pop_count_;
399 }
400 return values_.RemoveLast();
401 }
402
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000403 void Drop(int count);
404
405 HValue* Top() const { return ExpressionStackAt(0); }
406
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000407 bool ExpressionStackIsEmpty() const;
408
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000409 HValue* ExpressionStackAt(int index_from_top) const {
410 int index = length() - index_from_top - 1;
411 ASSERT(HasExpressionAt(index));
412 return values_[index];
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000413 }
414
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000415 void SetExpressionStackAt(int index_from_top, HValue* value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000416
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000417 HEnvironment* Copy() const;
418 HEnvironment* CopyWithoutHistory() const;
419 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
420
421 // Create an "inlined version" of this environment, where the original
422 // environment is the outer environment but the top expression stack
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000423 // elements are moved to an inner environment as parameters.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000424 HEnvironment* CopyForInlining(Handle<JSFunction> target,
425 FunctionLiteral* function,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000426 HConstant* undefined,
427 CallKind call_kind) const;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000428
429 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000430
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000431 void ClearHistory() {
432 pop_count_ = 0;
433 push_count_ = 0;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000434 assigned_variables_.Rewind(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000435 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000436
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000437 void SetValueAt(int index, HValue* value) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000438 ASSERT(index < length());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000439 values_[index] = value;
440 }
441
442 void PrintTo(StringStream* stream);
443 void PrintToStd();
444
445 private:
446 explicit HEnvironment(const HEnvironment* other);
447
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000448 // True if index is included in the expression stack part of the environment.
449 bool HasExpressionAt(int index) const;
450
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000451 void Initialize(int parameter_count, int local_count, int stack_height);
452 void Initialize(const HEnvironment* other);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000453
454 // Map a variable to an environment index. Parameter indices are shifted
455 // by 1 (receiver is parameter index -1 but environment index 0).
456 // Stack-allocated local indices are shifted by the number of parameters.
457 int IndexFor(Variable* variable) const {
458 Slot* slot = variable->AsSlot();
459 ASSERT(slot != NULL && slot->IsStackAllocated());
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000460 int shift = (slot->type() == Slot::PARAMETER)
461 ? 1
462 : parameter_count_ + specials_count_;
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000463 return slot->index() + shift;
464 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000465
466 Handle<JSFunction> closure_;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000467 // Value array [parameters] [specials] [locals] [temporaries].
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000468 ZoneList<HValue*> values_;
469 ZoneList<int> assigned_variables_;
470 int parameter_count_;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000471 int specials_count_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000472 int local_count_;
473 HEnvironment* outer_;
474 int pop_count_;
475 int push_count_;
476 int ast_id_;
477};
478
479
480class HGraphBuilder;
481
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000482enum ArgumentsAllowedFlag {
483 ARGUMENTS_NOT_ALLOWED,
484 ARGUMENTS_ALLOWED
485};
486
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000487// This class is not BASE_EMBEDDED because our inlining implementation uses
488// new and delete.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000489class AstContext {
490 public:
491 bool IsEffect() const { return kind_ == Expression::kEffect; }
492 bool IsValue() const { return kind_ == Expression::kValue; }
493 bool IsTest() const { return kind_ == Expression::kTest; }
494
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000495 // 'Fill' this context with a hydrogen value. The value is assumed to
496 // have already been inserted in the instruction stream (or not need to
497 // be, e.g., HPhi). Call this function in tail position in the Visit
498 // functions for expressions.
499 virtual void ReturnValue(HValue* value) = 0;
500
501 // Add a hydrogen instruction to the instruction stream (recording an
502 // environment simulation if necessary) and then fill this context with
503 // the instruction as value.
504 virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;
505
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000506 // Finishes the current basic block and materialize a boolean for
507 // value context, nothing for effect, generate a branch for test context.
508 // Call this function in tail position in the Visit functions for
509 // expressions.
510 virtual void ReturnControl(HControlInstruction* instr, int ast_id) = 0;
511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000512 void set_for_typeof(bool for_typeof) { for_typeof_ = for_typeof; }
513 bool is_for_typeof() { return for_typeof_; }
514
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000515 protected:
516 AstContext(HGraphBuilder* owner, Expression::Context kind);
517 virtual ~AstContext();
518
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000519 HGraphBuilder* owner() const { return owner_; }
520
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000521 inline Zone* zone();
522
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000523 // We want to be able to assert, in a context-specific way, that the stack
524 // height makes sense when the context is filled.
525#ifdef DEBUG
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000526 int original_length_;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000527#endif
528
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000529 private:
530 HGraphBuilder* owner_;
531 Expression::Context kind_;
532 AstContext* outer_;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000533 bool for_typeof_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000534};
535
536
537class EffectContext: public AstContext {
538 public:
539 explicit EffectContext(HGraphBuilder* owner)
540 : AstContext(owner, Expression::kEffect) {
541 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000542 virtual ~EffectContext();
543
544 virtual void ReturnValue(HValue* value);
545 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000546 virtual void ReturnControl(HControlInstruction* instr, int ast_id);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000547};
548
549
550class ValueContext: public AstContext {
551 public:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000552 explicit ValueContext(HGraphBuilder* owner, ArgumentsAllowedFlag flag)
553 : AstContext(owner, Expression::kValue), flag_(flag) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000554 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000555 virtual ~ValueContext();
556
557 virtual void ReturnValue(HValue* value);
558 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000559 virtual void ReturnControl(HControlInstruction* instr, int ast_id);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000560
561 bool arguments_allowed() { return flag_ == ARGUMENTS_ALLOWED; }
562
563 private:
564 ArgumentsAllowedFlag flag_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000565};
566
567
568class TestContext: public AstContext {
569 public:
570 TestContext(HGraphBuilder* owner,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000571 Expression* condition,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000572 HBasicBlock* if_true,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000573 HBasicBlock* if_false)
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000574 : AstContext(owner, Expression::kTest),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000575 condition_(condition),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000576 if_true_(if_true),
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000577 if_false_(if_false) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000578 }
579
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000580 virtual void ReturnValue(HValue* value);
581 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000582 virtual void ReturnControl(HControlInstruction* instr, int ast_id);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000583
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000584 static TestContext* cast(AstContext* context) {
585 ASSERT(context->IsTest());
586 return reinterpret_cast<TestContext*>(context);
587 }
588
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000589 Expression* condition() const { return condition_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000590 HBasicBlock* if_true() const { return if_true_; }
591 HBasicBlock* if_false() const { return if_false_; }
592
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000593 private:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000594 // Build the shared core part of the translation unpacking a value into
595 // control flow.
596 void BuildBranch(HValue* value);
597
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000598 Expression* condition_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000599 HBasicBlock* if_true_;
600 HBasicBlock* if_false_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000601};
602
603
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000604class FunctionState BASE_EMBEDDED {
605 public:
606 FunctionState(HGraphBuilder* owner,
607 CompilationInfo* info,
608 TypeFeedbackOracle* oracle);
609 ~FunctionState();
610
611 CompilationInfo* compilation_info() { return compilation_info_; }
612 TypeFeedbackOracle* oracle() { return oracle_; }
613 AstContext* call_context() { return call_context_; }
614 HBasicBlock* function_return() { return function_return_; }
615 TestContext* test_context() { return test_context_; }
616 void ClearInlinedTestContext() {
617 delete test_context_;
618 test_context_ = NULL;
619 }
620
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000621 FunctionState* outer() { return outer_; }
622
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000623 private:
624 HGraphBuilder* owner_;
625
626 CompilationInfo* compilation_info_;
627 TypeFeedbackOracle* oracle_;
628
629 // During function inlining, expression context of the call being
630 // inlined. NULL when not inlining.
631 AstContext* call_context_;
632
633 // When inlining in an effect of value context, this is the return block.
634 // It is NULL otherwise. When inlining in a test context, there are a
635 // pair of return blocks in the context. When not inlining, there is no
636 // local return point.
637 HBasicBlock* function_return_;
638
639 // When inlining a call in a test context, a context containing a pair of
640 // return blocks. NULL in all other cases.
641 TestContext* test_context_;
642
643 FunctionState* outer_;
644};
645
646
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000647class HGraphBuilder: public AstVisitor {
648 public:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000649 enum BreakType { BREAK, CONTINUE };
650
651 // A class encapsulating (lazily-allocated) break and continue blocks for
652 // a breakable statement. Separated from BreakAndContinueScope so that it
653 // can have a separate lifetime.
654 class BreakAndContinueInfo BASE_EMBEDDED {
655 public:
656 explicit BreakAndContinueInfo(BreakableStatement* target)
657 : target_(target), break_block_(NULL), continue_block_(NULL) {
658 }
659
660 BreakableStatement* target() { return target_; }
661 HBasicBlock* break_block() { return break_block_; }
662 void set_break_block(HBasicBlock* block) { break_block_ = block; }
663 HBasicBlock* continue_block() { return continue_block_; }
664 void set_continue_block(HBasicBlock* block) { continue_block_ = block; }
665
666 private:
667 BreakableStatement* target_;
668 HBasicBlock* break_block_;
669 HBasicBlock* continue_block_;
670 };
671
672 // A helper class to maintain a stack of current BreakAndContinueInfo
673 // structures mirroring BreakableStatement nesting.
674 class BreakAndContinueScope BASE_EMBEDDED {
675 public:
676 BreakAndContinueScope(BreakAndContinueInfo* info, HGraphBuilder* owner)
677 : info_(info), owner_(owner), next_(owner->break_scope()) {
678 owner->set_break_scope(this);
679 }
680
681 ~BreakAndContinueScope() { owner_->set_break_scope(next_); }
682
683 BreakAndContinueInfo* info() { return info_; }
684 HGraphBuilder* owner() { return owner_; }
685 BreakAndContinueScope* next() { return next_; }
686
687 // Search the break stack for a break or continue target.
688 HBasicBlock* Get(BreakableStatement* stmt, BreakType type);
689
690 private:
691 BreakAndContinueInfo* info_;
692 HGraphBuilder* owner_;
693 BreakAndContinueScope* next_;
694 };
695
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000696 HGraphBuilder(CompilationInfo* info, TypeFeedbackOracle* oracle);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000697
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000698 HGraph* CreateGraph();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000699
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000700 // Simple accessors.
701 HGraph* graph() const { return graph_; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000702 BreakAndContinueScope* break_scope() const { return break_scope_; }
703 void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000704
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000705 HBasicBlock* current_block() const { return current_block_; }
706 void set_current_block(HBasicBlock* block) { current_block_ = block; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000707 HEnvironment* environment() const {
708 return current_block()->last_environment();
709 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000710
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000711 bool inline_bailout() { return inline_bailout_; }
712
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000713 // Adding instructions.
714 HInstruction* AddInstruction(HInstruction* instr);
ager@chromium.org04921a82011-06-27 13:21:41 +0000715 void AddSimulate(int ast_id);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000716
717 // Bailout environment manipulation.
718 void Push(HValue* value) { environment()->Push(value); }
719 HValue* Pop() { return environment()->Pop(); }
720
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000721 void Bailout(const char* reason);
722
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000723 HBasicBlock* CreateJoin(HBasicBlock* first,
724 HBasicBlock* second,
725 int join_id);
726
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000727 TypeFeedbackOracle* oracle() const { return function_state()->oracle(); }
728
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000729 private:
730 // Type of a member function that generates inline code for a native function.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000731 typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000732
733 // Forward declarations for inner scope classes.
734 class SubgraphScope;
735
736 static const InlineFunctionGenerator kInlineFunctionGenerators[];
737
738 static const int kMaxCallPolymorphism = 4;
739 static const int kMaxLoadPolymorphism = 4;
740 static const int kMaxStorePolymorphism = 4;
741
742 static const int kMaxInlinedNodes = 196;
743 static const int kMaxInlinedSize = 196;
744 static const int kMaxSourceSize = 600;
745
746 // Simple accessors.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000747 FunctionState* function_state() const { return function_state_; }
748 void set_function_state(FunctionState* state) { function_state_ = state; }
749
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000750 AstContext* ast_context() const { return ast_context_; }
751 void set_ast_context(AstContext* context) { ast_context_ = context; }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000752
753 // Accessors forwarded to the function state.
754 CompilationInfo* info() const {
755 return function_state()->compilation_info();
756 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000757
758 AstContext* call_context() const {
759 return function_state()->call_context();
760 }
761 HBasicBlock* function_return() const {
762 return function_state()->function_return();
763 }
764 TestContext* inlined_test_context() const {
765 return function_state()->test_context();
766 }
767 void ClearInlinedTestContext() {
768 function_state()->ClearInlinedTestContext();
769 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000770 bool function_strict_mode() {
771 return function_state()->compilation_info()->is_strict_mode();
772 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000773
774 // Generators for inline runtime functions.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000775#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000776 void Generate##Name(CallRuntime* call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000777
778 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
779 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
780#undef INLINE_FUNCTION_GENERATOR_DECLARATION
781
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000782 void VisitDelete(UnaryOperation* expr);
783 void VisitVoid(UnaryOperation* expr);
784 void VisitTypeof(UnaryOperation* expr);
785 void VisitAdd(UnaryOperation* expr);
786 void VisitSub(UnaryOperation* expr);
787 void VisitBitNot(UnaryOperation* expr);
788 void VisitNot(UnaryOperation* expr);
789
790 void VisitComma(BinaryOperation* expr);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000791 void VisitLogicalExpression(BinaryOperation* expr);
792 void VisitArithmeticExpression(BinaryOperation* expr);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000793
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000794 void PreProcessOsrEntry(IterationStatement* statement);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000795 // True iff. we are compiling for OSR and the statement is the entry.
796 bool HasOsrEntryAt(IterationStatement* statement);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000797 void VisitLoopBody(IterationStatement* stmt,
ager@chromium.org04921a82011-06-27 13:21:41 +0000798 HBasicBlock* loop_entry,
799 BreakAndContinueInfo* break_info);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000800
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000801 // Create a back edge in the flow graph. body_exit is the predecessor
802 // block and loop_entry is the successor block. loop_successor is the
803 // block where control flow exits the loop normally (e.g., via failure of
804 // the condition) and break_block is the block where control flow breaks
805 // from the loop. All blocks except loop_entry can be NULL. The return
806 // value is the new successor block which is the join of loop_successor
807 // and break_block, or NULL.
808 HBasicBlock* CreateLoop(IterationStatement* statement,
809 HBasicBlock* loop_entry,
810 HBasicBlock* body_exit,
811 HBasicBlock* loop_successor,
812 HBasicBlock* break_block);
813
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000814 HBasicBlock* JoinContinue(IterationStatement* statement,
815 HBasicBlock* exit_block,
816 HBasicBlock* continue_block);
817
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000818 HValue* Top() const { return environment()->Top(); }
819 void Drop(int n) { environment()->Drop(n); }
820 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
821
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000822 // The value of the arguments object is allowed in some but not most value
823 // contexts. (It's allowed in all effect contexts and disallowed in all
824 // test contexts.)
825 void VisitForValue(Expression* expr,
826 ArgumentsAllowedFlag flag = ARGUMENTS_NOT_ALLOWED);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000827 void VisitForTypeOf(Expression* expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000828 void VisitForEffect(Expression* expr);
829 void VisitForControl(Expression* expr,
830 HBasicBlock* true_block,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000831 HBasicBlock* false_block);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000832
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000833 // Visit an argument subexpression and emit a push to the outgoing
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000834 // arguments. Returns the hydrogen value that was pushed.
835 HValue* VisitArgument(Expression* expr);
836
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000837 void VisitArgumentList(ZoneList<Expression*>* arguments);
838
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000839 // Visit a list of expressions from left to right, each in a value context.
840 void VisitExpressions(ZoneList<Expression*>* exprs);
841
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000842 void AddPhi(HPhi* phi);
843
844 void PushAndAdd(HInstruction* instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000845
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000846 // Remove the arguments from the bailout environment and emit instructions
847 // to push them as outgoing parameters.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000848 template <int V> HInstruction* PreProcessCall(HCall<V>* call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000849
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000850 void TraceRepresentation(Token::Value op,
851 TypeInfo info,
852 HValue* value,
853 Representation rep);
854 void AssumeRepresentation(HValue* value, Representation rep);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000855 static Representation ToRepresentation(TypeInfo info);
856
857 void SetupScope(Scope* scope);
858 virtual void VisitStatements(ZoneList<Statement*>* statements);
859
860#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
861 AST_NODE_LIST(DECLARE_VISIT)
862#undef DECLARE_VISIT
863
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000864 HBasicBlock* CreateBasicBlock(HEnvironment* env);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000865 HBasicBlock* CreateLoopHeaderBlock();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000866
867 // Helpers for flow graph construction.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000868 enum GlobalPropertyAccess {
869 kUseCell,
870 kUseGeneric
871 };
872 GlobalPropertyAccess LookupGlobalProperty(Variable* var,
873 LookupResult* lookup,
874 bool is_store);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000875
876 bool TryArgumentsAccess(Property* expr);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000877
878 // Try to optimize fun.apply(receiver, arguments) pattern.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000879 bool TryCallApply(Call* expr);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000880
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000881 bool TryInline(Call* expr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000882 bool TryInlineBuiltinFunction(Call* expr,
883 HValue* receiver,
884 Handle<Map> receiver_map,
885 CheckType check_type);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000886
887 // If --trace-inlining, print a line of the inlining trace. Inlining
888 // succeeded if the reason string is NULL and failed if there is a
889 // non-NULL reason string.
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000890 void TraceInline(Handle<JSFunction> target,
891 Handle<JSFunction> caller,
892 const char* failure_reason);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000893
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000894 void HandleGlobalVariableAssignment(Variable* var,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000895 HValue* value,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000896 int position,
897 int ast_id);
898
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000899 void HandlePropertyAssignment(Assignment* expr);
900 void HandleCompoundAssignment(Assignment* expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000901 void HandlePolymorphicStoreNamedField(Assignment* expr,
902 HValue* object,
903 HValue* value,
904 ZoneMapList* types,
905 Handle<String> name);
906 void HandlePolymorphicCallNamed(Call* expr,
907 HValue* receiver,
908 ZoneMapList* types,
909 Handle<String> name);
ager@chromium.org04921a82011-06-27 13:21:41 +0000910 void HandleLiteralCompareTypeof(CompareOperation* compare_expr,
911 Expression* expr,
912 Handle<String> check);
913 void HandleLiteralCompareUndefined(CompareOperation* compare_expr,
914 Expression* expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000915
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000916 HStringCharCodeAt* BuildStringCharCodeAt(HValue* context,
917 HValue* string,
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000918 HValue* index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000919 HInstruction* BuildBinaryOperation(BinaryOperation* expr,
920 HValue* left,
921 HValue* right);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000922 HInstruction* BuildIncrement(bool returns_original_input,
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000923 CountOperation* expr);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000924 HLoadNamedField* BuildLoadNamedField(HValue* object,
925 Property* expr,
926 Handle<Map> type,
927 LookupResult* result,
928 bool smi_and_map_check);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000929 HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000930 HInstruction* BuildLoadKeyedGeneric(HValue* object,
931 HValue* key);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000932 HInstruction* BuildExternalArrayElementAccess(
933 HValue* external_elements,
934 HValue* checked_key,
935 HValue* val,
936 JSObject::ElementsKind elements_kind,
937 bool is_store);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000938
whesse@chromium.org7b260152011-06-20 15:33:18 +0000939 HInstruction* BuildMonomorphicElementAccess(HValue* object,
940 HValue* key,
941 HValue* val,
942 Expression* expr,
943 bool is_store);
944 HValue* HandlePolymorphicElementAccess(HValue* object,
945 HValue* key,
946 HValue* val,
947 Expression* prop,
948 int ast_id,
949 int position,
950 bool is_store,
951 bool* has_side_effects);
952
953 HValue* HandleKeyedElementAccess(HValue* obj,
954 HValue* key,
955 HValue* val,
956 Expression* expr,
957 int ast_id,
958 int position,
959 bool is_store,
960 bool* has_side_effects);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000961
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000962 HInstruction* BuildLoadNamed(HValue* object,
963 Property* prop,
964 Handle<Map> map,
965 Handle<String> name);
966 HInstruction* BuildStoreNamed(HValue* object,
967 HValue* value,
968 Expression* expr);
969 HInstruction* BuildStoreNamedField(HValue* object,
970 Handle<String> name,
971 HValue* value,
972 Handle<Map> type,
973 LookupResult* lookup,
974 bool smi_and_map_check);
975 HInstruction* BuildStoreNamedGeneric(HValue* object,
976 Handle<String> name,
977 HValue* value);
978 HInstruction* BuildStoreKeyedGeneric(HValue* object,
979 HValue* key,
980 HValue* value);
981
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000982 HValue* BuildContextChainWalk(Variable* var);
983
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000984 void AddCheckConstantFunction(Call* expr,
985 HValue* receiver,
986 Handle<Map> receiver_map,
987 bool smi_and_map_check);
988
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000989 Zone* zone() { return zone_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000990
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000991 // The translation state of the currently-being-translated function.
992 FunctionState* function_state_;
993
994 // The base of the function state stack.
995 FunctionState initial_function_state_;
996
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000997 // Expression context of the currently visited subexpression. NULL when
998 // visiting statements.
999 AstContext* ast_context_;
1000
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001001 // A stack of breakable statements entered.
1002 BreakAndContinueScope* break_scope_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001003
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001004 HGraph* graph_;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001005 HBasicBlock* current_block_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001006
1007 int inlined_count_;
1008
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001009 Zone* zone_;
1010
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001011 bool inline_bailout_;
1012
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001013 friend class FunctionState; // Pushes and pops the state stack.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001014 friend class AstContext; // Pushes and pops the AST context stack.
1015
1016 DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
1017};
1018
1019
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001020Zone* AstContext::zone() { return owner_->zone(); }
1021
1022
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001023class HValueMap: public ZoneObject {
1024 public:
1025 HValueMap()
1026 : array_size_(0),
1027 lists_size_(0),
1028 count_(0),
1029 present_flags_(0),
1030 array_(NULL),
1031 lists_(NULL),
1032 free_list_head_(kNil) {
1033 ResizeLists(kInitialSize);
1034 Resize(kInitialSize);
1035 }
1036
1037 void Kill(int flags);
1038
1039 void Add(HValue* value) {
1040 present_flags_ |= value->flags();
1041 Insert(value);
1042 }
1043
1044 HValue* Lookup(HValue* value) const;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001045
1046 HValueMap* Copy(Zone* zone) const {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001047 return new(zone) HValueMap(zone, this);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001048 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001049
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001050 bool IsEmpty() const { return count_ == 0; }
1051
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001052 private:
1053 // A linked list of HValue* values. Stored in arrays.
1054 struct HValueMapListElement {
1055 HValue* value;
1056 int next; // Index in the array of the next list element.
1057 };
1058 static const int kNil = -1; // The end of a linked list
1059
1060 // Must be a power of 2.
1061 static const int kInitialSize = 16;
1062
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001063 HValueMap(Zone* zone, const HValueMap* other);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001064
1065 void Resize(int new_size);
1066 void ResizeLists(int new_size);
1067 void Insert(HValue* value);
1068 uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); }
1069
1070 int array_size_;
1071 int lists_size_;
1072 int count_; // The number of values stored in the HValueMap.
1073 int present_flags_; // All flags that are in any value in the HValueMap.
1074 HValueMapListElement* array_; // Primary store - contains the first value
1075 // with a given hash. Colliding elements are stored in linked lists.
1076 HValueMapListElement* lists_; // The linked lists containing hash collisions.
1077 int free_list_head_; // Unused elements in lists_ are on the free list.
1078};
1079
1080
1081class HStatistics: public Malloced {
1082 public:
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001083 void Initialize(CompilationInfo* info);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001084 void Print();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001085 void SaveTiming(const char* name, int64_t ticks, unsigned size);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001086 static HStatistics* Instance() {
1087 static SetOncePointer<HStatistics> instance;
1088 if (!instance.is_set()) {
1089 instance.set(new HStatistics());
1090 }
1091 return instance.get();
1092 }
1093
1094 private:
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001095 HStatistics()
1096 : timing_(5),
1097 names_(5),
1098 sizes_(5),
1099 total_(0),
1100 total_size_(0),
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001101 full_code_gen_(0),
1102 source_size_(0) { }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001103
1104 List<int64_t> timing_;
1105 List<const char*> names_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001106 List<unsigned> sizes_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001107 int64_t total_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001108 unsigned total_size_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001109 int64_t full_code_gen_;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001110 double source_size_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001111};
1112
1113
1114class HPhase BASE_EMBEDDED {
1115 public:
1116 static const char* const kFullCodeGen;
1117 static const char* const kTotal;
1118
1119 explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); }
1120 HPhase(const char* name, HGraph* graph) {
1121 Begin(name, graph, NULL, NULL);
1122 }
1123 HPhase(const char* name, LChunk* chunk) {
1124 Begin(name, NULL, chunk, NULL);
1125 }
1126 HPhase(const char* name, LAllocator* allocator) {
1127 Begin(name, NULL, NULL, allocator);
1128 }
1129
1130 ~HPhase() {
1131 End();
1132 }
1133
1134 private:
1135 void Begin(const char* name,
1136 HGraph* graph,
1137 LChunk* chunk,
1138 LAllocator* allocator);
1139 void End() const;
1140
1141 int64_t start_;
1142 const char* name_;
1143 HGraph* graph_;
1144 LChunk* chunk_;
1145 LAllocator* allocator_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001146 unsigned start_allocation_size_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001147};
1148
1149
1150class HTracer: public Malloced {
1151 public:
1152 void TraceCompilation(FunctionLiteral* function);
1153 void TraceHydrogen(const char* name, HGraph* graph);
1154 void TraceLithium(const char* name, LChunk* chunk);
1155 void TraceLiveRanges(const char* name, LAllocator* allocator);
1156
1157 static HTracer* Instance() {
1158 static SetOncePointer<HTracer> instance;
1159 if (!instance.is_set()) {
1160 instance.set(new HTracer("hydrogen.cfg"));
1161 }
1162 return instance.get();
1163 }
1164
1165 private:
1166 class Tag BASE_EMBEDDED {
1167 public:
1168 Tag(HTracer* tracer, const char* name) {
1169 name_ = name;
1170 tracer_ = tracer;
1171 tracer->PrintIndent();
1172 tracer->trace_.Add("begin_%s\n", name);
1173 tracer->indent_++;
1174 }
1175
1176 ~Tag() {
1177 tracer_->indent_--;
1178 tracer_->PrintIndent();
1179 tracer_->trace_.Add("end_%s\n", name_);
1180 ASSERT(tracer_->indent_ >= 0);
1181 tracer_->FlushToFile();
1182 }
1183
1184 private:
1185 HTracer* tracer_;
1186 const char* name_;
1187 };
1188
1189 explicit HTracer(const char* filename)
1190 : filename_(filename), trace_(&string_allocator_), indent_(0) {
1191 WriteChars(filename, "", 0, false);
1192 }
1193
1194 void TraceLiveRange(LiveRange* range, const char* type);
1195 void Trace(const char* name, HGraph* graph, LChunk* chunk);
1196 void FlushToFile();
1197
1198 void PrintEmptyProperty(const char* name) {
1199 PrintIndent();
1200 trace_.Add("%s\n", name);
1201 }
1202
1203 void PrintStringProperty(const char* name, const char* value) {
1204 PrintIndent();
1205 trace_.Add("%s \"%s\"\n", name, value);
1206 }
1207
1208 void PrintLongProperty(const char* name, int64_t value) {
1209 PrintIndent();
1210 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
1211 }
1212
1213 void PrintBlockProperty(const char* name, int block_id) {
1214 PrintIndent();
1215 trace_.Add("%s \"B%d\"\n", name, block_id);
1216 }
1217
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001218 void PrintIntProperty(const char* name, int value) {
1219 PrintIndent();
1220 trace_.Add("%s %d\n", name, value);
1221 }
1222
1223 void PrintIndent() {
1224 for (int i = 0; i < indent_; i++) {
1225 trace_.Add(" ");
1226 }
1227 }
1228
1229 const char* filename_;
1230 HeapStringAllocator string_allocator_;
1231 StringStream trace_;
1232 int indent_;
1233};
1234
1235
1236} } // namespace v8::internal
1237
1238#endif // V8_HYDROGEN_H_