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