1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef V8_CRANKSHAFT_HYDROGEN_H_
6 #define V8_CRANKSHAFT_HYDROGEN_H_
7
8 #include "src/accessors.h"
9 #include "src/allocation.h"
10 #include "src/ast/ast-type-bounds.h"
11 #include "src/ast/scopes.h"
12 #include "src/bailout-reason.h"
13 #include "src/compilation-info.h"
14 #include "src/compiler.h"
15 #include "src/crankshaft/compilation-phase.h"
16 #include "src/crankshaft/hydrogen-instructions.h"
17 #include "src/globals.h"
18 #include "src/parsing/parse-info.h"
19 #include "src/zone/zone.h"
20
21 namespace v8 {
22 namespace internal {
23
24 // Forward declarations.
25 class BitVector;
26 class FunctionState;
27 class HEnvironment;
28 class HGraph;
29 class HLoopInformation;
30 class HOsrBuilder;
31 class HTracer;
32 class LAllocator;
33 class LChunk;
34 class LiveRange;
35
36 class HCompilationJob final : public CompilationJob {
37 public:
HCompilationJob(Handle<JSFunction> function)38 explicit HCompilationJob(Handle<JSFunction> function)
39 : CompilationJob(function->GetIsolate(), &info_, "Crankshaft"),
40 zone_(function->GetIsolate()->allocator(), ZONE_NAME),
41 parse_info_(&zone_, handle(function->shared())),
42 info_(&parse_info_, function),
43 graph_(nullptr),
44 chunk_(nullptr) {}
45
46 protected:
47 virtual Status PrepareJobImpl();
48 virtual Status ExecuteJobImpl();
49 virtual Status FinalizeJobImpl();
50
51 private:
52 Zone zone_;
53 ParseInfo parse_info_;
54 CompilationInfo info_;
55 HGraph* graph_;
56 LChunk* chunk_;
57 };
58
59 class HBasicBlock final : public ZoneObject {
60 public:
61 explicit HBasicBlock(HGraph* graph);
~HBasicBlock()62 ~HBasicBlock() { }
63
64 // Simple accessors.
block_id()65 int block_id() const { return block_id_; }
set_block_id(int id)66 void set_block_id(int id) { block_id_ = id; }
graph()67 HGraph* graph() const { return graph_; }
68 Isolate* isolate() const;
phis()69 const ZoneList<HPhi*>* phis() const { return &phis_; }
first()70 HInstruction* first() const { return first_; }
last()71 HInstruction* last() const { return last_; }
set_last(HInstruction * instr)72 void set_last(HInstruction* instr) { last_ = instr; }
end()73 HControlInstruction* end() const { return end_; }
loop_information()74 HLoopInformation* loop_information() const { return loop_information_; }
current_loop()75 HLoopInformation* current_loop() const {
76 return IsLoopHeader() ? loop_information()
77 : (parent_loop_header() != NULL
78 ? parent_loop_header()->loop_information() : NULL);
79 }
predecessors()80 const ZoneList<HBasicBlock*>* predecessors() const { return &predecessors_; }
HasPredecessor()81 bool HasPredecessor() const { return predecessors_.length() > 0; }
dominated_blocks()82 const ZoneList<HBasicBlock*>* dominated_blocks() const {
83 return &dominated_blocks_;
84 }
deleted_phis()85 const ZoneList<int>* deleted_phis() const {
86 return &deleted_phis_;
87 }
RecordDeletedPhi(int merge_index)88 void RecordDeletedPhi(int merge_index) {
89 deleted_phis_.Add(merge_index, zone());
90 }
dominator()91 HBasicBlock* dominator() const { return dominator_; }
last_environment()92 HEnvironment* last_environment() const { return last_environment_; }
argument_count()93 int argument_count() const { return argument_count_; }
set_argument_count(int count)94 void set_argument_count(int count) { argument_count_ = count; }
first_instruction_index()95 int first_instruction_index() const { return first_instruction_index_; }
set_first_instruction_index(int index)96 void set_first_instruction_index(int index) {
97 first_instruction_index_ = index;
98 }
last_instruction_index()99 int last_instruction_index() const { return last_instruction_index_; }
set_last_instruction_index(int index)100 void set_last_instruction_index(int index) {
101 last_instruction_index_ = index;
102 }
is_osr_entry()103 bool is_osr_entry() { return is_osr_entry_; }
set_osr_entry()104 void set_osr_entry() { is_osr_entry_ = true; }
105
106 void AttachLoopInformation();
107 void DetachLoopInformation();
IsLoopHeader()108 bool IsLoopHeader() const { return loop_information() != NULL; }
IsStartBlock()109 bool IsStartBlock() const { return block_id() == 0; }
110 void PostProcessLoopHeader(IterationStatement* stmt);
111
IsFinished()112 bool IsFinished() const { return end_ != NULL; }
113 void AddPhi(HPhi* phi);
114 void RemovePhi(HPhi* phi);
115 void AddInstruction(HInstruction* instr, SourcePosition position);
116 bool Dominates(HBasicBlock* other) const;
117 bool EqualToOrDominates(HBasicBlock* other) const;
118 int LoopNestingDepth() const;
119
120 void SetInitialEnvironment(HEnvironment* env);
ClearEnvironment()121 void ClearEnvironment() {
122 DCHECK(IsFinished());
123 DCHECK(end()->SuccessorCount() == 0);
124 last_environment_ = NULL;
125 }
HasEnvironment()126 bool HasEnvironment() const { return last_environment_ != NULL; }
127 void UpdateEnvironment(HEnvironment* env);
parent_loop_header()128 HBasicBlock* parent_loop_header() const { return parent_loop_header_; }
129
set_parent_loop_header(HBasicBlock * block)130 void set_parent_loop_header(HBasicBlock* block) {
131 DCHECK(parent_loop_header_ == NULL);
132 parent_loop_header_ = block;
133 }
134
HasParentLoopHeader()135 bool HasParentLoopHeader() const { return parent_loop_header_ != NULL; }
136
137 void SetJoinId(BailoutId ast_id);
138
139 int PredecessorIndexOf(HBasicBlock* predecessor) const;
140 HPhi* AddNewPhi(int merged_index);
141 HSimulate* AddNewSimulate(BailoutId ast_id, SourcePosition position,
142 RemovableSimulate removable = FIXED_SIMULATE) {
143 HSimulate* instr = CreateSimulate(ast_id, removable);
144 AddInstruction(instr, position);
145 return instr;
146 }
147 void AssignCommonDominator(HBasicBlock* other);
148 void AssignLoopSuccessorDominators();
149
150 // If a target block is tagged as an inline function return, all
151 // predecessors should contain the inlined exit sequence:
152 //
153 // LeaveInlined
154 // Simulate (caller's environment)
155 // Goto (target block)
IsInlineReturnTarget()156 bool IsInlineReturnTarget() const { return is_inline_return_target_; }
MarkAsInlineReturnTarget(HBasicBlock * inlined_entry_block)157 void MarkAsInlineReturnTarget(HBasicBlock* inlined_entry_block) {
158 is_inline_return_target_ = true;
159 inlined_entry_block_ = inlined_entry_block;
160 }
inlined_entry_block()161 HBasicBlock* inlined_entry_block() { return inlined_entry_block_; }
162
IsDeoptimizing()163 bool IsDeoptimizing() const {
164 return end() != NULL && end()->IsDeoptimize();
165 }
166
167 void MarkUnreachable();
IsUnreachable()168 bool IsUnreachable() const { return !is_reachable_; }
IsReachable()169 bool IsReachable() const { return is_reachable_; }
170
IsLoopSuccessorDominator()171 bool IsLoopSuccessorDominator() const {
172 return dominates_loop_successors_;
173 }
MarkAsLoopSuccessorDominator()174 void MarkAsLoopSuccessorDominator() {
175 dominates_loop_successors_ = true;
176 }
177
IsOrdered()178 bool IsOrdered() const { return is_ordered_; }
MarkAsOrdered()179 void MarkAsOrdered() { is_ordered_ = true; }
180
181 void MarkSuccEdgeUnreachable(int succ);
182
183 inline Zone* zone() const;
184
185 #ifdef DEBUG
186 void Verify();
187 #endif
188
189 protected:
190 friend class HGraphBuilder;
191
192 HSimulate* CreateSimulate(BailoutId ast_id, RemovableSimulate removable);
193 void Finish(HControlInstruction* last, SourcePosition position);
194 void FinishExit(HControlInstruction* instruction, SourcePosition position);
195 void Goto(HBasicBlock* block, SourcePosition position,
196 FunctionState* state = NULL, bool add_simulate = true);
GotoNoSimulate(HBasicBlock * block,SourcePosition position)197 void GotoNoSimulate(HBasicBlock* block, SourcePosition position) {
198 Goto(block, position, NULL, false);
199 }
200
201 // Add the inlined function exit sequence, adding an HLeaveInlined
202 // instruction and updating the bailout environment.
203 void AddLeaveInlined(HValue* return_value, FunctionState* state,
204 SourcePosition position);
205
206 private:
207 void RegisterPredecessor(HBasicBlock* pred);
208 void AddDominatedBlock(HBasicBlock* block);
209
210 int block_id_;
211 HGraph* graph_;
212 ZoneList<HPhi*> phis_;
213 HInstruction* first_;
214 HInstruction* last_;
215 HControlInstruction* end_;
216 HLoopInformation* loop_information_;
217 ZoneList<HBasicBlock*> predecessors_;
218 HBasicBlock* dominator_;
219 ZoneList<HBasicBlock*> dominated_blocks_;
220 HEnvironment* last_environment_;
221 // Outgoing parameter count at block exit, set during lithium translation.
222 int argument_count_;
223 // Instruction indices into the lithium code stream.
224 int first_instruction_index_;
225 int last_instruction_index_;
226 ZoneList<int> deleted_phis_;
227 HBasicBlock* parent_loop_header_;
228 // For blocks marked as inline return target: the block with HEnterInlined.
229 HBasicBlock* inlined_entry_block_;
230 bool is_inline_return_target_ : 1;
231 bool is_reachable_ : 1;
232 bool dominates_loop_successors_ : 1;
233 bool is_osr_entry_ : 1;
234 bool is_ordered_ : 1;
235 };
236
237
238 std::ostream& operator<<(std::ostream& os, const HBasicBlock& b);
239
240
241 class HPredecessorIterator final BASE_EMBEDDED {
242 public:
HPredecessorIterator(HBasicBlock * block)243 explicit HPredecessorIterator(HBasicBlock* block)
244 : predecessor_list_(block->predecessors()), current_(0) { }
245
Done()246 bool Done() { return current_ >= predecessor_list_->length(); }
Current()247 HBasicBlock* Current() { return predecessor_list_->at(current_); }
Advance()248 void Advance() { current_++; }
249
250 private:
251 const ZoneList<HBasicBlock*>* predecessor_list_;
252 int current_;
253 };
254
255
256 class HInstructionIterator final BASE_EMBEDDED {
257 public:
HInstructionIterator(HBasicBlock * block)258 explicit HInstructionIterator(HBasicBlock* block)
259 : instr_(block->first()) {
260 next_ = Done() ? NULL : instr_->next();
261 }
262
Done()263 inline bool Done() const { return instr_ == NULL; }
Current()264 inline HInstruction* Current() { return instr_; }
Advance()265 inline void Advance() {
266 instr_ = next_;
267 next_ = Done() ? NULL : instr_->next();
268 }
269
270 private:
271 HInstruction* instr_;
272 HInstruction* next_;
273 };
274
275
276 class HLoopInformation final : public ZoneObject {
277 public:
HLoopInformation(HBasicBlock * loop_header,Zone * zone)278 HLoopInformation(HBasicBlock* loop_header, Zone* zone)
279 : back_edges_(4, zone),
280 loop_header_(loop_header),
281 blocks_(8, zone),
282 stack_check_(NULL) {
283 blocks_.Add(loop_header, zone);
284 }
~HLoopInformation()285 ~HLoopInformation() {}
286
back_edges()287 const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; }
blocks()288 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
loop_header()289 HBasicBlock* loop_header() const { return loop_header_; }
290 HBasicBlock* GetLastBackEdge() const;
291 void RegisterBackEdge(HBasicBlock* block);
292
stack_check()293 HStackCheck* stack_check() const { return stack_check_; }
set_stack_check(HStackCheck * stack_check)294 void set_stack_check(HStackCheck* stack_check) {
295 stack_check_ = stack_check;
296 }
297
IsNestedInThisLoop(HLoopInformation * other)298 bool IsNestedInThisLoop(HLoopInformation* other) {
299 while (other != NULL) {
300 if (other == this) {
301 return true;
302 }
303 other = other->parent_loop();
304 }
305 return false;
306 }
parent_loop()307 HLoopInformation* parent_loop() {
308 HBasicBlock* parent_header = loop_header()->parent_loop_header();
309 return parent_header != NULL ? parent_header->loop_information() : NULL;
310 }
311
312 private:
313 void AddBlock(HBasicBlock* block);
314
315 ZoneList<HBasicBlock*> back_edges_;
316 HBasicBlock* loop_header_;
317 ZoneList<HBasicBlock*> blocks_;
318 HStackCheck* stack_check_;
319 };
320
321 class HGraph final : public ZoneObject {
322 public:
323 explicit HGraph(CompilationInfo* info, CallInterfaceDescriptor descriptor);
324
isolate()325 Isolate* isolate() const { return isolate_; }
zone()326 Zone* zone() const { return zone_; }
info()327 CompilationInfo* info() const { return info_; }
descriptor()328 CallInterfaceDescriptor descriptor() const { return descriptor_; }
329
blocks()330 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
phi_list()331 const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
entry_block()332 HBasicBlock* entry_block() const { return entry_block_; }
start_environment()333 HEnvironment* start_environment() const { return start_environment_; }
334
335 void FinalizeUniqueness();
336 void OrderBlocks();
337 void AssignDominators();
338 void RestoreActualValues();
339
340 // Returns false if there are phi-uses of the arguments-object
341 // which are not supported by the optimizing compiler.
342 bool CheckArgumentsPhiUses();
343
344 // Returns false if there are phi-uses of an uninitialized const
345 // which are not supported by the optimizing compiler.
346 bool CheckConstPhiUses();
347
348 void CollectPhis();
349
350 HConstant* GetConstantUndefined();
351 HConstant* GetConstant0();
352 HConstant* GetConstant1();
353 HConstant* GetConstantMinus1();
354 HConstant* GetConstantTrue();
355 HConstant* GetConstantFalse();
356 HConstant* GetConstantBool(bool value);
357 HConstant* GetConstantHole();
358 HConstant* GetConstantNull();
359 HConstant* GetConstantOptimizedOut();
360 HConstant* GetInvalidContext();
361
362 bool IsConstantUndefined(HConstant* constant);
363 bool IsConstant0(HConstant* constant);
364 bool IsConstant1(HConstant* constant);
365 bool IsConstantMinus1(HConstant* constant);
366 bool IsConstantTrue(HConstant* constant);
367 bool IsConstantFalse(HConstant* constant);
368 bool IsConstantHole(HConstant* constant);
369 bool IsConstantNull(HConstant* constant);
370 bool IsStandardConstant(HConstant* constant);
371
372 HBasicBlock* CreateBasicBlock();
373
GetMaximumValueID()374 int GetMaximumValueID() const { return values_.length(); }
GetNextBlockID()375 int GetNextBlockID() { return next_block_id_++; }
GetNextValueID(HValue * value)376 int GetNextValueID(HValue* value) {
377 DCHECK(!disallow_adding_new_values_);
378 values_.Add(value, zone());
379 return values_.length() - 1;
380 }
LookupValue(int id)381 HValue* LookupValue(int id) const {
382 if (id >= 0 && id < values_.length()) return values_[id];
383 return NULL;
384 }
DisallowAddingNewValues()385 void DisallowAddingNewValues() {
386 disallow_adding_new_values_ = true;
387 }
388
389 bool Optimize(BailoutReason* bailout_reason);
390
391 #ifdef DEBUG
392 void Verify(bool do_full_verify) const;
393 #endif
394
has_osr()395 bool has_osr() {
396 return osr_ != NULL;
397 }
398
set_osr(HOsrBuilder * osr)399 void set_osr(HOsrBuilder* osr) {
400 osr_ = osr;
401 }
402
osr()403 HOsrBuilder* osr() {
404 return osr_;
405 }
406
update_type_change_checksum(int delta)407 int update_type_change_checksum(int delta) {
408 type_change_checksum_ += delta;
409 return type_change_checksum_;
410 }
411
update_maximum_environment_size(int environment_size)412 void update_maximum_environment_size(int environment_size) {
413 if (environment_size > maximum_environment_size_) {
414 maximum_environment_size_ = environment_size;
415 }
416 }
maximum_environment_size()417 int maximum_environment_size() { return maximum_environment_size_; }
418
allow_code_motion()419 bool allow_code_motion() const { return allow_code_motion_; }
set_allow_code_motion(bool value)420 void set_allow_code_motion(bool value) { allow_code_motion_ = value; }
421
use_optimistic_licm()422 bool use_optimistic_licm() const { return use_optimistic_licm_; }
set_use_optimistic_licm(bool value)423 void set_use_optimistic_licm(bool value) { use_optimistic_licm_ = value; }
424
MarkDependsOnEmptyArrayProtoElements()425 void MarkDependsOnEmptyArrayProtoElements() {
426 // Add map dependency if not already added.
427 if (depends_on_empty_array_proto_elements_) return;
428 info()->dependencies()->AssumePropertyCell(
429 isolate()->factory()->array_protector());
430 depends_on_empty_array_proto_elements_ = true;
431 }
432
depends_on_empty_array_proto_elements()433 bool depends_on_empty_array_proto_elements() {
434 return depends_on_empty_array_proto_elements_;
435 }
436
MarkDependsOnStringLengthOverflow()437 void MarkDependsOnStringLengthOverflow() {
438 if (depends_on_string_length_overflow_) return;
439 info()->dependencies()->AssumePropertyCell(
440 isolate()->factory()->string_length_protector());
441 depends_on_string_length_overflow_ = true;
442 }
443
has_uint32_instructions()444 bool has_uint32_instructions() {
445 DCHECK(uint32_instructions_ == NULL || !uint32_instructions_->is_empty());
446 return uint32_instructions_ != NULL;
447 }
448
uint32_instructions()449 ZoneList<HInstruction*>* uint32_instructions() {
450 DCHECK(uint32_instructions_ == NULL || !uint32_instructions_->is_empty());
451 return uint32_instructions_;
452 }
453
RecordUint32Instruction(HInstruction * instr)454 void RecordUint32Instruction(HInstruction* instr) {
455 DCHECK(uint32_instructions_ == NULL || !uint32_instructions_->is_empty());
456 if (uint32_instructions_ == NULL) {
457 uint32_instructions_ = new(zone()) ZoneList<HInstruction*>(4, zone());
458 }
459 uint32_instructions_->Add(instr, zone());
460 }
461
IncrementInNoSideEffectsScope()462 void IncrementInNoSideEffectsScope() { no_side_effects_scope_count_++; }
DecrementInNoSideEffectsScope()463 void DecrementInNoSideEffectsScope() { no_side_effects_scope_count_--; }
IsInsideNoSideEffectsScope()464 bool IsInsideNoSideEffectsScope() { return no_side_effects_scope_count_ > 0; }
465
466 // If we are tracking source positions then this function assigns a unique
467 // identifier to each inlining and dumps function source if it was inlined
468 // for the first time during the current optimization.
469 int TraceInlinedFunction(Handle<SharedFunctionInfo> shared,
470 SourcePosition position);
471
472 private:
473 HConstant* ReinsertConstantIfNecessary(HConstant* constant);
474 HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
475 int32_t integer_value);
476
477 template<class Phase>
Run()478 void Run() {
479 Phase phase(this);
480 phase.Run();
481 }
482
483 Isolate* isolate_;
484 int next_block_id_;
485 HBasicBlock* entry_block_;
486 HEnvironment* start_environment_;
487 ZoneList<HBasicBlock*> blocks_;
488 ZoneList<HValue*> values_;
489 ZoneList<HPhi*>* phi_list_;
490 ZoneList<HInstruction*>* uint32_instructions_;
491 SetOncePointer<HConstant> constant_undefined_;
492 SetOncePointer<HConstant> constant_0_;
493 SetOncePointer<HConstant> constant_1_;
494 SetOncePointer<HConstant> constant_minus1_;
495 SetOncePointer<HConstant> constant_true_;
496 SetOncePointer<HConstant> constant_false_;
497 SetOncePointer<HConstant> constant_the_hole_;
498 SetOncePointer<HConstant> constant_null_;
499 SetOncePointer<HConstant> constant_optimized_out_;
500 SetOncePointer<HConstant> constant_invalid_context_;
501
502 HOsrBuilder* osr_;
503
504 CompilationInfo* info_;
505 CallInterfaceDescriptor descriptor_;
506 Zone* zone_;
507
508 bool allow_code_motion_;
509 bool use_optimistic_licm_;
510 bool depends_on_empty_array_proto_elements_;
511 bool depends_on_string_length_overflow_;
512 int type_change_checksum_;
513 int maximum_environment_size_;
514 int no_side_effects_scope_count_;
515 bool disallow_adding_new_values_;
516
517 DISALLOW_COPY_AND_ASSIGN(HGraph);
518 };
519
520
zone()521 Zone* HBasicBlock::zone() const { return graph_->zone(); }
522
523
524 // Type of stack frame an environment might refer to.
525 enum FrameType {
526 JS_FUNCTION,
527 JS_CONSTRUCT,
528 JS_GETTER,
529 JS_SETTER,
530 ARGUMENTS_ADAPTOR,
531 TAIL_CALLER_FUNCTION,
532 STUB
533 };
534
535 class HEnvironment final : public ZoneObject {
536 public:
537 HEnvironment(HEnvironment* outer,
538 Scope* scope,
539 Handle<JSFunction> closure,
540 Zone* zone);
541
542 HEnvironment(Zone* zone, int parameter_count);
543
arguments_environment()544 HEnvironment* arguments_environment() {
545 return outer()->frame_type() == ARGUMENTS_ADAPTOR ? outer() : this;
546 }
547
548 // Simple accessors.
closure()549 Handle<JSFunction> closure() const { return closure_; }
values()550 const ZoneList<HValue*>* values() const { return &values_; }
assigned_variables()551 const GrowableBitVector* assigned_variables() const {
552 return &assigned_variables_;
553 }
frame_type()554 FrameType frame_type() const { return frame_type_; }
parameter_count()555 int parameter_count() const { return parameter_count_; }
specials_count()556 int specials_count() const { return specials_count_; }
local_count()557 int local_count() const { return local_count_; }
outer()558 HEnvironment* outer() const { return outer_; }
pop_count()559 int pop_count() const { return pop_count_; }
push_count()560 int push_count() const { return push_count_; }
561
ast_id()562 BailoutId ast_id() const { return ast_id_; }
set_ast_id(BailoutId id)563 void set_ast_id(BailoutId id) { ast_id_ = id; }
564
entry()565 HEnterInlined* entry() const { return entry_; }
set_entry(HEnterInlined * entry)566 void set_entry(HEnterInlined* entry) { entry_ = entry; }
567
length()568 int length() const { return values_.length(); }
569
first_expression_index()570 int first_expression_index() const {
571 return parameter_count() + specials_count() + local_count();
572 }
573
first_local_index()574 int first_local_index() const {
575 return parameter_count() + specials_count();
576 }
577
Bind(Variable * variable,HValue * value)578 void Bind(Variable* variable, HValue* value) {
579 Bind(IndexFor(variable), value);
580 }
581
582 void Bind(int index, HValue* value);
583
BindContext(HValue * value)584 void BindContext(HValue* value) {
585 Bind(parameter_count(), value);
586 }
587
Lookup(Variable * variable)588 HValue* Lookup(Variable* variable) const {
589 return Lookup(IndexFor(variable));
590 }
591
Lookup(int index)592 HValue* Lookup(int index) const {
593 HValue* result = values_[index];
594 DCHECK(result != NULL);
595 return result;
596 }
597
context()598 HValue* context() const {
599 // Return first special.
600 return Lookup(parameter_count());
601 }
602
Push(HValue * value)603 void Push(HValue* value) {
604 DCHECK(value != NULL);
605 ++push_count_;
606 values_.Add(value, zone());
607 }
608
Pop()609 HValue* Pop() {
610 DCHECK(!ExpressionStackIsEmpty());
611 if (push_count_ > 0) {
612 --push_count_;
613 } else {
614 ++pop_count_;
615 }
616 return values_.RemoveLast();
617 }
618
619 void Drop(int count);
620
Top()621 HValue* Top() const { return ExpressionStackAt(0); }
622
623 bool ExpressionStackIsEmpty() const;
624
ExpressionStackAt(int index_from_top)625 HValue* ExpressionStackAt(int index_from_top) const {
626 int index = length() - index_from_top - 1;
627 DCHECK(HasExpressionAt(index));
628 return values_[index];
629 }
630
631 void SetExpressionStackAt(int index_from_top, HValue* value);
632 HValue* RemoveExpressionStackAt(int index_from_top);
633
634 void Print() const;
635
636 HEnvironment* Copy() const;
637 HEnvironment* CopyWithoutHistory() const;
638 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
639
640 // Create an "inlined version" of this environment, where the original
641 // environment is the outer environment but the top expression stack
642 // elements are moved to an inner environment as parameters.
643 HEnvironment* CopyForInlining(Handle<JSFunction> target, int arguments,
644 FunctionLiteral* function, HConstant* undefined,
645 InliningKind inlining_kind,
646 TailCallMode syntactic_tail_call_mode) const;
647
DiscardInlined(bool drop_extra)648 HEnvironment* DiscardInlined(bool drop_extra) {
649 HEnvironment* outer = outer_;
650 while (outer->frame_type() != JS_FUNCTION &&
651 outer->frame_type() != TAIL_CALLER_FUNCTION) {
652 outer = outer->outer_;
653 }
654 if (drop_extra) outer->Drop(1);
655 if (outer->frame_type() == TAIL_CALLER_FUNCTION) {
656 outer->ClearTailCallerMark();
657 }
658 return outer;
659 }
660
661 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
662
ClearHistory()663 void ClearHistory() {
664 pop_count_ = 0;
665 push_count_ = 0;
666 assigned_variables_.Clear();
667 }
668
SetValueAt(int index,HValue * value)669 void SetValueAt(int index, HValue* value) {
670 DCHECK(index < length());
671 values_[index] = value;
672 }
673
674 // Map a variable to an environment index. Parameter indices are shifted
675 // by 1 (receiver is parameter index -1 but environment index 0).
676 // Stack-allocated local indices are shifted by the number of parameters.
IndexFor(Variable * variable)677 int IndexFor(Variable* variable) const {
678 DCHECK(variable->IsStackAllocated());
679 int shift = variable->IsParameter()
680 ? 1
681 : parameter_count_ + specials_count_;
682 return variable->index() + shift;
683 }
684
is_local_index(int i)685 bool is_local_index(int i) const {
686 return i >= first_local_index() && i < first_expression_index();
687 }
688
is_parameter_index(int i)689 bool is_parameter_index(int i) const {
690 return i >= 0 && i < parameter_count();
691 }
692
is_special_index(int i)693 bool is_special_index(int i) const {
694 return i >= parameter_count() && i < parameter_count() + specials_count();
695 }
696
zone()697 Zone* zone() const { return zone_; }
698
699 private:
700 HEnvironment(const HEnvironment* other, Zone* zone);
701
702 HEnvironment(HEnvironment* outer,
703 Handle<JSFunction> closure,
704 FrameType frame_type,
705 int arguments,
706 Zone* zone);
707
708 // Create an artificial stub environment (e.g. for argument adaptor or
709 // constructor stub).
710 HEnvironment* CreateStubEnvironment(HEnvironment* outer,
711 Handle<JSFunction> target,
712 FrameType frame_type,
713 int arguments) const;
714
715 // Marks current environment as tail caller by setting frame type to
716 // TAIL_CALLER_FUNCTION.
717 void MarkAsTailCaller();
718 void ClearTailCallerMark();
719
720 // True if index is included in the expression stack part of the environment.
721 bool HasExpressionAt(int index) const;
722
723 void Initialize(int parameter_count, int local_count, int stack_height);
724 void Initialize(const HEnvironment* other);
725
726 Handle<JSFunction> closure_;
727 // Value array [parameters] [specials] [locals] [temporaries].
728 ZoneList<HValue*> values_;
729 GrowableBitVector assigned_variables_;
730 FrameType frame_type_;
731 int parameter_count_;
732 int specials_count_;
733 int local_count_;
734 HEnvironment* outer_;
735 HEnterInlined* entry_;
736 int pop_count_;
737 int push_count_;
738 BailoutId ast_id_;
739 Zone* zone_;
740 };
741
742
743 std::ostream& operator<<(std::ostream& os, const HEnvironment& env);
744
745
746 class HOptimizedGraphBuilder;
747
748 enum ArgumentsAllowedFlag {
749 ARGUMENTS_NOT_ALLOWED,
750 ARGUMENTS_ALLOWED,
751 ARGUMENTS_FAKED
752 };
753
754
755 class HIfContinuation;
756
757 // This class is not BASE_EMBEDDED because our inlining implementation uses
758 // new and delete.
759 class AstContext {
760 public:
IsEffect()761 bool IsEffect() const { return kind_ == Expression::kEffect; }
IsValue()762 bool IsValue() const { return kind_ == Expression::kValue; }
IsTest()763 bool IsTest() const { return kind_ == Expression::kTest; }
764
765 // 'Fill' this context with a hydrogen value. The value is assumed to
766 // have already been inserted in the instruction stream (or not need to
767 // be, e.g., HPhi). Call this function in tail position in the Visit
768 // functions for expressions.
769 virtual void ReturnValue(HValue* value) = 0;
770
771 // Add a hydrogen instruction to the instruction stream (recording an
772 // environment simulation if necessary) and then fill this context with
773 // the instruction as value.
774 virtual void ReturnInstruction(HInstruction* instr, BailoutId ast_id) = 0;
775
776 // Finishes the current basic block and materialize a boolean for
777 // value context, nothing for effect, generate a branch for test context.
778 // Call this function in tail position in the Visit functions for
779 // expressions.
780 virtual void ReturnControl(HControlInstruction* instr, BailoutId ast_id) = 0;
781
782 // Finishes the current basic block and materialize a boolean for
783 // value context, nothing for effect, generate a branch for test context.
784 // Call this function in tail position in the Visit functions for
785 // expressions that use an IfBuilder.
786 virtual void ReturnContinuation(HIfContinuation* continuation,
787 BailoutId ast_id) = 0;
788
set_typeof_mode(TypeofMode typeof_mode)789 void set_typeof_mode(TypeofMode typeof_mode) { typeof_mode_ = typeof_mode; }
typeof_mode()790 TypeofMode typeof_mode() { return typeof_mode_; }
791
792 protected:
793 AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind);
794 virtual ~AstContext();
795
owner()796 HOptimizedGraphBuilder* owner() const { return owner_; }
797
798 inline Zone* zone() const;
799
800 // We want to be able to assert, in a context-specific way, that the stack
801 // height makes sense when the context is filled.
802 #ifdef DEBUG
803 int original_length_;
804 #endif
805
806 private:
807 HOptimizedGraphBuilder* owner_;
808 Expression::Context kind_;
809 AstContext* outer_;
810 TypeofMode typeof_mode_;
811 };
812
813
814 class EffectContext final : public AstContext {
815 public:
EffectContext(HOptimizedGraphBuilder * owner)816 explicit EffectContext(HOptimizedGraphBuilder* owner)
817 : AstContext(owner, Expression::kEffect) {
818 }
819 ~EffectContext() override;
820
821 void ReturnValue(HValue* value) override;
822 void ReturnInstruction(HInstruction* instr, BailoutId ast_id) override;
823 void ReturnControl(HControlInstruction* instr, BailoutId ast_id) override;
824 void ReturnContinuation(HIfContinuation* continuation,
825 BailoutId ast_id) override;
826 };
827
828
829 class ValueContext final : public AstContext {
830 public:
ValueContext(HOptimizedGraphBuilder * owner,ArgumentsAllowedFlag flag)831 ValueContext(HOptimizedGraphBuilder* owner, ArgumentsAllowedFlag flag)
832 : AstContext(owner, Expression::kValue), flag_(flag) {
833 }
834 ~ValueContext() override;
835
836 void ReturnValue(HValue* value) override;
837 void ReturnInstruction(HInstruction* instr, BailoutId ast_id) override;
838 void ReturnControl(HControlInstruction* instr, BailoutId ast_id) override;
839 void ReturnContinuation(HIfContinuation* continuation,
840 BailoutId ast_id) override;
841
arguments_allowed()842 bool arguments_allowed() { return flag_ == ARGUMENTS_ALLOWED; }
843
844 private:
845 ArgumentsAllowedFlag flag_;
846 };
847
848
849 class TestContext final : public AstContext {
850 public:
TestContext(HOptimizedGraphBuilder * owner,Expression * condition,HBasicBlock * if_true,HBasicBlock * if_false)851 TestContext(HOptimizedGraphBuilder* owner,
852 Expression* condition,
853 HBasicBlock* if_true,
854 HBasicBlock* if_false)
855 : AstContext(owner, Expression::kTest),
856 condition_(condition),
857 if_true_(if_true),
858 if_false_(if_false) {
859 }
860
861 void ReturnValue(HValue* value) override;
862 void ReturnInstruction(HInstruction* instr, BailoutId ast_id) override;
863 void ReturnControl(HControlInstruction* instr, BailoutId ast_id) override;
864 void ReturnContinuation(HIfContinuation* continuation,
865 BailoutId ast_id) override;
866
cast(AstContext * context)867 static TestContext* cast(AstContext* context) {
868 DCHECK(context->IsTest());
869 return reinterpret_cast<TestContext*>(context);
870 }
871
condition()872 Expression* condition() const { return condition_; }
if_true()873 HBasicBlock* if_true() const { return if_true_; }
if_false()874 HBasicBlock* if_false() const { return if_false_; }
875
876 private:
877 // Build the shared core part of the translation unpacking a value into
878 // control flow.
879 void BuildBranch(HValue* value);
880
881 Expression* condition_;
882 HBasicBlock* if_true_;
883 HBasicBlock* if_false_;
884 };
885
886
887 class FunctionState final {
888 public:
889 FunctionState(HOptimizedGraphBuilder* owner, CompilationInfo* info,
890 InliningKind inlining_kind, int inlining_id,
891 TailCallMode tail_call_mode);
892 ~FunctionState();
893
compilation_info()894 CompilationInfo* compilation_info() { return compilation_info_; }
call_context()895 AstContext* call_context() { return call_context_; }
inlining_kind()896 InliningKind inlining_kind() const { return inlining_kind_; }
function_return()897 HBasicBlock* function_return() { return function_return_; }
test_context()898 TestContext* test_context() { return test_context_; }
ClearInlinedTestContext()899 void ClearInlinedTestContext() {
900 delete test_context_;
901 test_context_ = NULL;
902 }
903
outer()904 FunctionState* outer() { return outer_; }
905
ComputeTailCallMode(TailCallMode tail_call_mode)906 TailCallMode ComputeTailCallMode(TailCallMode tail_call_mode) const {
907 if (tail_call_mode_ == TailCallMode::kDisallow) return tail_call_mode_;
908 return tail_call_mode;
909 }
910
entry()911 HEnterInlined* entry() { return entry_; }
set_entry(HEnterInlined * entry)912 void set_entry(HEnterInlined* entry) { entry_ = entry; }
913
arguments_object()914 HArgumentsObject* arguments_object() { return arguments_object_; }
set_arguments_object(HArgumentsObject * arguments_object)915 void set_arguments_object(HArgumentsObject* arguments_object) {
916 arguments_object_ = arguments_object;
917 }
918
arguments_elements()919 HArgumentsElements* arguments_elements() { return arguments_elements_; }
set_arguments_elements(HArgumentsElements * arguments_elements)920 void set_arguments_elements(HArgumentsElements* arguments_elements) {
921 arguments_elements_ = arguments_elements;
922 }
923
arguments_pushed()924 bool arguments_pushed() { return arguments_elements() != NULL; }
925
inlining_id()926 int inlining_id() const { return inlining_id_; }
927
IncrementInDoExpressionScope()928 void IncrementInDoExpressionScope() { do_expression_scope_count_++; }
DecrementInDoExpressionScope()929 void DecrementInDoExpressionScope() { do_expression_scope_count_--; }
IsInsideDoExpressionScope()930 bool IsInsideDoExpressionScope() { return do_expression_scope_count_ > 0; }
931
932 private:
933 HOptimizedGraphBuilder* owner_;
934
935 CompilationInfo* compilation_info_;
936
937 // During function inlining, expression context of the call being
938 // inlined. NULL when not inlining.
939 AstContext* call_context_;
940
941 // The kind of call which is currently being inlined.
942 InliningKind inlining_kind_;
943
944 // Defines whether the calls with TailCallMode::kAllow in the function body
945 // can be generated as tail calls.
946 TailCallMode tail_call_mode_;
947
948 // When inlining in an effect or value context, this is the return block.
949 // It is NULL otherwise. When inlining in a test context, there are a
950 // pair of return blocks in the context. When not inlining, there is no
951 // local return point.
952 HBasicBlock* function_return_;
953
954 // When inlining a call in a test context, a context containing a pair of
955 // return blocks. NULL in all other cases.
956 TestContext* test_context_;
957
958 // When inlining HEnterInlined instruction corresponding to the function
959 // entry.
960 HEnterInlined* entry_;
961
962 HArgumentsObject* arguments_object_;
963 HArgumentsElements* arguments_elements_;
964
965 int inlining_id_;
966 SourcePosition outer_source_position_;
967
968 int do_expression_scope_count_;
969
970 FunctionState* outer_;
971 };
972
973
974 class HIfContinuation final {
975 public:
HIfContinuation()976 HIfContinuation()
977 : continuation_captured_(false),
978 true_branch_(NULL),
979 false_branch_(NULL) {}
HIfContinuation(HBasicBlock * true_branch,HBasicBlock * false_branch)980 HIfContinuation(HBasicBlock* true_branch,
981 HBasicBlock* false_branch)
982 : continuation_captured_(true), true_branch_(true_branch),
983 false_branch_(false_branch) {}
~HIfContinuation()984 ~HIfContinuation() { DCHECK(!continuation_captured_); }
985
Capture(HBasicBlock * true_branch,HBasicBlock * false_branch)986 void Capture(HBasicBlock* true_branch,
987 HBasicBlock* false_branch) {
988 DCHECK(!continuation_captured_);
989 true_branch_ = true_branch;
990 false_branch_ = false_branch;
991 continuation_captured_ = true;
992 }
993
Continue(HBasicBlock ** true_branch,HBasicBlock ** false_branch)994 void Continue(HBasicBlock** true_branch,
995 HBasicBlock** false_branch) {
996 DCHECK(continuation_captured_);
997 *true_branch = true_branch_;
998 *false_branch = false_branch_;
999 continuation_captured_ = false;
1000 }
1001
IsTrueReachable()1002 bool IsTrueReachable() { return true_branch_ != NULL; }
IsFalseReachable()1003 bool IsFalseReachable() { return false_branch_ != NULL; }
TrueAndFalseReachable()1004 bool TrueAndFalseReachable() {
1005 return IsTrueReachable() || IsFalseReachable();
1006 }
1007
true_branch()1008 HBasicBlock* true_branch() const { return true_branch_; }
false_branch()1009 HBasicBlock* false_branch() const { return false_branch_; }
1010
1011 private:
1012 bool continuation_captured_;
1013 HBasicBlock* true_branch_;
1014 HBasicBlock* false_branch_;
1015 };
1016
1017
1018 class HAllocationMode final BASE_EMBEDDED {
1019 public:
HAllocationMode(Handle<AllocationSite> feedback_site)1020 explicit HAllocationMode(Handle<AllocationSite> feedback_site)
1021 : current_site_(NULL), feedback_site_(feedback_site),
1022 pretenure_flag_(NOT_TENURED) {}
HAllocationMode(HValue * current_site)1023 explicit HAllocationMode(HValue* current_site)
1024 : current_site_(current_site), pretenure_flag_(NOT_TENURED) {}
HAllocationMode(PretenureFlag pretenure_flag)1025 explicit HAllocationMode(PretenureFlag pretenure_flag)
1026 : current_site_(NULL), pretenure_flag_(pretenure_flag) {}
HAllocationMode()1027 HAllocationMode()
1028 : current_site_(NULL), pretenure_flag_(NOT_TENURED) {}
1029
current_site()1030 HValue* current_site() const { return current_site_; }
feedback_site()1031 Handle<AllocationSite> feedback_site() const { return feedback_site_; }
1032
CreateAllocationMementos()1033 bool CreateAllocationMementos() const WARN_UNUSED_RESULT {
1034 return current_site() != NULL;
1035 }
1036
GetPretenureMode()1037 PretenureFlag GetPretenureMode() const WARN_UNUSED_RESULT {
1038 if (!feedback_site().is_null()) return feedback_site()->GetPretenureMode();
1039 return pretenure_flag_;
1040 }
1041
1042 private:
1043 HValue* current_site_;
1044 Handle<AllocationSite> feedback_site_;
1045 PretenureFlag pretenure_flag_;
1046 };
1047
1048
1049 class HGraphBuilder {
1050 public:
HGraphBuilder(CompilationInfo * info,CallInterfaceDescriptor descriptor,bool track_positions)1051 explicit HGraphBuilder(CompilationInfo* info,
1052 CallInterfaceDescriptor descriptor,
1053 bool track_positions)
1054 : info_(info),
1055 descriptor_(descriptor),
1056 graph_(NULL),
1057 current_block_(NULL),
1058 scope_(info->scope()),
1059 position_(SourcePosition::Unknown()),
1060 track_positions_(track_positions) {}
~HGraphBuilder()1061 virtual ~HGraphBuilder() {}
1062
scope()1063 Scope* scope() const { return scope_; }
set_scope(Scope * scope)1064 void set_scope(Scope* scope) { scope_ = scope; }
1065
current_block()1066 HBasicBlock* current_block() const { return current_block_; }
set_current_block(HBasicBlock * block)1067 void set_current_block(HBasicBlock* block) { current_block_ = block; }
environment()1068 HEnvironment* environment() const {
1069 return current_block()->last_environment();
1070 }
zone()1071 Zone* zone() const { return info_->zone(); }
graph()1072 HGraph* graph() const { return graph_; }
isolate()1073 Isolate* isolate() const { return graph_->isolate(); }
top_info()1074 CompilationInfo* top_info() { return info_; }
1075
1076 HGraph* CreateGraph();
1077
1078 // Bailout environment manipulation.
Push(HValue * value)1079 void Push(HValue* value) { environment()->Push(value); }
Pop()1080 HValue* Pop() { return environment()->Pop(); }
1081
1082 virtual HValue* context() = 0;
1083
1084 // Adding instructions.
1085 HInstruction* AddInstruction(HInstruction* instr);
1086 void FinishCurrentBlock(HControlInstruction* last);
1087 void FinishExitCurrentBlock(HControlInstruction* instruction);
1088
1089 void Goto(HBasicBlock* from,
1090 HBasicBlock* target,
1091 FunctionState* state = NULL,
1092 bool add_simulate = true) {
1093 from->Goto(target, source_position(), state, add_simulate);
1094 }
1095 void Goto(HBasicBlock* target,
1096 FunctionState* state = NULL,
1097 bool add_simulate = true) {
1098 Goto(current_block(), target, state, add_simulate);
1099 }
GotoNoSimulate(HBasicBlock * from,HBasicBlock * target)1100 void GotoNoSimulate(HBasicBlock* from, HBasicBlock* target) {
1101 Goto(from, target, NULL, false);
1102 }
GotoNoSimulate(HBasicBlock * target)1103 void GotoNoSimulate(HBasicBlock* target) {
1104 Goto(target, NULL, false);
1105 }
AddLeaveInlined(HBasicBlock * block,HValue * return_value,FunctionState * state)1106 void AddLeaveInlined(HBasicBlock* block,
1107 HValue* return_value,
1108 FunctionState* state) {
1109 block->AddLeaveInlined(return_value, state, source_position());
1110 }
AddLeaveInlined(HValue * return_value,FunctionState * state)1111 void AddLeaveInlined(HValue* return_value, FunctionState* state) {
1112 return AddLeaveInlined(current_block(), return_value, state);
1113 }
1114
1115 template <class I>
NewUncasted()1116 HInstruction* NewUncasted() {
1117 return I::New(isolate(), zone(), context());
1118 }
1119
1120 template <class I>
New()1121 I* New() {
1122 return I::New(isolate(), zone(), context());
1123 }
1124
1125 template<class I>
AddUncasted()1126 HInstruction* AddUncasted() { return AddInstruction(NewUncasted<I>());}
1127
1128 template<class I>
Add()1129 I* Add() { return AddInstructionTyped(New<I>());}
1130
1131 template<class I, class P1>
NewUncasted(P1 p1)1132 HInstruction* NewUncasted(P1 p1) {
1133 return I::New(isolate(), zone(), context(), p1);
1134 }
1135
1136 template <class I, class P1>
New(P1 p1)1137 I* New(P1 p1) {
1138 return I::New(isolate(), zone(), context(), p1);
1139 }
1140
1141 template<class I, class P1>
AddUncasted(P1 p1)1142 HInstruction* AddUncasted(P1 p1) {
1143 HInstruction* result = AddInstruction(NewUncasted<I>(p1));
1144 // Specializations must have their parameters properly casted
1145 // to avoid landing here.
1146 DCHECK(!result->IsReturn() && !result->IsSimulate() &&
1147 !result->IsDeoptimize());
1148 return result;
1149 }
1150
1151 template<class I, class P1>
Add(P1 p1)1152 I* Add(P1 p1) {
1153 I* result = AddInstructionTyped(New<I>(p1));
1154 // Specializations must have their parameters properly casted
1155 // to avoid landing here.
1156 DCHECK(!result->IsReturn() && !result->IsSimulate() &&
1157 !result->IsDeoptimize());
1158 return result;
1159 }
1160
1161 template<class I, class P1, class P2>
NewUncasted(P1 p1,P2 p2)1162 HInstruction* NewUncasted(P1 p1, P2 p2) {
1163 return I::New(isolate(), zone(), context(), p1, p2);
1164 }
1165
1166 template<class I, class P1, class P2>
New(P1 p1,P2 p2)1167 I* New(P1 p1, P2 p2) {
1168 return I::New(isolate(), zone(), context(), p1, p2);
1169 }
1170
1171 template<class I, class P1, class P2>
AddUncasted(P1 p1,P2 p2)1172 HInstruction* AddUncasted(P1 p1, P2 p2) {
1173 HInstruction* result = AddInstruction(NewUncasted<I>(p1, p2));
1174 // Specializations must have their parameters properly casted
1175 // to avoid landing here.
1176 DCHECK(!result->IsSimulate());
1177 return result;
1178 }
1179
1180 template<class I, class P1, class P2>
Add(P1 p1,P2 p2)1181 I* Add(P1 p1, P2 p2) {
1182 I* result = AddInstructionTyped(New<I>(p1, p2));
1183 // Specializations must have their parameters properly casted
1184 // to avoid landing here.
1185 DCHECK(!result->IsSimulate());
1186 return result;
1187 }
1188
1189 template<class I, class P1, class P2, class P3>
NewUncasted(P1 p1,P2 p2,P3 p3)1190 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3) {
1191 return I::New(isolate(), zone(), context(), p1, p2, p3);
1192 }
1193
1194 template<class I, class P1, class P2, class P3>
New(P1 p1,P2 p2,P3 p3)1195 I* New(P1 p1, P2 p2, P3 p3) {
1196 return I::New(isolate(), zone(), context(), p1, p2, p3);
1197 }
1198
1199 template<class I, class P1, class P2, class P3>
AddUncasted(P1 p1,P2 p2,P3 p3)1200 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3) {
1201 return AddInstruction(NewUncasted<I>(p1, p2, p3));
1202 }
1203
1204 template<class I, class P1, class P2, class P3>
Add(P1 p1,P2 p2,P3 p3)1205 I* Add(P1 p1, P2 p2, P3 p3) {
1206 return AddInstructionTyped(New<I>(p1, p2, p3));
1207 }
1208
1209 template<class I, class P1, class P2, class P3, class P4>
NewUncasted(P1 p1,P2 p2,P3 p3,P4 p4)1210 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4) {
1211 return I::New(isolate(), zone(), context(), p1, p2, p3, p4);
1212 }
1213
1214 template<class I, class P1, class P2, class P3, class P4>
New(P1 p1,P2 p2,P3 p3,P4 p4)1215 I* New(P1 p1, P2 p2, P3 p3, P4 p4) {
1216 return I::New(isolate(), zone(), context(), p1, p2, p3, p4);
1217 }
1218
1219 template<class I, class P1, class P2, class P3, class P4>
AddUncasted(P1 p1,P2 p2,P3 p3,P4 p4)1220 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4) {
1221 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4));
1222 }
1223
1224 template<class I, class P1, class P2, class P3, class P4>
Add(P1 p1,P2 p2,P3 p3,P4 p4)1225 I* Add(P1 p1, P2 p2, P3 p3, P4 p4) {
1226 return AddInstructionTyped(New<I>(p1, p2, p3, p4));
1227 }
1228
1229 template<class I, class P1, class P2, class P3, class P4, class P5>
NewUncasted(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5)1230 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
1231 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5);
1232 }
1233
1234 template<class I, class P1, class P2, class P3, class P4, class P5>
New(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5)1235 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
1236 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5);
1237 }
1238
1239 template<class I, class P1, class P2, class P3, class P4, class P5>
AddUncasted(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5)1240 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
1241 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5));
1242 }
1243
1244 template<class I, class P1, class P2, class P3, class P4, class P5>
Add(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5)1245 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
1246 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5));
1247 }
1248
1249 template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
NewUncasted(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6)1250 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
1251 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6);
1252 }
1253
1254 template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
New(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6)1255 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
1256 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6);
1257 }
1258
1259 template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
AddUncasted(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6)1260 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
1261 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6));
1262 }
1263
1264 template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
Add(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6)1265 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
1266 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6));
1267 }
1268
1269 template<class I, class P1, class P2, class P3, class P4,
1270 class P5, class P6, class P7>
NewUncasted(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7)1271 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
1272 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6, p7);
1273 }
1274
1275 template<class I, class P1, class P2, class P3, class P4,
1276 class P5, class P6, class P7>
New(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7)1277 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
1278 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6, p7);
1279 }
1280
1281 template<class I, class P1, class P2, class P3,
1282 class P4, class P5, class P6, class P7>
AddUncasted(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7)1283 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
1284 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7));
1285 }
1286
1287 template<class I, class P1, class P2, class P3,
1288 class P4, class P5, class P6, class P7>
Add(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7)1289 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
1290 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6, p7));
1291 }
1292
1293 template<class I, class P1, class P2, class P3, class P4,
1294 class P5, class P6, class P7, class P8>
NewUncasted(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7,P8 p8)1295 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4,
1296 P5 p5, P6 p6, P7 p7, P8 p8) {
1297 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6, p7, p8);
1298 }
1299
1300 template<class I, class P1, class P2, class P3, class P4,
1301 class P5, class P6, class P7, class P8>
New(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7,P8 p8)1302 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) {
1303 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6, p7, p8);
1304 }
1305
1306 template<class I, class P1, class P2, class P3, class P4,
1307 class P5, class P6, class P7, class P8>
AddUncasted(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7,P8 p8)1308 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4,
1309 P5 p5, P6 p6, P7 p7, P8 p8) {
1310 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7, p8));
1311 }
1312
1313 template<class I, class P1, class P2, class P3, class P4,
1314 class P5, class P6, class P7, class P8>
Add(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7,P8 p8)1315 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) {
1316 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6, p7, p8));
1317 }
1318
1319 template <class I, class P1, class P2, class P3, class P4, class P5, class P6,
1320 class P7, class P8, class P9>
New(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7,P8 p8,P9 p9)1321 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9) {
1322 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6, p7, p8,
1323 p9);
1324 }
1325
1326 template <class I, class P1, class P2, class P3, class P4, class P5, class P6,
1327 class P7, class P8, class P9>
AddUncasted(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7,P8 p8,P9 p9)1328 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7,
1329 P8 p8, P9 p9) {
1330 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7, p8, p9));
1331 }
1332
1333 template <class I, class P1, class P2, class P3, class P4, class P5, class P6,
1334 class P7, class P8, class P9>
Add(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7,P8 p8,P9 p9)1335 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9) {
1336 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6, p7, p8, p9));
1337 }
1338
1339 void AddSimulate(BailoutId id, RemovableSimulate removable = FIXED_SIMULATE);
1340
1341 // When initializing arrays, we'll unfold the loop if the number of elements
1342 // is known at compile time and is <= kElementLoopUnrollThreshold.
1343 static const int kElementLoopUnrollThreshold = 8;
1344
1345 protected:
1346 virtual bool BuildGraph() = 0;
1347
1348 HBasicBlock* CreateBasicBlock(HEnvironment* env);
1349 HBasicBlock* CreateLoopHeaderBlock();
1350
1351 template <class BitFieldClass>
BuildDecodeField(HValue * encoded_field)1352 HValue* BuildDecodeField(HValue* encoded_field) {
1353 HValue* mask_value = Add<HConstant>(static_cast<int>(BitFieldClass::kMask));
1354 HValue* masked_field =
1355 AddUncasted<HBitwise>(Token::BIT_AND, encoded_field, mask_value);
1356 return AddUncasted<HShr>(masked_field,
1357 Add<HConstant>(static_cast<int>(BitFieldClass::kShift)));
1358 }
1359
1360 HValue* BuildGetElementsKind(HValue* object);
1361
1362 HValue* BuildEnumLength(HValue* map);
1363
1364 HValue* BuildCheckHeapObject(HValue* object);
1365 HValue* BuildCheckString(HValue* string);
1366 HValue* BuildWrapReceiver(HValue* object, HValue* function);
1367
1368 // Building common constructs
1369 HValue* BuildCheckForCapacityGrow(HValue* object,
1370 HValue* elements,
1371 ElementsKind kind,
1372 HValue* length,
1373 HValue* key,
1374 bool is_js_array,
1375 PropertyAccessType access_type);
1376
1377 HValue* BuildCheckAndGrowElementsCapacity(HValue* object, HValue* elements,
1378 ElementsKind kind, HValue* length,
1379 HValue* capacity, HValue* key);
1380
1381 HValue* BuildCopyElementsOnWrite(HValue* object,
1382 HValue* elements,
1383 ElementsKind kind,
1384 HValue* length);
1385
1386 void BuildTransitionElementsKind(HValue* object,
1387 HValue* map,
1388 ElementsKind from_kind,
1389 ElementsKind to_kind,
1390 bool is_jsarray);
1391
1392 HValue* BuildNumberToString(HValue* object, AstType* type);
1393 HValue* BuildToNumber(HValue* input);
1394 HValue* BuildToObject(HValue* receiver);
1395
1396 HValue* BuildUncheckedDictionaryElementLoad(HValue* receiver,
1397 HValue* elements, HValue* key,
1398 HValue* hash);
1399
1400 // ES6 section 7.4.7 CreateIterResultObject ( value, done )
1401 HValue* BuildCreateIterResultObject(HValue* value, HValue* done);
1402
1403 // Allocates a new object according with the given allocation properties.
1404 HAllocate* BuildAllocate(HValue* object_size,
1405 HType type,
1406 InstanceType instance_type,
1407 HAllocationMode allocation_mode);
1408 // Computes the sum of two string lengths, taking care of overflow handling.
1409 HValue* BuildAddStringLengths(HValue* left_length, HValue* right_length);
1410 // Creates a cons string using the two input strings.
1411 HValue* BuildCreateConsString(HValue* length,
1412 HValue* left,
1413 HValue* right,
1414 HAllocationMode allocation_mode);
1415 // Copies characters from one sequential string to another.
1416 void BuildCopySeqStringChars(HValue* src,
1417 HValue* src_offset,
1418 String::Encoding src_encoding,
1419 HValue* dst,
1420 HValue* dst_offset,
1421 String::Encoding dst_encoding,
1422 HValue* length);
1423
1424 // Align an object size to object alignment boundary
1425 HValue* BuildObjectSizeAlignment(HValue* unaligned_size, int header_size);
1426
1427 // Both operands are non-empty strings.
1428 HValue* BuildUncheckedStringAdd(HValue* left,
1429 HValue* right,
1430 HAllocationMode allocation_mode);
1431 // Add two strings using allocation mode, validating type feedback.
1432 HValue* BuildStringAdd(HValue* left,
1433 HValue* right,
1434 HAllocationMode allocation_mode);
1435
1436 HInstruction* BuildUncheckedMonomorphicElementAccess(
1437 HValue* checked_object,
1438 HValue* key,
1439 HValue* val,
1440 bool is_js_array,
1441 ElementsKind elements_kind,
1442 PropertyAccessType access_type,
1443 LoadKeyedHoleMode load_mode,
1444 KeyedAccessStoreMode store_mode);
1445
1446 HInstruction* AddElementAccess(
1447 HValue* elements, HValue* checked_key, HValue* val, HValue* dependency,
1448 HValue* backing_store_owner, ElementsKind elements_kind,
1449 PropertyAccessType access_type,
1450 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE);
1451
1452 HInstruction* AddLoadStringInstanceType(HValue* string);
1453 HInstruction* AddLoadStringLength(HValue* string);
1454 HInstruction* BuildLoadStringLength(HValue* string);
AddStoreMapConstant(HValue * object,Handle<Map> map)1455 HStoreNamedField* AddStoreMapConstant(HValue* object, Handle<Map> map) {
1456 return Add<HStoreNamedField>(object, HObjectAccess::ForMap(),
1457 Add<HConstant>(map));
1458 }
1459 HLoadNamedField* AddLoadMap(HValue* object,
1460 HValue* dependency = NULL);
1461 HLoadNamedField* AddLoadElements(HValue* object,
1462 HValue* dependency = NULL);
1463
1464 bool MatchRotateRight(HValue* left,
1465 HValue* right,
1466 HValue** operand,
1467 HValue** shift_amount);
1468
1469 HValue* BuildBinaryOperation(Token::Value op, HValue* left, HValue* right,
1470 AstType* left_type, AstType* right_type,
1471 AstType* result_type, Maybe<int> fixed_right_arg,
1472 HAllocationMode allocation_mode,
1473 BailoutId opt_id = BailoutId::None());
1474
1475 HLoadNamedField* AddLoadFixedArrayLength(HValue *object,
1476 HValue *dependency = NULL);
1477
1478 HLoadNamedField* AddLoadArrayLength(HValue *object,
1479 ElementsKind kind,
1480 HValue *dependency = NULL);
1481
1482 HValue* AddLoadJSBuiltin(int context_index);
1483
1484 HValue* EnforceNumberType(HValue* number, AstType* expected);
1485 HValue* TruncateToNumber(HValue* value, AstType** expected);
1486
1487 void FinishExitWithHardDeoptimization(DeoptimizeReason reason);
1488
1489 void AddIncrementCounter(StatsCounter* counter);
1490
1491 class IfBuilder final {
1492 public:
1493 // If using this constructor, Initialize() must be called explicitly!
1494 IfBuilder();
1495
1496 explicit IfBuilder(HGraphBuilder* builder);
1497 IfBuilder(HGraphBuilder* builder,
1498 HIfContinuation* continuation);
1499
~IfBuilder()1500 ~IfBuilder() {
1501 if (!finished_) End();
1502 }
1503
1504 void Initialize(HGraphBuilder* builder);
1505
1506 template<class Condition>
If(HValue * p)1507 Condition* If(HValue *p) {
1508 Condition* compare = builder()->New<Condition>(p);
1509 AddCompare(compare);
1510 return compare;
1511 }
1512
1513 template<class Condition, class P2>
If(HValue * p1,P2 p2)1514 Condition* If(HValue* p1, P2 p2) {
1515 Condition* compare = builder()->New<Condition>(p1, p2);
1516 AddCompare(compare);
1517 return compare;
1518 }
1519
1520 template<class Condition, class P2, class P3>
If(HValue * p1,P2 p2,P3 p3)1521 Condition* If(HValue* p1, P2 p2, P3 p3) {
1522 Condition* compare = builder()->New<Condition>(p1, p2, p3);
1523 AddCompare(compare);
1524 return compare;
1525 }
1526
1527 template<class Condition>
IfNot(HValue * p)1528 Condition* IfNot(HValue* p) {
1529 Condition* compare = If<Condition>(p);
1530 compare->Not();
1531 return compare;
1532 }
1533
1534 template<class Condition, class P2>
IfNot(HValue * p1,P2 p2)1535 Condition* IfNot(HValue* p1, P2 p2) {
1536 Condition* compare = If<Condition>(p1, p2);
1537 compare->Not();
1538 return compare;
1539 }
1540
1541 template<class Condition, class P2, class P3>
IfNot(HValue * p1,P2 p2,P3 p3)1542 Condition* IfNot(HValue* p1, P2 p2, P3 p3) {
1543 Condition* compare = If<Condition>(p1, p2, p3);
1544 compare->Not();
1545 return compare;
1546 }
1547
1548 template<class Condition>
OrIf(HValue * p)1549 Condition* OrIf(HValue *p) {
1550 Or();
1551 return If<Condition>(p);
1552 }
1553
1554 template<class Condition, class P2>
OrIf(HValue * p1,P2 p2)1555 Condition* OrIf(HValue* p1, P2 p2) {
1556 Or();
1557 return If<Condition>(p1, p2);
1558 }
1559
1560 template<class Condition, class P2, class P3>
OrIf(HValue * p1,P2 p2,P3 p3)1561 Condition* OrIf(HValue* p1, P2 p2, P3 p3) {
1562 Or();
1563 return If<Condition>(p1, p2, p3);
1564 }
1565
1566 template<class Condition>
AndIf(HValue * p)1567 Condition* AndIf(HValue *p) {
1568 And();
1569 return If<Condition>(p);
1570 }
1571
1572 template<class Condition, class P2>
AndIf(HValue * p1,P2 p2)1573 Condition* AndIf(HValue* p1, P2 p2) {
1574 And();
1575 return If<Condition>(p1, p2);
1576 }
1577
1578 template<class Condition, class P2, class P3>
AndIf(HValue * p1,P2 p2,P3 p3)1579 Condition* AndIf(HValue* p1, P2 p2, P3 p3) {
1580 And();
1581 return If<Condition>(p1, p2, p3);
1582 }
1583
1584 void Or();
1585 void And();
1586
1587 // Captures the current state of this IfBuilder in the specified
1588 // continuation and ends this IfBuilder.
1589 void CaptureContinuation(HIfContinuation* continuation);
1590
1591 // Joins the specified continuation from this IfBuilder and ends this
1592 // IfBuilder. This appends a Goto instruction from the true branch of
1593 // this IfBuilder to the true branch of the continuation unless the
1594 // true branch of this IfBuilder is already finished. And vice versa
1595 // for the false branch.
1596 //
1597 // The basic idea is as follows: You have several nested IfBuilder's
1598 // that you want to join based on two possible outcomes (i.e. success
1599 // and failure, or whatever). You can do this easily using this method
1600 // now, for example:
1601 //
1602 // HIfContinuation cont(graph()->CreateBasicBlock(),
1603 // graph()->CreateBasicBlock());
1604 // ...
1605 // IfBuilder if_whatever(this);
1606 // if_whatever.If<Condition>(arg);
1607 // if_whatever.Then();
1608 // ...
1609 // if_whatever.Else();
1610 // ...
1611 // if_whatever.JoinContinuation(&cont);
1612 // ...
1613 // IfBuilder if_something(this);
1614 // if_something.If<Condition>(arg1, arg2);
1615 // if_something.Then();
1616 // ...
1617 // if_something.Else();
1618 // ...
1619 // if_something.JoinContinuation(&cont);
1620 // ...
1621 // IfBuilder if_finally(this, &cont);
1622 // if_finally.Then();
1623 // // continues after then code of if_whatever or if_something.
1624 // ...
1625 // if_finally.Else();
1626 // // continues after else code of if_whatever or if_something.
1627 // ...
1628 // if_finally.End();
1629 void JoinContinuation(HIfContinuation* continuation);
1630
1631 void Then();
1632 void Else();
1633 void End();
1634 void EndUnreachable();
1635
1636 void Deopt(DeoptimizeReason reason);
ThenDeopt(DeoptimizeReason reason)1637 void ThenDeopt(DeoptimizeReason reason) {
1638 Then();
1639 Deopt(reason);
1640 }
ElseDeopt(DeoptimizeReason reason)1641 void ElseDeopt(DeoptimizeReason reason) {
1642 Else();
1643 Deopt(reason);
1644 }
1645
1646 void Return(HValue* value);
1647
1648 private:
1649 void InitializeDontCreateBlocks(HGraphBuilder* builder);
1650
1651 HControlInstruction* AddCompare(HControlInstruction* compare);
1652
builder()1653 HGraphBuilder* builder() const {
1654 DCHECK(builder_ != NULL); // Have you called "Initialize"?
1655 return builder_;
1656 }
1657
1658 void AddMergeAtJoinBlock(bool deopt);
1659
1660 void Finish();
1661 void Finish(HBasicBlock** then_continuation,
1662 HBasicBlock** else_continuation);
1663
1664 class MergeAtJoinBlock : public ZoneObject {
1665 public:
MergeAtJoinBlock(HBasicBlock * block,bool deopt,MergeAtJoinBlock * next)1666 MergeAtJoinBlock(HBasicBlock* block,
1667 bool deopt,
1668 MergeAtJoinBlock* next)
1669 : block_(block),
1670 deopt_(deopt),
1671 next_(next) {}
1672 HBasicBlock* block_;
1673 bool deopt_;
1674 MergeAtJoinBlock* next_;
1675 };
1676
1677 HGraphBuilder* builder_;
1678 bool finished_ : 1;
1679 bool did_then_ : 1;
1680 bool did_else_ : 1;
1681 bool did_else_if_ : 1;
1682 bool did_and_ : 1;
1683 bool did_or_ : 1;
1684 bool captured_ : 1;
1685 bool needs_compare_ : 1;
1686 bool pending_merge_block_ : 1;
1687 HBasicBlock* first_true_block_;
1688 HBasicBlock* first_false_block_;
1689 HBasicBlock* split_edge_merge_block_;
1690 MergeAtJoinBlock* merge_at_join_blocks_;
1691 int normal_merge_at_join_block_count_;
1692 int deopt_merge_at_join_block_count_;
1693 };
1694
1695 class LoopBuilder final {
1696 public:
1697 enum Direction {
1698 kPreIncrement,
1699 kPostIncrement,
1700 kPreDecrement,
1701 kPostDecrement,
1702 kWhileTrue
1703 };
1704
1705 explicit LoopBuilder(HGraphBuilder* builder); // while (true) {...}
1706 LoopBuilder(HGraphBuilder* builder,
1707 HValue* context,
1708 Direction direction);
1709 LoopBuilder(HGraphBuilder* builder,
1710 HValue* context,
1711 Direction direction,
1712 HValue* increment_amount);
1713
~LoopBuilder()1714 ~LoopBuilder() {
1715 DCHECK(finished_);
1716 }
1717
1718 HValue* BeginBody(
1719 HValue* initial,
1720 HValue* terminating,
1721 Token::Value token);
1722
1723 void BeginBody(int drop_count);
1724
1725 void Break();
1726
1727 void EndBody();
1728
1729 private:
1730 void Initialize(HGraphBuilder* builder, HValue* context,
1731 Direction direction, HValue* increment_amount);
zone()1732 Zone* zone() { return builder_->zone(); }
1733
1734 HGraphBuilder* builder_;
1735 HValue* context_;
1736 HValue* increment_amount_;
1737 HInstruction* increment_;
1738 HPhi* phi_;
1739 HBasicBlock* header_block_;
1740 HBasicBlock* body_block_;
1741 HBasicBlock* exit_block_;
1742 HBasicBlock* exit_trampoline_block_;
1743 Direction direction_;
1744 bool finished_;
1745 };
1746
1747 HValue* BuildNewElementsCapacity(HValue* old_capacity);
1748
1749 HValue* BuildCalculateElementsSize(ElementsKind kind,
1750 HValue* capacity);
1751 HAllocate* AllocateJSArrayObject(AllocationSiteMode mode);
1752 HConstant* EstablishElementsAllocationSize(ElementsKind kind, int capacity);
1753
1754 HAllocate* BuildAllocateElements(ElementsKind kind, HValue* size_in_bytes);
1755
1756 void BuildInitializeElementsHeader(HValue* elements,
1757 ElementsKind kind,
1758 HValue* capacity);
1759
1760 // Build allocation and header initialization code for respective successor
1761 // of FixedArrayBase.
1762 HValue* BuildAllocateAndInitializeArray(ElementsKind kind, HValue* capacity);
1763
1764 // |array| must have been allocated with enough room for
1765 // 1) the JSArray and 2) an AllocationMemento if mode requires it.
1766 // If the |elements| value provided is NULL then the array elements storage
1767 // is initialized with empty array.
1768 void BuildJSArrayHeader(HValue* array,
1769 HValue* array_map,
1770 HValue* elements,
1771 AllocationSiteMode mode,
1772 ElementsKind elements_kind,
1773 HValue* allocation_site_payload,
1774 HValue* length_field);
1775
1776 HValue* BuildGrowElementsCapacity(HValue* object,
1777 HValue* elements,
1778 ElementsKind kind,
1779 ElementsKind new_kind,
1780 HValue* length,
1781 HValue* new_capacity);
1782
1783 void BuildFillElementsWithValue(HValue* elements,
1784 ElementsKind elements_kind,
1785 HValue* from,
1786 HValue* to,
1787 HValue* value);
1788
1789 void BuildFillElementsWithHole(HValue* elements,
1790 ElementsKind elements_kind,
1791 HValue* from,
1792 HValue* to);
1793
1794 void BuildCopyProperties(HValue* from_properties, HValue* to_properties,
1795 HValue* length, HValue* capacity);
1796
1797 void BuildCopyElements(HValue* from_elements,
1798 ElementsKind from_elements_kind,
1799 HValue* to_elements,
1800 ElementsKind to_elements_kind,
1801 HValue* length,
1802 HValue* capacity);
1803
1804 HValue* BuildElementIndexHash(HValue* index);
1805
1806 void BuildCreateAllocationMemento(HValue* previous_object,
1807 HValue* previous_object_size,
1808 HValue* payload);
1809
1810 HInstruction* BuildConstantMapCheck(Handle<JSObject> constant);
1811 HInstruction* BuildCheckPrototypeMaps(Handle<JSObject> prototype,
1812 Handle<JSObject> holder);
1813
1814 HInstruction* BuildGetNativeContext(HValue* closure);
1815 HInstruction* BuildGetNativeContext();
1816
1817 // Builds a loop version if |depth| is specified or unrolls the loop to
1818 // |depth_value| iterations otherwise.
1819 HValue* BuildGetParentContext(HValue* depth, int depth_value);
1820
1821 HInstruction* BuildGetArrayFunction();
1822 HValue* BuildArrayBufferViewFieldAccessor(HValue* object,
1823 HValue* checked_object,
1824 FieldIndex index);
1825
1826
1827 protected:
SetSourcePosition(int position)1828 void SetSourcePosition(int position) {
1829 if (position != kNoSourcePosition) {
1830 position_.SetScriptOffset(position);
1831 }
1832 // Otherwise position remains unknown.
1833 }
1834
EnterInlinedSource(int inlining_id)1835 void EnterInlinedSource(int inlining_id) {
1836 if (is_tracking_positions()) {
1837 position_.SetInliningId(inlining_id);
1838 }
1839 }
1840
1841 // Convert the given absolute offset from the start of the script to
1842 // the SourcePosition assuming that this position corresponds to the
1843 // same function as position_.
ScriptPositionToSourcePosition(int position)1844 SourcePosition ScriptPositionToSourcePosition(int position) {
1845 if (position == kNoSourcePosition) {
1846 return SourcePosition::Unknown();
1847 }
1848 return SourcePosition(position, position_.InliningId());
1849 }
1850
source_position()1851 SourcePosition source_position() { return position_; }
set_source_position(SourcePosition position)1852 void set_source_position(SourcePosition position) { position_ = position; }
1853
is_tracking_positions()1854 bool is_tracking_positions() { return track_positions_; }
1855
1856 void TraceInlinedFunction(Handle<SharedFunctionInfo> shared,
1857 SourcePosition position, int inlining_id);
1858
1859 HValue* BuildAllocateEmptyArrayBuffer(HValue* byte_length);
1860 template <typename ViewClass>
1861 void BuildArrayBufferViewInitialization(HValue* obj,
1862 HValue* buffer,
1863 HValue* byte_offset,
1864 HValue* byte_length);
1865
1866 private:
1867 HGraphBuilder();
1868
1869 template <class I>
AddInstructionTyped(I * instr)1870 I* AddInstructionTyped(I* instr) {
1871 return I::cast(AddInstruction(instr));
1872 }
1873
1874 CompilationInfo* info_;
1875 CallInterfaceDescriptor descriptor_;
1876 HGraph* graph_;
1877 HBasicBlock* current_block_;
1878 Scope* scope_;
1879 SourcePosition position_;
1880 bool track_positions_;
1881 };
1882
1883 template <>
1884 inline HDeoptimize* HGraphBuilder::Add<HDeoptimize>(
1885 DeoptimizeReason reason, Deoptimizer::BailoutType type) {
1886 if (type == Deoptimizer::SOFT) {
1887 isolate()->counters()->soft_deopts_requested()->Increment();
1888 if (FLAG_always_opt) return NULL;
1889 }
1890 if (current_block()->IsDeoptimizing()) return NULL;
1891 HBasicBlock* after_deopt_block = CreateBasicBlock(
1892 current_block()->last_environment());
1893 HDeoptimize* instr = New<HDeoptimize>(reason, type, after_deopt_block);
1894 if (type == Deoptimizer::SOFT) {
1895 isolate()->counters()->soft_deopts_inserted()->Increment();
1896 }
1897 FinishCurrentBlock(instr);
1898 set_current_block(after_deopt_block);
1899 return instr;
1900 }
1901
1902 template <>
1903 inline HInstruction* HGraphBuilder::AddUncasted<HDeoptimize>(
1904 DeoptimizeReason reason, Deoptimizer::BailoutType type) {
1905 return Add<HDeoptimize>(reason, type);
1906 }
1907
1908
1909 template<>
1910 inline HSimulate* HGraphBuilder::Add<HSimulate>(
1911 BailoutId id,
1912 RemovableSimulate removable) {
1913 HSimulate* instr = current_block()->CreateSimulate(id, removable);
1914 AddInstruction(instr);
1915 return instr;
1916 }
1917
1918
1919 template<>
1920 inline HSimulate* HGraphBuilder::Add<HSimulate>(
1921 BailoutId id) {
1922 return Add<HSimulate>(id, FIXED_SIMULATE);
1923 }
1924
1925
1926 template<>
1927 inline HInstruction* HGraphBuilder::AddUncasted<HSimulate>(BailoutId id) {
1928 return Add<HSimulate>(id, FIXED_SIMULATE);
1929 }
1930
1931
1932 template<>
1933 inline HReturn* HGraphBuilder::Add<HReturn>(HValue* value) {
1934 int num_parameters = graph()->info()->num_parameters();
1935 HValue* params = AddUncasted<HConstant>(num_parameters);
1936 HReturn* return_instruction = New<HReturn>(value, params);
1937 FinishExitCurrentBlock(return_instruction);
1938 return return_instruction;
1939 }
1940
1941
1942 template<>
1943 inline HReturn* HGraphBuilder::Add<HReturn>(HConstant* value) {
1944 return Add<HReturn>(static_cast<HValue*>(value));
1945 }
1946
1947 template<>
1948 inline HInstruction* HGraphBuilder::AddUncasted<HReturn>(HValue* value) {
1949 return Add<HReturn>(value);
1950 }
1951
1952
1953 template<>
1954 inline HInstruction* HGraphBuilder::AddUncasted<HReturn>(HConstant* value) {
1955 return Add<HReturn>(value);
1956 }
1957
1958
1959 template<>
1960 inline HCallRuntime* HGraphBuilder::Add<HCallRuntime>(
1961 const Runtime::Function* c_function,
1962 int argument_count) {
1963 HCallRuntime* instr = New<HCallRuntime>(c_function, argument_count);
1964 if (graph()->info()->IsStub()) {
1965 // When compiling code stubs, we don't want to save all double registers
1966 // upon entry to the stub, but instead have the call runtime instruction
1967 // save the double registers only on-demand (in the fallback case).
1968 instr->set_save_doubles(kSaveFPRegs);
1969 }
1970 AddInstruction(instr);
1971 return instr;
1972 }
1973
1974
1975 template<>
1976 inline HInstruction* HGraphBuilder::AddUncasted<HCallRuntime>(
1977 Handle<String> name,
1978 const Runtime::Function* c_function,
1979 int argument_count) {
1980 return Add<HCallRuntime>(c_function, argument_count);
1981 }
1982
1983
1984 template <>
1985 inline HParameter* HGraphBuilder::New<HParameter>(unsigned index) {
1986 return HParameter::New(isolate(), zone(), nullptr, index);
1987 }
1988
1989
1990 template <>
1991 inline HParameter* HGraphBuilder::New<HParameter>(
1992 unsigned index, HParameter::ParameterKind kind) {
1993 return HParameter::New(isolate(), zone(), nullptr, index, kind);
1994 }
1995
1996
1997 template <>
1998 inline HParameter* HGraphBuilder::New<HParameter>(
1999 unsigned index, HParameter::ParameterKind kind, Representation r) {
2000 return HParameter::New(isolate(), zone(), nullptr, index, kind, r);
2001 }
2002
2003
2004 template <>
2005 inline HPrologue* HGraphBuilder::New<HPrologue>() {
2006 return HPrologue::New(zone());
2007 }
2008
2009
2010 template <>
2011 inline HContext* HGraphBuilder::New<HContext>() {
2012 return HContext::New(zone());
2013 }
2014
2015 // This AstVistor is not final, and provides the AstVisitor methods as virtual
2016 // methods so they can be specialized by subclasses.
2017 class HOptimizedGraphBuilder : public HGraphBuilder,
2018 public AstVisitor<HOptimizedGraphBuilder> {
2019 public:
2020 // A class encapsulating (lazily-allocated) break and continue blocks for
2021 // a breakable statement. Separated from BreakAndContinueScope so that it
2022 // can have a separate lifetime.
2023 class BreakAndContinueInfo final BASE_EMBEDDED {
2024 public:
2025 explicit BreakAndContinueInfo(BreakableStatement* target,
2026 Scope* scope,
2027 int drop_extra = 0)
target_(target)2028 : target_(target),
2029 break_block_(NULL),
2030 continue_block_(NULL),
2031 scope_(scope),
2032 drop_extra_(drop_extra) {
2033 }
2034
target()2035 BreakableStatement* target() { return target_; }
break_block()2036 HBasicBlock* break_block() { return break_block_; }
set_break_block(HBasicBlock * block)2037 void set_break_block(HBasicBlock* block) { break_block_ = block; }
continue_block()2038 HBasicBlock* continue_block() { return continue_block_; }
set_continue_block(HBasicBlock * block)2039 void set_continue_block(HBasicBlock* block) { continue_block_ = block; }
scope()2040 Scope* scope() { return scope_; }
drop_extra()2041 int drop_extra() { return drop_extra_; }
2042
2043 private:
2044 BreakableStatement* target_;
2045 HBasicBlock* break_block_;
2046 HBasicBlock* continue_block_;
2047 Scope* scope_;
2048 int drop_extra_;
2049 };
2050
2051 // A helper class to maintain a stack of current BreakAndContinueInfo
2052 // structures mirroring BreakableStatement nesting.
2053 class BreakAndContinueScope final BASE_EMBEDDED {
2054 public:
BreakAndContinueScope(BreakAndContinueInfo * info,HOptimizedGraphBuilder * owner)2055 BreakAndContinueScope(BreakAndContinueInfo* info,
2056 HOptimizedGraphBuilder* owner)
2057 : info_(info), owner_(owner), next_(owner->break_scope()) {
2058 owner->set_break_scope(this);
2059 }
2060
~BreakAndContinueScope()2061 ~BreakAndContinueScope() { owner_->set_break_scope(next_); }
2062
info()2063 BreakAndContinueInfo* info() { return info_; }
owner()2064 HOptimizedGraphBuilder* owner() { return owner_; }
next()2065 BreakAndContinueScope* next() { return next_; }
2066
2067 // Search the break stack for a break or continue target.
2068 enum BreakType { BREAK, CONTINUE };
2069 HBasicBlock* Get(BreakableStatement* stmt, BreakType type,
2070 Scope** scope, int* drop_extra);
2071
2072 private:
2073 BreakAndContinueInfo* info_;
2074 HOptimizedGraphBuilder* owner_;
2075 BreakAndContinueScope* next_;
2076 };
2077
2078 explicit HOptimizedGraphBuilder(CompilationInfo* info, bool track_positions);
2079
2080 bool BuildGraph() override;
2081
2082 // Simple accessors.
break_scope()2083 BreakAndContinueScope* break_scope() const { return break_scope_; }
set_break_scope(BreakAndContinueScope * head)2084 void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; }
2085
context()2086 HValue* context() override { return environment()->context(); }
2087
osr()2088 HOsrBuilder* osr() const { return osr_; }
2089
2090 void Bailout(BailoutReason reason);
2091
2092 HBasicBlock* CreateJoin(HBasicBlock* first,
2093 HBasicBlock* second,
2094 BailoutId join_id);
2095
function_state()2096 FunctionState* function_state() const { return function_state_; }
2097
2098 void VisitDeclarations(Declaration::List* declarations);
2099
bounds()2100 AstTypeBounds* bounds() { return &bounds_; }
2101
new(size_t size,Zone * zone)2102 void* operator new(size_t size, Zone* zone) { return zone->New(size); }
delete(void * pointer,Zone * zone)2103 void operator delete(void* pointer, Zone* zone) { }
delete(void * pointer)2104 void operator delete(void* pointer) { }
2105
2106 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
2107
2108 protected:
2109 // Forward declarations for inner scope classes.
2110 class SubgraphScope;
2111
2112 static const int kMaxCallPolymorphism = 4;
2113 static const int kMaxLoadPolymorphism = 4;
2114 static const int kMaxStorePolymorphism = 4;
2115
2116 // Even in the 'unlimited' case we have to have some limit in order not to
2117 // overflow the stack.
2118 static const int kUnlimitedMaxInlinedSourceSize = 100000;
2119 static const int kUnlimitedMaxInlinedNodes = 10000;
2120 static const int kUnlimitedMaxInlinedNodesCumulative = 10000;
2121
2122 // Maximum depth and total number of elements and properties for literal
2123 // graphs to be considered for fast deep-copying.
2124 static const int kMaxFastLiteralDepth = 3;
2125 static const int kMaxFastLiteralProperties = 8;
2126
2127 // Simple accessors.
set_function_state(FunctionState * state)2128 void set_function_state(FunctionState* state) { function_state_ = state; }
2129
ast_context()2130 AstContext* ast_context() const { return ast_context_; }
set_ast_context(AstContext * context)2131 void set_ast_context(AstContext* context) { ast_context_ = context; }
2132
2133 // Accessors forwarded to the function state.
current_info()2134 CompilationInfo* current_info() const {
2135 return function_state()->compilation_info();
2136 }
call_context()2137 AstContext* call_context() const {
2138 return function_state()->call_context();
2139 }
function_return()2140 HBasicBlock* function_return() const {
2141 return function_state()->function_return();
2142 }
inlined_test_context()2143 TestContext* inlined_test_context() const {
2144 return function_state()->test_context();
2145 }
current_closure()2146 Handle<JSFunction> current_closure() const {
2147 return current_info()->closure();
2148 }
current_shared_info()2149 Handle<SharedFunctionInfo> current_shared_info() const {
2150 return current_info()->shared_info();
2151 }
current_feedback_vector()2152 TypeFeedbackVector* current_feedback_vector() const {
2153 return current_closure()->feedback_vector();
2154 }
ClearInlinedTestContext()2155 void ClearInlinedTestContext() {
2156 function_state()->ClearInlinedTestContext();
2157 }
function_language_mode()2158 LanguageMode function_language_mode() {
2159 return function_state()->compilation_info()->parse_info()->language_mode();
2160 }
2161
2162 #define FOR_EACH_HYDROGEN_INTRINSIC(F) \
2163 F(IsSmi) \
2164 F(IsArray) \
2165 F(IsTypedArray) \
2166 F(IsRegExp) \
2167 F(IsJSProxy) \
2168 F(Call) \
2169 F(NewObject) \
2170 F(ToInteger) \
2171 F(ToObject) \
2172 F(ToString) \
2173 F(ToLength) \
2174 F(ToNumber) \
2175 F(IsJSReceiver) \
2176 F(DebugBreakInOptimizedCode) \
2177 F(StringCharCodeAt) \
2178 F(SubString) \
2179 F(RegExpExec) \
2180 F(NumberToString) \
2181 F(DebugIsActive) \
2182 /* Typed Arrays */ \
2183 F(TypedArrayInitialize) \
2184 F(MaxSmi) \
2185 F(TypedArrayMaxSizeInHeap) \
2186 F(ArrayBufferViewGetByteLength) \
2187 F(ArrayBufferViewGetByteOffset) \
2188 F(TypedArrayGetLength) \
2189 /* ArrayBuffer */ \
2190 F(ArrayBufferGetByteLength) \
2191 /* ES6 Collections */ \
2192 F(MapClear) \
2193 F(MapInitialize) \
2194 F(SetClear) \
2195 F(SetInitialize) \
2196 F(FixedArrayGet) \
2197 F(FixedArraySet) \
2198 F(JSCollectionGetTable) \
2199 F(StringGetRawHashField) \
2200 F(TheHole) \
2201 /* ES6 Iterators */ \
2202 F(CreateIterResultObject) \
2203 /* Arrays */ \
2204 F(HasFastPackedElements)
2205
2206 #define GENERATOR_DECLARATION(Name) void Generate##Name(CallRuntime* call);
2207 FOR_EACH_HYDROGEN_INTRINSIC(GENERATOR_DECLARATION)
2208 #undef GENERATOR_DECLARATION
2209
2210 void VisitDelete(UnaryOperation* expr);
2211 void VisitVoid(UnaryOperation* expr);
2212 void VisitTypeof(UnaryOperation* expr);
2213 void VisitNot(UnaryOperation* expr);
2214
2215 void VisitComma(BinaryOperation* expr);
2216 void VisitLogicalExpression(BinaryOperation* expr);
2217 void VisitArithmeticExpression(BinaryOperation* expr);
2218
2219 void VisitLoopBody(IterationStatement* stmt, BailoutId stack_check_id,
2220 HBasicBlock* loop_entry);
2221
2222 void BuildForInBody(ForInStatement* stmt, Variable* each_var,
2223 HValue* enumerable);
2224
2225 // Create a back edge in the flow graph. body_exit is the predecessor
2226 // block and loop_entry is the successor block. loop_successor is the
2227 // block where control flow exits the loop normally (e.g., via failure of
2228 // the condition) and break_block is the block where control flow breaks
2229 // from the loop. All blocks except loop_entry can be NULL. The return
2230 // value is the new successor block which is the join of loop_successor
2231 // and break_block, or NULL.
2232 HBasicBlock* CreateLoop(IterationStatement* statement,
2233 HBasicBlock* loop_entry,
2234 HBasicBlock* body_exit,
2235 HBasicBlock* loop_successor,
2236 HBasicBlock* break_block);
2237
2238 // Build a loop entry
2239 HBasicBlock* BuildLoopEntry();
2240
2241 // Builds a loop entry respectful of OSR requirements
2242 HBasicBlock* BuildLoopEntry(IterationStatement* statement);
2243
2244 HBasicBlock* JoinContinue(IterationStatement* statement,
2245 BailoutId continue_id, HBasicBlock* exit_block,
2246 HBasicBlock* continue_block);
2247
Top()2248 HValue* Top() const { return environment()->Top(); }
Drop(int n)2249 void Drop(int n) { environment()->Drop(n); }
Bind(Variable * var,HValue * value)2250 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
IsEligibleForEnvironmentLivenessAnalysis(Variable * var,int index,HEnvironment * env)2251 bool IsEligibleForEnvironmentLivenessAnalysis(Variable* var,
2252 int index,
2253 HEnvironment* env) {
2254 if (!FLAG_analyze_environment_liveness) return false;
2255 // Zapping parameters isn't safe because function.arguments can inspect them
2256 // at any time.
2257 return env->is_local_index(index);
2258 }
BindIfLive(Variable * var,HValue * value)2259 void BindIfLive(Variable* var, HValue* value) {
2260 HEnvironment* env = environment();
2261 int index = env->IndexFor(var);
2262 env->Bind(index, value);
2263 if (IsEligibleForEnvironmentLivenessAnalysis(var, index, env)) {
2264 HEnvironmentMarker* bind =
2265 Add<HEnvironmentMarker>(HEnvironmentMarker::BIND, index);
2266 USE(bind);
2267 #ifdef DEBUG
2268 bind->set_closure(env->closure());
2269 #endif
2270 }
2271 }
LookupAndMakeLive(Variable * var)2272 HValue* LookupAndMakeLive(Variable* var) {
2273 HEnvironment* env = environment();
2274 int index = env->IndexFor(var);
2275 if (IsEligibleForEnvironmentLivenessAnalysis(var, index, env)) {
2276 HEnvironmentMarker* lookup =
2277 Add<HEnvironmentMarker>(HEnvironmentMarker::LOOKUP, index);
2278 USE(lookup);
2279 #ifdef DEBUG
2280 lookup->set_closure(env->closure());
2281 #endif
2282 }
2283 return env->Lookup(index);
2284 }
2285
2286 // The value of the arguments object is allowed in some but not most value
2287 // contexts. (It's allowed in all effect contexts and disallowed in all
2288 // test contexts.)
2289 void VisitForValue(Expression* expr,
2290 ArgumentsAllowedFlag flag = ARGUMENTS_NOT_ALLOWED);
2291 void VisitForTypeOf(Expression* expr);
2292 void VisitForEffect(Expression* expr);
2293 void VisitForControl(Expression* expr,
2294 HBasicBlock* true_block,
2295 HBasicBlock* false_block);
2296
2297 // Visit a list of expressions from left to right, each in a value context.
2298 void VisitExpressions(ZoneList<Expression*>* exprs);
2299 void VisitExpressions(ZoneList<Expression*>* exprs,
2300 ArgumentsAllowedFlag flag);
2301
2302 // Remove the arguments from the bailout environment and emit instructions
2303 // to push them as outgoing parameters.
2304 template <class Instruction> HInstruction* PreProcessCall(Instruction* call);
2305 void PushArgumentsFromEnvironment(int count);
2306
2307 void SetUpScope(DeclarationScope* scope);
2308 void VisitStatements(ZoneList<Statement*>* statements);
2309
2310 #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
2311 AST_NODE_LIST(DECLARE_VISIT)
2312 #undef DECLARE_VISIT
2313
2314 private:
2315 bool CanInlineGlobalPropertyAccess(Variable* var, LookupIterator* it,
2316 PropertyAccessType access_type);
2317
2318 bool CanInlineGlobalPropertyAccess(LookupIterator* it,
2319 PropertyAccessType access_type);
2320
2321 void InlineGlobalPropertyLoad(LookupIterator* it, BailoutId ast_id);
2322 HInstruction* InlineGlobalPropertyStore(LookupIterator* it, HValue* value,
2323 BailoutId ast_id);
2324
2325 void EnsureArgumentsArePushedForAccess();
2326 bool TryArgumentsAccess(Property* expr);
2327
2328 // Shared code for .call and .apply optimizations.
2329 void HandleIndirectCall(Call* expr, HValue* function, int arguments_count);
2330 // Try to optimize indirect calls such as fun.apply(receiver, arguments)
2331 // or fun.call(...).
2332 bool TryIndirectCall(Call* expr);
2333 void BuildFunctionApply(Call* expr);
2334 void BuildFunctionCall(Call* expr);
2335
2336 template <class T>
2337 bool TryHandleArrayCall(T* expr, HValue* function);
2338
2339 enum ArrayIndexOfMode { kFirstIndexOf, kLastIndexOf };
2340 HValue* BuildArrayIndexOf(HValue* receiver,
2341 HValue* search_element,
2342 ElementsKind kind,
2343 ArrayIndexOfMode mode);
2344
2345 HValue* ImplicitReceiverFor(HValue* function,
2346 Handle<JSFunction> target);
2347
2348 int InliningAstSize(Handle<JSFunction> target);
2349 bool TryInline(Handle<JSFunction> target, int arguments_count,
2350 HValue* implicit_return_value, BailoutId ast_id,
2351 BailoutId return_id, InliningKind inlining_kind,
2352 TailCallMode syntactic_tail_call_mode);
2353
2354 bool TryInlineCall(Call* expr);
2355 bool TryInlineConstruct(CallNew* expr, HValue* implicit_return_value);
2356 bool TryInlineGetter(Handle<Object> getter, Handle<Map> receiver_map,
2357 BailoutId ast_id, BailoutId return_id);
2358 bool TryInlineSetter(Handle<Object> setter, Handle<Map> receiver_map,
2359 BailoutId id, BailoutId assignment_id,
2360 HValue* implicit_return_value);
2361 bool TryInlineIndirectCall(Handle<JSFunction> function, Call* expr,
2362 int arguments_count);
2363 bool TryInlineBuiltinGetterCall(Handle<JSFunction> function,
2364 Handle<Map> receiver_map, BailoutId ast_id);
2365 bool TryInlineBuiltinMethodCall(Handle<JSFunction> function,
2366 Handle<Map> receiver_map, BailoutId ast_id,
2367 int args_count_no_receiver);
2368 bool TryInlineBuiltinFunctionCall(Call* expr);
2369 enum ApiCallType {
2370 kCallApiFunction,
2371 kCallApiMethod,
2372 kCallApiGetter,
2373 kCallApiSetter
2374 };
2375 bool TryInlineApiMethodCall(Call* expr,
2376 HValue* receiver,
2377 SmallMapList* receiver_types);
2378 bool TryInlineApiFunctionCall(Call* expr, HValue* receiver);
2379 bool TryInlineApiGetter(Handle<Object> function, Handle<Map> receiver_map,
2380 BailoutId ast_id);
2381 bool TryInlineApiSetter(Handle<Object> function, Handle<Map> receiver_map,
2382 BailoutId ast_id);
2383 bool TryInlineApiCall(Handle<Object> function, HValue* receiver,
2384 SmallMapList* receiver_maps, int argc, BailoutId ast_id,
2385 ApiCallType call_type,
2386 TailCallMode syntactic_tail_call_mode);
2387 static bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map);
2388 static bool CanInlineArrayResizeOperation(Handle<Map> receiver_map);
2389
2390 // If --trace-inlining, print a line of the inlining trace. Inlining
2391 // succeeded if the reason string is NULL and failed if there is a
2392 // non-NULL reason string.
2393 void TraceInline(Handle<JSFunction> target, Handle<JSFunction> caller,
2394 const char* failure_reason,
2395 TailCallMode tail_call_mode = TailCallMode::kDisallow);
2396
2397 void HandleGlobalVariableAssignment(Variable* var, HValue* value,
2398 FeedbackVectorSlot slot,
2399 BailoutId ast_id);
2400
2401 void HandlePropertyAssignment(Assignment* expr);
2402 void HandleCompoundAssignment(Assignment* expr);
2403 void HandlePolymorphicNamedFieldAccess(
2404 PropertyAccessType access_type, Expression* expr, FeedbackVectorSlot slot,
2405 BailoutId ast_id, BailoutId return_id, HValue* object, HValue* value,
2406 SmallMapList* types, Handle<Name> name);
2407
2408 HValue* BuildAllocateExternalElements(
2409 ExternalArrayType array_type,
2410 bool is_zero_byte_offset,
2411 HValue* buffer, HValue* byte_offset, HValue* length);
2412 HValue* BuildAllocateFixedTypedArray(ExternalArrayType array_type,
2413 size_t element_size,
2414 ElementsKind fixed_elements_kind,
2415 HValue* byte_length, HValue* length,
2416 bool initialize);
2417
2418 // TODO(adamk): Move all OrderedHashTable functions to their own class.
2419 HValue* BuildOrderedHashTableHashToBucket(HValue* hash, HValue* num_buckets);
2420 template <typename CollectionType>
2421 HValue* BuildOrderedHashTableHashToEntry(HValue* table, HValue* hash,
2422 HValue* num_buckets);
2423 template <typename CollectionType>
2424 HValue* BuildOrderedHashTableEntryToIndex(HValue* entry, HValue* num_buckets);
2425 template <typename CollectionType>
2426 HValue* BuildOrderedHashTableFindEntry(HValue* table, HValue* key,
2427 HValue* hash);
2428 template <typename CollectionType>
2429 HValue* BuildOrderedHashTableAddEntry(HValue* table, HValue* key,
2430 HValue* hash,
2431 HIfContinuation* join_continuation);
2432 template <typename CollectionType>
2433 HValue* BuildAllocateOrderedHashTable();
2434 template <typename CollectionType>
2435 void BuildOrderedHashTableClear(HValue* receiver);
2436 template <typename CollectionType>
2437 void BuildJSCollectionDelete(CallRuntime* call,
2438 const Runtime::Function* c_function);
2439 template <typename CollectionType>
2440 void BuildJSCollectionHas(CallRuntime* call,
2441 const Runtime::Function* c_function);
2442 HValue* BuildStringHashLoadIfIsStringAndHashComputed(
2443 HValue* object, HIfContinuation* continuation);
2444
array_function()2445 Handle<JSFunction> array_function() {
2446 return handle(isolate()->native_context()->array_function());
2447 }
2448
2449 bool TryInlineArrayCall(Expression* expression, int argument_count,
2450 Handle<AllocationSite> site);
2451
2452 void BuildInitializeInobjectProperties(HValue* receiver,
2453 Handle<Map> initial_map);
2454
2455 class PropertyAccessInfo {
2456 public:
PropertyAccessInfo(HOptimizedGraphBuilder * builder,PropertyAccessType access_type,Handle<Map> map,Handle<Name> name)2457 PropertyAccessInfo(HOptimizedGraphBuilder* builder,
2458 PropertyAccessType access_type, Handle<Map> map,
2459 Handle<Name> name)
2460 : builder_(builder),
2461 access_type_(access_type),
2462 map_(map),
2463 name_(isolate()->factory()->InternalizeName(name)),
2464 field_type_(HType::Tagged()),
2465 access_(HObjectAccess::ForMap()),
2466 lookup_type_(NOT_FOUND),
2467 details_(NONE, DATA, Representation::None()) {}
2468
2469 // Checkes whether this PropertyAccessInfo can be handled as a monomorphic
2470 // load named. It additionally fills in the fields necessary to generate the
2471 // lookup code.
2472 bool CanAccessMonomorphic();
2473
2474 // Checks whether all types behave uniform when loading name. If all maps
2475 // behave the same, a single monomorphic load instruction can be emitted,
2476 // guarded by a single map-checks instruction that whether the receiver is
2477 // an instance of any of the types.
2478 // This method skips the first type in types, assuming that this
2479 // PropertyAccessInfo is built for types->first().
2480 bool CanAccessAsMonomorphic(SmallMapList* types);
2481
2482 bool NeedsWrappingFor(Handle<JSFunction> target) const;
2483
2484 Handle<Map> map();
name()2485 Handle<Name> name() const { return name_; }
2486
IsJSObjectFieldAccessor()2487 bool IsJSObjectFieldAccessor() {
2488 int offset; // unused
2489 return Accessors::IsJSObjectFieldAccessor(map_, name_, &offset);
2490 }
2491
GetJSObjectFieldAccess(HObjectAccess * access)2492 bool GetJSObjectFieldAccess(HObjectAccess* access) {
2493 int offset;
2494 if (Accessors::IsJSObjectFieldAccessor(map_, name_, &offset)) {
2495 if (IsStringType()) {
2496 DCHECK(Name::Equals(isolate()->factory()->length_string(), name_));
2497 *access = HObjectAccess::ForStringLength();
2498 } else if (IsArrayType()) {
2499 DCHECK(Name::Equals(isolate()->factory()->length_string(), name_));
2500 *access = HObjectAccess::ForArrayLength(map_->elements_kind());
2501 } else {
2502 *access = HObjectAccess::ForMapAndOffset(map_, offset);
2503 }
2504 return true;
2505 }
2506 return false;
2507 }
2508
has_holder()2509 bool has_holder() { return !holder_.is_null(); }
IsLoad()2510 bool IsLoad() const { return access_type_ == LOAD; }
2511
isolate()2512 Isolate* isolate() const { return builder_->isolate(); }
holder()2513 Handle<JSObject> holder() { return holder_; }
accessor()2514 Handle<Object> accessor() { return accessor_; }
constant()2515 Handle<Object> constant() { return constant_; }
transition()2516 Handle<Map> transition() { return transition_; }
field_maps()2517 SmallMapList* field_maps() { return &field_maps_; }
field_type()2518 HType field_type() const { return field_type_; }
access()2519 HObjectAccess access() { return access_; }
2520
IsFound()2521 bool IsFound() const { return lookup_type_ != NOT_FOUND; }
IsProperty()2522 bool IsProperty() const { return IsFound() && !IsTransition(); }
IsTransition()2523 bool IsTransition() const { return lookup_type_ == TRANSITION_TYPE; }
IsData()2524 bool IsData() const {
2525 return lookup_type_ == DESCRIPTOR_TYPE && details_.type() == DATA;
2526 }
IsDataConstant()2527 bool IsDataConstant() const {
2528 return lookup_type_ == DESCRIPTOR_TYPE &&
2529 details_.type() == DATA_CONSTANT;
2530 }
IsAccessorConstant()2531 bool IsAccessorConstant() const {
2532 return !IsTransition() && details_.type() == ACCESSOR_CONSTANT;
2533 }
IsConfigurable()2534 bool IsConfigurable() const { return details_.IsConfigurable(); }
IsReadOnly()2535 bool IsReadOnly() const { return details_.IsReadOnly(); }
2536
IsStringType()2537 bool IsStringType() { return map_->instance_type() < FIRST_NONSTRING_TYPE; }
IsNumberType()2538 bool IsNumberType() { return map_->instance_type() == HEAP_NUMBER_TYPE; }
IsValueWrapped()2539 bool IsValueWrapped() { return IsStringType() || IsNumberType(); }
IsArrayType()2540 bool IsArrayType() { return map_->instance_type() == JS_ARRAY_TYPE; }
2541
2542 private:
GetConstantFromMap(Handle<Map> map)2543 Handle<Object> GetConstantFromMap(Handle<Map> map) const {
2544 DCHECK_EQ(DESCRIPTOR_TYPE, lookup_type_);
2545 DCHECK(number_ < map->NumberOfOwnDescriptors());
2546 return handle(map->instance_descriptors()->GetValue(number_), isolate());
2547 }
GetAccessorsFromMap(Handle<Map> map)2548 Handle<Object> GetAccessorsFromMap(Handle<Map> map) const {
2549 return GetConstantFromMap(map);
2550 }
2551 Handle<FieldType> GetFieldTypeFromMap(Handle<Map> map) const;
GetFieldOwnerFromMap(Handle<Map> map)2552 Handle<Map> GetFieldOwnerFromMap(Handle<Map> map) const {
2553 DCHECK(IsFound());
2554 DCHECK(number_ < map->NumberOfOwnDescriptors());
2555 return handle(map->FindFieldOwner(number_));
2556 }
GetLocalFieldIndexFromMap(Handle<Map> map)2557 int GetLocalFieldIndexFromMap(Handle<Map> map) const {
2558 DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
2559 lookup_type_ == TRANSITION_TYPE);
2560 DCHECK(number_ < map->NumberOfOwnDescriptors());
2561 int field_index = map->instance_descriptors()->GetFieldIndex(number_);
2562 return field_index - map->GetInObjectProperties();
2563 }
2564
LookupDescriptor(Map * map,Name * name)2565 void LookupDescriptor(Map* map, Name* name) {
2566 DescriptorArray* descriptors = map->instance_descriptors();
2567 int number = descriptors->SearchWithCache(isolate(), name, map);
2568 if (number == DescriptorArray::kNotFound) return NotFound();
2569 lookup_type_ = DESCRIPTOR_TYPE;
2570 details_ = descriptors->GetDetails(number);
2571 number_ = number;
2572 }
LookupTransition(Map * map,Name * name,PropertyAttributes attributes)2573 void LookupTransition(Map* map, Name* name, PropertyAttributes attributes) {
2574 Map* target =
2575 TransitionArray::SearchTransition(map, kData, name, attributes);
2576 if (target == NULL) return NotFound();
2577 lookup_type_ = TRANSITION_TYPE;
2578 transition_ = handle(target);
2579 number_ = transition_->LastAdded();
2580 details_ = transition_->instance_descriptors()->GetDetails(number_);
2581 }
NotFound()2582 void NotFound() {
2583 lookup_type_ = NOT_FOUND;
2584 details_ = PropertyDetails::Empty();
2585 }
representation()2586 Representation representation() const {
2587 DCHECK(IsFound());
2588 return details_.representation();
2589 }
IsTransitionToData()2590 bool IsTransitionToData() const {
2591 return IsTransition() && details_.type() == DATA;
2592 }
2593
zone()2594 Zone* zone() { return builder_->zone(); }
top_info()2595 CompilationInfo* top_info() { return builder_->top_info(); }
current_info()2596 CompilationInfo* current_info() { return builder_->current_info(); }
2597
2598 bool LoadResult(Handle<Map> map);
2599 bool LoadFieldMaps(Handle<Map> map);
2600 bool LookupDescriptor();
2601 bool LookupInPrototypes();
2602 bool IsIntegerIndexedExotic();
2603 bool IsCompatible(PropertyAccessInfo* other);
2604
GeneralizeRepresentation(Representation r)2605 void GeneralizeRepresentation(Representation r) {
2606 access_ = access_.WithRepresentation(
2607 access_.representation().generalize(r));
2608 }
2609
2610 HOptimizedGraphBuilder* builder_;
2611 PropertyAccessType access_type_;
2612 Handle<Map> map_;
2613 Handle<Name> name_;
2614 Handle<JSObject> holder_;
2615 Handle<Object> accessor_;
2616 Handle<JSObject> api_holder_;
2617 Handle<Object> constant_;
2618 SmallMapList field_maps_;
2619 HType field_type_;
2620 HObjectAccess access_;
2621
2622 enum { NOT_FOUND, DESCRIPTOR_TYPE, TRANSITION_TYPE } lookup_type_;
2623 Handle<Map> transition_;
2624 int number_;
2625 PropertyDetails details_;
2626 };
2627
2628 HValue* BuildMonomorphicAccess(PropertyAccessInfo* info, HValue* object,
2629 HValue* checked_object, HValue* value,
2630 BailoutId ast_id, BailoutId return_id,
2631 bool can_inline_accessor = true);
2632
2633 HValue* BuildNamedAccess(PropertyAccessType access, BailoutId ast_id,
2634 BailoutId reutrn_id, Expression* expr,
2635 FeedbackVectorSlot slot, HValue* object,
2636 Handle<Name> name, HValue* value,
2637 bool is_uninitialized = false);
2638
2639 void HandlePolymorphicCallNamed(Call* expr,
2640 HValue* receiver,
2641 SmallMapList* types,
2642 Handle<String> name);
2643 void HandleLiteralCompareTypeof(CompareOperation* expr,
2644 Expression* sub_expr,
2645 Handle<String> check);
2646 void HandleLiteralCompareNil(CompareOperation* expr,
2647 Expression* sub_expr,
2648 NilValue nil);
2649
2650 enum PushBeforeSimulateBehavior {
2651 PUSH_BEFORE_SIMULATE,
2652 NO_PUSH_BEFORE_SIMULATE
2653 };
2654
2655 HControlInstruction* BuildCompareInstruction(
2656 Token::Value op, HValue* left, HValue* right, AstType* left_type,
2657 AstType* right_type, AstType* combined_type, SourcePosition left_position,
2658 SourcePosition right_position, PushBeforeSimulateBehavior push_sim_result,
2659 BailoutId bailout_id);
2660
2661 HInstruction* BuildStringCharCodeAt(HValue* string,
2662 HValue* index);
2663
2664 HValue* BuildBinaryOperation(
2665 BinaryOperation* expr,
2666 HValue* left,
2667 HValue* right,
2668 PushBeforeSimulateBehavior push_sim_result);
2669 HInstruction* BuildIncrement(CountOperation* expr);
2670 HInstruction* BuildKeyedGeneric(PropertyAccessType access_type,
2671 Expression* expr, FeedbackVectorSlot slot,
2672 HValue* object, HValue* key, HValue* value);
2673
2674 HInstruction* TryBuildConsolidatedElementLoad(HValue* object,
2675 HValue* key,
2676 HValue* val,
2677 SmallMapList* maps);
2678
2679 LoadKeyedHoleMode BuildKeyedHoleMode(Handle<Map> map);
2680
2681 HInstruction* BuildMonomorphicElementAccess(HValue* object,
2682 HValue* key,
2683 HValue* val,
2684 HValue* dependency,
2685 Handle<Map> map,
2686 PropertyAccessType access_type,
2687 KeyedAccessStoreMode store_mode);
2688
2689 HValue* HandlePolymorphicElementAccess(
2690 Expression* expr, FeedbackVectorSlot slot, HValue* object, HValue* key,
2691 HValue* val, SmallMapList* maps, PropertyAccessType access_type,
2692 KeyedAccessStoreMode store_mode, bool* has_side_effects);
2693
2694 HValue* HandleKeyedElementAccess(HValue* obj, HValue* key, HValue* val,
2695 Expression* expr, FeedbackVectorSlot slot,
2696 BailoutId ast_id, BailoutId return_id,
2697 PropertyAccessType access_type,
2698 bool* has_side_effects);
2699
2700 HInstruction* BuildNamedGeneric(PropertyAccessType access, Expression* expr,
2701 FeedbackVectorSlot slot, HValue* object,
2702 Handle<Name> name, HValue* value,
2703 bool is_uninitialized = false);
2704
2705 HCheckMaps* AddCheckMap(HValue* object, Handle<Map> map);
2706
2707 void BuildLoad(Property* property,
2708 BailoutId ast_id);
2709 void PushLoad(Property* property,
2710 HValue* object,
2711 HValue* key);
2712
2713 void BuildStoreForEffect(Expression* expression, Property* prop,
2714 FeedbackVectorSlot slot, BailoutId ast_id,
2715 BailoutId return_id, HValue* object, HValue* key,
2716 HValue* value);
2717
2718 void BuildStore(Expression* expression, Property* prop,
2719 FeedbackVectorSlot slot, BailoutId ast_id,
2720 BailoutId return_id, bool is_uninitialized = false);
2721
2722 HInstruction* BuildLoadNamedField(PropertyAccessInfo* info,
2723 HValue* checked_object);
2724 HInstruction* BuildStoreNamedField(PropertyAccessInfo* info,
2725 HValue* checked_object,
2726 HValue* value);
2727
2728 HValue* BuildContextChainWalk(Variable* var);
2729
2730 HValue* AddThisFunction();
2731 HInstruction* BuildThisFunction();
2732
2733 HInstruction* BuildFastLiteral(Handle<JSObject> boilerplate_object,
2734 AllocationSiteUsageContext* site_context);
2735
2736 void BuildEmitObjectHeader(Handle<JSObject> boilerplate_object,
2737 HInstruction* object);
2738
2739 void BuildEmitInObjectProperties(Handle<JSObject> boilerplate_object,
2740 HInstruction* object,
2741 AllocationSiteUsageContext* site_context,
2742 PretenureFlag pretenure_flag);
2743
2744 void BuildEmitElements(Handle<JSObject> boilerplate_object,
2745 Handle<FixedArrayBase> elements,
2746 HValue* object_elements,
2747 AllocationSiteUsageContext* site_context);
2748
2749 void BuildEmitFixedDoubleArray(Handle<FixedArrayBase> elements,
2750 ElementsKind kind,
2751 HValue* object_elements);
2752
2753 void BuildEmitFixedArray(Handle<FixedArrayBase> elements,
2754 ElementsKind kind,
2755 HValue* object_elements,
2756 AllocationSiteUsageContext* site_context);
2757
2758 void AddCheckPrototypeMaps(Handle<JSObject> holder,
2759 Handle<Map> receiver_map);
2760
2761 void BuildEnsureCallable(HValue* object);
2762
2763 HInstruction* NewCallFunction(HValue* function, int argument_count,
2764 TailCallMode syntactic_tail_call_mode,
2765 ConvertReceiverMode convert_mode,
2766 TailCallMode tail_call_mode);
2767
2768 HInstruction* NewCallFunctionViaIC(HValue* function, int argument_count,
2769 TailCallMode syntactic_tail_call_mode,
2770 ConvertReceiverMode convert_mode,
2771 TailCallMode tail_call_mode,
2772 FeedbackVectorSlot slot);
2773
2774 HInstruction* NewCallConstantFunction(Handle<JSFunction> target,
2775 int argument_count,
2776 TailCallMode syntactic_tail_call_mode,
2777 TailCallMode tail_call_mode);
2778
2779 bool CanBeFunctionApplyArguments(Call* expr);
2780
2781 bool IsAnyParameterContextAllocated();
2782
2783 // The translation state of the currently-being-translated function.
2784 FunctionState* function_state_;
2785
2786 // The base of the function state stack.
2787 FunctionState initial_function_state_;
2788
2789 // Expression context of the currently visited subexpression. NULL when
2790 // visiting statements.
2791 AstContext* ast_context_;
2792
2793 // A stack of breakable statements entered.
2794 BreakAndContinueScope* break_scope_;
2795
2796 int inlined_count_;
2797 ZoneList<Handle<Object> > globals_;
2798
2799 bool inline_bailout_;
2800
2801 HOsrBuilder* osr_;
2802
2803 AstTypeBounds bounds_;
2804
2805 friend class FunctionState; // Pushes and pops the state stack.
2806 friend class AstContext; // Pushes and pops the AST context stack.
2807 friend class KeyedLoadFastElementStub;
2808 friend class HOsrBuilder;
2809
2810 DISALLOW_COPY_AND_ASSIGN(HOptimizedGraphBuilder);
2811 };
2812
2813
zone()2814 Zone* AstContext::zone() const { return owner_->zone(); }
2815
2816
2817 class HStatistics final : public Malloced {
2818 public:
HStatistics()2819 HStatistics()
2820 : times_(5),
2821 names_(5),
2822 sizes_(5),
2823 total_size_(0),
2824 source_size_(0) { }
2825
2826 void Initialize(CompilationInfo* info);
2827 void Print();
2828 void SaveTiming(const char* name, base::TimeDelta time, size_t size);
2829
IncrementFullCodeGen(base::TimeDelta full_code_gen)2830 void IncrementFullCodeGen(base::TimeDelta full_code_gen) {
2831 full_code_gen_ += full_code_gen;
2832 }
2833
IncrementCreateGraph(base::TimeDelta delta)2834 void IncrementCreateGraph(base::TimeDelta delta) { create_graph_ += delta; }
2835
IncrementOptimizeGraph(base::TimeDelta delta)2836 void IncrementOptimizeGraph(base::TimeDelta delta) {
2837 optimize_graph_ += delta;
2838 }
2839
IncrementGenerateCode(base::TimeDelta delta)2840 void IncrementGenerateCode(base::TimeDelta delta) { generate_code_ += delta; }
2841
IncrementSubtotals(base::TimeDelta create_graph,base::TimeDelta optimize_graph,base::TimeDelta generate_code)2842 void IncrementSubtotals(base::TimeDelta create_graph,
2843 base::TimeDelta optimize_graph,
2844 base::TimeDelta generate_code) {
2845 IncrementCreateGraph(create_graph);
2846 IncrementOptimizeGraph(optimize_graph);
2847 IncrementGenerateCode(generate_code);
2848 }
2849
2850 private:
2851 List<base::TimeDelta> times_;
2852 List<const char*> names_;
2853 List<size_t> sizes_;
2854 base::TimeDelta create_graph_;
2855 base::TimeDelta optimize_graph_;
2856 base::TimeDelta generate_code_;
2857 size_t total_size_;
2858 base::TimeDelta full_code_gen_;
2859 double source_size_;
2860 };
2861
2862
2863 class HPhase : public CompilationPhase {
2864 public:
HPhase(const char * name,HGraph * graph)2865 HPhase(const char* name, HGraph* graph)
2866 : CompilationPhase(name, graph->info()),
2867 graph_(graph) { }
2868 ~HPhase();
2869
2870 protected:
graph()2871 HGraph* graph() const { return graph_; }
2872
2873 private:
2874 HGraph* graph_;
2875
2876 DISALLOW_COPY_AND_ASSIGN(HPhase);
2877 };
2878
2879
2880 class HTracer final : public Malloced {
2881 public:
HTracer(int isolate_id)2882 explicit HTracer(int isolate_id)
2883 : trace_(&string_allocator_), indent_(0) {
2884 if (FLAG_trace_hydrogen_file == NULL) {
2885 SNPrintF(filename_,
2886 "hydrogen-%d-%d.cfg",
2887 base::OS::GetCurrentProcessId(),
2888 isolate_id);
2889 } else {
2890 StrNCpy(filename_, FLAG_trace_hydrogen_file, filename_.length());
2891 }
2892 WriteChars(filename_.start(), "", 0, false);
2893 }
2894
2895 void TraceCompilation(CompilationInfo* info);
2896 void TraceHydrogen(const char* name, HGraph* graph);
2897 void TraceLithium(const char* name, LChunk* chunk);
2898 void TraceLiveRanges(const char* name, LAllocator* allocator);
2899
2900 private:
2901 class Tag final BASE_EMBEDDED {
2902 public:
Tag(HTracer * tracer,const char * name)2903 Tag(HTracer* tracer, const char* name) {
2904 name_ = name;
2905 tracer_ = tracer;
2906 tracer->PrintIndent();
2907 tracer->trace_.Add("begin_%s\n", name);
2908 tracer->indent_++;
2909 }
2910
~Tag()2911 ~Tag() {
2912 tracer_->indent_--;
2913 tracer_->PrintIndent();
2914 tracer_->trace_.Add("end_%s\n", name_);
2915 DCHECK(tracer_->indent_ >= 0);
2916 tracer_->FlushToFile();
2917 }
2918
2919 private:
2920 HTracer* tracer_;
2921 const char* name_;
2922 };
2923
2924 void TraceLiveRange(LiveRange* range, const char* type, Zone* zone);
2925 void Trace(const char* name, HGraph* graph, LChunk* chunk);
2926 void FlushToFile();
2927
PrintEmptyProperty(const char * name)2928 void PrintEmptyProperty(const char* name) {
2929 PrintIndent();
2930 trace_.Add("%s\n", name);
2931 }
2932
PrintStringProperty(const char * name,const char * value)2933 void PrintStringProperty(const char* name, const char* value) {
2934 PrintIndent();
2935 trace_.Add("%s \"%s\"\n", name, value);
2936 }
2937
PrintLongProperty(const char * name,int64_t value)2938 void PrintLongProperty(const char* name, int64_t value) {
2939 PrintIndent();
2940 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
2941 }
2942
PrintBlockProperty(const char * name,int block_id)2943 void PrintBlockProperty(const char* name, int block_id) {
2944 PrintIndent();
2945 trace_.Add("%s \"B%d\"\n", name, block_id);
2946 }
2947
PrintIntProperty(const char * name,int value)2948 void PrintIntProperty(const char* name, int value) {
2949 PrintIndent();
2950 trace_.Add("%s %d\n", name, value);
2951 }
2952
PrintIndent()2953 void PrintIndent() {
2954 for (int i = 0; i < indent_; i++) {
2955 trace_.Add(" ");
2956 }
2957 }
2958
2959 EmbeddedVector<char, 64> filename_;
2960 HeapStringAllocator string_allocator_;
2961 StringStream trace_;
2962 int indent_;
2963 };
2964
2965
2966 class NoObservableSideEffectsScope final {
2967 public:
NoObservableSideEffectsScope(HGraphBuilder * builder)2968 explicit NoObservableSideEffectsScope(HGraphBuilder* builder) :
2969 builder_(builder) {
2970 builder_->graph()->IncrementInNoSideEffectsScope();
2971 }
~NoObservableSideEffectsScope()2972 ~NoObservableSideEffectsScope() {
2973 builder_->graph()->DecrementInNoSideEffectsScope();
2974 }
2975
2976 private:
2977 HGraphBuilder* builder_;
2978 };
2979
2980 class DoExpressionScope final {
2981 public:
DoExpressionScope(HOptimizedGraphBuilder * builder)2982 explicit DoExpressionScope(HOptimizedGraphBuilder* builder)
2983 : builder_(builder) {
2984 builder_->function_state()->IncrementInDoExpressionScope();
2985 }
~DoExpressionScope()2986 ~DoExpressionScope() {
2987 builder_->function_state()->DecrementInDoExpressionScope();
2988 }
2989
2990 private:
2991 HOptimizedGraphBuilder* builder_;
2992 };
2993
2994 } // namespace internal
2995 } // namespace v8
2996
2997 #endif // V8_CRANKSHAFT_HYDROGEN_H_
2998