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