blob: 6fa3d1b9ff32cbafe55d839d7c429eeb5380c0db [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 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;
jkummerow@chromium.org28faa982012-04-13 09:58:30 +000045class FunctionState;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000046class HEnvironment;
47class HGraph;
48class HLoopInformation;
49class HTracer;
50class LAllocator;
51class LChunk;
52class LiveRange;
53
54
55class HBasicBlock: public ZoneObject {
56 public:
57 explicit HBasicBlock(HGraph* graph);
58 virtual ~HBasicBlock() { }
59
60 // Simple accessors.
61 int block_id() const { return block_id_; }
62 void set_block_id(int id) { block_id_ = id; }
63 HGraph* graph() const { return graph_; }
64 const ZoneList<HPhi*>* phis() const { return &phis_; }
65 HInstruction* first() const { return first_; }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000066 HInstruction* last() const { return last_; }
67 void set_last(HInstruction* instr) { last_ = instr; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000068 HInstruction* GetLastInstruction();
69 HControlInstruction* end() const { return end_; }
70 HLoopInformation* loop_information() const { return loop_information_; }
71 const ZoneList<HBasicBlock*>* predecessors() const { return &predecessors_; }
72 bool HasPredecessor() const { return predecessors_.length() > 0; }
73 const ZoneList<HBasicBlock*>* dominated_blocks() const {
74 return &dominated_blocks_;
75 }
76 const ZoneList<int>* deleted_phis() const {
77 return &deleted_phis_;
78 }
79 void RecordDeletedPhi(int merge_index) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +000080 deleted_phis_.Add(merge_index, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000081 }
82 HBasicBlock* dominator() const { return dominator_; }
83 HEnvironment* last_environment() const { return last_environment_; }
84 int argument_count() const { return argument_count_; }
85 void set_argument_count(int count) { argument_count_ = count; }
86 int first_instruction_index() const { return first_instruction_index_; }
87 void set_first_instruction_index(int index) {
88 first_instruction_index_ = index;
89 }
90 int last_instruction_index() const { return last_instruction_index_; }
91 void set_last_instruction_index(int index) {
92 last_instruction_index_ = index;
93 }
94
95 void AttachLoopInformation();
96 void DetachLoopInformation();
97 bool IsLoopHeader() const { return loop_information() != NULL; }
98 bool IsStartBlock() const { return block_id() == 0; }
99 void PostProcessLoopHeader(IterationStatement* stmt);
100
101 bool IsFinished() const { return end_ != NULL; }
102 void AddPhi(HPhi* phi);
103 void RemovePhi(HPhi* phi);
104 void AddInstruction(HInstruction* instr);
105 bool Dominates(HBasicBlock* other) const;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000106 int LoopNestingDepth() const;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000107
108 void SetInitialEnvironment(HEnvironment* env);
109 void ClearEnvironment() { last_environment_ = NULL; }
110 bool HasEnvironment() const { return last_environment_ != NULL; }
111 void UpdateEnvironment(HEnvironment* env) { last_environment_ = env; }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000112 HBasicBlock* parent_loop_header() const { return parent_loop_header_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000113
114 void set_parent_loop_header(HBasicBlock* block) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000115 ASSERT(parent_loop_header_ == NULL);
116 parent_loop_header_ = block;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000117 }
118
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000119 bool HasParentLoopHeader() const { return parent_loop_header_ != NULL; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000120
ager@chromium.org04921a82011-06-27 13:21:41 +0000121 void SetJoinId(int ast_id);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000122
123 void Finish(HControlInstruction* last);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000124 void FinishExit(HControlInstruction* instruction);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000125 void Goto(HBasicBlock* block, FunctionState* state = NULL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000126
127 int PredecessorIndexOf(HBasicBlock* predecessor) const;
ager@chromium.org04921a82011-06-27 13:21:41 +0000128 void AddSimulate(int ast_id) { AddInstruction(CreateSimulate(ast_id)); }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000129 void AssignCommonDominator(HBasicBlock* other);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000130 void AssignLoopSuccessorDominators();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000131
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000132 void FinishExitWithDeoptimization(HDeoptimize::UseEnvironment has_uses) {
133 FinishExit(CreateDeoptimize(has_uses));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000134 }
135
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000136 // Add the inlined function exit sequence, adding an HLeaveInlined
137 // instruction and updating the bailout environment.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000138 void AddLeaveInlined(HValue* return_value,
139 HBasicBlock* target,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000140 FunctionState* state = NULL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000141
142 // If a target block is tagged as an inline function return, all
143 // predecessors should contain the inlined exit sequence:
144 //
145 // LeaveInlined
146 // Simulate (caller's environment)
147 // Goto (target block)
148 bool IsInlineReturnTarget() const { return is_inline_return_target_; }
149 void MarkAsInlineReturnTarget() { is_inline_return_target_ = true; }
150
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000151 bool IsDeoptimizing() const { return is_deoptimizing_; }
152 void MarkAsDeoptimizing() { is_deoptimizing_ = true; }
153
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000154 bool IsLoopSuccessorDominator() const {
155 return dominates_loop_successors_;
156 }
157 void MarkAsLoopSuccessorDominator() {
158 dominates_loop_successors_ = true;
159 }
160
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000161 inline Zone* zone() const;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000162
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000163#ifdef DEBUG
164 void Verify();
165#endif
166
167 private:
168 void RegisterPredecessor(HBasicBlock* pred);
169 void AddDominatedBlock(HBasicBlock* block);
170
ager@chromium.org04921a82011-06-27 13:21:41 +0000171 HSimulate* CreateSimulate(int ast_id);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000172 HDeoptimize* CreateDeoptimize(HDeoptimize::UseEnvironment has_uses);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000173
174 int block_id_;
175 HGraph* graph_;
176 ZoneList<HPhi*> phis_;
177 HInstruction* first_;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000178 HInstruction* last_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000179 HControlInstruction* end_;
180 HLoopInformation* loop_information_;
181 ZoneList<HBasicBlock*> predecessors_;
182 HBasicBlock* dominator_;
183 ZoneList<HBasicBlock*> dominated_blocks_;
184 HEnvironment* last_environment_;
185 // Outgoing parameter count at block exit, set during lithium translation.
186 int argument_count_;
187 // Instruction indices into the lithium code stream.
188 int first_instruction_index_;
189 int last_instruction_index_;
190 ZoneList<int> deleted_phis_;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000191 HBasicBlock* parent_loop_header_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000192 bool is_inline_return_target_;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000193 bool is_deoptimizing_;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000194 bool dominates_loop_successors_;
195};
196
197
198class HPredecessorIterator BASE_EMBEDDED {
199 public:
200 explicit HPredecessorIterator(HBasicBlock* block)
201 : predecessor_list_(block->predecessors()), current_(0) { }
202
203 bool Done() { return current_ >= predecessor_list_->length(); }
204 HBasicBlock* Current() { return predecessor_list_->at(current_); }
205 void Advance() { current_++; }
206
207 private:
208 const ZoneList<HBasicBlock*>* predecessor_list_;
209 int current_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000210};
211
212
213class HLoopInformation: public ZoneObject {
214 public:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000215 HLoopInformation(HBasicBlock* loop_header, Zone* zone)
216 : back_edges_(4, zone),
ager@chromium.org04921a82011-06-27 13:21:41 +0000217 loop_header_(loop_header),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000218 blocks_(8, zone),
ager@chromium.org04921a82011-06-27 13:21:41 +0000219 stack_check_(NULL) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000220 blocks_.Add(loop_header, zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000221 }
222 virtual ~HLoopInformation() {}
223
224 const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; }
225 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
226 HBasicBlock* loop_header() const { return loop_header_; }
227 HBasicBlock* GetLastBackEdge() const;
228 void RegisterBackEdge(HBasicBlock* block);
229
ager@chromium.org04921a82011-06-27 13:21:41 +0000230 HStackCheck* stack_check() const { return stack_check_; }
231 void set_stack_check(HStackCheck* stack_check) {
232 stack_check_ = stack_check;
233 }
234
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000235 private:
236 void AddBlock(HBasicBlock* block);
237
238 ZoneList<HBasicBlock*> back_edges_;
239 HBasicBlock* loop_header_;
240 ZoneList<HBasicBlock*> blocks_;
ager@chromium.org04921a82011-06-27 13:21:41 +0000241 HStackCheck* stack_check_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000242};
243
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +0000244class BoundsCheckTable;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000245class HGraph: public ZoneObject {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000246 public:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000247 HGraph(CompilationInfo* info, Zone* zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000248
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000249 Isolate* isolate() { return isolate_; }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000250 Zone* zone() const { return zone_; }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000251
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000252 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
253 const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000254 HBasicBlock* entry_block() const { return entry_block_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000255 HEnvironment* start_environment() const { return start_environment_; }
256
257 void InitializeInferredTypes();
258 void InsertTypeConversions();
259 void InsertRepresentationChanges();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000260 void MarkDeoptimizeOnUndefined();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000261 void ComputeMinusZeroChecks();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000262 bool ProcessArgumentsObject();
263 void EliminateRedundantPhis();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000264 void EliminateUnreachablePhis();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000265 void Canonicalize();
266 void OrderBlocks();
267 void AssignDominators();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000268 void ReplaceCheckedValues();
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +0000269 void EliminateRedundantBoundsChecks();
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +0000270 void DehoistSimpleArrayIndexComputations();
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000271 void PropagateDeoptimizingMark();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000272
273 // Returns false if there are phi-uses of the arguments-object
274 // which are not supported by the optimizing compiler.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000275 bool CheckArgumentsPhiUses();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +0000276
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000277 // Returns false if there are phi-uses of an uninitialized const
278 // which are not supported by the optimizing compiler.
279 bool CheckConstPhiUses();
280
281 void CollectPhis();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000282
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000283 Handle<Code> Compile(CompilationInfo* info, Zone* zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000284
285 void set_undefined_constant(HConstant* constant) {
286 undefined_constant_.set(constant);
287 }
288 HConstant* GetConstantUndefined() const { return undefined_constant_.get(); }
289 HConstant* GetConstant1();
290 HConstant* GetConstantMinus1();
291 HConstant* GetConstantTrue();
292 HConstant* GetConstantFalse();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000293 HConstant* GetConstantHole();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000294
295 HBasicBlock* CreateBasicBlock();
296 HArgumentsObject* GetArgumentsObject() const {
297 return arguments_object_.get();
298 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000299
300 void SetArgumentsObject(HArgumentsObject* object) {
301 arguments_object_.set(object);
302 }
303
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000304 int GetMaximumValueID() const { return values_.length(); }
305 int GetNextBlockID() { return next_block_id_++; }
306 int GetNextValueID(HValue* value) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000307 values_.Add(value, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000308 return values_.length() - 1;
309 }
310 HValue* LookupValue(int id) const {
311 if (id >= 0 && id < values_.length()) return values_[id];
312 return NULL;
313 }
314
315#ifdef DEBUG
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000316 void Verify(bool do_full_verify) const;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000317#endif
318
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000319 bool has_osr_loop_entry() {
320 return osr_loop_entry_.is_set();
321 }
322
323 HBasicBlock* osr_loop_entry() {
324 return osr_loop_entry_.get();
325 }
326
327 void set_osr_loop_entry(HBasicBlock* entry) {
328 osr_loop_entry_.set(entry);
329 }
330
331 ZoneList<HUnknownOSRValue*>* osr_values() {
332 return osr_values_.get();
333 }
334
335 void set_osr_values(ZoneList<HUnknownOSRValue*>* values) {
336 osr_values_.set(values);
337 }
338
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000339 void MarkRecursive() {
340 is_recursive_ = true;
341 }
342
343 bool is_recursive() const {
344 return is_recursive_;
345 }
346
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000347 private:
348 void Postorder(HBasicBlock* block,
349 BitVector* visited,
350 ZoneList<HBasicBlock*>* order,
351 HBasicBlock* loop_header);
352 void PostorderLoopBlocks(HLoopInformation* loop,
353 BitVector* visited,
354 ZoneList<HBasicBlock*>* order,
355 HBasicBlock* loop_header);
356 HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
357 Object* value);
358
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000359 void MarkAsDeoptimizingRecursively(HBasicBlock* block);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000360 void InsertTypeConversions(HInstruction* instr);
361 void PropagateMinusZeroChecks(HValue* value, BitVector* visited);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000362 void RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000363 void InsertRepresentationChangeForUse(HValue* value,
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000364 HValue* use_value,
365 int use_index,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000366 Representation to);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000367 void InsertRepresentationChangesForValue(HValue* value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000368 void InferTypes(ZoneList<HValue*>* worklist);
369 void InitializeInferredTypes(int from_inclusive, int to_inclusive);
370 void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +0000371 void EliminateRedundantBoundsChecks(HBasicBlock* bb, BoundsCheckTable* table);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000372
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000373 Isolate* isolate_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000374 int next_block_id_;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000375 HBasicBlock* entry_block_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000376 HEnvironment* start_environment_;
377 ZoneList<HBasicBlock*> blocks_;
378 ZoneList<HValue*> values_;
379 ZoneList<HPhi*>* phi_list_;
380 SetOncePointer<HConstant> undefined_constant_;
381 SetOncePointer<HConstant> constant_1_;
382 SetOncePointer<HConstant> constant_minus1_;
383 SetOncePointer<HConstant> constant_true_;
384 SetOncePointer<HConstant> constant_false_;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000385 SetOncePointer<HConstant> constant_hole_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000386 SetOncePointer<HArgumentsObject> arguments_object_;
387
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000388 SetOncePointer<HBasicBlock> osr_loop_entry_;
389 SetOncePointer<ZoneList<HUnknownOSRValue*> > osr_values_;
390
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000391 Zone* zone_;
392
393 bool is_recursive_;
394
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000395 DISALLOW_COPY_AND_ASSIGN(HGraph);
396};
397
398
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000399Zone* HBasicBlock::zone() const { return graph_->zone(); }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000400
401
ulan@chromium.org967e2702012-02-28 09:49:15 +0000402// Type of stack frame an environment might refer to.
403enum FrameType { JS_FUNCTION, JS_CONSTRUCT, ARGUMENTS_ADAPTOR };
404
405
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000406class HEnvironment: public ZoneObject {
407 public:
408 HEnvironment(HEnvironment* outer,
409 Scope* scope,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000410 Handle<JSFunction> closure,
411 Zone* zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000412
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000413 HEnvironment* DiscardInlined(bool drop_extra) {
ulan@chromium.org967e2702012-02-28 09:49:15 +0000414 HEnvironment* outer = outer_;
415 while (outer->frame_type() != JS_FUNCTION) outer = outer->outer_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000416 if (drop_extra) outer->Drop(1);
417 return outer;
418 }
419
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000420 HEnvironment* arguments_environment() {
421 return outer()->frame_type() == ARGUMENTS_ADAPTOR ? outer() : this;
422 }
423
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000424 // Simple accessors.
425 Handle<JSFunction> closure() const { return closure_; }
426 const ZoneList<HValue*>* values() const { return &values_; }
427 const ZoneList<int>* assigned_variables() const {
428 return &assigned_variables_;
429 }
ulan@chromium.org967e2702012-02-28 09:49:15 +0000430 FrameType frame_type() const { return frame_type_; }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000431 int parameter_count() const { return parameter_count_; }
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000432 int specials_count() const { return specials_count_; }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000433 int local_count() const { return local_count_; }
434 HEnvironment* outer() const { return outer_; }
435 int pop_count() const { return pop_count_; }
436 int push_count() const { return push_count_; }
437
438 int ast_id() const { return ast_id_; }
439 void set_ast_id(int id) { ast_id_ = id; }
440
441 int length() const { return values_.length(); }
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000442 bool is_special_index(int i) const {
443 return i >= parameter_count() && i < parameter_count() + specials_count();
444 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000445
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000446 int first_expression_index() const {
447 return parameter_count() + specials_count() + local_count();
448 }
449
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000450 void Bind(Variable* variable, HValue* value) {
451 Bind(IndexFor(variable), value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000452 }
453
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000454 void Bind(int index, HValue* value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000455
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000456 void BindContext(HValue* value) {
457 Bind(parameter_count(), value);
458 }
459
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000460 HValue* Lookup(Variable* variable) const {
461 return Lookup(IndexFor(variable));
462 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000463
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000464 HValue* Lookup(int index) const {
465 HValue* result = values_[index];
466 ASSERT(result != NULL);
467 return result;
468 }
469
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000470 HValue* LookupContext() const {
471 // Return first special.
472 return Lookup(parameter_count());
473 }
474
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000475 void Push(HValue* value) {
476 ASSERT(value != NULL);
477 ++push_count_;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000478 values_.Add(value, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000479 }
480
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000481 HValue* Pop() {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000482 ASSERT(!ExpressionStackIsEmpty());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000483 if (push_count_ > 0) {
484 --push_count_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000485 } else {
486 ++pop_count_;
487 }
488 return values_.RemoveLast();
489 }
490
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000491 void Drop(int count);
492
493 HValue* Top() const { return ExpressionStackAt(0); }
494
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000495 bool ExpressionStackIsEmpty() const;
496
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000497 HValue* ExpressionStackAt(int index_from_top) const {
498 int index = length() - index_from_top - 1;
499 ASSERT(HasExpressionAt(index));
500 return values_[index];
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000501 }
502
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000503 void SetExpressionStackAt(int index_from_top, HValue* value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000504
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000505 HEnvironment* Copy() const;
506 HEnvironment* CopyWithoutHistory() const;
507 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
508
509 // Create an "inlined version" of this environment, where the original
510 // environment is the outer environment but the top expression stack
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000511 // elements are moved to an inner environment as parameters.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000512 HEnvironment* CopyForInlining(Handle<JSFunction> target,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000513 int arguments,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000514 FunctionLiteral* function,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000515 HConstant* undefined,
ulan@chromium.org967e2702012-02-28 09:49:15 +0000516 CallKind call_kind,
517 bool is_construct) const;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000518
519 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000520
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000521 void ClearHistory() {
522 pop_count_ = 0;
523 push_count_ = 0;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000524 assigned_variables_.Rewind(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000525 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000526
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000527 void SetValueAt(int index, HValue* value) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000528 ASSERT(index < length());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000529 values_[index] = value;
530 }
531
532 void PrintTo(StringStream* stream);
533 void PrintToStd();
534
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000535 Zone* zone() const { return zone_; }
536
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000537 private:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000538 HEnvironment(const HEnvironment* other, Zone* zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000539
ulan@chromium.org967e2702012-02-28 09:49:15 +0000540 HEnvironment(HEnvironment* outer,
541 Handle<JSFunction> closure,
542 FrameType frame_type,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000543 int arguments,
544 Zone* zone);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000545
ulan@chromium.org967e2702012-02-28 09:49:15 +0000546 // Create an artificial stub environment (e.g. for argument adaptor or
547 // constructor stub).
548 HEnvironment* CreateStubEnvironment(HEnvironment* outer,
549 Handle<JSFunction> target,
550 FrameType frame_type,
551 int arguments) const;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000552
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000553 // True if index is included in the expression stack part of the environment.
554 bool HasExpressionAt(int index) const;
555
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000556 void Initialize(int parameter_count, int local_count, int stack_height);
557 void Initialize(const HEnvironment* other);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000558
559 // Map a variable to an environment index. Parameter indices are shifted
560 // by 1 (receiver is parameter index -1 but environment index 0).
561 // Stack-allocated local indices are shifted by the number of parameters.
562 int IndexFor(Variable* variable) const {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000563 ASSERT(variable->IsStackAllocated());
564 int shift = variable->IsParameter()
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000565 ? 1
566 : parameter_count_ + specials_count_;
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000567 return variable->index() + shift;
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000568 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000569
570 Handle<JSFunction> closure_;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000571 // Value array [parameters] [specials] [locals] [temporaries].
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000572 ZoneList<HValue*> values_;
573 ZoneList<int> assigned_variables_;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000574 FrameType frame_type_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000575 int parameter_count_;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000576 int specials_count_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000577 int local_count_;
578 HEnvironment* outer_;
579 int pop_count_;
580 int push_count_;
581 int ast_id_;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000582 Zone* zone_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000583};
584
585
586class HGraphBuilder;
587
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000588enum ArgumentsAllowedFlag {
589 ARGUMENTS_NOT_ALLOWED,
590 ARGUMENTS_ALLOWED
591};
592
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000593// This class is not BASE_EMBEDDED because our inlining implementation uses
594// new and delete.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000595class AstContext {
596 public:
597 bool IsEffect() const { return kind_ == Expression::kEffect; }
598 bool IsValue() const { return kind_ == Expression::kValue; }
599 bool IsTest() const { return kind_ == Expression::kTest; }
600
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000601 // 'Fill' this context with a hydrogen value. The value is assumed to
602 // have already been inserted in the instruction stream (or not need to
603 // be, e.g., HPhi). Call this function in tail position in the Visit
604 // functions for expressions.
605 virtual void ReturnValue(HValue* value) = 0;
606
607 // Add a hydrogen instruction to the instruction stream (recording an
608 // environment simulation if necessary) and then fill this context with
609 // the instruction as value.
610 virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;
611
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000612 // Finishes the current basic block and materialize a boolean for
613 // value context, nothing for effect, generate a branch for test context.
614 // Call this function in tail position in the Visit functions for
615 // expressions.
616 virtual void ReturnControl(HControlInstruction* instr, int ast_id) = 0;
617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000618 void set_for_typeof(bool for_typeof) { for_typeof_ = for_typeof; }
619 bool is_for_typeof() { return for_typeof_; }
620
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000621 protected:
622 AstContext(HGraphBuilder* owner, Expression::Context kind);
623 virtual ~AstContext();
624
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000625 HGraphBuilder* owner() const { return owner_; }
626
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000627 inline Zone* zone() const;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000628
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000629 // We want to be able to assert, in a context-specific way, that the stack
630 // height makes sense when the context is filled.
631#ifdef DEBUG
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000632 int original_length_;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000633#endif
634
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000635 private:
636 HGraphBuilder* owner_;
637 Expression::Context kind_;
638 AstContext* outer_;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639 bool for_typeof_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000640};
641
642
643class EffectContext: public AstContext {
644 public:
645 explicit EffectContext(HGraphBuilder* owner)
646 : AstContext(owner, Expression::kEffect) {
647 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000648 virtual ~EffectContext();
649
650 virtual void ReturnValue(HValue* value);
651 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000652 virtual void ReturnControl(HControlInstruction* instr, int ast_id);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000653};
654
655
656class ValueContext: public AstContext {
657 public:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000658 explicit ValueContext(HGraphBuilder* owner, ArgumentsAllowedFlag flag)
659 : AstContext(owner, Expression::kValue), flag_(flag) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000660 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000661 virtual ~ValueContext();
662
663 virtual void ReturnValue(HValue* value);
664 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000665 virtual void ReturnControl(HControlInstruction* instr, int ast_id);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000666
667 bool arguments_allowed() { return flag_ == ARGUMENTS_ALLOWED; }
668
669 private:
670 ArgumentsAllowedFlag flag_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000671};
672
673
674class TestContext: public AstContext {
675 public:
676 TestContext(HGraphBuilder* owner,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000677 Expression* condition,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000678 HBasicBlock* if_true,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000679 HBasicBlock* if_false)
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000680 : AstContext(owner, Expression::kTest),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000681 condition_(condition),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000682 if_true_(if_true),
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000683 if_false_(if_false) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000684 }
685
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000686 virtual void ReturnValue(HValue* value);
687 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000688 virtual void ReturnControl(HControlInstruction* instr, int ast_id);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000689
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000690 static TestContext* cast(AstContext* context) {
691 ASSERT(context->IsTest());
692 return reinterpret_cast<TestContext*>(context);
693 }
694
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000695 Expression* condition() const { return condition_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000696 HBasicBlock* if_true() const { return if_true_; }
697 HBasicBlock* if_false() const { return if_false_; }
698
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000699 private:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000700 // Build the shared core part of the translation unpacking a value into
701 // control flow.
702 void BuildBranch(HValue* value);
703
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000704 Expression* condition_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000705 HBasicBlock* if_true_;
706 HBasicBlock* if_false_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000707};
708
709
ulan@chromium.org967e2702012-02-28 09:49:15 +0000710enum ReturnHandlingFlag {
711 NORMAL_RETURN,
712 DROP_EXTRA_ON_RETURN,
713 CONSTRUCT_CALL_RETURN
714};
715
716
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000717class FunctionState {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000718 public:
719 FunctionState(HGraphBuilder* owner,
720 CompilationInfo* info,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000721 TypeFeedbackOracle* oracle,
ulan@chromium.org967e2702012-02-28 09:49:15 +0000722 ReturnHandlingFlag return_handling);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000723 ~FunctionState();
724
725 CompilationInfo* compilation_info() { return compilation_info_; }
726 TypeFeedbackOracle* oracle() { return oracle_; }
727 AstContext* call_context() { return call_context_; }
ulan@chromium.org967e2702012-02-28 09:49:15 +0000728 bool drop_extra() { return return_handling_ == DROP_EXTRA_ON_RETURN; }
729 bool is_construct() { return return_handling_ == CONSTRUCT_CALL_RETURN; }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000730 HBasicBlock* function_return() { return function_return_; }
731 TestContext* test_context() { return test_context_; }
732 void ClearInlinedTestContext() {
733 delete test_context_;
734 test_context_ = NULL;
735 }
736
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000737 FunctionState* outer() { return outer_; }
738
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000739 HEnterInlined* entry() { return entry_; }
740 void set_entry(HEnterInlined* entry) { entry_ = entry; }
741
742 HArgumentsElements* arguments_elements() { return arguments_elements_; }
743 void set_arguments_elements(HArgumentsElements* arguments_elements) {
744 arguments_elements_ = arguments_elements;
745 }
746
747 bool arguments_pushed() { return arguments_elements() != NULL; }
748
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000749 private:
750 HGraphBuilder* owner_;
751
752 CompilationInfo* compilation_info_;
753 TypeFeedbackOracle* oracle_;
754
755 // During function inlining, expression context of the call being
756 // inlined. NULL when not inlining.
757 AstContext* call_context_;
758
ulan@chromium.org967e2702012-02-28 09:49:15 +0000759 // Indicate whether we have to perform special handling on return from
760 // inlined functions.
761 // - DROP_EXTRA_ON_RETURN: Drop an extra value from the environment.
762 // - CONSTRUCT_CALL_RETURN: Either use allocated receiver or return value.
763 ReturnHandlingFlag return_handling_;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000764
ulan@chromium.org967e2702012-02-28 09:49:15 +0000765 // When inlining in an effect or value context, this is the return block.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000766 // It is NULL otherwise. When inlining in a test context, there are a
767 // pair of return blocks in the context. When not inlining, there is no
768 // local return point.
769 HBasicBlock* function_return_;
770
771 // When inlining a call in a test context, a context containing a pair of
772 // return blocks. NULL in all other cases.
773 TestContext* test_context_;
774
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000775 // When inlining HEnterInlined instruction corresponding to the function
776 // entry.
777 HEnterInlined* entry_;
778
779 HArgumentsElements* arguments_elements_;
780
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000781 FunctionState* outer_;
782};
783
784
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000785class HGraphBuilder: public AstVisitor {
786 public:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000787 enum BreakType { BREAK, CONTINUE };
erikcorry0ad885c2011-11-21 13:51:57 +0000788 enum SwitchType { UNKNOWN_SWITCH, SMI_SWITCH, STRING_SWITCH };
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000789
790 // A class encapsulating (lazily-allocated) break and continue blocks for
791 // a breakable statement. Separated from BreakAndContinueScope so that it
792 // can have a separate lifetime.
793 class BreakAndContinueInfo BASE_EMBEDDED {
794 public:
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000795 explicit BreakAndContinueInfo(BreakableStatement* target,
796 int drop_extra = 0)
797 : target_(target),
798 break_block_(NULL),
799 continue_block_(NULL),
800 drop_extra_(drop_extra) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000801 }
802
803 BreakableStatement* target() { return target_; }
804 HBasicBlock* break_block() { return break_block_; }
805 void set_break_block(HBasicBlock* block) { break_block_ = block; }
806 HBasicBlock* continue_block() { return continue_block_; }
807 void set_continue_block(HBasicBlock* block) { continue_block_ = block; }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000808 int drop_extra() { return drop_extra_; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000809
810 private:
811 BreakableStatement* target_;
812 HBasicBlock* break_block_;
813 HBasicBlock* continue_block_;
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000814 int drop_extra_;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000815 };
816
817 // A helper class to maintain a stack of current BreakAndContinueInfo
818 // structures mirroring BreakableStatement nesting.
819 class BreakAndContinueScope BASE_EMBEDDED {
820 public:
821 BreakAndContinueScope(BreakAndContinueInfo* info, HGraphBuilder* owner)
822 : info_(info), owner_(owner), next_(owner->break_scope()) {
823 owner->set_break_scope(this);
824 }
825
826 ~BreakAndContinueScope() { owner_->set_break_scope(next_); }
827
828 BreakAndContinueInfo* info() { return info_; }
829 HGraphBuilder* owner() { return owner_; }
830 BreakAndContinueScope* next() { return next_; }
831
832 // Search the break stack for a break or continue target.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000833 HBasicBlock* Get(BreakableStatement* stmt, BreakType type, int* drop_extra);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000834
835 private:
836 BreakAndContinueInfo* info_;
837 HGraphBuilder* owner_;
838 BreakAndContinueScope* next_;
839 };
840
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000841 HGraphBuilder(CompilationInfo* info, TypeFeedbackOracle* oracle, Zone* zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000842
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000843 HGraph* CreateGraph();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000844
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000845 // Simple accessors.
846 HGraph* graph() const { return graph_; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000847 BreakAndContinueScope* break_scope() const { return break_scope_; }
848 void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000849
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000850 HBasicBlock* current_block() const { return current_block_; }
851 void set_current_block(HBasicBlock* block) { current_block_ = block; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000852 HEnvironment* environment() const {
853 return current_block()->last_environment();
854 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000855
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000856 bool inline_bailout() { return inline_bailout_; }
857
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000858 // Adding instructions.
859 HInstruction* AddInstruction(HInstruction* instr);
ager@chromium.org04921a82011-06-27 13:21:41 +0000860 void AddSimulate(int ast_id);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000861
862 // Bailout environment manipulation.
863 void Push(HValue* value) { environment()->Push(value); }
864 HValue* Pop() { return environment()->Pop(); }
865
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000866 void Bailout(const char* reason);
867
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000868 HBasicBlock* CreateJoin(HBasicBlock* first,
869 HBasicBlock* second,
870 int join_id);
871
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000872 TypeFeedbackOracle* oracle() const { return function_state()->oracle(); }
873
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000874 FunctionState* function_state() const { return function_state_; }
875
yangguo@chromium.org56454712012-02-16 15:33:53 +0000876 void VisitDeclarations(ZoneList<Declaration*>* declarations);
877
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000878 private:
879 // Type of a member function that generates inline code for a native function.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000880 typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000881
882 // Forward declarations for inner scope classes.
883 class SubgraphScope;
884
885 static const InlineFunctionGenerator kInlineFunctionGenerators[];
886
887 static const int kMaxCallPolymorphism = 4;
888 static const int kMaxLoadPolymorphism = 4;
889 static const int kMaxStorePolymorphism = 4;
890
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000891 // Even in the 'unlimited' case we have to have some limit in order not to
892 // overflow the stack.
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +0000893 static const int kUnlimitedMaxInlinedSourceSize = 100000;
894 static const int kUnlimitedMaxInlinedNodes = 10000;
895 static const int kUnlimitedMaxInlinedNodesCumulative = 10000;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000896
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000897 // Simple accessors.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000898 void set_function_state(FunctionState* state) { function_state_ = state; }
899
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000900 AstContext* ast_context() const { return ast_context_; }
901 void set_ast_context(AstContext* context) { ast_context_ = context; }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000902
903 // Accessors forwarded to the function state.
904 CompilationInfo* info() const {
905 return function_state()->compilation_info();
906 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000907 AstContext* call_context() const {
908 return function_state()->call_context();
909 }
910 HBasicBlock* function_return() const {
911 return function_state()->function_return();
912 }
913 TestContext* inlined_test_context() const {
914 return function_state()->test_context();
915 }
916 void ClearInlinedTestContext() {
917 function_state()->ClearInlinedTestContext();
918 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000919 StrictModeFlag function_strict_mode_flag() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000920 return function_state()->compilation_info()->is_classic_mode()
921 ? kNonStrictMode : kStrictMode;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000922 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000923
924 // Generators for inline runtime functions.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000925#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000926 void Generate##Name(CallRuntime* call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000927
928 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
929 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
930#undef INLINE_FUNCTION_GENERATOR_DECLARATION
931
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000932 void VisitDelete(UnaryOperation* expr);
933 void VisitVoid(UnaryOperation* expr);
934 void VisitTypeof(UnaryOperation* expr);
935 void VisitAdd(UnaryOperation* expr);
936 void VisitSub(UnaryOperation* expr);
937 void VisitBitNot(UnaryOperation* expr);
938 void VisitNot(UnaryOperation* expr);
939
940 void VisitComma(BinaryOperation* expr);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000941 void VisitLogicalExpression(BinaryOperation* expr);
942 void VisitArithmeticExpression(BinaryOperation* expr);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000943
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000944 bool PreProcessOsrEntry(IterationStatement* statement);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000945 // True iff. we are compiling for OSR and the statement is the entry.
946 bool HasOsrEntryAt(IterationStatement* statement);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000947 void VisitLoopBody(IterationStatement* stmt,
ager@chromium.org04921a82011-06-27 13:21:41 +0000948 HBasicBlock* loop_entry,
949 BreakAndContinueInfo* break_info);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000950
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000951 // Create a back edge in the flow graph. body_exit is the predecessor
952 // block and loop_entry is the successor block. loop_successor is the
953 // block where control flow exits the loop normally (e.g., via failure of
954 // the condition) and break_block is the block where control flow breaks
955 // from the loop. All blocks except loop_entry can be NULL. The return
956 // value is the new successor block which is the join of loop_successor
957 // and break_block, or NULL.
958 HBasicBlock* CreateLoop(IterationStatement* statement,
959 HBasicBlock* loop_entry,
960 HBasicBlock* body_exit,
961 HBasicBlock* loop_successor,
962 HBasicBlock* break_block);
963
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000964 HBasicBlock* JoinContinue(IterationStatement* statement,
965 HBasicBlock* exit_block,
966 HBasicBlock* continue_block);
967
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000968 HValue* Top() const { return environment()->Top(); }
969 void Drop(int n) { environment()->Drop(n); }
970 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
971
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000972 // The value of the arguments object is allowed in some but not most value
973 // contexts. (It's allowed in all effect contexts and disallowed in all
974 // test contexts.)
975 void VisitForValue(Expression* expr,
976 ArgumentsAllowedFlag flag = ARGUMENTS_NOT_ALLOWED);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000977 void VisitForTypeOf(Expression* expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000978 void VisitForEffect(Expression* expr);
979 void VisitForControl(Expression* expr,
980 HBasicBlock* true_block,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000981 HBasicBlock* false_block);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000982
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000983 // Visit an argument subexpression and emit a push to the outgoing
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000984 // arguments. Returns the hydrogen value that was pushed.
985 HValue* VisitArgument(Expression* expr);
986
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000987 void VisitArgumentList(ZoneList<Expression*>* arguments);
988
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000989 // Visit a list of expressions from left to right, each in a value context.
990 void VisitExpressions(ZoneList<Expression*>* exprs);
991
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000992 void AddPhi(HPhi* phi);
993
994 void PushAndAdd(HInstruction* instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000995
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000996 // Remove the arguments from the bailout environment and emit instructions
997 // to push them as outgoing parameters.
ulan@chromium.org967e2702012-02-28 09:49:15 +0000998 template <class Instruction> HInstruction* PreProcessCall(Instruction* call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000999
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001000 void TraceRepresentation(Token::Value op,
1001 TypeInfo info,
1002 HValue* value,
1003 Representation rep);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001004 static Representation ToRepresentation(TypeInfo info);
1005
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001006 void SetUpScope(Scope* scope);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001007 virtual void VisitStatements(ZoneList<Statement*>* statements);
1008
1009#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
1010 AST_NODE_LIST(DECLARE_VISIT)
1011#undef DECLARE_VISIT
1012
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001013 HBasicBlock* CreateBasicBlock(HEnvironment* env);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001014 HBasicBlock* CreateLoopHeaderBlock();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001015
1016 // Helpers for flow graph construction.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001017 enum GlobalPropertyAccess {
1018 kUseCell,
1019 kUseGeneric
1020 };
1021 GlobalPropertyAccess LookupGlobalProperty(Variable* var,
1022 LookupResult* lookup,
1023 bool is_store);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001024
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001025 void EnsureArgumentsArePushedForAccess();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001026 bool TryArgumentsAccess(Property* expr);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001027
1028 // Try to optimize fun.apply(receiver, arguments) pattern.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001029 bool TryCallApply(Call* expr);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001030
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001031 int InliningAstSize(Handle<JSFunction> target);
ulan@chromium.org967e2702012-02-28 09:49:15 +00001032 bool TryInline(CallKind call_kind,
1033 Handle<JSFunction> target,
1034 ZoneList<Expression*>* arguments,
1035 HValue* receiver,
1036 int ast_id,
1037 int return_id,
1038 ReturnHandlingFlag return_handling);
1039
1040 bool TryInlineCall(Call* expr, bool drop_extra = false);
1041 bool TryInlineConstruct(CallNew* expr, HValue* receiver);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001042 bool TryInlineBuiltinMethodCall(Call* expr,
ulan@chromium.org967e2702012-02-28 09:49:15 +00001043 HValue* receiver,
1044 Handle<Map> receiver_map,
1045 CheckType check_type);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001046 bool TryInlineBuiltinFunctionCall(Call* expr, bool drop_extra);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001047
1048 // If --trace-inlining, print a line of the inlining trace. Inlining
1049 // succeeded if the reason string is NULL and failed if there is a
1050 // non-NULL reason string.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001051 void TraceInline(Handle<JSFunction> target,
1052 Handle<JSFunction> caller,
1053 const char* failure_reason);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001054
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001055 void HandleGlobalVariableAssignment(Variable* var,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001056 HValue* value,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001057 int position,
1058 int ast_id);
1059
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001060 void HandlePropertyAssignment(Assignment* expr);
1061 void HandleCompoundAssignment(Assignment* expr);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001062 void HandlePolymorphicLoadNamedField(Property* expr,
1063 HValue* object,
1064 SmallMapList* types,
1065 Handle<String> name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001066 void HandlePolymorphicStoreNamedField(Assignment* expr,
1067 HValue* object,
1068 HValue* value,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00001069 SmallMapList* types,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001070 Handle<String> name);
1071 void HandlePolymorphicCallNamed(Call* expr,
1072 HValue* receiver,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00001073 SmallMapList* types,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001074 Handle<String> name);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001075 void HandleLiteralCompareTypeof(CompareOperation* expr,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001076 HTypeof* typeof_expr,
ager@chromium.org04921a82011-06-27 13:21:41 +00001077 Handle<String> check);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001078 void HandleLiteralCompareNil(CompareOperation* expr,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001079 HValue* value,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001080 NilValue nil);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001081
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001082 HStringCharCodeAt* BuildStringCharCodeAt(HValue* context,
1083 HValue* string,
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001084 HValue* index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001085 HInstruction* BuildBinaryOperation(BinaryOperation* expr,
1086 HValue* left,
1087 HValue* right);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001088 HInstruction* BuildIncrement(bool returns_original_input,
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001089 CountOperation* expr);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001090 HLoadNamedField* BuildLoadNamedField(HValue* object,
1091 Property* expr,
1092 Handle<Map> type,
1093 LookupResult* result,
1094 bool smi_and_map_check);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001095 HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001096 HInstruction* BuildLoadKeyedGeneric(HValue* object,
1097 HValue* key);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001098 HInstruction* BuildExternalArrayElementAccess(
1099 HValue* external_elements,
1100 HValue* checked_key,
1101 HValue* val,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001102 ElementsKind elements_kind,
whesse@chromium.org7b260152011-06-20 15:33:18 +00001103 bool is_store);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001104 HInstruction* BuildFastElementAccess(HValue* elements,
1105 HValue* checked_key,
1106 HValue* val,
1107 ElementsKind elements_kind,
1108 bool is_store);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001109
whesse@chromium.org7b260152011-06-20 15:33:18 +00001110 HInstruction* BuildMonomorphicElementAccess(HValue* object,
1111 HValue* key,
1112 HValue* val,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001113 HValue* dependency,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001114 Handle<Map> map,
whesse@chromium.org7b260152011-06-20 15:33:18 +00001115 bool is_store);
1116 HValue* HandlePolymorphicElementAccess(HValue* object,
1117 HValue* key,
1118 HValue* val,
1119 Expression* prop,
1120 int ast_id,
1121 int position,
1122 bool is_store,
1123 bool* has_side_effects);
1124
1125 HValue* HandleKeyedElementAccess(HValue* obj,
1126 HValue* key,
1127 HValue* val,
1128 Expression* expr,
1129 int ast_id,
1130 int position,
1131 bool is_store,
1132 bool* has_side_effects);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001133
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001134 HInstruction* BuildLoadNamed(HValue* object,
1135 Property* prop,
1136 Handle<Map> map,
1137 Handle<String> name);
1138 HInstruction* BuildStoreNamed(HValue* object,
1139 HValue* value,
1140 Expression* expr);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001141 HInstruction* BuildStoreNamed(HValue* object,
1142 HValue* value,
1143 ObjectLiteral::Property* prop);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001144 HInstruction* BuildStoreNamedField(HValue* object,
1145 Handle<String> name,
1146 HValue* value,
1147 Handle<Map> type,
1148 LookupResult* lookup,
1149 bool smi_and_map_check);
1150 HInstruction* BuildStoreNamedGeneric(HValue* object,
1151 Handle<String> name,
1152 HValue* value);
1153 HInstruction* BuildStoreKeyedGeneric(HValue* object,
1154 HValue* key,
1155 HValue* value);
1156
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001157 HValue* BuildContextChainWalk(Variable* var);
1158
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001159 void AddCheckConstantFunction(Call* expr,
1160 HValue* receiver,
1161 Handle<Map> receiver_map,
1162 bool smi_and_map_check);
1163
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001164 Zone* zone() const { return zone_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001165
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001166 // The translation state of the currently-being-translated function.
1167 FunctionState* function_state_;
1168
1169 // The base of the function state stack.
1170 FunctionState initial_function_state_;
1171
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001172 // Expression context of the currently visited subexpression. NULL when
1173 // visiting statements.
1174 AstContext* ast_context_;
1175
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001176 // A stack of breakable statements entered.
1177 BreakAndContinueScope* break_scope_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001178
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001179 HGraph* graph_;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001180 HBasicBlock* current_block_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001181
1182 int inlined_count_;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001183 ZoneList<Handle<Object> > globals_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001184
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001185 Zone* zone_;
1186
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001187 bool inline_bailout_;
1188
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001189 friend class FunctionState; // Pushes and pops the state stack.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001190 friend class AstContext; // Pushes and pops the AST context stack.
1191
1192 DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
1193};
1194
1195
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001196Zone* AstContext::zone() const { return owner_->zone(); }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001197
1198
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001199class HValueMap: public ZoneObject {
1200 public:
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001201 explicit HValueMap(Zone* zone)
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001202 : array_size_(0),
1203 lists_size_(0),
1204 count_(0),
1205 present_flags_(0),
1206 array_(NULL),
1207 lists_(NULL),
1208 free_list_head_(kNil) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001209 ResizeLists(kInitialSize, zone);
1210 Resize(kInitialSize, zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001211 }
1212
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001213 void Kill(GVNFlagSet flags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001214
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001215 void Add(HValue* value, Zone* zone) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001216 present_flags_.Add(value->gvn_flags());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001217 Insert(value, zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001218 }
1219
1220 HValue* Lookup(HValue* value) const;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001221
1222 HValueMap* Copy(Zone* zone) const {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001223 return new(zone) HValueMap(zone, this);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001224 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001225
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001226 bool IsEmpty() const { return count_ == 0; }
1227
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001228 private:
1229 // A linked list of HValue* values. Stored in arrays.
1230 struct HValueMapListElement {
1231 HValue* value;
1232 int next; // Index in the array of the next list element.
1233 };
1234 static const int kNil = -1; // The end of a linked list
1235
1236 // Must be a power of 2.
1237 static const int kInitialSize = 16;
1238
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001239 HValueMap(Zone* zone, const HValueMap* other);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001240
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001241 void Resize(int new_size, Zone* zone);
1242 void ResizeLists(int new_size, Zone* zone);
1243 void Insert(HValue* value, Zone* zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001244 uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); }
1245
1246 int array_size_;
1247 int lists_size_;
1248 int count_; // The number of values stored in the HValueMap.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001249 GVNFlagSet present_flags_; // All flags that are in any value in the
1250 // HValueMap.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001251 HValueMapListElement* array_; // Primary store - contains the first value
1252 // with a given hash. Colliding elements are stored in linked lists.
1253 HValueMapListElement* lists_; // The linked lists containing hash collisions.
1254 int free_list_head_; // Unused elements in lists_ are on the free list.
1255};
1256
1257
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001258class HSideEffectMap BASE_EMBEDDED {
1259 public:
1260 HSideEffectMap();
1261 explicit HSideEffectMap(HSideEffectMap* other);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001262 HSideEffectMap& operator= (const HSideEffectMap& other);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001263
1264 void Kill(GVNFlagSet flags);
1265
1266 void Store(GVNFlagSet flags, HInstruction* instr);
1267
1268 bool IsEmpty() const { return count_ == 0; }
1269
1270 inline HInstruction* operator[](int i) const {
1271 ASSERT(0 <= i);
1272 ASSERT(i < kNumberOfTrackedSideEffects);
1273 return data_[i];
1274 }
1275 inline HInstruction* at(int i) const { return operator[](i); }
1276
1277 private:
1278 int count_;
1279 HInstruction* data_[kNumberOfTrackedSideEffects];
1280};
1281
1282
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001283class HStatistics: public Malloced {
1284 public:
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001285 void Initialize(CompilationInfo* info);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001286 void Print();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001287 void SaveTiming(const char* name, int64_t ticks, unsigned size);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001288 static HStatistics* Instance() {
1289 static SetOncePointer<HStatistics> instance;
1290 if (!instance.is_set()) {
1291 instance.set(new HStatistics());
1292 }
1293 return instance.get();
1294 }
1295
1296 private:
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001297 HStatistics()
1298 : timing_(5),
1299 names_(5),
1300 sizes_(5),
1301 total_(0),
1302 total_size_(0),
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001303 full_code_gen_(0),
1304 source_size_(0) { }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001305
1306 List<int64_t> timing_;
1307 List<const char*> names_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001308 List<unsigned> sizes_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001309 int64_t total_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001310 unsigned total_size_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001311 int64_t full_code_gen_;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001312 double source_size_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001313};
1314
1315
1316class HPhase BASE_EMBEDDED {
1317 public:
1318 static const char* const kFullCodeGen;
1319 static const char* const kTotal;
1320
1321 explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); }
1322 HPhase(const char* name, HGraph* graph) {
1323 Begin(name, graph, NULL, NULL);
1324 }
1325 HPhase(const char* name, LChunk* chunk) {
1326 Begin(name, NULL, chunk, NULL);
1327 }
1328 HPhase(const char* name, LAllocator* allocator) {
1329 Begin(name, NULL, NULL, allocator);
1330 }
1331
1332 ~HPhase() {
1333 End();
1334 }
1335
1336 private:
1337 void Begin(const char* name,
1338 HGraph* graph,
1339 LChunk* chunk,
1340 LAllocator* allocator);
1341 void End() const;
1342
1343 int64_t start_;
1344 const char* name_;
1345 HGraph* graph_;
1346 LChunk* chunk_;
1347 LAllocator* allocator_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001348 unsigned start_allocation_size_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001349};
1350
1351
1352class HTracer: public Malloced {
1353 public:
1354 void TraceCompilation(FunctionLiteral* function);
1355 void TraceHydrogen(const char* name, HGraph* graph);
1356 void TraceLithium(const char* name, LChunk* chunk);
1357 void TraceLiveRanges(const char* name, LAllocator* allocator);
1358
1359 static HTracer* Instance() {
1360 static SetOncePointer<HTracer> instance;
1361 if (!instance.is_set()) {
1362 instance.set(new HTracer("hydrogen.cfg"));
1363 }
1364 return instance.get();
1365 }
1366
1367 private:
1368 class Tag BASE_EMBEDDED {
1369 public:
1370 Tag(HTracer* tracer, const char* name) {
1371 name_ = name;
1372 tracer_ = tracer;
1373 tracer->PrintIndent();
1374 tracer->trace_.Add("begin_%s\n", name);
1375 tracer->indent_++;
1376 }
1377
1378 ~Tag() {
1379 tracer_->indent_--;
1380 tracer_->PrintIndent();
1381 tracer_->trace_.Add("end_%s\n", name_);
1382 ASSERT(tracer_->indent_ >= 0);
1383 tracer_->FlushToFile();
1384 }
1385
1386 private:
1387 HTracer* tracer_;
1388 const char* name_;
1389 };
1390
1391 explicit HTracer(const char* filename)
1392 : filename_(filename), trace_(&string_allocator_), indent_(0) {
1393 WriteChars(filename, "", 0, false);
1394 }
1395
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001396 void TraceLiveRange(LiveRange* range, const char* type, Zone* zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001397 void Trace(const char* name, HGraph* graph, LChunk* chunk);
1398 void FlushToFile();
1399
1400 void PrintEmptyProperty(const char* name) {
1401 PrintIndent();
1402 trace_.Add("%s\n", name);
1403 }
1404
1405 void PrintStringProperty(const char* name, const char* value) {
1406 PrintIndent();
1407 trace_.Add("%s \"%s\"\n", name, value);
1408 }
1409
1410 void PrintLongProperty(const char* name, int64_t value) {
1411 PrintIndent();
1412 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
1413 }
1414
1415 void PrintBlockProperty(const char* name, int block_id) {
1416 PrintIndent();
1417 trace_.Add("%s \"B%d\"\n", name, block_id);
1418 }
1419
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001420 void PrintIntProperty(const char* name, int value) {
1421 PrintIndent();
1422 trace_.Add("%s %d\n", name, value);
1423 }
1424
1425 void PrintIndent() {
1426 for (int i = 0; i < indent_; i++) {
1427 trace_.Add(" ");
1428 }
1429 }
1430
1431 const char* filename_;
1432 HeapStringAllocator string_allocator_;
1433 StringStream trace_;
1434 int indent_;
1435};
1436
1437
1438} } // namespace v8::internal
1439
1440#endif // V8_HYDROGEN_H_