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