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