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