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