1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include "v8.h"
29 #include "hydrogen.h"
30
31 #include "codegen.h"
32 #include "data-flow.h"
33 #include "full-codegen.h"
34 #include "hashmap.h"
35 #include "lithium-allocator.h"
36 #include "parser.h"
37 #include "scopes.h"
38 #include "stub-cache.h"
39
40 #if V8_TARGET_ARCH_IA32
41 #include "ia32/lithium-codegen-ia32.h"
42 #elif V8_TARGET_ARCH_X64
43 #include "x64/lithium-codegen-x64.h"
44 #elif V8_TARGET_ARCH_ARM
45 #include "arm/lithium-codegen-arm.h"
46 #elif V8_TARGET_ARCH_MIPS
47 #include "mips/lithium-codegen-mips.h"
48 #else
49 #error Unsupported target architecture.
50 #endif
51
52 namespace v8 {
53 namespace internal {
54
HBasicBlock(HGraph * graph)55 HBasicBlock::HBasicBlock(HGraph* graph)
56 : block_id_(graph->GetNextBlockID()),
57 graph_(graph),
58 phis_(4),
59 first_(NULL),
60 last_(NULL),
61 end_(NULL),
62 loop_information_(NULL),
63 predecessors_(2),
64 dominator_(NULL),
65 dominated_blocks_(4),
66 last_environment_(NULL),
67 argument_count_(-1),
68 first_instruction_index_(-1),
69 last_instruction_index_(-1),
70 deleted_phis_(4),
71 parent_loop_header_(NULL),
72 is_inline_return_target_(false) {
73 }
74
75
AttachLoopInformation()76 void HBasicBlock::AttachLoopInformation() {
77 ASSERT(!IsLoopHeader());
78 loop_information_ = new(zone()) HLoopInformation(this);
79 }
80
81
DetachLoopInformation()82 void HBasicBlock::DetachLoopInformation() {
83 ASSERT(IsLoopHeader());
84 loop_information_ = NULL;
85 }
86
87
AddPhi(HPhi * phi)88 void HBasicBlock::AddPhi(HPhi* phi) {
89 ASSERT(!IsStartBlock());
90 phis_.Add(phi);
91 phi->SetBlock(this);
92 }
93
94
RemovePhi(HPhi * phi)95 void HBasicBlock::RemovePhi(HPhi* phi) {
96 ASSERT(phi->block() == this);
97 ASSERT(phis_.Contains(phi));
98 ASSERT(phi->HasNoUses() || !phi->is_live());
99 phi->ClearOperands();
100 phis_.RemoveElement(phi);
101 phi->SetBlock(NULL);
102 }
103
104
AddInstruction(HInstruction * instr)105 void HBasicBlock::AddInstruction(HInstruction* instr) {
106 ASSERT(!IsStartBlock() || !IsFinished());
107 ASSERT(!instr->IsLinked());
108 ASSERT(!IsFinished());
109 if (first_ == NULL) {
110 HBlockEntry* entry = new(zone()) HBlockEntry();
111 entry->InitializeAsFirst(this);
112 first_ = last_ = entry;
113 }
114 instr->InsertAfter(last_);
115 last_ = instr;
116 }
117
118
CreateDeoptimize()119 HDeoptimize* HBasicBlock::CreateDeoptimize() {
120 ASSERT(HasEnvironment());
121 HEnvironment* environment = last_environment();
122
123 HDeoptimize* instr = new(zone()) HDeoptimize(environment->length());
124
125 for (int i = 0; i < environment->length(); i++) {
126 HValue* val = environment->values()->at(i);
127 instr->AddEnvironmentValue(val);
128 }
129
130 return instr;
131 }
132
133
CreateSimulate(int id)134 HSimulate* HBasicBlock::CreateSimulate(int id) {
135 ASSERT(HasEnvironment());
136 HEnvironment* environment = last_environment();
137 ASSERT(id == AstNode::kNoNumber ||
138 environment->closure()->shared()->VerifyBailoutId(id));
139
140 int push_count = environment->push_count();
141 int pop_count = environment->pop_count();
142
143 HSimulate* instr = new(zone()) HSimulate(id, pop_count);
144 for (int i = push_count - 1; i >= 0; --i) {
145 instr->AddPushedValue(environment->ExpressionStackAt(i));
146 }
147 for (int i = 0; i < environment->assigned_variables()->length(); ++i) {
148 int index = environment->assigned_variables()->at(i);
149 instr->AddAssignedValue(index, environment->Lookup(index));
150 }
151 environment->ClearHistory();
152 return instr;
153 }
154
155
Finish(HControlInstruction * end)156 void HBasicBlock::Finish(HControlInstruction* end) {
157 ASSERT(!IsFinished());
158 AddInstruction(end);
159 end_ = end;
160 if (end->FirstSuccessor() != NULL) {
161 end->FirstSuccessor()->RegisterPredecessor(this);
162 if (end->SecondSuccessor() != NULL) {
163 end->SecondSuccessor()->RegisterPredecessor(this);
164 }
165 }
166 }
167
168
Goto(HBasicBlock * block,bool include_stack_check)169 void HBasicBlock::Goto(HBasicBlock* block, bool include_stack_check) {
170 if (block->IsInlineReturnTarget()) {
171 AddInstruction(new(zone()) HLeaveInlined);
172 last_environment_ = last_environment()->outer();
173 }
174 AddSimulate(AstNode::kNoNumber);
175 HGoto* instr = new(zone()) HGoto(block);
176 instr->set_include_stack_check(include_stack_check);
177 Finish(instr);
178 }
179
180
AddLeaveInlined(HValue * return_value,HBasicBlock * target)181 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) {
182 ASSERT(target->IsInlineReturnTarget());
183 ASSERT(return_value != NULL);
184 AddInstruction(new(zone()) HLeaveInlined);
185 last_environment_ = last_environment()->outer();
186 last_environment()->Push(return_value);
187 AddSimulate(AstNode::kNoNumber);
188 HGoto* instr = new(zone()) HGoto(target);
189 Finish(instr);
190 }
191
192
SetInitialEnvironment(HEnvironment * env)193 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) {
194 ASSERT(!HasEnvironment());
195 ASSERT(first() == NULL);
196 UpdateEnvironment(env);
197 }
198
199
SetJoinId(int id)200 void HBasicBlock::SetJoinId(int id) {
201 int length = predecessors_.length();
202 ASSERT(length > 0);
203 for (int i = 0; i < length; i++) {
204 HBasicBlock* predecessor = predecessors_[i];
205 ASSERT(predecessor->end()->IsGoto());
206 HSimulate* simulate = HSimulate::cast(predecessor->end()->previous());
207 // We only need to verify the ID once.
208 ASSERT(i != 0 ||
209 predecessor->last_environment()->closure()->shared()
210 ->VerifyBailoutId(id));
211 simulate->set_ast_id(id);
212 }
213 }
214
215
Dominates(HBasicBlock * other) const216 bool HBasicBlock::Dominates(HBasicBlock* other) const {
217 HBasicBlock* current = other->dominator();
218 while (current != NULL) {
219 if (current == this) return true;
220 current = current->dominator();
221 }
222 return false;
223 }
224
225
PostProcessLoopHeader(IterationStatement * stmt)226 void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) {
227 ASSERT(IsLoopHeader());
228
229 SetJoinId(stmt->EntryId());
230 if (predecessors()->length() == 1) {
231 // This is a degenerated loop.
232 DetachLoopInformation();
233 return;
234 }
235
236 // Only the first entry into the loop is from outside the loop. All other
237 // entries must be back edges.
238 for (int i = 1; i < predecessors()->length(); ++i) {
239 loop_information()->RegisterBackEdge(predecessors()->at(i));
240 }
241 }
242
243
RegisterPredecessor(HBasicBlock * pred)244 void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) {
245 if (!predecessors_.is_empty()) {
246 // Only loop header blocks can have a predecessor added after
247 // instructions have been added to the block (they have phis for all
248 // values in the environment, these phis may be eliminated later).
249 ASSERT(IsLoopHeader() || first_ == NULL);
250 HEnvironment* incoming_env = pred->last_environment();
251 if (IsLoopHeader()) {
252 ASSERT(phis()->length() == incoming_env->length());
253 for (int i = 0; i < phis_.length(); ++i) {
254 phis_[i]->AddInput(incoming_env->values()->at(i));
255 }
256 } else {
257 last_environment()->AddIncomingEdge(this, pred->last_environment());
258 }
259 } else if (!HasEnvironment() && !IsFinished()) {
260 ASSERT(!IsLoopHeader());
261 SetInitialEnvironment(pred->last_environment()->Copy());
262 }
263
264 predecessors_.Add(pred);
265 }
266
267
AddDominatedBlock(HBasicBlock * block)268 void HBasicBlock::AddDominatedBlock(HBasicBlock* block) {
269 ASSERT(!dominated_blocks_.Contains(block));
270 // Keep the list of dominated blocks sorted such that if there is two
271 // succeeding block in this list, the predecessor is before the successor.
272 int index = 0;
273 while (index < dominated_blocks_.length() &&
274 dominated_blocks_[index]->block_id() < block->block_id()) {
275 ++index;
276 }
277 dominated_blocks_.InsertAt(index, block);
278 }
279
280
AssignCommonDominator(HBasicBlock * other)281 void HBasicBlock::AssignCommonDominator(HBasicBlock* other) {
282 if (dominator_ == NULL) {
283 dominator_ = other;
284 other->AddDominatedBlock(this);
285 } else if (other->dominator() != NULL) {
286 HBasicBlock* first = dominator_;
287 HBasicBlock* second = other;
288
289 while (first != second) {
290 if (first->block_id() > second->block_id()) {
291 first = first->dominator();
292 } else {
293 second = second->dominator();
294 }
295 ASSERT(first != NULL && second != NULL);
296 }
297
298 if (dominator_ != first) {
299 ASSERT(dominator_->dominated_blocks_.Contains(this));
300 dominator_->dominated_blocks_.RemoveElement(this);
301 dominator_ = first;
302 first->AddDominatedBlock(this);
303 }
304 }
305 }
306
307
PredecessorIndexOf(HBasicBlock * predecessor) const308 int HBasicBlock::PredecessorIndexOf(HBasicBlock* predecessor) const {
309 for (int i = 0; i < predecessors_.length(); ++i) {
310 if (predecessors_[i] == predecessor) return i;
311 }
312 UNREACHABLE();
313 return -1;
314 }
315
316
317 #ifdef DEBUG
Verify()318 void HBasicBlock::Verify() {
319 // Check that every block is finished.
320 ASSERT(IsFinished());
321 ASSERT(block_id() >= 0);
322
323 // Check that the incoming edges are in edge split form.
324 if (predecessors_.length() > 1) {
325 for (int i = 0; i < predecessors_.length(); ++i) {
326 ASSERT(predecessors_[i]->end()->SecondSuccessor() == NULL);
327 }
328 }
329 }
330 #endif
331
332
RegisterBackEdge(HBasicBlock * block)333 void HLoopInformation::RegisterBackEdge(HBasicBlock* block) {
334 this->back_edges_.Add(block);
335 AddBlock(block);
336 }
337
338
GetLastBackEdge() const339 HBasicBlock* HLoopInformation::GetLastBackEdge() const {
340 int max_id = -1;
341 HBasicBlock* result = NULL;
342 for (int i = 0; i < back_edges_.length(); ++i) {
343 HBasicBlock* cur = back_edges_[i];
344 if (cur->block_id() > max_id) {
345 max_id = cur->block_id();
346 result = cur;
347 }
348 }
349 return result;
350 }
351
352
AddBlock(HBasicBlock * block)353 void HLoopInformation::AddBlock(HBasicBlock* block) {
354 if (block == loop_header()) return;
355 if (block->parent_loop_header() == loop_header()) return;
356 if (block->parent_loop_header() != NULL) {
357 AddBlock(block->parent_loop_header());
358 } else {
359 block->set_parent_loop_header(loop_header());
360 blocks_.Add(block);
361 for (int i = 0; i < block->predecessors()->length(); ++i) {
362 AddBlock(block->predecessors()->at(i));
363 }
364 }
365 }
366
367
368 #ifdef DEBUG
369
370 // Checks reachability of the blocks in this graph and stores a bit in
371 // the BitVector "reachable()" for every block that can be reached
372 // from the start block of the graph. If "dont_visit" is non-null, the given
373 // block is treated as if it would not be part of the graph. "visited_count()"
374 // returns the number of reachable blocks.
375 class ReachabilityAnalyzer BASE_EMBEDDED {
376 public:
ReachabilityAnalyzer(HBasicBlock * entry_block,int block_count,HBasicBlock * dont_visit)377 ReachabilityAnalyzer(HBasicBlock* entry_block,
378 int block_count,
379 HBasicBlock* dont_visit)
380 : visited_count_(0),
381 stack_(16),
382 reachable_(block_count),
383 dont_visit_(dont_visit) {
384 PushBlock(entry_block);
385 Analyze();
386 }
387
visited_count() const388 int visited_count() const { return visited_count_; }
reachable() const389 const BitVector* reachable() const { return &reachable_; }
390
391 private:
PushBlock(HBasicBlock * block)392 void PushBlock(HBasicBlock* block) {
393 if (block != NULL && block != dont_visit_ &&
394 !reachable_.Contains(block->block_id())) {
395 reachable_.Add(block->block_id());
396 stack_.Add(block);
397 visited_count_++;
398 }
399 }
400
Analyze()401 void Analyze() {
402 while (!stack_.is_empty()) {
403 HControlInstruction* end = stack_.RemoveLast()->end();
404 PushBlock(end->FirstSuccessor());
405 PushBlock(end->SecondSuccessor());
406 }
407 }
408
409 int visited_count_;
410 ZoneList<HBasicBlock*> stack_;
411 BitVector reachable_;
412 HBasicBlock* dont_visit_;
413 };
414
415
Verify() const416 void HGraph::Verify() const {
417 for (int i = 0; i < blocks_.length(); i++) {
418 HBasicBlock* block = blocks_.at(i);
419
420 block->Verify();
421
422 // Check that every block contains at least one node and that only the last
423 // node is a control instruction.
424 HInstruction* current = block->first();
425 ASSERT(current != NULL && current->IsBlockEntry());
426 while (current != NULL) {
427 ASSERT((current->next() == NULL) == current->IsControlInstruction());
428 ASSERT(current->block() == block);
429 current->Verify();
430 current = current->next();
431 }
432
433 // Check that successors are correctly set.
434 HBasicBlock* first = block->end()->FirstSuccessor();
435 HBasicBlock* second = block->end()->SecondSuccessor();
436 ASSERT(second == NULL || first != NULL);
437
438 // Check that the predecessor array is correct.
439 if (first != NULL) {
440 ASSERT(first->predecessors()->Contains(block));
441 if (second != NULL) {
442 ASSERT(second->predecessors()->Contains(block));
443 }
444 }
445
446 // Check that phis have correct arguments.
447 for (int j = 0; j < block->phis()->length(); j++) {
448 HPhi* phi = block->phis()->at(j);
449 phi->Verify();
450 }
451
452 // Check that all join blocks have predecessors that end with an
453 // unconditional goto and agree on their environment node id.
454 if (block->predecessors()->length() >= 2) {
455 int id = block->predecessors()->first()->last_environment()->ast_id();
456 for (int k = 0; k < block->predecessors()->length(); k++) {
457 HBasicBlock* predecessor = block->predecessors()->at(k);
458 ASSERT(predecessor->end()->IsGoto());
459 ASSERT(predecessor->last_environment()->ast_id() == id);
460 }
461 }
462 }
463
464 // Check special property of first block to have no predecessors.
465 ASSERT(blocks_.at(0)->predecessors()->is_empty());
466
467 // Check that the graph is fully connected.
468 ReachabilityAnalyzer analyzer(entry_block_, blocks_.length(), NULL);
469 ASSERT(analyzer.visited_count() == blocks_.length());
470
471 // Check that entry block dominator is NULL.
472 ASSERT(entry_block_->dominator() == NULL);
473
474 // Check dominators.
475 for (int i = 0; i < blocks_.length(); ++i) {
476 HBasicBlock* block = blocks_.at(i);
477 if (block->dominator() == NULL) {
478 // Only start block may have no dominator assigned to.
479 ASSERT(i == 0);
480 } else {
481 // Assert that block is unreachable if dominator must not be visited.
482 ReachabilityAnalyzer dominator_analyzer(entry_block_,
483 blocks_.length(),
484 block->dominator());
485 ASSERT(!dominator_analyzer.reachable()->Contains(block->block_id()));
486 }
487 }
488 }
489
490 #endif
491
492
GetConstant(SetOncePointer<HConstant> * pointer,Object * value)493 HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer,
494 Object* value) {
495 if (!pointer->is_set()) {
496 HConstant* constant = new(zone()) HConstant(Handle<Object>(value),
497 Representation::Tagged());
498 constant->InsertAfter(GetConstantUndefined());
499 pointer->set(constant);
500 }
501 return pointer->get();
502 }
503
504
GetConstant1()505 HConstant* HGraph::GetConstant1() {
506 return GetConstant(&constant_1_, Smi::FromInt(1));
507 }
508
509
GetConstantMinus1()510 HConstant* HGraph::GetConstantMinus1() {
511 return GetConstant(&constant_minus1_, Smi::FromInt(-1));
512 }
513
514
GetConstantTrue()515 HConstant* HGraph::GetConstantTrue() {
516 return GetConstant(&constant_true_, isolate()->heap()->true_value());
517 }
518
519
GetConstantFalse()520 HConstant* HGraph::GetConstantFalse() {
521 return GetConstant(&constant_false_, isolate()->heap()->false_value());
522 }
523
524
CreateJoin(HBasicBlock * first,HBasicBlock * second,int join_id)525 HBasicBlock* HGraphBuilder::CreateJoin(HBasicBlock* first,
526 HBasicBlock* second,
527 int join_id) {
528 if (first == NULL) {
529 return second;
530 } else if (second == NULL) {
531 return first;
532 } else {
533 HBasicBlock* join_block = graph_->CreateBasicBlock();
534 first->Goto(join_block);
535 second->Goto(join_block);
536 join_block->SetJoinId(join_id);
537 return join_block;
538 }
539 }
540
541
JoinContinue(IterationStatement * statement,HBasicBlock * exit_block,HBasicBlock * continue_block)542 HBasicBlock* HGraphBuilder::JoinContinue(IterationStatement* statement,
543 HBasicBlock* exit_block,
544 HBasicBlock* continue_block) {
545 if (continue_block != NULL) {
546 if (exit_block != NULL) exit_block->Goto(continue_block);
547 continue_block->SetJoinId(statement->ContinueId());
548 return continue_block;
549 }
550 return exit_block;
551 }
552
553
CreateLoop(IterationStatement * statement,HBasicBlock * loop_entry,HBasicBlock * body_exit,HBasicBlock * loop_successor,HBasicBlock * break_block)554 HBasicBlock* HGraphBuilder::CreateLoop(IterationStatement* statement,
555 HBasicBlock* loop_entry,
556 HBasicBlock* body_exit,
557 HBasicBlock* loop_successor,
558 HBasicBlock* break_block) {
559 if (body_exit != NULL) body_exit->Goto(loop_entry, true);
560 loop_entry->PostProcessLoopHeader(statement);
561 if (break_block != NULL) {
562 if (loop_successor != NULL) loop_successor->Goto(break_block);
563 break_block->SetJoinId(statement->ExitId());
564 return break_block;
565 }
566 return loop_successor;
567 }
568
569
FinishExit(HControlInstruction * instruction)570 void HBasicBlock::FinishExit(HControlInstruction* instruction) {
571 Finish(instruction);
572 ClearEnvironment();
573 }
574
575
HGraph(CompilationInfo * info)576 HGraph::HGraph(CompilationInfo* info)
577 : isolate_(info->isolate()),
578 next_block_id_(0),
579 entry_block_(NULL),
580 blocks_(8),
581 values_(16),
582 phi_list_(NULL) {
583 start_environment_ =
584 new(zone()) HEnvironment(NULL, info->scope(), info->closure());
585 start_environment_->set_ast_id(AstNode::kFunctionEntryId);
586 entry_block_ = CreateBasicBlock();
587 entry_block_->SetInitialEnvironment(start_environment_);
588 }
589
590
Compile(CompilationInfo * info)591 Handle<Code> HGraph::Compile(CompilationInfo* info) {
592 int values = GetMaximumValueID();
593 if (values > LAllocator::max_initial_value_ids()) {
594 if (FLAG_trace_bailout) PrintF("Function is too big\n");
595 return Handle<Code>::null();
596 }
597
598 LAllocator allocator(values, this);
599 LChunkBuilder builder(info, this, &allocator);
600 LChunk* chunk = builder.Build();
601 if (chunk == NULL) return Handle<Code>::null();
602
603 if (!FLAG_alloc_lithium) return Handle<Code>::null();
604
605 allocator.Allocate(chunk);
606
607 if (!FLAG_use_lithium) return Handle<Code>::null();
608
609 MacroAssembler assembler(info->isolate(), NULL, 0);
610 LCodeGen generator(chunk, &assembler, info);
611
612 if (FLAG_eliminate_empty_blocks) {
613 chunk->MarkEmptyBlocks();
614 }
615
616 if (generator.GenerateCode()) {
617 if (FLAG_trace_codegen) {
618 PrintF("Crankshaft Compiler - ");
619 }
620 CodeGenerator::MakeCodePrologue(info);
621 Code::Flags flags =
622 Code::ComputeFlags(Code::OPTIMIZED_FUNCTION, NOT_IN_LOOP);
623 Handle<Code> code =
624 CodeGenerator::MakeCodeEpilogue(&assembler, flags, info);
625 generator.FinishCode(code);
626 CodeGenerator::PrintCode(code, info);
627 return code;
628 }
629 return Handle<Code>::null();
630 }
631
632
CreateBasicBlock()633 HBasicBlock* HGraph::CreateBasicBlock() {
634 HBasicBlock* result = new(zone()) HBasicBlock(this);
635 blocks_.Add(result);
636 return result;
637 }
638
639
Canonicalize()640 void HGraph::Canonicalize() {
641 if (!FLAG_use_canonicalizing) return;
642 HPhase phase("Canonicalize", this);
643 for (int i = 0; i < blocks()->length(); ++i) {
644 HInstruction* instr = blocks()->at(i)->first();
645 while (instr != NULL) {
646 HValue* value = instr->Canonicalize();
647 if (value != instr) instr->ReplaceAndDelete(value);
648 instr = instr->next();
649 }
650 }
651 }
652
653
OrderBlocks()654 void HGraph::OrderBlocks() {
655 HPhase phase("Block ordering");
656 BitVector visited(blocks_.length());
657
658 ZoneList<HBasicBlock*> reverse_result(8);
659 HBasicBlock* start = blocks_[0];
660 Postorder(start, &visited, &reverse_result, NULL);
661
662 blocks_.Rewind(0);
663 int index = 0;
664 for (int i = reverse_result.length() - 1; i >= 0; --i) {
665 HBasicBlock* b = reverse_result[i];
666 blocks_.Add(b);
667 b->set_block_id(index++);
668 }
669 }
670
671
PostorderLoopBlocks(HLoopInformation * loop,BitVector * visited,ZoneList<HBasicBlock * > * order,HBasicBlock * loop_header)672 void HGraph::PostorderLoopBlocks(HLoopInformation* loop,
673 BitVector* visited,
674 ZoneList<HBasicBlock*>* order,
675 HBasicBlock* loop_header) {
676 for (int i = 0; i < loop->blocks()->length(); ++i) {
677 HBasicBlock* b = loop->blocks()->at(i);
678 Postorder(b->end()->SecondSuccessor(), visited, order, loop_header);
679 Postorder(b->end()->FirstSuccessor(), visited, order, loop_header);
680 if (b->IsLoopHeader() && b != loop->loop_header()) {
681 PostorderLoopBlocks(b->loop_information(), visited, order, loop_header);
682 }
683 }
684 }
685
686
Postorder(HBasicBlock * block,BitVector * visited,ZoneList<HBasicBlock * > * order,HBasicBlock * loop_header)687 void HGraph::Postorder(HBasicBlock* block,
688 BitVector* visited,
689 ZoneList<HBasicBlock*>* order,
690 HBasicBlock* loop_header) {
691 if (block == NULL || visited->Contains(block->block_id())) return;
692 if (block->parent_loop_header() != loop_header) return;
693 visited->Add(block->block_id());
694 if (block->IsLoopHeader()) {
695 PostorderLoopBlocks(block->loop_information(), visited, order, loop_header);
696 Postorder(block->end()->SecondSuccessor(), visited, order, block);
697 Postorder(block->end()->FirstSuccessor(), visited, order, block);
698 } else {
699 Postorder(block->end()->SecondSuccessor(), visited, order, loop_header);
700 Postorder(block->end()->FirstSuccessor(), visited, order, loop_header);
701 }
702 ASSERT(block->end()->FirstSuccessor() == NULL ||
703 order->Contains(block->end()->FirstSuccessor()) ||
704 block->end()->FirstSuccessor()->IsLoopHeader());
705 ASSERT(block->end()->SecondSuccessor() == NULL ||
706 order->Contains(block->end()->SecondSuccessor()) ||
707 block->end()->SecondSuccessor()->IsLoopHeader());
708 order->Add(block);
709 }
710
711
AssignDominators()712 void HGraph::AssignDominators() {
713 HPhase phase("Assign dominators", this);
714 for (int i = 0; i < blocks_.length(); ++i) {
715 if (blocks_[i]->IsLoopHeader()) {
716 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->first());
717 } else {
718 for (int j = 0; j < blocks_[i]->predecessors()->length(); ++j) {
719 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j));
720 }
721 }
722 }
723 }
724
725
EliminateRedundantPhis()726 void HGraph::EliminateRedundantPhis() {
727 HPhase phase("Redundant phi elimination", this);
728
729 // Worklist of phis that can potentially be eliminated. Initialized
730 // with all phi nodes. When elimination of a phi node modifies
731 // another phi node the modified phi node is added to the worklist.
732 ZoneList<HPhi*> worklist(blocks_.length());
733 for (int i = 0; i < blocks_.length(); ++i) {
734 worklist.AddAll(*blocks_[i]->phis());
735 }
736
737 while (!worklist.is_empty()) {
738 HPhi* phi = worklist.RemoveLast();
739 HBasicBlock* block = phi->block();
740
741 // Skip phi node if it was already replaced.
742 if (block == NULL) continue;
743
744 // Get replacement value if phi is redundant.
745 HValue* value = phi->GetRedundantReplacement();
746
747 if (value != NULL) {
748 // Iterate through uses finding the ones that should be
749 // replaced.
750 SmallPointerList<HValue>* uses = phi->uses();
751 while (!uses->is_empty()) {
752 HValue* use = uses->RemoveLast();
753 if (use != NULL) {
754 phi->ReplaceAtUse(use, value);
755 if (use->IsPhi()) worklist.Add(HPhi::cast(use));
756 }
757 }
758 block->RemovePhi(phi);
759 }
760 }
761 }
762
763
EliminateUnreachablePhis()764 void HGraph::EliminateUnreachablePhis() {
765 HPhase phase("Unreachable phi elimination", this);
766
767 // Initialize worklist.
768 ZoneList<HPhi*> phi_list(blocks_.length());
769 ZoneList<HPhi*> worklist(blocks_.length());
770 for (int i = 0; i < blocks_.length(); ++i) {
771 for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
772 HPhi* phi = blocks_[i]->phis()->at(j);
773 phi_list.Add(phi);
774 // We can't eliminate phis in the receiver position in the environment
775 // because in case of throwing an error we need this value to
776 // construct a stack trace.
777 if (phi->HasRealUses() || phi->IsReceiver()) {
778 phi->set_is_live(true);
779 worklist.Add(phi);
780 }
781 }
782 }
783
784 // Iteratively mark live phis.
785 while (!worklist.is_empty()) {
786 HPhi* phi = worklist.RemoveLast();
787 for (int i = 0; i < phi->OperandCount(); i++) {
788 HValue* operand = phi->OperandAt(i);
789 if (operand->IsPhi() && !HPhi::cast(operand)->is_live()) {
790 HPhi::cast(operand)->set_is_live(true);
791 worklist.Add(HPhi::cast(operand));
792 }
793 }
794 }
795
796 // Remove unreachable phis.
797 for (int i = 0; i < phi_list.length(); i++) {
798 HPhi* phi = phi_list[i];
799 if (!phi->is_live()) {
800 HBasicBlock* block = phi->block();
801 block->RemovePhi(phi);
802 block->RecordDeletedPhi(phi->merged_index());
803 }
804 }
805 }
806
807
CollectPhis()808 bool HGraph::CollectPhis() {
809 int block_count = blocks_.length();
810 phi_list_ = new ZoneList<HPhi*>(block_count);
811 for (int i = 0; i < block_count; ++i) {
812 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
813 HPhi* phi = blocks_[i]->phis()->at(j);
814 phi_list_->Add(phi);
815 // We don't support phi uses of arguments for now.
816 if (phi->CheckFlag(HValue::kIsArguments)) return false;
817 }
818 }
819 return true;
820 }
821
822
InferTypes(ZoneList<HValue * > * worklist)823 void HGraph::InferTypes(ZoneList<HValue*>* worklist) {
824 BitVector in_worklist(GetMaximumValueID());
825 for (int i = 0; i < worklist->length(); ++i) {
826 ASSERT(!in_worklist.Contains(worklist->at(i)->id()));
827 in_worklist.Add(worklist->at(i)->id());
828 }
829
830 while (!worklist->is_empty()) {
831 HValue* current = worklist->RemoveLast();
832 in_worklist.Remove(current->id());
833 if (current->UpdateInferredType()) {
834 for (int j = 0; j < current->uses()->length(); j++) {
835 HValue* use = current->uses()->at(j);
836 if (!in_worklist.Contains(use->id())) {
837 in_worklist.Add(use->id());
838 worklist->Add(use);
839 }
840 }
841 }
842 }
843 }
844
845
846 class HRangeAnalysis BASE_EMBEDDED {
847 public:
HRangeAnalysis(HGraph * graph)848 explicit HRangeAnalysis(HGraph* graph) : graph_(graph), changed_ranges_(16) {}
849
850 void Analyze();
851
852 private:
853 void TraceRange(const char* msg, ...);
854 void Analyze(HBasicBlock* block);
855 void InferControlFlowRange(HTest* test, HBasicBlock* dest);
856 void InferControlFlowRange(Token::Value op, HValue* value, HValue* other);
857 void InferPhiRange(HPhi* phi);
858 void InferRange(HValue* value);
859 void RollBackTo(int index);
860 void AddRange(HValue* value, Range* range);
861
862 HGraph* graph_;
863 ZoneList<HValue*> changed_ranges_;
864 };
865
866
TraceRange(const char * msg,...)867 void HRangeAnalysis::TraceRange(const char* msg, ...) {
868 if (FLAG_trace_range) {
869 va_list arguments;
870 va_start(arguments, msg);
871 OS::VPrint(msg, arguments);
872 va_end(arguments);
873 }
874 }
875
876
Analyze()877 void HRangeAnalysis::Analyze() {
878 HPhase phase("Range analysis", graph_);
879 Analyze(graph_->blocks()->at(0));
880 }
881
882
Analyze(HBasicBlock * block)883 void HRangeAnalysis::Analyze(HBasicBlock* block) {
884 TraceRange("Analyzing block B%d\n", block->block_id());
885
886 int last_changed_range = changed_ranges_.length() - 1;
887
888 // Infer range based on control flow.
889 if (block->predecessors()->length() == 1) {
890 HBasicBlock* pred = block->predecessors()->first();
891 if (pred->end()->IsTest()) {
892 InferControlFlowRange(HTest::cast(pred->end()), block);
893 }
894 }
895
896 // Process phi instructions.
897 for (int i = 0; i < block->phis()->length(); ++i) {
898 HPhi* phi = block->phis()->at(i);
899 InferPhiRange(phi);
900 }
901
902 // Go through all instructions of the current block.
903 HInstruction* instr = block->first();
904 while (instr != block->end()) {
905 InferRange(instr);
906 instr = instr->next();
907 }
908
909 // Continue analysis in all dominated blocks.
910 for (int i = 0; i < block->dominated_blocks()->length(); ++i) {
911 Analyze(block->dominated_blocks()->at(i));
912 }
913
914 RollBackTo(last_changed_range);
915 }
916
917
InferControlFlowRange(HTest * test,HBasicBlock * dest)918 void HRangeAnalysis::InferControlFlowRange(HTest* test, HBasicBlock* dest) {
919 ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest));
920 if (test->value()->IsCompare()) {
921 HCompare* compare = HCompare::cast(test->value());
922 if (compare->GetInputRepresentation().IsInteger32()) {
923 Token::Value op = compare->token();
924 if (test->SecondSuccessor() == dest) {
925 op = Token::NegateCompareOp(op);
926 }
927 Token::Value inverted_op = Token::InvertCompareOp(op);
928 InferControlFlowRange(op, compare->left(), compare->right());
929 InferControlFlowRange(inverted_op, compare->right(), compare->left());
930 }
931 }
932 }
933
934
935 // We know that value [op] other. Use this information to update the range on
936 // value.
InferControlFlowRange(Token::Value op,HValue * value,HValue * other)937 void HRangeAnalysis::InferControlFlowRange(Token::Value op,
938 HValue* value,
939 HValue* other) {
940 Range temp_range;
941 Range* range = other->range() != NULL ? other->range() : &temp_range;
942 Range* new_range = NULL;
943
944 TraceRange("Control flow range infer %d %s %d\n",
945 value->id(),
946 Token::Name(op),
947 other->id());
948
949 if (op == Token::EQ || op == Token::EQ_STRICT) {
950 // The same range has to apply for value.
951 new_range = range->Copy();
952 } else if (op == Token::LT || op == Token::LTE) {
953 new_range = range->CopyClearLower();
954 if (op == Token::LT) {
955 new_range->AddConstant(-1);
956 }
957 } else if (op == Token::GT || op == Token::GTE) {
958 new_range = range->CopyClearUpper();
959 if (op == Token::GT) {
960 new_range->AddConstant(1);
961 }
962 }
963
964 if (new_range != NULL && !new_range->IsMostGeneric()) {
965 AddRange(value, new_range);
966 }
967 }
968
969
InferPhiRange(HPhi * phi)970 void HRangeAnalysis::InferPhiRange(HPhi* phi) {
971 // TODO(twuerthinger): Infer loop phi ranges.
972 InferRange(phi);
973 }
974
975
InferRange(HValue * value)976 void HRangeAnalysis::InferRange(HValue* value) {
977 ASSERT(!value->HasRange());
978 if (!value->representation().IsNone()) {
979 value->ComputeInitialRange();
980 Range* range = value->range();
981 TraceRange("Initial inferred range of %d (%s) set to [%d,%d]\n",
982 value->id(),
983 value->Mnemonic(),
984 range->lower(),
985 range->upper());
986 }
987 }
988
989
RollBackTo(int index)990 void HRangeAnalysis::RollBackTo(int index) {
991 for (int i = index + 1; i < changed_ranges_.length(); ++i) {
992 changed_ranges_[i]->RemoveLastAddedRange();
993 }
994 changed_ranges_.Rewind(index + 1);
995 }
996
997
AddRange(HValue * value,Range * range)998 void HRangeAnalysis::AddRange(HValue* value, Range* range) {
999 Range* original_range = value->range();
1000 value->AddNewRange(range);
1001 changed_ranges_.Add(value);
1002 Range* new_range = value->range();
1003 TraceRange("Updated range of %d set to [%d,%d]\n",
1004 value->id(),
1005 new_range->lower(),
1006 new_range->upper());
1007 if (original_range != NULL) {
1008 TraceRange("Original range was [%d,%d]\n",
1009 original_range->lower(),
1010 original_range->upper());
1011 }
1012 TraceRange("New information was [%d,%d]\n",
1013 range->lower(),
1014 range->upper());
1015 }
1016
1017
TraceGVN(const char * msg,...)1018 void TraceGVN(const char* msg, ...) {
1019 if (FLAG_trace_gvn) {
1020 va_list arguments;
1021 va_start(arguments, msg);
1022 OS::VPrint(msg, arguments);
1023 va_end(arguments);
1024 }
1025 }
1026
1027
HValueMap(const HValueMap * other)1028 HValueMap::HValueMap(const HValueMap* other)
1029 : array_size_(other->array_size_),
1030 lists_size_(other->lists_size_),
1031 count_(other->count_),
1032 present_flags_(other->present_flags_),
1033 array_(ZONE->NewArray<HValueMapListElement>(other->array_size_)),
1034 lists_(ZONE->NewArray<HValueMapListElement>(other->lists_size_)),
1035 free_list_head_(other->free_list_head_) {
1036 memcpy(array_, other->array_, array_size_ * sizeof(HValueMapListElement));
1037 memcpy(lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement));
1038 }
1039
1040
Kill(int flags)1041 void HValueMap::Kill(int flags) {
1042 int depends_flags = HValue::ConvertChangesToDependsFlags(flags);
1043 if ((present_flags_ & depends_flags) == 0) return;
1044 present_flags_ = 0;
1045 for (int i = 0; i < array_size_; ++i) {
1046 HValue* value = array_[i].value;
1047 if (value != NULL) {
1048 // Clear list of collisions first, so we know if it becomes empty.
1049 int kept = kNil; // List of kept elements.
1050 int next;
1051 for (int current = array_[i].next; current != kNil; current = next) {
1052 next = lists_[current].next;
1053 if ((lists_[current].value->flags() & depends_flags) != 0) {
1054 // Drop it.
1055 count_--;
1056 lists_[current].next = free_list_head_;
1057 free_list_head_ = current;
1058 } else {
1059 // Keep it.
1060 lists_[current].next = kept;
1061 kept = current;
1062 present_flags_ |= lists_[current].value->flags();
1063 }
1064 }
1065 array_[i].next = kept;
1066
1067 // Now possibly drop directly indexed element.
1068 if ((array_[i].value->flags() & depends_flags) != 0) { // Drop it.
1069 count_--;
1070 int head = array_[i].next;
1071 if (head == kNil) {
1072 array_[i].value = NULL;
1073 } else {
1074 array_[i].value = lists_[head].value;
1075 array_[i].next = lists_[head].next;
1076 lists_[head].next = free_list_head_;
1077 free_list_head_ = head;
1078 }
1079 } else {
1080 present_flags_ |= array_[i].value->flags(); // Keep it.
1081 }
1082 }
1083 }
1084 }
1085
1086
Lookup(HValue * value) const1087 HValue* HValueMap::Lookup(HValue* value) const {
1088 uint32_t hash = static_cast<uint32_t>(value->Hashcode());
1089 uint32_t pos = Bound(hash);
1090 if (array_[pos].value != NULL) {
1091 if (array_[pos].value->Equals(value)) return array_[pos].value;
1092 int next = array_[pos].next;
1093 while (next != kNil) {
1094 if (lists_[next].value->Equals(value)) return lists_[next].value;
1095 next = lists_[next].next;
1096 }
1097 }
1098 return NULL;
1099 }
1100
1101
Resize(int new_size)1102 void HValueMap::Resize(int new_size) {
1103 ASSERT(new_size > count_);
1104 // Hashing the values into the new array has no more collisions than in the
1105 // old hash map, so we can use the existing lists_ array, if we are careful.
1106
1107 // Make sure we have at least one free element.
1108 if (free_list_head_ == kNil) {
1109 ResizeLists(lists_size_ << 1);
1110 }
1111
1112 HValueMapListElement* new_array =
1113 ZONE->NewArray<HValueMapListElement>(new_size);
1114 memset(new_array, 0, sizeof(HValueMapListElement) * new_size);
1115
1116 HValueMapListElement* old_array = array_;
1117 int old_size = array_size_;
1118
1119 int old_count = count_;
1120 count_ = 0;
1121 // Do not modify present_flags_. It is currently correct.
1122 array_size_ = new_size;
1123 array_ = new_array;
1124
1125 if (old_array != NULL) {
1126 // Iterate over all the elements in lists, rehashing them.
1127 for (int i = 0; i < old_size; ++i) {
1128 if (old_array[i].value != NULL) {
1129 int current = old_array[i].next;
1130 while (current != kNil) {
1131 Insert(lists_[current].value);
1132 int next = lists_[current].next;
1133 lists_[current].next = free_list_head_;
1134 free_list_head_ = current;
1135 current = next;
1136 }
1137 // Rehash the directly stored value.
1138 Insert(old_array[i].value);
1139 }
1140 }
1141 }
1142 USE(old_count);
1143 ASSERT(count_ == old_count);
1144 }
1145
1146
ResizeLists(int new_size)1147 void HValueMap::ResizeLists(int new_size) {
1148 ASSERT(new_size > lists_size_);
1149
1150 HValueMapListElement* new_lists =
1151 ZONE->NewArray<HValueMapListElement>(new_size);
1152 memset(new_lists, 0, sizeof(HValueMapListElement) * new_size);
1153
1154 HValueMapListElement* old_lists = lists_;
1155 int old_size = lists_size_;
1156
1157 lists_size_ = new_size;
1158 lists_ = new_lists;
1159
1160 if (old_lists != NULL) {
1161 memcpy(lists_, old_lists, old_size * sizeof(HValueMapListElement));
1162 }
1163 for (int i = old_size; i < lists_size_; ++i) {
1164 lists_[i].next = free_list_head_;
1165 free_list_head_ = i;
1166 }
1167 }
1168
1169
Insert(HValue * value)1170 void HValueMap::Insert(HValue* value) {
1171 ASSERT(value != NULL);
1172 // Resizing when half of the hashtable is filled up.
1173 if (count_ >= array_size_ >> 1) Resize(array_size_ << 1);
1174 ASSERT(count_ < array_size_);
1175 count_++;
1176 uint32_t pos = Bound(static_cast<uint32_t>(value->Hashcode()));
1177 if (array_[pos].value == NULL) {
1178 array_[pos].value = value;
1179 array_[pos].next = kNil;
1180 } else {
1181 if (free_list_head_ == kNil) {
1182 ResizeLists(lists_size_ << 1);
1183 }
1184 int new_element_pos = free_list_head_;
1185 ASSERT(new_element_pos != kNil);
1186 free_list_head_ = lists_[free_list_head_].next;
1187 lists_[new_element_pos].value = value;
1188 lists_[new_element_pos].next = array_[pos].next;
1189 ASSERT(array_[pos].next == kNil || lists_[array_[pos].next].value != NULL);
1190 array_[pos].next = new_element_pos;
1191 }
1192 }
1193
1194
1195 class HStackCheckEliminator BASE_EMBEDDED {
1196 public:
HStackCheckEliminator(HGraph * graph)1197 explicit HStackCheckEliminator(HGraph* graph) : graph_(graph) { }
1198
1199 void Process();
1200
1201 private:
1202 void RemoveStackCheck(HBasicBlock* block);
1203
1204 HGraph* graph_;
1205 };
1206
1207
Process()1208 void HStackCheckEliminator::Process() {
1209 // For each loop block walk the dominator tree from the backwards branch to
1210 // the loop header. If a call instruction is encountered the backwards branch
1211 // is dominated by a call and the stack check in the backwards branch can be
1212 // removed.
1213 for (int i = 0; i < graph_->blocks()->length(); i++) {
1214 HBasicBlock* block = graph_->blocks()->at(i);
1215 if (block->IsLoopHeader()) {
1216 HBasicBlock* back_edge = block->loop_information()->GetLastBackEdge();
1217 HBasicBlock* dominator = back_edge;
1218 bool back_edge_dominated_by_call = false;
1219 while (dominator != block && !back_edge_dominated_by_call) {
1220 HInstruction* instr = dominator->first();
1221 while (instr != NULL && !back_edge_dominated_by_call) {
1222 if (instr->IsCall()) {
1223 RemoveStackCheck(back_edge);
1224 back_edge_dominated_by_call = true;
1225 }
1226 instr = instr->next();
1227 }
1228 dominator = dominator->dominator();
1229 }
1230 }
1231 }
1232 }
1233
1234
RemoveStackCheck(HBasicBlock * block)1235 void HStackCheckEliminator::RemoveStackCheck(HBasicBlock* block) {
1236 HInstruction* instr = block->first();
1237 while (instr != NULL) {
1238 if (instr->IsGoto()) {
1239 HGoto::cast(instr)->set_include_stack_check(false);
1240 return;
1241 }
1242 instr = instr->next();
1243 }
1244 }
1245
1246
1247 class HGlobalValueNumberer BASE_EMBEDDED {
1248 public:
HGlobalValueNumberer(HGraph * graph,CompilationInfo * info)1249 explicit HGlobalValueNumberer(HGraph* graph, CompilationInfo* info)
1250 : graph_(graph),
1251 info_(info),
1252 block_side_effects_(graph_->blocks()->length()),
1253 loop_side_effects_(graph_->blocks()->length()) {
1254 ASSERT(info->isolate()->heap()->allow_allocation(false));
1255 block_side_effects_.AddBlock(0, graph_->blocks()->length());
1256 loop_side_effects_.AddBlock(0, graph_->blocks()->length());
1257 }
~HGlobalValueNumberer()1258 ~HGlobalValueNumberer() {
1259 ASSERT(!info_->isolate()->heap()->allow_allocation(true));
1260 }
1261
1262 void Analyze();
1263
1264 private:
1265 void AnalyzeBlock(HBasicBlock* block, HValueMap* map);
1266 void ComputeBlockSideEffects();
1267 void LoopInvariantCodeMotion();
1268 void ProcessLoopBlock(HBasicBlock* block,
1269 HBasicBlock* before_loop,
1270 int loop_kills);
1271 bool AllowCodeMotion();
1272 bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header);
1273
graph()1274 HGraph* graph() { return graph_; }
info()1275 CompilationInfo* info() { return info_; }
zone()1276 Zone* zone() { return graph_->zone(); }
1277
1278 HGraph* graph_;
1279 CompilationInfo* info_;
1280
1281 // A map of block IDs to their side effects.
1282 ZoneList<int> block_side_effects_;
1283
1284 // A map of loop header block IDs to their loop's side effects.
1285 ZoneList<int> loop_side_effects_;
1286 };
1287
1288
Analyze()1289 void HGlobalValueNumberer::Analyze() {
1290 ComputeBlockSideEffects();
1291 if (FLAG_loop_invariant_code_motion) {
1292 LoopInvariantCodeMotion();
1293 }
1294 HValueMap* map = new(zone()) HValueMap();
1295 AnalyzeBlock(graph_->blocks()->at(0), map);
1296 }
1297
1298
ComputeBlockSideEffects()1299 void HGlobalValueNumberer::ComputeBlockSideEffects() {
1300 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) {
1301 // Compute side effects for the block.
1302 HBasicBlock* block = graph_->blocks()->at(i);
1303 HInstruction* instr = block->first();
1304 int id = block->block_id();
1305 int side_effects = 0;
1306 while (instr != NULL) {
1307 side_effects |= (instr->flags() & HValue::ChangesFlagsMask());
1308 instr = instr->next();
1309 }
1310 block_side_effects_[id] |= side_effects;
1311
1312 // Loop headers are part of their loop.
1313 if (block->IsLoopHeader()) {
1314 loop_side_effects_[id] |= side_effects;
1315 }
1316
1317 // Propagate loop side effects upwards.
1318 if (block->HasParentLoopHeader()) {
1319 int header_id = block->parent_loop_header()->block_id();
1320 loop_side_effects_[header_id] |=
1321 block->IsLoopHeader() ? loop_side_effects_[id] : side_effects;
1322 }
1323 }
1324 }
1325
1326
LoopInvariantCodeMotion()1327 void HGlobalValueNumberer::LoopInvariantCodeMotion() {
1328 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) {
1329 HBasicBlock* block = graph_->blocks()->at(i);
1330 if (block->IsLoopHeader()) {
1331 int side_effects = loop_side_effects_[block->block_id()];
1332 TraceGVN("Try loop invariant motion for block B%d effects=0x%x\n",
1333 block->block_id(),
1334 side_effects);
1335
1336 HBasicBlock* last = block->loop_information()->GetLastBackEdge();
1337 for (int j = block->block_id(); j <= last->block_id(); ++j) {
1338 ProcessLoopBlock(graph_->blocks()->at(j), block, side_effects);
1339 }
1340 }
1341 }
1342 }
1343
1344
ProcessLoopBlock(HBasicBlock * block,HBasicBlock * loop_header,int loop_kills)1345 void HGlobalValueNumberer::ProcessLoopBlock(HBasicBlock* block,
1346 HBasicBlock* loop_header,
1347 int loop_kills) {
1348 HBasicBlock* pre_header = loop_header->predecessors()->at(0);
1349 int depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills);
1350 TraceGVN("Loop invariant motion for B%d depends_flags=0x%x\n",
1351 block->block_id(),
1352 depends_flags);
1353 HInstruction* instr = block->first();
1354 while (instr != NULL) {
1355 HInstruction* next = instr->next();
1356 if (instr->CheckFlag(HValue::kUseGVN) &&
1357 (instr->flags() & depends_flags) == 0) {
1358 TraceGVN("Checking instruction %d (%s)\n",
1359 instr->id(),
1360 instr->Mnemonic());
1361 bool inputs_loop_invariant = true;
1362 for (int i = 0; i < instr->OperandCount(); ++i) {
1363 if (instr->OperandAt(i)->IsDefinedAfter(pre_header)) {
1364 inputs_loop_invariant = false;
1365 }
1366 }
1367
1368 if (inputs_loop_invariant && ShouldMove(instr, loop_header)) {
1369 TraceGVN("Found loop invariant instruction %d\n", instr->id());
1370 // Move the instruction out of the loop.
1371 instr->Unlink();
1372 instr->InsertBefore(pre_header->end());
1373 }
1374 }
1375 instr = next;
1376 }
1377 }
1378
1379
AllowCodeMotion()1380 bool HGlobalValueNumberer::AllowCodeMotion() {
1381 return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount;
1382 }
1383
1384
ShouldMove(HInstruction * instr,HBasicBlock * loop_header)1385 bool HGlobalValueNumberer::ShouldMove(HInstruction* instr,
1386 HBasicBlock* loop_header) {
1387 // If we've disabled code motion, don't move any instructions.
1388 if (!AllowCodeMotion()) return false;
1389
1390 // If --aggressive-loop-invariant-motion, move everything except change
1391 // instructions.
1392 if (FLAG_aggressive_loop_invariant_motion && !instr->IsChange()) {
1393 return true;
1394 }
1395
1396 // Otherwise only move instructions that postdominate the loop header
1397 // (i.e. are always executed inside the loop). This is to avoid
1398 // unnecessary deoptimizations assuming the loop is executed at least
1399 // once. TODO(fschneider): Better type feedback should give us
1400 // information about code that was never executed.
1401 HBasicBlock* block = instr->block();
1402 bool result = true;
1403 if (block != loop_header) {
1404 for (int i = 1; i < loop_header->predecessors()->length(); ++i) {
1405 bool found = false;
1406 HBasicBlock* pred = loop_header->predecessors()->at(i);
1407 while (pred != loop_header) {
1408 if (pred == block) found = true;
1409 pred = pred->dominator();
1410 }
1411 if (!found) {
1412 result = false;
1413 break;
1414 }
1415 }
1416 }
1417 return result;
1418 }
1419
1420
AnalyzeBlock(HBasicBlock * block,HValueMap * map)1421 void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
1422 TraceGVN("Analyzing block B%d\n", block->block_id());
1423
1424 // If this is a loop header kill everything killed by the loop.
1425 if (block->IsLoopHeader()) {
1426 map->Kill(loop_side_effects_[block->block_id()]);
1427 }
1428
1429 // Go through all instructions of the current block.
1430 HInstruction* instr = block->first();
1431 while (instr != NULL) {
1432 HInstruction* next = instr->next();
1433 int flags = (instr->flags() & HValue::ChangesFlagsMask());
1434 if (flags != 0) {
1435 ASSERT(!instr->CheckFlag(HValue::kUseGVN));
1436 // Clear all instructions in the map that are affected by side effects.
1437 map->Kill(flags);
1438 TraceGVN("Instruction %d kills\n", instr->id());
1439 } else if (instr->CheckFlag(HValue::kUseGVN)) {
1440 HValue* other = map->Lookup(instr);
1441 if (other != NULL) {
1442 ASSERT(instr->Equals(other) && other->Equals(instr));
1443 TraceGVN("Replacing value %d (%s) with value %d (%s)\n",
1444 instr->id(),
1445 instr->Mnemonic(),
1446 other->id(),
1447 other->Mnemonic());
1448 instr->ReplaceAndDelete(other);
1449 } else {
1450 map->Add(instr);
1451 }
1452 }
1453 instr = next;
1454 }
1455
1456 // Recursively continue analysis for all immediately dominated blocks.
1457 int length = block->dominated_blocks()->length();
1458 for (int i = 0; i < length; ++i) {
1459 HBasicBlock* dominated = block->dominated_blocks()->at(i);
1460 // No need to copy the map for the last child in the dominator tree.
1461 HValueMap* successor_map = (i == length - 1) ? map : map->Copy(zone());
1462
1463 // If the dominated block is not a successor to this block we have to
1464 // kill everything killed on any path between this block and the
1465 // dominated block. Note we rely on the block ordering.
1466 bool is_successor = false;
1467 int predecessor_count = dominated->predecessors()->length();
1468 for (int j = 0; !is_successor && j < predecessor_count; ++j) {
1469 is_successor = (dominated->predecessors()->at(j) == block);
1470 }
1471
1472 if (!is_successor) {
1473 int side_effects = 0;
1474 for (int j = block->block_id() + 1; j < dominated->block_id(); ++j) {
1475 side_effects |= block_side_effects_[j];
1476 }
1477 successor_map->Kill(side_effects);
1478 }
1479
1480 AnalyzeBlock(dominated, successor_map);
1481 }
1482 }
1483
1484
1485 class HInferRepresentation BASE_EMBEDDED {
1486 public:
HInferRepresentation(HGraph * graph)1487 explicit HInferRepresentation(HGraph* graph)
1488 : graph_(graph), worklist_(8), in_worklist_(graph->GetMaximumValueID()) {}
1489
1490 void Analyze();
1491
1492 private:
1493 Representation TryChange(HValue* current);
1494 void AddToWorklist(HValue* current);
1495 void InferBasedOnInputs(HValue* current);
1496 void AddDependantsToWorklist(HValue* current);
1497 void InferBasedOnUses(HValue* current);
1498
zone()1499 Zone* zone() { return graph_->zone(); }
1500
1501 HGraph* graph_;
1502 ZoneList<HValue*> worklist_;
1503 BitVector in_worklist_;
1504 };
1505
1506
AddToWorklist(HValue * current)1507 void HInferRepresentation::AddToWorklist(HValue* current) {
1508 if (current->representation().IsSpecialization()) return;
1509 if (!current->CheckFlag(HValue::kFlexibleRepresentation)) return;
1510 if (in_worklist_.Contains(current->id())) return;
1511 worklist_.Add(current);
1512 in_worklist_.Add(current->id());
1513 }
1514
1515
1516 // This method tries to specialize the representation type of the value
1517 // given as a parameter. The value is asked to infer its representation type
1518 // based on its inputs. If the inferred type is more specialized, then this
1519 // becomes the new representation type of the node.
InferBasedOnInputs(HValue * current)1520 void HInferRepresentation::InferBasedOnInputs(HValue* current) {
1521 Representation r = current->representation();
1522 if (r.IsSpecialization()) return;
1523 ASSERT(current->CheckFlag(HValue::kFlexibleRepresentation));
1524 Representation inferred = current->InferredRepresentation();
1525 if (inferred.IsSpecialization()) {
1526 current->ChangeRepresentation(inferred);
1527 AddDependantsToWorklist(current);
1528 }
1529 }
1530
1531
AddDependantsToWorklist(HValue * current)1532 void HInferRepresentation::AddDependantsToWorklist(HValue* current) {
1533 for (int i = 0; i < current->uses()->length(); ++i) {
1534 AddToWorklist(current->uses()->at(i));
1535 }
1536 for (int i = 0; i < current->OperandCount(); ++i) {
1537 AddToWorklist(current->OperandAt(i));
1538 }
1539 }
1540
1541
1542 // This method calculates whether specializing the representation of the value
1543 // given as the parameter has a benefit in terms of less necessary type
1544 // conversions. If there is a benefit, then the representation of the value is
1545 // specialized.
InferBasedOnUses(HValue * current)1546 void HInferRepresentation::InferBasedOnUses(HValue* current) {
1547 Representation r = current->representation();
1548 if (r.IsSpecialization() || current->HasNoUses()) return;
1549 ASSERT(current->CheckFlag(HValue::kFlexibleRepresentation));
1550 Representation new_rep = TryChange(current);
1551 if (!new_rep.IsNone()) {
1552 if (!current->representation().Equals(new_rep)) {
1553 current->ChangeRepresentation(new_rep);
1554 AddDependantsToWorklist(current);
1555 }
1556 }
1557 }
1558
1559
TryChange(HValue * current)1560 Representation HInferRepresentation::TryChange(HValue* current) {
1561 // Array of use counts for each representation.
1562 int use_count[Representation::kNumRepresentations];
1563 for (int i = 0; i < Representation::kNumRepresentations; i++) {
1564 use_count[i] = 0;
1565 }
1566
1567 for (int i = 0; i < current->uses()->length(); ++i) {
1568 HValue* use = current->uses()->at(i);
1569 int index = use->LookupOperandIndex(0, current);
1570 Representation req_rep = use->RequiredInputRepresentation(index);
1571 if (req_rep.IsNone()) continue;
1572 if (use->IsPhi()) {
1573 HPhi* phi = HPhi::cast(use);
1574 phi->AddIndirectUsesTo(&use_count[0]);
1575 }
1576 use_count[req_rep.kind()]++;
1577 }
1578 int tagged_count = use_count[Representation::kTagged];
1579 int double_count = use_count[Representation::kDouble];
1580 int int32_count = use_count[Representation::kInteger32];
1581 int non_tagged_count = double_count + int32_count;
1582
1583 // If a non-loop phi has tagged uses, don't convert it to untagged.
1584 if (current->IsPhi() && !current->block()->IsLoopHeader()) {
1585 if (tagged_count > 0) return Representation::None();
1586 }
1587
1588 if (non_tagged_count >= tagged_count) {
1589 // More untagged than tagged.
1590 if (double_count > 0) {
1591 // There is at least one usage that is a double => guess that the
1592 // correct representation is double.
1593 return Representation::Double();
1594 } else if (int32_count > 0) {
1595 return Representation::Integer32();
1596 }
1597 }
1598 return Representation::None();
1599 }
1600
1601
Analyze()1602 void HInferRepresentation::Analyze() {
1603 HPhase phase("Infer representations", graph_);
1604
1605 // (1) Initialize bit vectors and count real uses. Each phi
1606 // gets a bit-vector of length <number of phis>.
1607 const ZoneList<HPhi*>* phi_list = graph_->phi_list();
1608 int num_phis = phi_list->length();
1609 ScopedVector<BitVector*> connected_phis(num_phis);
1610 for (int i = 0; i < num_phis; i++) {
1611 phi_list->at(i)->InitRealUses(i);
1612 connected_phis[i] = new(zone()) BitVector(num_phis);
1613 connected_phis[i]->Add(i);
1614 }
1615
1616 // (2) Do a fixed point iteration to find the set of connected phis.
1617 // A phi is connected to another phi if its value is used either
1618 // directly or indirectly through a transitive closure of the def-use
1619 // relation.
1620 bool change = true;
1621 while (change) {
1622 change = false;
1623 for (int i = 0; i < num_phis; i++) {
1624 HPhi* phi = phi_list->at(i);
1625 for (int j = 0; j < phi->uses()->length(); j++) {
1626 HValue* use = phi->uses()->at(j);
1627 if (use->IsPhi()) {
1628 int phi_use = HPhi::cast(use)->phi_id();
1629 if (connected_phis[i]->UnionIsChanged(*connected_phis[phi_use])) {
1630 change = true;
1631 }
1632 }
1633 }
1634 }
1635 }
1636
1637 // (3) Sum up the non-phi use counts of all connected phis.
1638 // Don't include the non-phi uses of the phi itself.
1639 for (int i = 0; i < num_phis; i++) {
1640 HPhi* phi = phi_list->at(i);
1641 for (BitVector::Iterator it(connected_phis.at(i));
1642 !it.Done();
1643 it.Advance()) {
1644 int index = it.Current();
1645 if (index != i) {
1646 HPhi* it_use = phi_list->at(it.Current());
1647 phi->AddNonPhiUsesFrom(it_use);
1648 }
1649 }
1650 }
1651
1652 for (int i = 0; i < graph_->blocks()->length(); ++i) {
1653 HBasicBlock* block = graph_->blocks()->at(i);
1654 const ZoneList<HPhi*>* phis = block->phis();
1655 for (int j = 0; j < phis->length(); ++j) {
1656 AddToWorklist(phis->at(j));
1657 }
1658
1659 HInstruction* current = block->first();
1660 while (current != NULL) {
1661 AddToWorklist(current);
1662 current = current->next();
1663 }
1664 }
1665
1666 while (!worklist_.is_empty()) {
1667 HValue* current = worklist_.RemoveLast();
1668 in_worklist_.Remove(current->id());
1669 InferBasedOnInputs(current);
1670 InferBasedOnUses(current);
1671 }
1672 }
1673
1674
InitializeInferredTypes()1675 void HGraph::InitializeInferredTypes() {
1676 HPhase phase("Inferring types", this);
1677 InitializeInferredTypes(0, this->blocks_.length() - 1);
1678 }
1679
1680
InitializeInferredTypes(int from_inclusive,int to_inclusive)1681 void HGraph::InitializeInferredTypes(int from_inclusive, int to_inclusive) {
1682 for (int i = from_inclusive; i <= to_inclusive; ++i) {
1683 HBasicBlock* block = blocks_[i];
1684
1685 const ZoneList<HPhi*>* phis = block->phis();
1686 for (int j = 0; j < phis->length(); j++) {
1687 phis->at(j)->UpdateInferredType();
1688 }
1689
1690 HInstruction* current = block->first();
1691 while (current != NULL) {
1692 current->UpdateInferredType();
1693 current = current->next();
1694 }
1695
1696 if (block->IsLoopHeader()) {
1697 HBasicBlock* last_back_edge =
1698 block->loop_information()->GetLastBackEdge();
1699 InitializeInferredTypes(i + 1, last_back_edge->block_id());
1700 // Skip all blocks already processed by the recursive call.
1701 i = last_back_edge->block_id();
1702 // Update phis of the loop header now after the whole loop body is
1703 // guaranteed to be processed.
1704 ZoneList<HValue*> worklist(block->phis()->length());
1705 for (int j = 0; j < block->phis()->length(); ++j) {
1706 worklist.Add(block->phis()->at(j));
1707 }
1708 InferTypes(&worklist);
1709 }
1710 }
1711 }
1712
1713
PropagateMinusZeroChecks(HValue * value,BitVector * visited)1714 void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) {
1715 HValue* current = value;
1716 while (current != NULL) {
1717 if (visited->Contains(current->id())) return;
1718
1719 // For phis, we must propagate the check to all of its inputs.
1720 if (current->IsPhi()) {
1721 visited->Add(current->id());
1722 HPhi* phi = HPhi::cast(current);
1723 for (int i = 0; i < phi->OperandCount(); ++i) {
1724 PropagateMinusZeroChecks(phi->OperandAt(i), visited);
1725 }
1726 break;
1727 }
1728
1729 // For multiplication and division, we must propagate to the left and
1730 // the right side.
1731 if (current->IsMul()) {
1732 HMul* mul = HMul::cast(current);
1733 mul->EnsureAndPropagateNotMinusZero(visited);
1734 PropagateMinusZeroChecks(mul->left(), visited);
1735 PropagateMinusZeroChecks(mul->right(), visited);
1736 } else if (current->IsDiv()) {
1737 HDiv* div = HDiv::cast(current);
1738 div->EnsureAndPropagateNotMinusZero(visited);
1739 PropagateMinusZeroChecks(div->left(), visited);
1740 PropagateMinusZeroChecks(div->right(), visited);
1741 }
1742
1743 current = current->EnsureAndPropagateNotMinusZero(visited);
1744 }
1745 }
1746
1747
InsertRepresentationChangeForUse(HValue * value,HValue * use,Representation to)1748 void HGraph::InsertRepresentationChangeForUse(HValue* value,
1749 HValue* use,
1750 Representation to) {
1751 // Insert the representation change right before its use. For phi-uses we
1752 // insert at the end of the corresponding predecessor.
1753 HInstruction* next = NULL;
1754 if (use->IsPhi()) {
1755 int index = 0;
1756 while (use->OperandAt(index) != value) ++index;
1757 next = use->block()->predecessors()->at(index)->end();
1758 } else {
1759 next = HInstruction::cast(use);
1760 }
1761
1762 // For constants we try to make the representation change at compile
1763 // time. When a representation change is not possible without loss of
1764 // information we treat constants like normal instructions and insert the
1765 // change instructions for them.
1766 HInstruction* new_value = NULL;
1767 bool is_truncating = use->CheckFlag(HValue::kTruncatingToInt32);
1768 bool deoptimize_on_undefined = use->CheckFlag(HValue::kDeoptimizeOnUndefined);
1769 if (value->IsConstant()) {
1770 HConstant* constant = HConstant::cast(value);
1771 // Try to create a new copy of the constant with the new representation.
1772 new_value = is_truncating
1773 ? constant->CopyToTruncatedInt32()
1774 : constant->CopyToRepresentation(to);
1775 }
1776
1777 if (new_value == NULL) {
1778 new_value = new(zone()) HChange(value, value->representation(), to,
1779 is_truncating, deoptimize_on_undefined);
1780 }
1781
1782 new_value->InsertBefore(next);
1783 value->ReplaceFirstAtUse(use, new_value, to);
1784 }
1785
1786
CompareConversionUses(HValue * a,HValue * b,Representation a_rep,Representation b_rep)1787 int CompareConversionUses(HValue* a,
1788 HValue* b,
1789 Representation a_rep,
1790 Representation b_rep) {
1791 if (a_rep.kind() > b_rep.kind()) {
1792 // Make sure specializations are separated in the result array.
1793 return 1;
1794 }
1795 // Put truncating conversions before non-truncating conversions.
1796 bool a_truncate = a->CheckFlag(HValue::kTruncatingToInt32);
1797 bool b_truncate = b->CheckFlag(HValue::kTruncatingToInt32);
1798 if (a_truncate != b_truncate) {
1799 return a_truncate ? -1 : 1;
1800 }
1801 // Sort by increasing block ID.
1802 return a->block()->block_id() - b->block()->block_id();
1803 }
1804
1805
InsertRepresentationChangesForValue(HValue * current,ZoneList<HValue * > * to_convert,ZoneList<Representation> * to_convert_reps)1806 void HGraph::InsertRepresentationChangesForValue(
1807 HValue* current,
1808 ZoneList<HValue*>* to_convert,
1809 ZoneList<Representation>* to_convert_reps) {
1810 Representation r = current->representation();
1811 if (r.IsNone()) return;
1812 if (current->uses()->length() == 0) return;
1813
1814 // Collect the representation changes in a sorted list. This allows
1815 // us to avoid duplicate changes without searching the list.
1816 ASSERT(to_convert->is_empty());
1817 ASSERT(to_convert_reps->is_empty());
1818 for (int i = 0; i < current->uses()->length(); ++i) {
1819 HValue* use = current->uses()->at(i);
1820 // The occurrences index means the index within the operand array of "use"
1821 // at which "current" is used. While iterating through the use array we
1822 // also have to iterate over the different occurrence indices.
1823 int occurrence_index = 0;
1824 if (use->UsesMultipleTimes(current)) {
1825 occurrence_index = current->uses()->CountOccurrences(use, 0, i - 1);
1826 if (FLAG_trace_representation) {
1827 PrintF("Instruction %d is used multiple times at %d; occurrence=%d\n",
1828 current->id(),
1829 use->id(),
1830 occurrence_index);
1831 }
1832 }
1833 int operand_index = use->LookupOperandIndex(occurrence_index, current);
1834 Representation req = use->RequiredInputRepresentation(operand_index);
1835 if (req.IsNone() || req.Equals(r)) continue;
1836 int index = 0;
1837 while (index < to_convert->length() &&
1838 CompareConversionUses(to_convert->at(index),
1839 use,
1840 to_convert_reps->at(index),
1841 req) < 0) {
1842 ++index;
1843 }
1844 if (FLAG_trace_representation) {
1845 PrintF("Inserting a representation change to %s of %d for use at %d\n",
1846 req.Mnemonic(),
1847 current->id(),
1848 use->id());
1849 }
1850 to_convert->InsertAt(index, use);
1851 to_convert_reps->InsertAt(index, req);
1852 }
1853
1854 for (int i = 0; i < to_convert->length(); ++i) {
1855 HValue* use = to_convert->at(i);
1856 Representation r_to = to_convert_reps->at(i);
1857 InsertRepresentationChangeForUse(current, use, r_to);
1858 }
1859
1860 if (current->uses()->is_empty()) {
1861 ASSERT(current->IsConstant());
1862 current->Delete();
1863 }
1864 to_convert->Rewind(0);
1865 to_convert_reps->Rewind(0);
1866 }
1867
1868
InsertRepresentationChanges()1869 void HGraph::InsertRepresentationChanges() {
1870 HPhase phase("Insert representation changes", this);
1871
1872
1873 // Compute truncation flag for phis: Initially assume that all
1874 // int32-phis allow truncation and iteratively remove the ones that
1875 // are used in an operation that does not allow a truncating
1876 // conversion.
1877 // TODO(fschneider): Replace this with a worklist-based iteration.
1878 for (int i = 0; i < phi_list()->length(); i++) {
1879 HPhi* phi = phi_list()->at(i);
1880 if (phi->representation().IsInteger32()) {
1881 phi->SetFlag(HValue::kTruncatingToInt32);
1882 }
1883 }
1884 bool change = true;
1885 while (change) {
1886 change = false;
1887 for (int i = 0; i < phi_list()->length(); i++) {
1888 HPhi* phi = phi_list()->at(i);
1889 if (!phi->CheckFlag(HValue::kTruncatingToInt32)) continue;
1890 for (int j = 0; j < phi->uses()->length(); j++) {
1891 HValue* use = phi->uses()->at(j);
1892 if (!use->CheckFlag(HValue::kTruncatingToInt32)) {
1893 phi->ClearFlag(HValue::kTruncatingToInt32);
1894 change = true;
1895 break;
1896 }
1897 }
1898 }
1899 }
1900
1901 ZoneList<HValue*> value_list(4);
1902 ZoneList<Representation> rep_list(4);
1903 for (int i = 0; i < blocks_.length(); ++i) {
1904 // Process phi instructions first.
1905 for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
1906 HPhi* phi = blocks_[i]->phis()->at(j);
1907 InsertRepresentationChangesForValue(phi, &value_list, &rep_list);
1908 }
1909
1910 // Process normal instructions.
1911 HInstruction* current = blocks_[i]->first();
1912 while (current != NULL) {
1913 InsertRepresentationChangesForValue(current, &value_list, &rep_list);
1914 current = current->next();
1915 }
1916 }
1917 }
1918
1919
RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi * phi)1920 void HGraph::RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi) {
1921 if (phi->CheckFlag(HValue::kDeoptimizeOnUndefined)) return;
1922 phi->SetFlag(HValue::kDeoptimizeOnUndefined);
1923 for (int i = 0; i < phi->OperandCount(); ++i) {
1924 HValue* input = phi->OperandAt(i);
1925 if (input->IsPhi()) {
1926 RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi::cast(input));
1927 }
1928 }
1929 }
1930
1931
MarkDeoptimizeOnUndefined()1932 void HGraph::MarkDeoptimizeOnUndefined() {
1933 HPhase phase("MarkDeoptimizeOnUndefined", this);
1934 // Compute DeoptimizeOnUndefined flag for phis.
1935 // Any phi that can reach a use with DeoptimizeOnUndefined set must
1936 // have DeoptimizeOnUndefined set. Currently only HCompare, with
1937 // double input representation, has this flag set.
1938 // The flag is used by HChange tagged->double, which must deoptimize
1939 // if one of its uses has this flag set.
1940 for (int i = 0; i < phi_list()->length(); i++) {
1941 HPhi* phi = phi_list()->at(i);
1942 if (phi->representation().IsDouble()) {
1943 for (int j = 0; j < phi->uses()->length(); j++) {
1944 HValue* use = phi->uses()->at(j);
1945 if (use->CheckFlag(HValue::kDeoptimizeOnUndefined)) {
1946 RecursivelyMarkPhiDeoptimizeOnUndefined(phi);
1947 break;
1948 }
1949 }
1950 }
1951 }
1952 }
1953
1954
ComputeMinusZeroChecks()1955 void HGraph::ComputeMinusZeroChecks() {
1956 BitVector visited(GetMaximumValueID());
1957 for (int i = 0; i < blocks_.length(); ++i) {
1958 for (HInstruction* current = blocks_[i]->first();
1959 current != NULL;
1960 current = current->next()) {
1961 if (current->IsChange()) {
1962 HChange* change = HChange::cast(current);
1963 // Propagate flags for negative zero checks upwards from conversions
1964 // int32-to-tagged and int32-to-double.
1965 Representation from = change->value()->representation();
1966 ASSERT(from.Equals(change->from()));
1967 if (from.IsInteger32()) {
1968 ASSERT(change->to().IsTagged() || change->to().IsDouble());
1969 ASSERT(visited.IsEmpty());
1970 PropagateMinusZeroChecks(change->value(), &visited);
1971 visited.Clear();
1972 }
1973 }
1974 }
1975 }
1976 }
1977
1978
1979 // Implementation of utility class to encapsulate the translation state for
1980 // a (possibly inlined) function.
FunctionState(HGraphBuilder * owner,CompilationInfo * info,TypeFeedbackOracle * oracle)1981 FunctionState::FunctionState(HGraphBuilder* owner,
1982 CompilationInfo* info,
1983 TypeFeedbackOracle* oracle)
1984 : owner_(owner),
1985 compilation_info_(info),
1986 oracle_(oracle),
1987 call_context_(NULL),
1988 function_return_(NULL),
1989 test_context_(NULL),
1990 outer_(owner->function_state()) {
1991 if (outer_ != NULL) {
1992 // State for an inline function.
1993 if (owner->ast_context()->IsTest()) {
1994 HBasicBlock* if_true = owner->graph()->CreateBasicBlock();
1995 HBasicBlock* if_false = owner->graph()->CreateBasicBlock();
1996 if_true->MarkAsInlineReturnTarget();
1997 if_false->MarkAsInlineReturnTarget();
1998 // The AstContext constructor pushed on the context stack. This newed
1999 // instance is the reason that AstContext can't be BASE_EMBEDDED.
2000 test_context_ = new TestContext(owner, if_true, if_false);
2001 } else {
2002 function_return_ = owner->graph()->CreateBasicBlock();
2003 function_return()->MarkAsInlineReturnTarget();
2004 }
2005 // Set this after possibly allocating a new TestContext above.
2006 call_context_ = owner->ast_context();
2007 }
2008
2009 // Push on the state stack.
2010 owner->set_function_state(this);
2011 }
2012
2013
~FunctionState()2014 FunctionState::~FunctionState() {
2015 delete test_context_;
2016 owner_->set_function_state(outer_);
2017 }
2018
2019
2020 // Implementation of utility classes to represent an expression's context in
2021 // the AST.
AstContext(HGraphBuilder * owner,Expression::Context kind)2022 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind)
2023 : owner_(owner),
2024 kind_(kind),
2025 outer_(owner->ast_context()),
2026 for_typeof_(false) {
2027 owner->set_ast_context(this); // Push.
2028 #ifdef DEBUG
2029 original_length_ = owner->environment()->length();
2030 #endif
2031 }
2032
2033
~AstContext()2034 AstContext::~AstContext() {
2035 owner_->set_ast_context(outer_); // Pop.
2036 }
2037
2038
~EffectContext()2039 EffectContext::~EffectContext() {
2040 ASSERT(owner()->HasStackOverflow() ||
2041 owner()->current_block() == NULL ||
2042 owner()->environment()->length() == original_length_);
2043 }
2044
2045
~ValueContext()2046 ValueContext::~ValueContext() {
2047 ASSERT(owner()->HasStackOverflow() ||
2048 owner()->current_block() == NULL ||
2049 owner()->environment()->length() == original_length_ + 1);
2050 }
2051
2052
ReturnValue(HValue * value)2053 void EffectContext::ReturnValue(HValue* value) {
2054 // The value is simply ignored.
2055 }
2056
2057
ReturnValue(HValue * value)2058 void ValueContext::ReturnValue(HValue* value) {
2059 // The value is tracked in the bailout environment, and communicated
2060 // through the environment as the result of the expression.
2061 owner()->Push(value);
2062 }
2063
2064
ReturnValue(HValue * value)2065 void TestContext::ReturnValue(HValue* value) {
2066 BuildBranch(value);
2067 }
2068
2069
ReturnInstruction(HInstruction * instr,int ast_id)2070 void EffectContext::ReturnInstruction(HInstruction* instr, int ast_id) {
2071 owner()->AddInstruction(instr);
2072 if (instr->HasSideEffects()) owner()->AddSimulate(ast_id);
2073 }
2074
2075
ReturnInstruction(HInstruction * instr,int ast_id)2076 void ValueContext::ReturnInstruction(HInstruction* instr, int ast_id) {
2077 owner()->AddInstruction(instr);
2078 owner()->Push(instr);
2079 if (instr->HasSideEffects()) owner()->AddSimulate(ast_id);
2080 }
2081
2082
ReturnInstruction(HInstruction * instr,int ast_id)2083 void TestContext::ReturnInstruction(HInstruction* instr, int ast_id) {
2084 HGraphBuilder* builder = owner();
2085 builder->AddInstruction(instr);
2086 // We expect a simulate after every expression with side effects, though
2087 // this one isn't actually needed (and wouldn't work if it were targeted).
2088 if (instr->HasSideEffects()) {
2089 builder->Push(instr);
2090 builder->AddSimulate(ast_id);
2091 builder->Pop();
2092 }
2093 BuildBranch(instr);
2094 }
2095
2096
BuildBranch(HValue * value)2097 void TestContext::BuildBranch(HValue* value) {
2098 // We expect the graph to be in edge-split form: there is no edge that
2099 // connects a branch node to a join node. We conservatively ensure that
2100 // property by always adding an empty block on the outgoing edges of this
2101 // branch.
2102 HGraphBuilder* builder = owner();
2103 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock();
2104 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock();
2105 HTest* test = new(zone()) HTest(value, empty_true, empty_false);
2106 builder->current_block()->Finish(test);
2107
2108 empty_true->Goto(if_true(), false);
2109 empty_false->Goto(if_false(), false);
2110 builder->set_current_block(NULL);
2111 }
2112
2113
2114 // HGraphBuilder infrastructure for bailing out and checking bailouts.
2115 #define BAILOUT(reason) \
2116 do { \
2117 Bailout(reason); \
2118 return; \
2119 } while (false)
2120
2121
2122 #define CHECK_BAILOUT \
2123 do { \
2124 if (HasStackOverflow()) return; \
2125 } while (false)
2126
2127
2128 #define VISIT_FOR_EFFECT(expr) \
2129 do { \
2130 VisitForEffect(expr); \
2131 if (HasStackOverflow()) return; \
2132 } while (false)
2133
2134
2135 #define VISIT_FOR_VALUE(expr) \
2136 do { \
2137 VisitForValue(expr); \
2138 if (HasStackOverflow()) return; \
2139 } while (false)
2140
2141
2142 #define VISIT_FOR_CONTROL(expr, true_block, false_block) \
2143 do { \
2144 VisitForControl(expr, true_block, false_block); \
2145 if (HasStackOverflow()) return; \
2146 } while (false)
2147
2148
Bailout(const char * reason)2149 void HGraphBuilder::Bailout(const char* reason) {
2150 if (FLAG_trace_bailout) {
2151 SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
2152 PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *name, reason);
2153 }
2154 SetStackOverflow();
2155 }
2156
2157
VisitForEffect(Expression * expr)2158 void HGraphBuilder::VisitForEffect(Expression* expr) {
2159 EffectContext for_effect(this);
2160 Visit(expr);
2161 }
2162
2163
VisitForValue(Expression * expr)2164 void HGraphBuilder::VisitForValue(Expression* expr) {
2165 ValueContext for_value(this);
2166 Visit(expr);
2167 }
2168
2169
VisitForTypeOf(Expression * expr)2170 void HGraphBuilder::VisitForTypeOf(Expression* expr) {
2171 ValueContext for_value(this);
2172 for_value.set_for_typeof(true);
2173 Visit(expr);
2174 }
2175
2176
2177
VisitForControl(Expression * expr,HBasicBlock * true_block,HBasicBlock * false_block)2178 void HGraphBuilder::VisitForControl(Expression* expr,
2179 HBasicBlock* true_block,
2180 HBasicBlock* false_block) {
2181 TestContext for_test(this, true_block, false_block);
2182 Visit(expr);
2183 }
2184
2185
VisitArgument(Expression * expr)2186 void HGraphBuilder::VisitArgument(Expression* expr) {
2187 VISIT_FOR_VALUE(expr);
2188 Push(AddInstruction(new(zone()) HPushArgument(Pop())));
2189 }
2190
2191
VisitArgumentList(ZoneList<Expression * > * arguments)2192 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) {
2193 for (int i = 0; i < arguments->length(); i++) {
2194 VisitArgument(arguments->at(i));
2195 if (HasStackOverflow() || current_block() == NULL) return;
2196 }
2197 }
2198
2199
VisitExpressions(ZoneList<Expression * > * exprs)2200 void HGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs) {
2201 for (int i = 0; i < exprs->length(); ++i) {
2202 VISIT_FOR_VALUE(exprs->at(i));
2203 }
2204 }
2205
2206
CreateGraph()2207 HGraph* HGraphBuilder::CreateGraph() {
2208 graph_ = new(zone()) HGraph(info());
2209 if (FLAG_hydrogen_stats) HStatistics::Instance()->Initialize(info());
2210
2211 {
2212 HPhase phase("Block building");
2213 current_block_ = graph()->entry_block();
2214
2215 Scope* scope = info()->scope();
2216 if (scope->HasIllegalRedeclaration()) {
2217 Bailout("function with illegal redeclaration");
2218 return NULL;
2219 }
2220 SetupScope(scope);
2221 VisitDeclarations(scope->declarations());
2222 AddInstruction(new(zone()) HStackCheck());
2223
2224 // Add an edge to the body entry. This is warty: the graph's start
2225 // environment will be used by the Lithium translation as the initial
2226 // environment on graph entry, but it has now been mutated by the
2227 // Hydrogen translation of the instructions in the start block. This
2228 // environment uses values which have not been defined yet. These
2229 // Hydrogen instructions will then be replayed by the Lithium
2230 // translation, so they cannot have an environment effect. The edge to
2231 // the body's entry block (along with some special logic for the start
2232 // block in HInstruction::InsertAfter) seals the start block from
2233 // getting unwanted instructions inserted.
2234 //
2235 // TODO(kmillikin): Fix this. Stop mutating the initial environment.
2236 // Make the Hydrogen instructions in the initial block into Hydrogen
2237 // values (but not instructions), present in the initial environment and
2238 // not replayed by the Lithium translation.
2239 HEnvironment* initial_env = environment()->CopyWithoutHistory();
2240 HBasicBlock* body_entry = CreateBasicBlock(initial_env);
2241 current_block()->Goto(body_entry);
2242 body_entry->SetJoinId(AstNode::kFunctionEntryId);
2243 set_current_block(body_entry);
2244 VisitStatements(info()->function()->body());
2245 if (HasStackOverflow()) return NULL;
2246
2247 if (current_block() != NULL) {
2248 HReturn* instr = new(zone()) HReturn(graph()->GetConstantUndefined());
2249 current_block()->FinishExit(instr);
2250 set_current_block(NULL);
2251 }
2252 }
2253
2254 graph()->OrderBlocks();
2255 graph()->AssignDominators();
2256 graph()->EliminateRedundantPhis();
2257 if (FLAG_eliminate_dead_phis) graph()->EliminateUnreachablePhis();
2258 if (!graph()->CollectPhis()) {
2259 Bailout("Phi-use of arguments object");
2260 return NULL;
2261 }
2262
2263 HInferRepresentation rep(graph());
2264 rep.Analyze();
2265
2266 if (FLAG_use_range) {
2267 HRangeAnalysis rangeAnalysis(graph());
2268 rangeAnalysis.Analyze();
2269 }
2270
2271 graph()->InitializeInferredTypes();
2272 graph()->Canonicalize();
2273 graph()->MarkDeoptimizeOnUndefined();
2274 graph()->InsertRepresentationChanges();
2275 graph()->ComputeMinusZeroChecks();
2276
2277 // Eliminate redundant stack checks on backwards branches.
2278 HStackCheckEliminator sce(graph());
2279 sce.Process();
2280
2281 // Perform common subexpression elimination and loop-invariant code motion.
2282 if (FLAG_use_gvn) {
2283 HPhase phase("Global value numbering", graph());
2284 HGlobalValueNumberer gvn(graph(), info());
2285 gvn.Analyze();
2286 }
2287
2288 // Replace the results of check instructions with the original value, if the
2289 // result is used. This is safe now, since we don't do code motion after this
2290 // point. It enables better register allocation since the value produced by
2291 // check instructions is really a copy of the original value.
2292 graph()->ReplaceCheckedValues();
2293
2294 return graph();
2295 }
2296
2297
ReplaceCheckedValues()2298 void HGraph::ReplaceCheckedValues() {
2299 HPhase phase("Replace checked values", this);
2300 for (int i = 0; i < blocks()->length(); ++i) {
2301 HInstruction* instr = blocks()->at(i)->first();
2302 while (instr != NULL) {
2303 if (instr->IsBoundsCheck()) {
2304 // Replace all uses of the checked value with the original input.
2305 ASSERT(instr->uses()->length() > 0);
2306 instr->ReplaceValue(HBoundsCheck::cast(instr)->index());
2307 }
2308 instr = instr->next();
2309 }
2310 }
2311 }
2312
2313
AddInstruction(HInstruction * instr)2314 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
2315 ASSERT(current_block() != NULL);
2316 current_block()->AddInstruction(instr);
2317 return instr;
2318 }
2319
2320
AddSimulate(int id)2321 void HGraphBuilder::AddSimulate(int id) {
2322 ASSERT(current_block() != NULL);
2323 current_block()->AddSimulate(id);
2324 }
2325
2326
AddPhi(HPhi * instr)2327 void HGraphBuilder::AddPhi(HPhi* instr) {
2328 ASSERT(current_block() != NULL);
2329 current_block()->AddPhi(instr);
2330 }
2331
2332
PushAndAdd(HInstruction * instr)2333 void HGraphBuilder::PushAndAdd(HInstruction* instr) {
2334 Push(instr);
2335 AddInstruction(instr);
2336 }
2337
2338
2339 template <int V>
PreProcessCall(HCall<V> * call)2340 HInstruction* HGraphBuilder::PreProcessCall(HCall<V>* call) {
2341 int count = call->argument_count();
2342 ZoneList<HValue*> arguments(count);
2343 for (int i = 0; i < count; ++i) {
2344 arguments.Add(Pop());
2345 }
2346
2347 while (!arguments.is_empty()) {
2348 AddInstruction(new(zone()) HPushArgument(arguments.RemoveLast()));
2349 }
2350 return call;
2351 }
2352
2353
SetupScope(Scope * scope)2354 void HGraphBuilder::SetupScope(Scope* scope) {
2355 // We don't yet handle the function name for named function expressions.
2356 if (scope->function() != NULL) BAILOUT("named function expression");
2357
2358 HConstant* undefined_constant = new(zone()) HConstant(
2359 isolate()->factory()->undefined_value(), Representation::Tagged());
2360 AddInstruction(undefined_constant);
2361 graph_->set_undefined_constant(undefined_constant);
2362
2363 // Set the initial values of parameters including "this". "This" has
2364 // parameter index 0.
2365 int count = scope->num_parameters() + 1;
2366 for (int i = 0; i < count; ++i) {
2367 HInstruction* parameter = AddInstruction(new(zone()) HParameter(i));
2368 environment()->Bind(i, parameter);
2369 }
2370
2371 // Set the initial values of stack-allocated locals.
2372 for (int i = count; i < environment()->length(); ++i) {
2373 environment()->Bind(i, undefined_constant);
2374 }
2375
2376 // Handle the arguments and arguments shadow variables specially (they do
2377 // not have declarations).
2378 if (scope->arguments() != NULL) {
2379 if (!scope->arguments()->IsStackAllocated() ||
2380 (scope->arguments_shadow() != NULL &&
2381 !scope->arguments_shadow()->IsStackAllocated())) {
2382 BAILOUT("context-allocated arguments");
2383 }
2384 HArgumentsObject* object = new(zone()) HArgumentsObject;
2385 AddInstruction(object);
2386 graph()->SetArgumentsObject(object);
2387 environment()->Bind(scope->arguments(), object);
2388 if (scope->arguments_shadow() != NULL) {
2389 environment()->Bind(scope->arguments_shadow(), object);
2390 }
2391 }
2392 }
2393
2394
VisitStatements(ZoneList<Statement * > * statements)2395 void HGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) {
2396 for (int i = 0; i < statements->length(); i++) {
2397 Visit(statements->at(i));
2398 if (HasStackOverflow() || current_block() == NULL) break;
2399 }
2400 }
2401
2402
CreateBasicBlock(HEnvironment * env)2403 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) {
2404 HBasicBlock* b = graph()->CreateBasicBlock();
2405 b->SetInitialEnvironment(env);
2406 return b;
2407 }
2408
2409
CreateLoopHeaderBlock()2410 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
2411 HBasicBlock* header = graph()->CreateBasicBlock();
2412 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header);
2413 header->SetInitialEnvironment(entry_env);
2414 header->AttachLoopInformation();
2415 return header;
2416 }
2417
2418
VisitBlock(Block * stmt)2419 void HGraphBuilder::VisitBlock(Block* stmt) {
2420 BreakAndContinueInfo break_info(stmt);
2421 { BreakAndContinueScope push(&break_info, this);
2422 VisitStatements(stmt->statements());
2423 CHECK_BAILOUT;
2424 }
2425 HBasicBlock* break_block = break_info.break_block();
2426 if (break_block != NULL) {
2427 if (current_block() != NULL) current_block()->Goto(break_block);
2428 break_block->SetJoinId(stmt->ExitId());
2429 set_current_block(break_block);
2430 }
2431 }
2432
2433
VisitExpressionStatement(ExpressionStatement * stmt)2434 void HGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
2435 VisitForEffect(stmt->expression());
2436 }
2437
2438
VisitEmptyStatement(EmptyStatement * stmt)2439 void HGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
2440 }
2441
2442
VisitIfStatement(IfStatement * stmt)2443 void HGraphBuilder::VisitIfStatement(IfStatement* stmt) {
2444 if (stmt->condition()->ToBooleanIsTrue()) {
2445 AddSimulate(stmt->ThenId());
2446 Visit(stmt->then_statement());
2447 } else if (stmt->condition()->ToBooleanIsFalse()) {
2448 AddSimulate(stmt->ElseId());
2449 Visit(stmt->else_statement());
2450 } else {
2451 HBasicBlock* cond_true = graph()->CreateBasicBlock();
2452 HBasicBlock* cond_false = graph()->CreateBasicBlock();
2453 VISIT_FOR_CONTROL(stmt->condition(), cond_true, cond_false);
2454 cond_true->SetJoinId(stmt->ThenId());
2455 cond_false->SetJoinId(stmt->ElseId());
2456
2457 set_current_block(cond_true);
2458 Visit(stmt->then_statement());
2459 CHECK_BAILOUT;
2460 HBasicBlock* other = current_block();
2461
2462 set_current_block(cond_false);
2463 Visit(stmt->else_statement());
2464 CHECK_BAILOUT;
2465
2466 HBasicBlock* join = CreateJoin(other, current_block(), stmt->id());
2467 set_current_block(join);
2468 }
2469 }
2470
2471
Get(BreakableStatement * stmt,BreakType type)2472 HBasicBlock* HGraphBuilder::BreakAndContinueScope::Get(
2473 BreakableStatement* stmt,
2474 BreakType type) {
2475 BreakAndContinueScope* current = this;
2476 while (current != NULL && current->info()->target() != stmt) {
2477 current = current->next();
2478 }
2479 ASSERT(current != NULL); // Always found (unless stack is malformed).
2480 HBasicBlock* block = NULL;
2481 switch (type) {
2482 case BREAK:
2483 block = current->info()->break_block();
2484 if (block == NULL) {
2485 block = current->owner()->graph()->CreateBasicBlock();
2486 current->info()->set_break_block(block);
2487 }
2488 break;
2489
2490 case CONTINUE:
2491 block = current->info()->continue_block();
2492 if (block == NULL) {
2493 block = current->owner()->graph()->CreateBasicBlock();
2494 current->info()->set_continue_block(block);
2495 }
2496 break;
2497 }
2498
2499 return block;
2500 }
2501
2502
VisitContinueStatement(ContinueStatement * stmt)2503 void HGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
2504 HBasicBlock* continue_block = break_scope()->Get(stmt->target(), CONTINUE);
2505 current_block()->Goto(continue_block);
2506 set_current_block(NULL);
2507 }
2508
2509
VisitBreakStatement(BreakStatement * stmt)2510 void HGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
2511 HBasicBlock* break_block = break_scope()->Get(stmt->target(), BREAK);
2512 current_block()->Goto(break_block);
2513 set_current_block(NULL);
2514 }
2515
2516
VisitReturnStatement(ReturnStatement * stmt)2517 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
2518 AstContext* context = call_context();
2519 if (context == NULL) {
2520 // Not an inlined return, so an actual one.
2521 VISIT_FOR_VALUE(stmt->expression());
2522 HValue* result = environment()->Pop();
2523 current_block()->FinishExit(new(zone()) HReturn(result));
2524 set_current_block(NULL);
2525 } else {
2526 // Return from an inlined function, visit the subexpression in the
2527 // expression context of the call.
2528 if (context->IsTest()) {
2529 TestContext* test = TestContext::cast(context);
2530 VisitForControl(stmt->expression(),
2531 test->if_true(),
2532 test->if_false());
2533 } else if (context->IsEffect()) {
2534 VISIT_FOR_EFFECT(stmt->expression());
2535 current_block()->Goto(function_return(), false);
2536 } else {
2537 ASSERT(context->IsValue());
2538 VISIT_FOR_VALUE(stmt->expression());
2539 HValue* return_value = environment()->Pop();
2540 current_block()->AddLeaveInlined(return_value, function_return());
2541 }
2542 set_current_block(NULL);
2543 }
2544 }
2545
2546
VisitWithEnterStatement(WithEnterStatement * stmt)2547 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) {
2548 BAILOUT("WithEnterStatement");
2549 }
2550
2551
VisitWithExitStatement(WithExitStatement * stmt)2552 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) {
2553 BAILOUT("WithExitStatement");
2554 }
2555
2556
VisitSwitchStatement(SwitchStatement * stmt)2557 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
2558 // We only optimize switch statements with smi-literal smi comparisons,
2559 // with a bounded number of clauses.
2560 const int kCaseClauseLimit = 128;
2561 ZoneList<CaseClause*>* clauses = stmt->cases();
2562 int clause_count = clauses->length();
2563 if (clause_count > kCaseClauseLimit) {
2564 BAILOUT("SwitchStatement: too many clauses");
2565 }
2566
2567 VISIT_FOR_VALUE(stmt->tag());
2568 AddSimulate(stmt->EntryId());
2569 HValue* tag_value = Pop();
2570 HBasicBlock* first_test_block = current_block();
2571
2572 // 1. Build all the tests, with dangling true branches. Unconditionally
2573 // deoptimize if we encounter a non-smi comparison.
2574 for (int i = 0; i < clause_count; ++i) {
2575 CaseClause* clause = clauses->at(i);
2576 if (clause->is_default()) continue;
2577 if (!clause->label()->IsSmiLiteral()) {
2578 BAILOUT("SwitchStatement: non-literal switch label");
2579 }
2580
2581 // Unconditionally deoptimize on the first non-smi compare.
2582 clause->RecordTypeFeedback(oracle());
2583 if (!clause->IsSmiCompare()) {
2584 current_block()->FinishExitWithDeoptimization();
2585 set_current_block(NULL);
2586 break;
2587 }
2588
2589 // Otherwise generate a compare and branch.
2590 VISIT_FOR_VALUE(clause->label());
2591 HValue* label_value = Pop();
2592 HCompare* compare =
2593 new(zone()) HCompare(tag_value, label_value, Token::EQ_STRICT);
2594 compare->SetInputRepresentation(Representation::Integer32());
2595 ASSERT(!compare->HasSideEffects());
2596 AddInstruction(compare);
2597 HBasicBlock* body_block = graph()->CreateBasicBlock();
2598 HBasicBlock* next_test_block = graph()->CreateBasicBlock();
2599 HTest* branch = new(zone()) HTest(compare, body_block, next_test_block);
2600 current_block()->Finish(branch);
2601 set_current_block(next_test_block);
2602 }
2603
2604 // Save the current block to use for the default or to join with the
2605 // exit. This block is NULL if we deoptimized.
2606 HBasicBlock* last_block = current_block();
2607
2608 // 2. Loop over the clauses and the linked list of tests in lockstep,
2609 // translating the clause bodies.
2610 HBasicBlock* curr_test_block = first_test_block;
2611 HBasicBlock* fall_through_block = NULL;
2612 BreakAndContinueInfo break_info(stmt);
2613 { BreakAndContinueScope push(&break_info, this);
2614 for (int i = 0; i < clause_count; ++i) {
2615 CaseClause* clause = clauses->at(i);
2616
2617 // Identify the block where normal (non-fall-through) control flow
2618 // goes to.
2619 HBasicBlock* normal_block = NULL;
2620 if (clause->is_default()) {
2621 if (last_block != NULL) {
2622 normal_block = last_block;
2623 last_block = NULL; // Cleared to indicate we've handled it.
2624 }
2625 } else if (!curr_test_block->end()->IsDeoptimize()) {
2626 normal_block = curr_test_block->end()->FirstSuccessor();
2627 curr_test_block = curr_test_block->end()->SecondSuccessor();
2628 }
2629
2630 // Identify a block to emit the body into.
2631 if (normal_block == NULL) {
2632 if (fall_through_block == NULL) {
2633 // (a) Unreachable.
2634 if (clause->is_default()) {
2635 continue; // Might still be reachable clause bodies.
2636 } else {
2637 break;
2638 }
2639 } else {
2640 // (b) Reachable only as fall through.
2641 set_current_block(fall_through_block);
2642 }
2643 } else if (fall_through_block == NULL) {
2644 // (c) Reachable only normally.
2645 set_current_block(normal_block);
2646 } else {
2647 // (d) Reachable both ways.
2648 HBasicBlock* join = CreateJoin(fall_through_block,
2649 normal_block,
2650 clause->EntryId());
2651 set_current_block(join);
2652 }
2653
2654 VisitStatements(clause->statements());
2655 CHECK_BAILOUT;
2656 fall_through_block = current_block();
2657 }
2658 }
2659
2660 // Create an up-to-3-way join. Use the break block if it exists since
2661 // it's already a join block.
2662 HBasicBlock* break_block = break_info.break_block();
2663 if (break_block == NULL) {
2664 set_current_block(CreateJoin(fall_through_block,
2665 last_block,
2666 stmt->ExitId()));
2667 } else {
2668 if (fall_through_block != NULL) fall_through_block->Goto(break_block);
2669 if (last_block != NULL) last_block->Goto(break_block);
2670 break_block->SetJoinId(stmt->ExitId());
2671 set_current_block(break_block);
2672 }
2673 }
2674
2675
HasOsrEntryAt(IterationStatement * statement)2676 bool HGraphBuilder::HasOsrEntryAt(IterationStatement* statement) {
2677 return statement->OsrEntryId() == info()->osr_ast_id();
2678 }
2679
2680
PreProcessOsrEntry(IterationStatement * statement)2681 void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) {
2682 if (!HasOsrEntryAt(statement)) return;
2683
2684 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock();
2685 HBasicBlock* osr_entry = graph()->CreateBasicBlock();
2686 HValue* true_value = graph()->GetConstantTrue();
2687 HTest* test = new(zone()) HTest(true_value, non_osr_entry, osr_entry);
2688 current_block()->Finish(test);
2689
2690 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock();
2691 non_osr_entry->Goto(loop_predecessor);
2692
2693 set_current_block(osr_entry);
2694 int osr_entry_id = statement->OsrEntryId();
2695 // We want the correct environment at the OsrEntry instruction. Build
2696 // it explicitly. The expression stack should be empty.
2697 int count = environment()->length();
2698 ASSERT(count ==
2699 (environment()->parameter_count() + environment()->local_count()));
2700 for (int i = 0; i < count; ++i) {
2701 HUnknownOSRValue* unknown = new(zone()) HUnknownOSRValue;
2702 AddInstruction(unknown);
2703 environment()->Bind(i, unknown);
2704 }
2705
2706 AddSimulate(osr_entry_id);
2707 AddInstruction(new(zone()) HOsrEntry(osr_entry_id));
2708 current_block()->Goto(loop_predecessor);
2709 loop_predecessor->SetJoinId(statement->EntryId());
2710 set_current_block(loop_predecessor);
2711 }
2712
2713
VisitDoWhileStatement(DoWhileStatement * stmt)2714 void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
2715 ASSERT(current_block() != NULL);
2716 PreProcessOsrEntry(stmt);
2717 HBasicBlock* loop_entry = CreateLoopHeaderBlock();
2718 current_block()->Goto(loop_entry, false);
2719 set_current_block(loop_entry);
2720
2721 BreakAndContinueInfo break_info(stmt);
2722 { BreakAndContinueScope push(&break_info, this);
2723 Visit(stmt->body());
2724 CHECK_BAILOUT;
2725 }
2726 HBasicBlock* body_exit =
2727 JoinContinue(stmt, current_block(), break_info.continue_block());
2728 HBasicBlock* loop_successor = NULL;
2729 if (body_exit != NULL && !stmt->cond()->ToBooleanIsTrue()) {
2730 set_current_block(body_exit);
2731 // The block for a true condition, the actual predecessor block of the
2732 // back edge.
2733 body_exit = graph()->CreateBasicBlock();
2734 loop_successor = graph()->CreateBasicBlock();
2735 VISIT_FOR_CONTROL(stmt->cond(), body_exit, loop_successor);
2736 body_exit->SetJoinId(stmt->BackEdgeId());
2737 loop_successor->SetJoinId(stmt->ExitId());
2738 }
2739 HBasicBlock* loop_exit = CreateLoop(stmt,
2740 loop_entry,
2741 body_exit,
2742 loop_successor,
2743 break_info.break_block());
2744 set_current_block(loop_exit);
2745 }
2746
2747
VisitWhileStatement(WhileStatement * stmt)2748 void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
2749 ASSERT(current_block() != NULL);
2750 PreProcessOsrEntry(stmt);
2751 HBasicBlock* loop_entry = CreateLoopHeaderBlock();
2752 current_block()->Goto(loop_entry, false);
2753 set_current_block(loop_entry);
2754
2755 // If the condition is constant true, do not generate a branch.
2756 HBasicBlock* loop_successor = NULL;
2757 if (!stmt->cond()->ToBooleanIsTrue()) {
2758 HBasicBlock* body_entry = graph()->CreateBasicBlock();
2759 loop_successor = graph()->CreateBasicBlock();
2760 VISIT_FOR_CONTROL(stmt->cond(), body_entry, loop_successor);
2761 body_entry->SetJoinId(stmt->BodyId());
2762 loop_successor->SetJoinId(stmt->ExitId());
2763 set_current_block(body_entry);
2764 }
2765
2766 BreakAndContinueInfo break_info(stmt);
2767 { BreakAndContinueScope push(&break_info, this);
2768 Visit(stmt->body());
2769 CHECK_BAILOUT;
2770 }
2771 HBasicBlock* body_exit =
2772 JoinContinue(stmt, current_block(), break_info.continue_block());
2773 HBasicBlock* loop_exit = CreateLoop(stmt,
2774 loop_entry,
2775 body_exit,
2776 loop_successor,
2777 break_info.break_block());
2778 set_current_block(loop_exit);
2779 }
2780
2781
VisitForStatement(ForStatement * stmt)2782 void HGraphBuilder::VisitForStatement(ForStatement* stmt) {
2783 if (stmt->init() != NULL) {
2784 Visit(stmt->init());
2785 CHECK_BAILOUT;
2786 }
2787 ASSERT(current_block() != NULL);
2788 PreProcessOsrEntry(stmt);
2789 HBasicBlock* loop_entry = CreateLoopHeaderBlock();
2790 current_block()->Goto(loop_entry, false);
2791 set_current_block(loop_entry);
2792
2793 HBasicBlock* loop_successor = NULL;
2794 if (stmt->cond() != NULL) {
2795 HBasicBlock* body_entry = graph()->CreateBasicBlock();
2796 loop_successor = graph()->CreateBasicBlock();
2797 VISIT_FOR_CONTROL(stmt->cond(), body_entry, loop_successor);
2798 body_entry->SetJoinId(stmt->BodyId());
2799 loop_successor->SetJoinId(stmt->ExitId());
2800 set_current_block(body_entry);
2801 }
2802
2803 BreakAndContinueInfo break_info(stmt);
2804 { BreakAndContinueScope push(&break_info, this);
2805 Visit(stmt->body());
2806 CHECK_BAILOUT;
2807 }
2808 HBasicBlock* body_exit =
2809 JoinContinue(stmt, current_block(), break_info.continue_block());
2810
2811 if (stmt->next() != NULL && body_exit != NULL) {
2812 set_current_block(body_exit);
2813 Visit(stmt->next());
2814 CHECK_BAILOUT;
2815 body_exit = current_block();
2816 }
2817
2818 HBasicBlock* loop_exit = CreateLoop(stmt,
2819 loop_entry,
2820 body_exit,
2821 loop_successor,
2822 break_info.break_block());
2823 set_current_block(loop_exit);
2824 }
2825
2826
VisitForInStatement(ForInStatement * stmt)2827 void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
2828 BAILOUT("ForInStatement");
2829 }
2830
2831
VisitTryCatchStatement(TryCatchStatement * stmt)2832 void HGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
2833 BAILOUT("TryCatchStatement");
2834 }
2835
2836
VisitTryFinallyStatement(TryFinallyStatement * stmt)2837 void HGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
2838 BAILOUT("TryFinallyStatement");
2839 }
2840
2841
VisitDebuggerStatement(DebuggerStatement * stmt)2842 void HGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
2843 BAILOUT("DebuggerStatement");
2844 }
2845
2846
SearchSharedFunctionInfo(Code * unoptimized_code,FunctionLiteral * expr)2847 static Handle<SharedFunctionInfo> SearchSharedFunctionInfo(
2848 Code* unoptimized_code, FunctionLiteral* expr) {
2849 int start_position = expr->start_position();
2850 RelocIterator it(unoptimized_code);
2851 for (;!it.done(); it.next()) {
2852 RelocInfo* rinfo = it.rinfo();
2853 if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue;
2854 Object* obj = rinfo->target_object();
2855 if (obj->IsSharedFunctionInfo()) {
2856 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
2857 if (shared->start_position() == start_position) {
2858 return Handle<SharedFunctionInfo>(shared);
2859 }
2860 }
2861 }
2862
2863 return Handle<SharedFunctionInfo>();
2864 }
2865
2866
VisitFunctionLiteral(FunctionLiteral * expr)2867 void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
2868 Handle<SharedFunctionInfo> shared_info =
2869 SearchSharedFunctionInfo(info()->shared_info()->code(),
2870 expr);
2871 if (shared_info.is_null()) {
2872 shared_info = Compiler::BuildFunctionInfo(expr, info()->script());
2873 }
2874 CHECK_BAILOUT;
2875 HFunctionLiteral* instr =
2876 new(zone()) HFunctionLiteral(shared_info, expr->pretenure());
2877 ast_context()->ReturnInstruction(instr, expr->id());
2878 }
2879
2880
VisitSharedFunctionInfoLiteral(SharedFunctionInfoLiteral * expr)2881 void HGraphBuilder::VisitSharedFunctionInfoLiteral(
2882 SharedFunctionInfoLiteral* expr) {
2883 BAILOUT("SharedFunctionInfoLiteral");
2884 }
2885
2886
VisitConditional(Conditional * expr)2887 void HGraphBuilder::VisitConditional(Conditional* expr) {
2888 HBasicBlock* cond_true = graph()->CreateBasicBlock();
2889 HBasicBlock* cond_false = graph()->CreateBasicBlock();
2890 VISIT_FOR_CONTROL(expr->condition(), cond_true, cond_false);
2891 cond_true->SetJoinId(expr->ThenId());
2892 cond_false->SetJoinId(expr->ElseId());
2893
2894 // Visit the true and false subexpressions in the same AST context as the
2895 // whole expression.
2896 set_current_block(cond_true);
2897 Visit(expr->then_expression());
2898 CHECK_BAILOUT;
2899 HBasicBlock* other = current_block();
2900
2901 set_current_block(cond_false);
2902 Visit(expr->else_expression());
2903 CHECK_BAILOUT;
2904
2905 if (!ast_context()->IsTest()) {
2906 HBasicBlock* join = CreateJoin(other, current_block(), expr->id());
2907 set_current_block(join);
2908 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
2909 }
2910 }
2911
2912
LookupGlobalProperty(Variable * var,LookupResult * lookup,bool is_store)2913 HGraphBuilder::GlobalPropertyAccess HGraphBuilder::LookupGlobalProperty(
2914 Variable* var, LookupResult* lookup, bool is_store) {
2915 if (var->is_this() || !info()->has_global_object()) {
2916 return kUseGeneric;
2917 }
2918 Handle<GlobalObject> global(info()->global_object());
2919 global->Lookup(*var->name(), lookup);
2920 if (!lookup->IsProperty() ||
2921 lookup->type() != NORMAL ||
2922 (is_store && lookup->IsReadOnly()) ||
2923 lookup->holder() != *global) {
2924 return kUseGeneric;
2925 }
2926
2927 return kUseCell;
2928 }
2929
2930
BuildContextChainWalk(Variable * var)2931 HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) {
2932 ASSERT(var->IsContextSlot());
2933 HInstruction* context = new(zone()) HContext;
2934 AddInstruction(context);
2935 int length = info()->scope()->ContextChainLength(var->scope());
2936 while (length-- > 0) {
2937 context = new(zone()) HOuterContext(context);
2938 AddInstruction(context);
2939 }
2940 return context;
2941 }
2942
2943
VisitVariableProxy(VariableProxy * expr)2944 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
2945 Variable* variable = expr->AsVariable();
2946 if (variable == NULL) {
2947 BAILOUT("reference to rewritten variable");
2948 } else if (variable->IsStackAllocated()) {
2949 if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) {
2950 BAILOUT("unsupported context for arguments object");
2951 }
2952 ast_context()->ReturnValue(environment()->Lookup(variable));
2953 } else if (variable->IsContextSlot()) {
2954 if (variable->mode() == Variable::CONST) {
2955 BAILOUT("reference to const context slot");
2956 }
2957 HValue* context = BuildContextChainWalk(variable);
2958 int index = variable->AsSlot()->index();
2959 HLoadContextSlot* instr = new(zone()) HLoadContextSlot(context, index);
2960 ast_context()->ReturnInstruction(instr, expr->id());
2961 } else if (variable->is_global()) {
2962 LookupResult lookup;
2963 GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup, false);
2964
2965 if (type == kUseCell &&
2966 info()->global_object()->IsAccessCheckNeeded()) {
2967 type = kUseGeneric;
2968 }
2969
2970 if (type == kUseCell) {
2971 Handle<GlobalObject> global(info()->global_object());
2972 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
2973 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
2974 HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole);
2975 ast_context()->ReturnInstruction(instr, expr->id());
2976 } else {
2977 HContext* context = new(zone()) HContext;
2978 AddInstruction(context);
2979 HGlobalObject* global_object = new(zone()) HGlobalObject(context);
2980 AddInstruction(global_object);
2981 HLoadGlobalGeneric* instr =
2982 new(zone()) HLoadGlobalGeneric(context,
2983 global_object,
2984 variable->name(),
2985 ast_context()->is_for_typeof());
2986 instr->set_position(expr->position());
2987 ASSERT(instr->HasSideEffects());
2988 ast_context()->ReturnInstruction(instr, expr->id());
2989 }
2990 } else {
2991 BAILOUT("reference to a variable which requires dynamic lookup");
2992 }
2993 }
2994
2995
VisitLiteral(Literal * expr)2996 void HGraphBuilder::VisitLiteral(Literal* expr) {
2997 HConstant* instr =
2998 new(zone()) HConstant(expr->handle(), Representation::Tagged());
2999 ast_context()->ReturnInstruction(instr, expr->id());
3000 }
3001
3002
VisitRegExpLiteral(RegExpLiteral * expr)3003 void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
3004 HRegExpLiteral* instr = new(zone()) HRegExpLiteral(expr->pattern(),
3005 expr->flags(),
3006 expr->literal_index());
3007 ast_context()->ReturnInstruction(instr, expr->id());
3008 }
3009
3010
VisitObjectLiteral(ObjectLiteral * expr)3011 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
3012 HContext* context = new(zone()) HContext;
3013 AddInstruction(context);
3014 HObjectLiteral* literal =
3015 new(zone()) HObjectLiteral(context,
3016 expr->constant_properties(),
3017 expr->fast_elements(),
3018 expr->literal_index(),
3019 expr->depth(),
3020 expr->has_function());
3021 // The object is expected in the bailout environment during computation
3022 // of the property values and is the value of the entire expression.
3023 PushAndAdd(literal);
3024
3025 expr->CalculateEmitStore();
3026
3027 for (int i = 0; i < expr->properties()->length(); i++) {
3028 ObjectLiteral::Property* property = expr->properties()->at(i);
3029 if (property->IsCompileTimeValue()) continue;
3030
3031 Literal* key = property->key();
3032 Expression* value = property->value();
3033
3034 switch (property->kind()) {
3035 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
3036 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
3037 // Fall through.
3038 case ObjectLiteral::Property::COMPUTED:
3039 if (key->handle()->IsSymbol()) {
3040 if (property->emit_store()) {
3041 VISIT_FOR_VALUE(value);
3042 HValue* value = Pop();
3043 Handle<String> name = Handle<String>::cast(key->handle());
3044 HStoreNamedGeneric* store =
3045 new(zone()) HStoreNamedGeneric(
3046 context,
3047 literal,
3048 name,
3049 value,
3050 function_strict_mode());
3051 AddInstruction(store);
3052 AddSimulate(key->id());
3053 } else {
3054 VISIT_FOR_EFFECT(value);
3055 }
3056 break;
3057 }
3058 // Fall through.
3059 case ObjectLiteral::Property::PROTOTYPE:
3060 case ObjectLiteral::Property::SETTER:
3061 case ObjectLiteral::Property::GETTER:
3062 BAILOUT("Object literal with complex property");
3063 default: UNREACHABLE();
3064 }
3065 }
3066
3067 if (expr->has_function()) {
3068 // Return the result of the transformation to fast properties
3069 // instead of the original since this operation changes the map
3070 // of the object. This makes sure that the original object won't
3071 // be used by other optimized code before it is transformed
3072 // (e.g. because of code motion).
3073 HToFastProperties* result = new(zone()) HToFastProperties(Pop());
3074 AddInstruction(result);
3075 ast_context()->ReturnValue(result);
3076 } else {
3077 ast_context()->ReturnValue(Pop());
3078 }
3079 }
3080
3081
VisitArrayLiteral(ArrayLiteral * expr)3082 void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
3083 ZoneList<Expression*>* subexprs = expr->values();
3084 int length = subexprs->length();
3085
3086 HArrayLiteral* literal = new(zone()) HArrayLiteral(expr->constant_elements(),
3087 length,
3088 expr->literal_index(),
3089 expr->depth());
3090 // The array is expected in the bailout environment during computation
3091 // of the property values and is the value of the entire expression.
3092 PushAndAdd(literal);
3093
3094 HLoadElements* elements = NULL;
3095
3096 for (int i = 0; i < length; i++) {
3097 Expression* subexpr = subexprs->at(i);
3098 // If the subexpression is a literal or a simple materialized literal it
3099 // is already set in the cloned array.
3100 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
3101
3102 VISIT_FOR_VALUE(subexpr);
3103 HValue* value = Pop();
3104 if (!Smi::IsValid(i)) BAILOUT("Non-smi key in array literal");
3105
3106 // Load the elements array before the first store.
3107 if (elements == NULL) {
3108 elements = new(zone()) HLoadElements(literal);
3109 AddInstruction(elements);
3110 }
3111
3112 HValue* key = AddInstruction(
3113 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)),
3114 Representation::Integer32()));
3115 AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value));
3116 AddSimulate(expr->GetIdForElement(i));
3117 }
3118 ast_context()->ReturnValue(Pop());
3119 }
3120
3121
VisitCatchExtensionObject(CatchExtensionObject * expr)3122 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) {
3123 BAILOUT("CatchExtensionObject");
3124 }
3125
3126
3127 // Sets the lookup result and returns true if the store can be inlined.
ComputeStoredField(Handle<Map> type,Handle<String> name,LookupResult * lookup)3128 static bool ComputeStoredField(Handle<Map> type,
3129 Handle<String> name,
3130 LookupResult* lookup) {
3131 type->LookupInDescriptors(NULL, *name, lookup);
3132 if (!lookup->IsPropertyOrTransition()) return false;
3133 if (lookup->type() == FIELD) return true;
3134 return (lookup->type() == MAP_TRANSITION) &&
3135 (type->unused_property_fields() > 0);
3136 }
3137
3138
ComputeStoredFieldIndex(Handle<Map> type,Handle<String> name,LookupResult * lookup)3139 static int ComputeStoredFieldIndex(Handle<Map> type,
3140 Handle<String> name,
3141 LookupResult* lookup) {
3142 ASSERT(lookup->type() == FIELD || lookup->type() == MAP_TRANSITION);
3143 if (lookup->type() == FIELD) {
3144 return lookup->GetLocalFieldIndexFromMap(*type);
3145 } else {
3146 Map* transition = lookup->GetTransitionMapFromMap(*type);
3147 return transition->PropertyIndexFor(*name) - type->inobject_properties();
3148 }
3149 }
3150
3151
BuildStoreNamedField(HValue * object,Handle<String> name,HValue * value,Handle<Map> type,LookupResult * lookup,bool smi_and_map_check)3152 HInstruction* HGraphBuilder::BuildStoreNamedField(HValue* object,
3153 Handle<String> name,
3154 HValue* value,
3155 Handle<Map> type,
3156 LookupResult* lookup,
3157 bool smi_and_map_check) {
3158 if (smi_and_map_check) {
3159 AddInstruction(new(zone()) HCheckNonSmi(object));
3160 AddInstruction(new(zone()) HCheckMap(object, type));
3161 }
3162
3163 int index = ComputeStoredFieldIndex(type, name, lookup);
3164 bool is_in_object = index < 0;
3165 int offset = index * kPointerSize;
3166 if (index < 0) {
3167 // Negative property indices are in-object properties, indexed
3168 // from the end of the fixed part of the object.
3169 offset += type->instance_size();
3170 } else {
3171 offset += FixedArray::kHeaderSize;
3172 }
3173 HStoreNamedField* instr =
3174 new(zone()) HStoreNamedField(object, name, value, is_in_object, offset);
3175 if (lookup->type() == MAP_TRANSITION) {
3176 Handle<Map> transition(lookup->GetTransitionMapFromMap(*type));
3177 instr->set_transition(transition);
3178 // TODO(fschneider): Record the new map type of the object in the IR to
3179 // enable elimination of redundant checks after the transition store.
3180 instr->SetFlag(HValue::kChangesMaps);
3181 }
3182 return instr;
3183 }
3184
3185
BuildStoreNamedGeneric(HValue * object,Handle<String> name,HValue * value)3186 HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object,
3187 Handle<String> name,
3188 HValue* value) {
3189 HContext* context = new(zone()) HContext;
3190 AddInstruction(context);
3191 return new(zone()) HStoreNamedGeneric(
3192 context,
3193 object,
3194 name,
3195 value,
3196 function_strict_mode());
3197 }
3198
3199
BuildStoreNamed(HValue * object,HValue * value,Expression * expr)3200 HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object,
3201 HValue* value,
3202 Expression* expr) {
3203 Property* prop = (expr->AsProperty() != NULL)
3204 ? expr->AsProperty()
3205 : expr->AsAssignment()->target()->AsProperty();
3206 Literal* key = prop->key()->AsLiteral();
3207 Handle<String> name = Handle<String>::cast(key->handle());
3208 ASSERT(!name.is_null());
3209
3210 LookupResult lookup;
3211 ZoneMapList* types = expr->GetReceiverTypes();
3212 bool is_monomorphic = expr->IsMonomorphic() &&
3213 ComputeStoredField(types->first(), name, &lookup);
3214
3215 return is_monomorphic
3216 ? BuildStoreNamedField(object, name, value, types->first(), &lookup,
3217 true) // Needs smi and map check.
3218 : BuildStoreNamedGeneric(object, name, value);
3219 }
3220
3221
HandlePolymorphicStoreNamedField(Assignment * expr,HValue * object,HValue * value,ZoneMapList * types,Handle<String> name)3222 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr,
3223 HValue* object,
3224 HValue* value,
3225 ZoneMapList* types,
3226 Handle<String> name) {
3227 // TODO(ager): We should recognize when the prototype chains for different
3228 // maps are identical. In that case we can avoid repeatedly generating the
3229 // same prototype map checks.
3230 int count = 0;
3231 HBasicBlock* join = NULL;
3232 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) {
3233 Handle<Map> map = types->at(i);
3234 LookupResult lookup;
3235 if (ComputeStoredField(map, name, &lookup)) {
3236 if (count == 0) {
3237 AddInstruction(new(zone()) HCheckNonSmi(object)); // Only needed once.
3238 join = graph()->CreateBasicBlock();
3239 }
3240 ++count;
3241 HBasicBlock* if_true = graph()->CreateBasicBlock();
3242 HBasicBlock* if_false = graph()->CreateBasicBlock();
3243 HCompareMap* compare =
3244 new(zone()) HCompareMap(object, map, if_true, if_false);
3245 current_block()->Finish(compare);
3246
3247 set_current_block(if_true);
3248 HInstruction* instr =
3249 BuildStoreNamedField(object, name, value, map, &lookup, false);
3250 instr->set_position(expr->position());
3251 // Goto will add the HSimulate for the store.
3252 AddInstruction(instr);
3253 if (!ast_context()->IsEffect()) Push(value);
3254 current_block()->Goto(join);
3255
3256 set_current_block(if_false);
3257 }
3258 }
3259
3260 // Finish up. Unconditionally deoptimize if we've handled all the maps we
3261 // know about and do not want to handle ones we've never seen. Otherwise
3262 // use a generic IC.
3263 if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
3264 current_block()->FinishExitWithDeoptimization();
3265 } else {
3266 HInstruction* instr = BuildStoreNamedGeneric(object, name, value);
3267 instr->set_position(expr->position());
3268 AddInstruction(instr);
3269
3270 if (join != NULL) {
3271 if (!ast_context()->IsEffect()) Push(value);
3272 current_block()->Goto(join);
3273 } else {
3274 // The HSimulate for the store should not see the stored value in
3275 // effect contexts (it is not materialized at expr->id() in the
3276 // unoptimized code).
3277 if (instr->HasSideEffects()) {
3278 if (ast_context()->IsEffect()) {
3279 AddSimulate(expr->id());
3280 } else {
3281 Push(value);
3282 AddSimulate(expr->id());
3283 Drop(1);
3284 }
3285 }
3286 ast_context()->ReturnValue(value);
3287 return;
3288 }
3289 }
3290
3291 ASSERT(join != NULL);
3292 join->SetJoinId(expr->id());
3293 set_current_block(join);
3294 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
3295 }
3296
3297
HandlePropertyAssignment(Assignment * expr)3298 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
3299 Property* prop = expr->target()->AsProperty();
3300 ASSERT(prop != NULL);
3301 expr->RecordTypeFeedback(oracle());
3302 VISIT_FOR_VALUE(prop->obj());
3303
3304 HValue* value = NULL;
3305 HInstruction* instr = NULL;
3306
3307 if (prop->key()->IsPropertyName()) {
3308 // Named store.
3309 VISIT_FOR_VALUE(expr->value());
3310 value = Pop();
3311 HValue* object = Pop();
3312
3313 Literal* key = prop->key()->AsLiteral();
3314 Handle<String> name = Handle<String>::cast(key->handle());
3315 ASSERT(!name.is_null());
3316
3317 ZoneMapList* types = expr->GetReceiverTypes();
3318 LookupResult lookup;
3319
3320 if (expr->IsMonomorphic()) {
3321 instr = BuildStoreNamed(object, value, expr);
3322
3323 } else if (types != NULL && types->length() > 1) {
3324 HandlePolymorphicStoreNamedField(expr, object, value, types, name);
3325 return;
3326
3327 } else {
3328 instr = BuildStoreNamedGeneric(object, name, value);
3329 }
3330
3331 } else {
3332 // Keyed store.
3333 VISIT_FOR_VALUE(prop->key());
3334 VISIT_FOR_VALUE(expr->value());
3335 value = Pop();
3336 HValue* key = Pop();
3337 HValue* object = Pop();
3338 instr = BuildStoreKeyed(object, key, value, expr);
3339 }
3340 Push(value);
3341 instr->set_position(expr->position());
3342 AddInstruction(instr);
3343 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
3344 ast_context()->ReturnValue(Pop());
3345 }
3346
3347
3348 // Because not every expression has a position and there is not common
3349 // superclass of Assignment and CountOperation, we cannot just pass the
3350 // owning expression instead of position and ast_id separately.
HandleGlobalVariableAssignment(Variable * var,HValue * value,int position,int ast_id)3351 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var,
3352 HValue* value,
3353 int position,
3354 int ast_id) {
3355 LookupResult lookup;
3356 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true);
3357 if (type == kUseCell) {
3358 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
3359 Handle<GlobalObject> global(info()->global_object());
3360 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
3361 HInstruction* instr = new(zone()) HStoreGlobalCell(value, cell, check_hole);
3362 instr->set_position(position);
3363 AddInstruction(instr);
3364 if (instr->HasSideEffects()) AddSimulate(ast_id);
3365 } else {
3366 HContext* context = new(zone()) HContext;
3367 AddInstruction(context);
3368 HGlobalObject* global_object = new(zone()) HGlobalObject(context);
3369 AddInstruction(global_object);
3370 HStoreGlobalGeneric* instr =
3371 new(zone()) HStoreGlobalGeneric(context,
3372 global_object,
3373 var->name(),
3374 value,
3375 function_strict_mode());
3376 instr->set_position(position);
3377 AddInstruction(instr);
3378 ASSERT(instr->HasSideEffects());
3379 if (instr->HasSideEffects()) AddSimulate(ast_id);
3380 }
3381 }
3382
3383
HandleCompoundAssignment(Assignment * expr)3384 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
3385 Expression* target = expr->target();
3386 VariableProxy* proxy = target->AsVariableProxy();
3387 Variable* var = proxy->AsVariable();
3388 Property* prop = target->AsProperty();
3389 ASSERT(var == NULL || prop == NULL);
3390
3391 // We have a second position recorded in the FullCodeGenerator to have
3392 // type feedback for the binary operation.
3393 BinaryOperation* operation = expr->binary_operation();
3394
3395 if (var != NULL) {
3396 VISIT_FOR_VALUE(operation);
3397
3398 if (var->is_global()) {
3399 HandleGlobalVariableAssignment(var,
3400 Top(),
3401 expr->position(),
3402 expr->AssignmentId());
3403 } else if (var->IsStackAllocated()) {
3404 Bind(var, Top());
3405 } else if (var->IsContextSlot()) {
3406 HValue* context = BuildContextChainWalk(var);
3407 int index = var->AsSlot()->index();
3408 HStoreContextSlot* instr =
3409 new(zone()) HStoreContextSlot(context, index, Top());
3410 AddInstruction(instr);
3411 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
3412 } else {
3413 BAILOUT("compound assignment to lookup slot");
3414 }
3415 ast_context()->ReturnValue(Pop());
3416
3417 } else if (prop != NULL) {
3418 prop->RecordTypeFeedback(oracle());
3419
3420 if (prop->key()->IsPropertyName()) {
3421 // Named property.
3422 VISIT_FOR_VALUE(prop->obj());
3423 HValue* obj = Top();
3424
3425 HInstruction* load = NULL;
3426 if (prop->IsMonomorphic()) {
3427 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
3428 Handle<Map> map = prop->GetReceiverTypes()->first();
3429 load = BuildLoadNamed(obj, prop, map, name);
3430 } else {
3431 load = BuildLoadNamedGeneric(obj, prop);
3432 }
3433 PushAndAdd(load);
3434 if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId());
3435
3436 VISIT_FOR_VALUE(expr->value());
3437 HValue* right = Pop();
3438 HValue* left = Pop();
3439
3440 HInstruction* instr = BuildBinaryOperation(operation, left, right);
3441 PushAndAdd(instr);
3442 if (instr->HasSideEffects()) AddSimulate(operation->id());
3443
3444 HInstruction* store = BuildStoreNamed(obj, instr, prop);
3445 AddInstruction(store);
3446 // Drop the simulated receiver and value. Return the value.
3447 Drop(2);
3448 Push(instr);
3449 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId());
3450 ast_context()->ReturnValue(Pop());
3451
3452 } else {
3453 // Keyed property.
3454 VISIT_FOR_VALUE(prop->obj());
3455 VISIT_FOR_VALUE(prop->key());
3456 HValue* obj = environment()->ExpressionStackAt(1);
3457 HValue* key = environment()->ExpressionStackAt(0);
3458
3459 HInstruction* load = BuildLoadKeyed(obj, key, prop);
3460 PushAndAdd(load);
3461 if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId());
3462
3463 VISIT_FOR_VALUE(expr->value());
3464 HValue* right = Pop();
3465 HValue* left = Pop();
3466
3467 HInstruction* instr = BuildBinaryOperation(operation, left, right);
3468 PushAndAdd(instr);
3469 if (instr->HasSideEffects()) AddSimulate(operation->id());
3470
3471 expr->RecordTypeFeedback(oracle());
3472 HInstruction* store = BuildStoreKeyed(obj, key, instr, expr);
3473 AddInstruction(store);
3474 // Drop the simulated receiver, key, and value. Return the value.
3475 Drop(3);
3476 Push(instr);
3477 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId());
3478 ast_context()->ReturnValue(Pop());
3479 }
3480
3481 } else {
3482 BAILOUT("invalid lhs in compound assignment");
3483 }
3484 }
3485
3486
VisitAssignment(Assignment * expr)3487 void HGraphBuilder::VisitAssignment(Assignment* expr) {
3488 VariableProxy* proxy = expr->target()->AsVariableProxy();
3489 Variable* var = proxy->AsVariable();
3490 Property* prop = expr->target()->AsProperty();
3491 ASSERT(var == NULL || prop == NULL);
3492
3493 if (expr->is_compound()) {
3494 HandleCompoundAssignment(expr);
3495 return;
3496 }
3497
3498 if (var != NULL) {
3499 if (proxy->IsArguments()) BAILOUT("assignment to arguments");
3500
3501 // Handle the assignment.
3502 if (var->IsStackAllocated()) {
3503 HValue* value = NULL;
3504 // Handle stack-allocated variables on the right-hand side directly.
3505 // We do not allow the arguments object to occur in a context where it
3506 // may escape, but assignments to stack-allocated locals are
3507 // permitted. Handling such assignments here bypasses the check for
3508 // the arguments object in VisitVariableProxy.
3509 Variable* rhs_var = expr->value()->AsVariableProxy()->AsVariable();
3510 if (rhs_var != NULL && rhs_var->IsStackAllocated()) {
3511 value = environment()->Lookup(rhs_var);
3512 } else {
3513 VISIT_FOR_VALUE(expr->value());
3514 value = Pop();
3515 }
3516 Bind(var, value);
3517 ast_context()->ReturnValue(value);
3518
3519 } else if (var->IsContextSlot() && var->mode() != Variable::CONST) {
3520 VISIT_FOR_VALUE(expr->value());
3521 HValue* context = BuildContextChainWalk(var);
3522 int index = var->AsSlot()->index();
3523 HStoreContextSlot* instr =
3524 new(zone()) HStoreContextSlot(context, index, Top());
3525 AddInstruction(instr);
3526 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
3527 ast_context()->ReturnValue(Pop());
3528
3529 } else if (var->is_global()) {
3530 VISIT_FOR_VALUE(expr->value());
3531 HandleGlobalVariableAssignment(var,
3532 Top(),
3533 expr->position(),
3534 expr->AssignmentId());
3535 ast_context()->ReturnValue(Pop());
3536
3537 } else {
3538 BAILOUT("assignment to LOOKUP or const CONTEXT variable");
3539 }
3540
3541 } else if (prop != NULL) {
3542 HandlePropertyAssignment(expr);
3543 } else {
3544 BAILOUT("invalid left-hand side in assignment");
3545 }
3546 }
3547
3548
VisitThrow(Throw * expr)3549 void HGraphBuilder::VisitThrow(Throw* expr) {
3550 // We don't optimize functions with invalid left-hand sides in
3551 // assignments, count operations, or for-in. Consequently throw can
3552 // currently only occur in an effect context.
3553 ASSERT(ast_context()->IsEffect());
3554 VISIT_FOR_VALUE(expr->exception());
3555
3556 HValue* value = environment()->Pop();
3557 HThrow* instr = new(zone()) HThrow(value);
3558 instr->set_position(expr->position());
3559 AddInstruction(instr);
3560 AddSimulate(expr->id());
3561 current_block()->FinishExit(new(zone()) HAbnormalExit);
3562 set_current_block(NULL);
3563 }
3564
3565
BuildLoadNamedField(HValue * object,Property * expr,Handle<Map> type,LookupResult * lookup,bool smi_and_map_check)3566 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object,
3567 Property* expr,
3568 Handle<Map> type,
3569 LookupResult* lookup,
3570 bool smi_and_map_check) {
3571 if (smi_and_map_check) {
3572 AddInstruction(new(zone()) HCheckNonSmi(object));
3573 AddInstruction(new(zone()) HCheckMap(object, type));
3574 }
3575
3576 int index = lookup->GetLocalFieldIndexFromMap(*type);
3577 if (index < 0) {
3578 // Negative property indices are in-object properties, indexed
3579 // from the end of the fixed part of the object.
3580 int offset = (index * kPointerSize) + type->instance_size();
3581 return new(zone()) HLoadNamedField(object, true, offset);
3582 } else {
3583 // Non-negative property indices are in the properties array.
3584 int offset = (index * kPointerSize) + FixedArray::kHeaderSize;
3585 return new(zone()) HLoadNamedField(object, false, offset);
3586 }
3587 }
3588
3589
BuildLoadNamedGeneric(HValue * obj,Property * expr)3590 HInstruction* HGraphBuilder::BuildLoadNamedGeneric(HValue* obj,
3591 Property* expr) {
3592 ASSERT(expr->key()->IsPropertyName());
3593 Handle<Object> name = expr->key()->AsLiteral()->handle();
3594 HContext* context = new(zone()) HContext;
3595 AddInstruction(context);
3596 return new(zone()) HLoadNamedGeneric(context, obj, name);
3597 }
3598
3599
BuildLoadNamed(HValue * obj,Property * expr,Handle<Map> map,Handle<String> name)3600 HInstruction* HGraphBuilder::BuildLoadNamed(HValue* obj,
3601 Property* expr,
3602 Handle<Map> map,
3603 Handle<String> name) {
3604 LookupResult lookup;
3605 map->LookupInDescriptors(NULL, *name, &lookup);
3606 if (lookup.IsProperty() && lookup.type() == FIELD) {
3607 return BuildLoadNamedField(obj,
3608 expr,
3609 map,
3610 &lookup,
3611 true);
3612 } else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) {
3613 AddInstruction(new(zone()) HCheckNonSmi(obj));
3614 AddInstruction(new(zone()) HCheckMap(obj, map));
3615 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map));
3616 return new(zone()) HConstant(function, Representation::Tagged());
3617 } else {
3618 return BuildLoadNamedGeneric(obj, expr);
3619 }
3620 }
3621
3622
BuildLoadKeyedGeneric(HValue * object,HValue * key)3623 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
3624 HValue* key) {
3625 HContext* context = new(zone()) HContext;
3626 AddInstruction(context);
3627 return new(zone()) HLoadKeyedGeneric(context, object, key);
3628 }
3629
3630
BuildLoadKeyedFastElement(HValue * object,HValue * key,Property * expr)3631 HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object,
3632 HValue* key,
3633 Property* expr) {
3634 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic());
3635 AddInstruction(new(zone()) HCheckNonSmi(object));
3636 Handle<Map> map = expr->GetMonomorphicReceiverType();
3637 ASSERT(map->has_fast_elements());
3638 AddInstruction(new(zone()) HCheckMap(object, map));
3639 bool is_array = (map->instance_type() == JS_ARRAY_TYPE);
3640 HLoadElements* elements = new(zone()) HLoadElements(object);
3641 HInstruction* length = NULL;
3642 HInstruction* checked_key = NULL;
3643 if (is_array) {
3644 length = AddInstruction(new(zone()) HJSArrayLength(object));
3645 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
3646 AddInstruction(elements);
3647 } else {
3648 AddInstruction(elements);
3649 length = AddInstruction(new(zone()) HFixedArrayLength(elements));
3650 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
3651 }
3652 return new(zone()) HLoadKeyedFastElement(elements, checked_key);
3653 }
3654
3655
BuildLoadKeyedSpecializedArrayElement(HValue * object,HValue * key,Property * expr)3656 HInstruction* HGraphBuilder::BuildLoadKeyedSpecializedArrayElement(
3657 HValue* object,
3658 HValue* key,
3659 Property* expr) {
3660 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic());
3661 AddInstruction(new(zone()) HCheckNonSmi(object));
3662 Handle<Map> map = expr->GetMonomorphicReceiverType();
3663 ASSERT(!map->has_fast_elements());
3664 ASSERT(map->has_external_array_elements());
3665 AddInstruction(new(zone()) HCheckMap(object, map));
3666 HLoadElements* elements = new(zone()) HLoadElements(object);
3667 AddInstruction(elements);
3668 HInstruction* length = new(zone()) HExternalArrayLength(elements);
3669 AddInstruction(length);
3670 HInstruction* checked_key =
3671 AddInstruction(new(zone()) HBoundsCheck(key, length));
3672 HLoadExternalArrayPointer* external_elements =
3673 new(zone()) HLoadExternalArrayPointer(elements);
3674 AddInstruction(external_elements);
3675 HLoadKeyedSpecializedArrayElement* pixel_array_value =
3676 new(zone()) HLoadKeyedSpecializedArrayElement(
3677 external_elements, checked_key, expr->external_array_type());
3678 return pixel_array_value;
3679 }
3680
3681
BuildLoadKeyed(HValue * obj,HValue * key,Property * prop)3682 HInstruction* HGraphBuilder::BuildLoadKeyed(HValue* obj,
3683 HValue* key,
3684 Property* prop) {
3685 if (prop->IsMonomorphic()) {
3686 Handle<Map> receiver_type(prop->GetMonomorphicReceiverType());
3687 // An object has either fast elements or pixel array elements, but never
3688 // both. Pixel array maps that are assigned to pixel array elements are
3689 // always created with the fast elements flag cleared.
3690 if (receiver_type->has_external_array_elements()) {
3691 return BuildLoadKeyedSpecializedArrayElement(obj, key, prop);
3692 } else if (receiver_type->has_fast_elements()) {
3693 return BuildLoadKeyedFastElement(obj, key, prop);
3694 }
3695 }
3696 return BuildLoadKeyedGeneric(obj, key);
3697 }
3698
3699
BuildStoreKeyedGeneric(HValue * object,HValue * key,HValue * value)3700 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object,
3701 HValue* key,
3702 HValue* value) {
3703 HContext* context = new(zone()) HContext;
3704 AddInstruction(context);
3705 return new(zone()) HStoreKeyedGeneric(
3706 context,
3707 object,
3708 key,
3709 value,
3710 function_strict_mode());
3711 }
3712
3713
BuildStoreKeyedFastElement(HValue * object,HValue * key,HValue * val,Expression * expr)3714 HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object,
3715 HValue* key,
3716 HValue* val,
3717 Expression* expr) {
3718 ASSERT(expr->IsMonomorphic());
3719 AddInstruction(new(zone()) HCheckNonSmi(object));
3720 Handle<Map> map = expr->GetMonomorphicReceiverType();
3721 ASSERT(map->has_fast_elements());
3722 AddInstruction(new(zone()) HCheckMap(object, map));
3723 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object));
3724 AddInstruction(new(zone()) HCheckMap(
3725 elements, isolate()->factory()->fixed_array_map()));
3726 bool is_array = (map->instance_type() == JS_ARRAY_TYPE);
3727 HInstruction* length = NULL;
3728 if (is_array) {
3729 length = AddInstruction(new(zone()) HJSArrayLength(object));
3730 } else {
3731 length = AddInstruction(new(zone()) HFixedArrayLength(elements));
3732 }
3733 HInstruction* checked_key =
3734 AddInstruction(new(zone()) HBoundsCheck(key, length));
3735 return new(zone()) HStoreKeyedFastElement(elements, checked_key, val);
3736 }
3737
3738
BuildStoreKeyedSpecializedArrayElement(HValue * object,HValue * key,HValue * val,Expression * expr)3739 HInstruction* HGraphBuilder::BuildStoreKeyedSpecializedArrayElement(
3740 HValue* object,
3741 HValue* key,
3742 HValue* val,
3743 Expression* expr) {
3744 ASSERT(expr->IsMonomorphic());
3745 AddInstruction(new(zone()) HCheckNonSmi(object));
3746 Handle<Map> map = expr->GetMonomorphicReceiverType();
3747 ASSERT(!map->has_fast_elements());
3748 ASSERT(map->has_external_array_elements());
3749 AddInstruction(new(zone()) HCheckMap(object, map));
3750 HLoadElements* elements = new(zone()) HLoadElements(object);
3751 AddInstruction(elements);
3752 HInstruction* length = AddInstruction(
3753 new(zone()) HExternalArrayLength(elements));
3754 HInstruction* checked_key =
3755 AddInstruction(new(zone()) HBoundsCheck(key, length));
3756 HLoadExternalArrayPointer* external_elements =
3757 new(zone()) HLoadExternalArrayPointer(elements);
3758 AddInstruction(external_elements);
3759 return new(zone()) HStoreKeyedSpecializedArrayElement(
3760 external_elements,
3761 checked_key,
3762 val,
3763 expr->external_array_type());
3764 }
3765
3766
BuildStoreKeyed(HValue * object,HValue * key,HValue * value,Expression * expr)3767 HInstruction* HGraphBuilder::BuildStoreKeyed(HValue* object,
3768 HValue* key,
3769 HValue* value,
3770 Expression* expr) {
3771 if (expr->IsMonomorphic()) {
3772 Handle<Map> receiver_type(expr->GetMonomorphicReceiverType());
3773 // An object has either fast elements or external array elements, but
3774 // never both. Pixel array maps that are assigned to pixel array elements
3775 // are always created with the fast elements flag cleared.
3776 if (receiver_type->has_external_array_elements()) {
3777 return BuildStoreKeyedSpecializedArrayElement(object,
3778 key,
3779 value,
3780 expr);
3781 } else if (receiver_type->has_fast_elements()) {
3782 return BuildStoreKeyedFastElement(object, key, value, expr);
3783 }
3784 }
3785 return BuildStoreKeyedGeneric(object, key, value);
3786 }
3787
3788
TryArgumentsAccess(Property * expr)3789 bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
3790 VariableProxy* proxy = expr->obj()->AsVariableProxy();
3791 if (proxy == NULL) return false;
3792 if (!proxy->var()->IsStackAllocated()) return false;
3793 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) {
3794 return false;
3795 }
3796
3797 // Our implementation of arguments (based on this stack frame or an
3798 // adapter below it) does not work for inlined functions.
3799 if (function_state()->outer() != NULL) {
3800 Bailout("arguments access in inlined function");
3801 return true;
3802 }
3803
3804 HInstruction* result = NULL;
3805 if (expr->key()->IsPropertyName()) {
3806 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
3807 if (!name->IsEqualTo(CStrVector("length"))) return false;
3808 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
3809 result = new(zone()) HArgumentsLength(elements);
3810 } else {
3811 Push(graph()->GetArgumentsObject());
3812 VisitForValue(expr->key());
3813 if (HasStackOverflow()) return false;
3814 HValue* key = Pop();
3815 Drop(1); // Arguments object.
3816 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
3817 HInstruction* length = AddInstruction(
3818 new(zone()) HArgumentsLength(elements));
3819 HInstruction* checked_key =
3820 AddInstruction(new(zone()) HBoundsCheck(key, length));
3821 result = new(zone()) HAccessArgumentsAt(elements, length, checked_key);
3822 }
3823 ast_context()->ReturnInstruction(result, expr->id());
3824 return true;
3825 }
3826
3827
VisitProperty(Property * expr)3828 void HGraphBuilder::VisitProperty(Property* expr) {
3829 expr->RecordTypeFeedback(oracle());
3830
3831 if (TryArgumentsAccess(expr)) return;
3832 CHECK_BAILOUT;
3833
3834 VISIT_FOR_VALUE(expr->obj());
3835
3836 HInstruction* instr = NULL;
3837 if (expr->IsArrayLength()) {
3838 HValue* array = Pop();
3839 AddInstruction(new(zone()) HCheckNonSmi(array));
3840 AddInstruction(new(zone()) HCheckInstanceType(array,
3841 JS_ARRAY_TYPE,
3842 JS_ARRAY_TYPE));
3843 instr = new(zone()) HJSArrayLength(array);
3844
3845 } else if (expr->IsStringLength()) {
3846 HValue* string = Pop();
3847 AddInstruction(new(zone()) HCheckNonSmi(string));
3848 AddInstruction(new(zone()) HCheckInstanceType(string,
3849 FIRST_STRING_TYPE,
3850 LAST_STRING_TYPE));
3851 instr = new(zone()) HStringLength(string);
3852 } else if (expr->IsStringAccess()) {
3853 VISIT_FOR_VALUE(expr->key());
3854 HValue* index = Pop();
3855 HValue* string = Pop();
3856 HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index);
3857 AddInstruction(char_code);
3858 instr = new(zone()) HStringCharFromCode(char_code);
3859
3860 } else if (expr->IsFunctionPrototype()) {
3861 HValue* function = Pop();
3862 AddInstruction(new(zone()) HCheckNonSmi(function));
3863 instr = new(zone()) HLoadFunctionPrototype(function);
3864
3865 } else if (expr->key()->IsPropertyName()) {
3866 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
3867 ZoneMapList* types = expr->GetReceiverTypes();
3868
3869 HValue* obj = Pop();
3870 if (expr->IsMonomorphic()) {
3871 instr = BuildLoadNamed(obj, expr, types->first(), name);
3872 } else if (types != NULL && types->length() > 1) {
3873 AddInstruction(new(zone()) HCheckNonSmi(obj));
3874 instr = new(zone()) HLoadNamedFieldPolymorphic(obj, types, name);
3875 } else {
3876 instr = BuildLoadNamedGeneric(obj, expr);
3877 }
3878
3879 } else {
3880 VISIT_FOR_VALUE(expr->key());
3881
3882 HValue* key = Pop();
3883 HValue* obj = Pop();
3884 instr = BuildLoadKeyed(obj, key, expr);
3885 }
3886 instr->set_position(expr->position());
3887 ast_context()->ReturnInstruction(instr, expr->id());
3888 }
3889
3890
AddCheckConstantFunction(Call * expr,HValue * receiver,Handle<Map> receiver_map,bool smi_and_map_check)3891 void HGraphBuilder::AddCheckConstantFunction(Call* expr,
3892 HValue* receiver,
3893 Handle<Map> receiver_map,
3894 bool smi_and_map_check) {
3895 // Constant functions have the nice property that the map will change if they
3896 // are overwritten. Therefore it is enough to check the map of the holder and
3897 // its prototypes.
3898 if (smi_and_map_check) {
3899 AddInstruction(new(zone()) HCheckNonSmi(receiver));
3900 AddInstruction(new(zone()) HCheckMap(receiver, receiver_map));
3901 }
3902 if (!expr->holder().is_null()) {
3903 AddInstruction(new(zone()) HCheckPrototypeMaps(
3904 Handle<JSObject>(JSObject::cast(receiver_map->prototype())),
3905 expr->holder()));
3906 }
3907 }
3908
3909
HandlePolymorphicCallNamed(Call * expr,HValue * receiver,ZoneMapList * types,Handle<String> name)3910 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
3911 HValue* receiver,
3912 ZoneMapList* types,
3913 Handle<String> name) {
3914 // TODO(ager): We should recognize when the prototype chains for different
3915 // maps are identical. In that case we can avoid repeatedly generating the
3916 // same prototype map checks.
3917 int argument_count = expr->arguments()->length() + 1; // Includes receiver.
3918 int count = 0;
3919 HBasicBlock* join = NULL;
3920 for (int i = 0; i < types->length() && count < kMaxCallPolymorphism; ++i) {
3921 Handle<Map> map = types->at(i);
3922 if (expr->ComputeTarget(map, name)) {
3923 if (count == 0) {
3924 // Only needed once.
3925 AddInstruction(new(zone()) HCheckNonSmi(receiver));
3926 join = graph()->CreateBasicBlock();
3927 }
3928 ++count;
3929 HBasicBlock* if_true = graph()->CreateBasicBlock();
3930 HBasicBlock* if_false = graph()->CreateBasicBlock();
3931 HCompareMap* compare =
3932 new(zone()) HCompareMap(receiver, map, if_true, if_false);
3933 current_block()->Finish(compare);
3934
3935 set_current_block(if_true);
3936 AddCheckConstantFunction(expr, receiver, map, false);
3937 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) {
3938 PrintF("Trying to inline the polymorphic call to %s\n",
3939 *name->ToCString());
3940 }
3941 if (!FLAG_polymorphic_inlining || !TryInline(expr)) {
3942 // Check for bailout, as trying to inline might fail due to bailout
3943 // during hydrogen processing.
3944 CHECK_BAILOUT;
3945 HCallConstantFunction* call =
3946 new(zone()) HCallConstantFunction(expr->target(), argument_count);
3947 call->set_position(expr->position());
3948 PreProcessCall(call);
3949 AddInstruction(call);
3950 if (!ast_context()->IsEffect()) Push(call);
3951 }
3952
3953 if (current_block() != NULL) current_block()->Goto(join);
3954 set_current_block(if_false);
3955 }
3956 }
3957
3958 // Finish up. Unconditionally deoptimize if we've handled all the maps we
3959 // know about and do not want to handle ones we've never seen. Otherwise
3960 // use a generic IC.
3961 if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
3962 current_block()->FinishExitWithDeoptimization();
3963 } else {
3964 HContext* context = new(zone()) HContext;
3965 AddInstruction(context);
3966 HCallNamed* call = new(zone()) HCallNamed(context, name, argument_count);
3967 call->set_position(expr->position());
3968 PreProcessCall(call);
3969
3970 if (join != NULL) {
3971 AddInstruction(call);
3972 if (!ast_context()->IsEffect()) Push(call);
3973 current_block()->Goto(join);
3974 } else {
3975 ast_context()->ReturnInstruction(call, expr->id());
3976 return;
3977 }
3978 }
3979
3980 // We assume that control flow is always live after an expression. So
3981 // even without predecessors to the join block, we set it as the exit
3982 // block and continue by adding instructions there.
3983 ASSERT(join != NULL);
3984 set_current_block(join);
3985 if (join->HasPredecessor()) {
3986 join->SetJoinId(expr->id());
3987 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
3988 }
3989 }
3990
3991
TraceInline(Handle<JSFunction> target,const char * reason)3992 void HGraphBuilder::TraceInline(Handle<JSFunction> target, const char* reason) {
3993 if (FLAG_trace_inlining) {
3994 if (reason == NULL) {
3995 // We are currently in the context of inlined function thus we have
3996 // to go to an outer FunctionState to get caller.
3997 SmartPointer<char> callee = target->shared()->DebugName()->ToCString();
3998 SmartPointer<char> caller =
3999 function_state()->outer()->compilation_info()->function()->
4000 debug_name()->ToCString();
4001 PrintF("Inlined %s called from %s.\n", *callee, *caller);
4002 } else {
4003 SmartPointer<char> callee = target->shared()->DebugName()->ToCString();
4004 SmartPointer<char> caller =
4005 info()->function()->debug_name()->ToCString();
4006 PrintF("Did not inline %s called from %s (%s).\n",
4007 *callee, *caller, reason);
4008 }
4009 }
4010 }
4011
4012
TryInline(Call * expr)4013 bool HGraphBuilder::TryInline(Call* expr) {
4014 if (!FLAG_use_inlining) return false;
4015
4016 // Precondition: call is monomorphic and we have found a target with the
4017 // appropriate arity.
4018 Handle<JSFunction> target = expr->target();
4019
4020 // Do a quick check on source code length to avoid parsing large
4021 // inlining candidates.
4022 if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) {
4023 TraceInline(target, "target text too big");
4024 return false;
4025 }
4026
4027 // Target must be inlineable.
4028 if (!target->IsInlineable()) {
4029 TraceInline(target, "target not inlineable");
4030 return false;
4031 }
4032
4033 // No context change required.
4034 CompilationInfo* outer_info = info();
4035 if (target->context() != outer_info->closure()->context() ||
4036 outer_info->scope()->contains_with() ||
4037 outer_info->scope()->num_heap_slots() > 0) {
4038 TraceInline(target, "target requires context change");
4039 return false;
4040 }
4041
4042 // Don't inline deeper than kMaxInliningLevels calls.
4043 HEnvironment* env = environment();
4044 int current_level = 1;
4045 while (env->outer() != NULL) {
4046 if (current_level == Compiler::kMaxInliningLevels) {
4047 TraceInline(target, "inline depth limit reached");
4048 return false;
4049 }
4050 current_level++;
4051 env = env->outer();
4052 }
4053
4054 // Don't inline recursive functions.
4055 if (target->shared() == outer_info->closure()->shared()) {
4056 TraceInline(target, "target is recursive");
4057 return false;
4058 }
4059
4060 // We don't want to add more than a certain number of nodes from inlining.
4061 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) {
4062 TraceInline(target, "cumulative AST node limit reached");
4063 return false;
4064 }
4065
4066 int count_before = AstNode::Count();
4067
4068 // Parse and allocate variables.
4069 CompilationInfo target_info(target);
4070 if (!ParserApi::Parse(&target_info) ||
4071 !Scope::Analyze(&target_info)) {
4072 if (target_info.isolate()->has_pending_exception()) {
4073 // Parse or scope error, never optimize this function.
4074 SetStackOverflow();
4075 target->shared()->set_optimization_disabled(true);
4076 }
4077 TraceInline(target, "parse failure");
4078 return false;
4079 }
4080
4081 if (target_info.scope()->num_heap_slots() > 0) {
4082 TraceInline(target, "target has context-allocated variables");
4083 return false;
4084 }
4085 FunctionLiteral* function = target_info.function();
4086
4087 // Count the number of AST nodes added by inlining this call.
4088 int nodes_added = AstNode::Count() - count_before;
4089 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) {
4090 TraceInline(target, "target AST is too large");
4091 return false;
4092 }
4093
4094 // Check if we can handle all declarations in the inlined functions.
4095 VisitDeclarations(target_info.scope()->declarations());
4096 if (HasStackOverflow()) {
4097 TraceInline(target, "target has non-trivial declaration");
4098 ClearStackOverflow();
4099 return false;
4100 }
4101
4102 // Don't inline functions that uses the arguments object or that
4103 // have a mismatching number of parameters.
4104 Handle<SharedFunctionInfo> target_shared(target->shared());
4105 int arity = expr->arguments()->length();
4106 if (function->scope()->arguments() != NULL ||
4107 arity != target_shared->formal_parameter_count()) {
4108 TraceInline(target, "target requires special argument handling");
4109 return false;
4110 }
4111
4112 // All statements in the body must be inlineable.
4113 for (int i = 0, count = function->body()->length(); i < count; ++i) {
4114 if (!function->body()->at(i)->IsInlineable()) {
4115 TraceInline(target, "target contains unsupported syntax");
4116 return false;
4117 }
4118 }
4119
4120 // Generate the deoptimization data for the unoptimized version of
4121 // the target function if we don't already have it.
4122 if (!target_shared->has_deoptimization_support()) {
4123 // Note that we compile here using the same AST that we will use for
4124 // generating the optimized inline code.
4125 target_info.EnableDeoptimizationSupport();
4126 if (!FullCodeGenerator::MakeCode(&target_info)) {
4127 TraceInline(target, "could not generate deoptimization info");
4128 return false;
4129 }
4130 target_shared->EnableDeoptimizationSupport(*target_info.code());
4131 Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG,
4132 &target_info,
4133 target_shared);
4134 }
4135
4136 // ----------------------------------------------------------------
4137 // Save the pending call context and type feedback oracle. Set up new ones
4138 // for the inlined function.
4139 ASSERT(target_shared->has_deoptimization_support());
4140 TypeFeedbackOracle target_oracle(
4141 Handle<Code>(target_shared->code()),
4142 Handle<Context>(target->context()->global_context()));
4143 FunctionState target_state(this, &target_info, &target_oracle);
4144
4145 HConstant* undefined = graph()->GetConstantUndefined();
4146 HEnvironment* inner_env =
4147 environment()->CopyForInlining(target, function, true, undefined);
4148 HBasicBlock* body_entry = CreateBasicBlock(inner_env);
4149 current_block()->Goto(body_entry);
4150
4151 body_entry->SetJoinId(expr->ReturnId());
4152 set_current_block(body_entry);
4153 AddInstruction(new(zone()) HEnterInlined(target, function));
4154 VisitStatements(function->body());
4155 if (HasStackOverflow()) {
4156 // Bail out if the inline function did, as we cannot residualize a call
4157 // instead.
4158 TraceInline(target, "inline graph construction failed");
4159 return false;
4160 }
4161
4162 // Update inlined nodes count.
4163 inlined_count_ += nodes_added;
4164
4165 TraceInline(target, NULL);
4166
4167 if (current_block() != NULL) {
4168 // Add a return of undefined if control can fall off the body. In a
4169 // test context, undefined is false.
4170 if (inlined_test_context() == NULL) {
4171 ASSERT(function_return() != NULL);
4172 ASSERT(call_context()->IsEffect() || call_context()->IsValue());
4173 if (call_context()->IsEffect()) {
4174 current_block()->Goto(function_return(), false);
4175 } else {
4176 current_block()->AddLeaveInlined(undefined, function_return());
4177 }
4178 } else {
4179 // The graph builder assumes control can reach both branches of a
4180 // test, so we materialize the undefined value and test it rather than
4181 // simply jumping to the false target.
4182 //
4183 // TODO(3168478): refactor to avoid this.
4184 HBasicBlock* empty_true = graph()->CreateBasicBlock();
4185 HBasicBlock* empty_false = graph()->CreateBasicBlock();
4186 HTest* test = new(zone()) HTest(undefined, empty_true, empty_false);
4187 current_block()->Finish(test);
4188
4189 empty_true->Goto(inlined_test_context()->if_true(), false);
4190 empty_false->Goto(inlined_test_context()->if_false(), false);
4191 }
4192 }
4193
4194 // Fix up the function exits.
4195 if (inlined_test_context() != NULL) {
4196 HBasicBlock* if_true = inlined_test_context()->if_true();
4197 HBasicBlock* if_false = inlined_test_context()->if_false();
4198 if_true->SetJoinId(expr->id());
4199 if_false->SetJoinId(expr->id());
4200 ASSERT(ast_context() == inlined_test_context());
4201 // Pop the return test context from the expression context stack.
4202 ClearInlinedTestContext();
4203
4204 // Forward to the real test context.
4205 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
4206 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
4207 if_true->Goto(true_target, false);
4208 if_false->Goto(false_target, false);
4209
4210 // TODO(kmillikin): Come up with a better way to handle this. It is too
4211 // subtle. NULL here indicates that the enclosing context has no control
4212 // flow to handle.
4213 set_current_block(NULL);
4214
4215 } else {
4216 function_return()->SetJoinId(expr->id());
4217 set_current_block(function_return());
4218 }
4219
4220 return true;
4221 }
4222
4223
TryInlineBuiltinFunction(Call * expr,HValue * receiver,Handle<Map> receiver_map,CheckType check_type)4224 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr,
4225 HValue* receiver,
4226 Handle<Map> receiver_map,
4227 CheckType check_type) {
4228 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null());
4229 // Try to inline calls like Math.* as operations in the calling function.
4230 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
4231 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
4232 int argument_count = expr->arguments()->length() + 1; // Plus receiver.
4233 switch (id) {
4234 case kStringCharCodeAt:
4235 case kStringCharAt:
4236 if (argument_count == 2 && check_type == STRING_CHECK) {
4237 HValue* index = Pop();
4238 HValue* string = Pop();
4239 ASSERT(!expr->holder().is_null());
4240 AddInstruction(new(zone()) HCheckPrototypeMaps(
4241 oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK),
4242 expr->holder()));
4243 HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index);
4244 if (id == kStringCharCodeAt) {
4245 ast_context()->ReturnInstruction(char_code, expr->id());
4246 return true;
4247 }
4248 AddInstruction(char_code);
4249 HStringCharFromCode* result =
4250 new(zone()) HStringCharFromCode(char_code);
4251 ast_context()->ReturnInstruction(result, expr->id());
4252 return true;
4253 }
4254 break;
4255 case kMathRound:
4256 case kMathFloor:
4257 case kMathAbs:
4258 case kMathSqrt:
4259 case kMathLog:
4260 case kMathSin:
4261 case kMathCos:
4262 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
4263 AddCheckConstantFunction(expr, receiver, receiver_map, true);
4264 HValue* argument = Pop();
4265 Drop(1); // Receiver.
4266 HUnaryMathOperation* op = new(zone()) HUnaryMathOperation(argument, id);
4267 op->set_position(expr->position());
4268 ast_context()->ReturnInstruction(op, expr->id());
4269 return true;
4270 }
4271 break;
4272 case kMathPow:
4273 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
4274 AddCheckConstantFunction(expr, receiver, receiver_map, true);
4275 HValue* right = Pop();
4276 HValue* left = Pop();
4277 Pop(); // Pop receiver.
4278 HInstruction* result = NULL;
4279 // Use sqrt() if exponent is 0.5 or -0.5.
4280 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) {
4281 double exponent = HConstant::cast(right)->DoubleValue();
4282 if (exponent == 0.5) {
4283 result = new(zone()) HUnaryMathOperation(left, kMathPowHalf);
4284 } else if (exponent == -0.5) {
4285 HConstant* double_one =
4286 new(zone()) HConstant(Handle<Object>(Smi::FromInt(1)),
4287 Representation::Double());
4288 AddInstruction(double_one);
4289 HUnaryMathOperation* square_root =
4290 new(zone()) HUnaryMathOperation(left, kMathPowHalf);
4291 AddInstruction(square_root);
4292 // MathPowHalf doesn't have side effects so there's no need for
4293 // an environment simulation here.
4294 ASSERT(!square_root->HasSideEffects());
4295 result = new(zone()) HDiv(double_one, square_root);
4296 } else if (exponent == 2.0) {
4297 result = new(zone()) HMul(left, left);
4298 }
4299 } else if (right->IsConstant() &&
4300 HConstant::cast(right)->HasInteger32Value() &&
4301 HConstant::cast(right)->Integer32Value() == 2) {
4302 result = new(zone()) HMul(left, left);
4303 }
4304
4305 if (result == NULL) {
4306 result = new(zone()) HPower(left, right);
4307 }
4308 ast_context()->ReturnInstruction(result, expr->id());
4309 return true;
4310 }
4311 break;
4312 default:
4313 // Not yet supported for inlining.
4314 break;
4315 }
4316 return false;
4317 }
4318
4319
TryCallApply(Call * expr)4320 bool HGraphBuilder::TryCallApply(Call* expr) {
4321 Expression* callee = expr->expression();
4322 Property* prop = callee->AsProperty();
4323 ASSERT(prop != NULL);
4324
4325 if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) {
4326 return false;
4327 }
4328 Handle<Map> function_map = expr->GetReceiverTypes()->first();
4329 if (function_map->instance_type() != JS_FUNCTION_TYPE ||
4330 !expr->target()->shared()->HasBuiltinFunctionId() ||
4331 expr->target()->shared()->builtin_function_id() != kFunctionApply) {
4332 return false;
4333 }
4334
4335 if (info()->scope()->arguments() == NULL) return false;
4336
4337 ZoneList<Expression*>* args = expr->arguments();
4338 if (args->length() != 2) return false;
4339
4340 VariableProxy* arg_two = args->at(1)->AsVariableProxy();
4341 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
4342 HValue* arg_two_value = environment()->Lookup(arg_two->var());
4343 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
4344
4345 // Our implementation of arguments (based on this stack frame or an
4346 // adapter below it) does not work for inlined functions.
4347 if (function_state()->outer() != NULL) {
4348 Bailout("Function.prototype.apply optimization in inlined function");
4349 return true;
4350 }
4351
4352 // Found pattern f.apply(receiver, arguments).
4353 VisitForValue(prop->obj());
4354 if (HasStackOverflow()) return false;
4355 HValue* function = Pop();
4356 VisitForValue(args->at(0));
4357 if (HasStackOverflow()) return false;
4358 HValue* receiver = Pop();
4359 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
4360 HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements));
4361 AddCheckConstantFunction(expr, function, function_map, true);
4362 HInstruction* result =
4363 new(zone()) HApplyArguments(function, receiver, length, elements);
4364 result->set_position(expr->position());
4365 ast_context()->ReturnInstruction(result, expr->id());
4366 return true;
4367 }
4368
4369
VisitCall(Call * expr)4370 void HGraphBuilder::VisitCall(Call* expr) {
4371 Expression* callee = expr->expression();
4372 int argument_count = expr->arguments()->length() + 1; // Plus receiver.
4373 HInstruction* call = NULL;
4374
4375 Property* prop = callee->AsProperty();
4376 if (prop != NULL) {
4377 if (!prop->key()->IsPropertyName()) {
4378 // Keyed function call.
4379 VISIT_FOR_VALUE(prop->obj());
4380
4381 VISIT_FOR_VALUE(prop->key());
4382 // Push receiver and key like the non-optimized code generator expects it.
4383 HValue* key = Pop();
4384 HValue* receiver = Pop();
4385 Push(key);
4386 Push(receiver);
4387
4388 VisitExpressions(expr->arguments());
4389 CHECK_BAILOUT;
4390
4391 HContext* context = new(zone()) HContext;
4392 AddInstruction(context);
4393 call = PreProcessCall(
4394 new(zone()) HCallKeyed(context, key, argument_count));
4395 call->set_position(expr->position());
4396 Drop(1); // Key.
4397 ast_context()->ReturnInstruction(call, expr->id());
4398 return;
4399 }
4400
4401 // Named function call.
4402 expr->RecordTypeFeedback(oracle());
4403
4404 if (TryCallApply(expr)) return;
4405 CHECK_BAILOUT;
4406
4407 VISIT_FOR_VALUE(prop->obj());
4408 VisitExpressions(expr->arguments());
4409 CHECK_BAILOUT;
4410
4411 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
4412
4413 expr->RecordTypeFeedback(oracle());
4414 ZoneMapList* types = expr->GetReceiverTypes();
4415
4416 HValue* receiver =
4417 environment()->ExpressionStackAt(expr->arguments()->length());
4418 if (expr->IsMonomorphic()) {
4419 Handle<Map> receiver_map =
4420 (types == NULL) ? Handle<Map>::null() : types->first();
4421 if (TryInlineBuiltinFunction(expr,
4422 receiver,
4423 receiver_map,
4424 expr->check_type())) {
4425 return;
4426 }
4427
4428 if (CallStubCompiler::HasCustomCallGenerator(*expr->target()) ||
4429 expr->check_type() != RECEIVER_MAP_CHECK) {
4430 // When the target has a custom call IC generator, use the IC,
4431 // because it is likely to generate better code. Also use the IC
4432 // when a primitive receiver check is required.
4433 HContext* context = new(zone()) HContext;
4434 AddInstruction(context);
4435 call = PreProcessCall(
4436 new(zone()) HCallNamed(context, name, argument_count));
4437 } else {
4438 AddCheckConstantFunction(expr, receiver, receiver_map, true);
4439
4440 if (TryInline(expr)) {
4441 return;
4442 } else {
4443 // Check for bailout, as the TryInline call in the if condition above
4444 // might return false due to bailout during hydrogen processing.
4445 CHECK_BAILOUT;
4446 call = PreProcessCall(
4447 new(zone()) HCallConstantFunction(expr->target(),
4448 argument_count));
4449 }
4450 }
4451 } else if (types != NULL && types->length() > 1) {
4452 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK);
4453 HandlePolymorphicCallNamed(expr, receiver, types, name);
4454 return;
4455
4456 } else {
4457 HContext* context = new(zone()) HContext;
4458 AddInstruction(context);
4459 call = PreProcessCall(
4460 new(zone()) HCallNamed(context, name, argument_count));
4461 }
4462
4463 } else {
4464 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
4465 bool global_call = (var != NULL) && var->is_global() && !var->is_this();
4466
4467 if (!global_call) {
4468 ++argument_count;
4469 VISIT_FOR_VALUE(expr->expression());
4470 }
4471
4472 if (global_call) {
4473 bool known_global_function = false;
4474 // If there is a global property cell for the name at compile time and
4475 // access check is not enabled we assume that the function will not change
4476 // and generate optimized code for calling the function.
4477 LookupResult lookup;
4478 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false);
4479 if (type == kUseCell &&
4480 !info()->global_object()->IsAccessCheckNeeded()) {
4481 Handle<GlobalObject> global(info()->global_object());
4482 known_global_function = expr->ComputeGlobalTarget(global, &lookup);
4483 }
4484 if (known_global_function) {
4485 // Push the global object instead of the global receiver because
4486 // code generated by the full code generator expects it.
4487 HContext* context = new(zone()) HContext;
4488 HGlobalObject* global_object = new(zone()) HGlobalObject(context);
4489 AddInstruction(context);
4490 PushAndAdd(global_object);
4491 VisitExpressions(expr->arguments());
4492 CHECK_BAILOUT;
4493
4494 VISIT_FOR_VALUE(expr->expression());
4495 HValue* function = Pop();
4496 AddInstruction(new(zone()) HCheckFunction(function, expr->target()));
4497
4498 // Replace the global object with the global receiver.
4499 HGlobalReceiver* global_receiver =
4500 new(zone()) HGlobalReceiver(global_object);
4501 // Index of the receiver from the top of the expression stack.
4502 const int receiver_index = argument_count - 1;
4503 AddInstruction(global_receiver);
4504 ASSERT(environment()->ExpressionStackAt(receiver_index)->
4505 IsGlobalObject());
4506 environment()->SetExpressionStackAt(receiver_index, global_receiver);
4507
4508 if (TryInline(expr)) {
4509 return;
4510 }
4511 // Check for bailout, as trying to inline might fail due to bailout
4512 // during hydrogen processing.
4513 CHECK_BAILOUT;
4514
4515 call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(),
4516 argument_count));
4517 } else {
4518 HContext* context = new(zone()) HContext;
4519 AddInstruction(context);
4520 PushAndAdd(new(zone()) HGlobalObject(context));
4521 VisitExpressions(expr->arguments());
4522 CHECK_BAILOUT;
4523
4524 call = PreProcessCall(new(zone()) HCallGlobal(context,
4525 var->name(),
4526 argument_count));
4527 }
4528
4529 } else {
4530 HContext* context = new(zone()) HContext;
4531 HGlobalObject* global_object = new(zone()) HGlobalObject(context);
4532 AddInstruction(context);
4533 AddInstruction(global_object);
4534 PushAndAdd(new(zone()) HGlobalReceiver(global_object));
4535 VisitExpressions(expr->arguments());
4536 CHECK_BAILOUT;
4537
4538 call = PreProcessCall(new(zone()) HCallFunction(context, argument_count));
4539 }
4540 }
4541
4542 call->set_position(expr->position());
4543 ast_context()->ReturnInstruction(call, expr->id());
4544 }
4545
4546
VisitCallNew(CallNew * expr)4547 void HGraphBuilder::VisitCallNew(CallNew* expr) {
4548 // The constructor function is also used as the receiver argument to the
4549 // JS construct call builtin.
4550 VISIT_FOR_VALUE(expr->expression());
4551 VisitExpressions(expr->arguments());
4552 CHECK_BAILOUT;
4553
4554 HContext* context = new(zone()) HContext;
4555 AddInstruction(context);
4556
4557 // The constructor is both an operand to the instruction and an argument
4558 // to the construct call.
4559 int arg_count = expr->arguments()->length() + 1; // Plus constructor.
4560 HValue* constructor = environment()->ExpressionStackAt(arg_count - 1);
4561 HCallNew* call = new(zone()) HCallNew(context, constructor, arg_count);
4562 call->set_position(expr->position());
4563 PreProcessCall(call);
4564 ast_context()->ReturnInstruction(call, expr->id());
4565 }
4566
4567
4568 // Support for generating inlined runtime functions.
4569
4570 // Lookup table for generators for runtime calls that are generated inline.
4571 // Elements of the table are member pointers to functions of HGraphBuilder.
4572 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \
4573 &HGraphBuilder::Generate##Name,
4574
4575 const HGraphBuilder::InlineFunctionGenerator
4576 HGraphBuilder::kInlineFunctionGenerators[] = {
4577 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
4578 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
4579 };
4580 #undef INLINE_FUNCTION_GENERATOR_ADDRESS
4581
4582
VisitCallRuntime(CallRuntime * expr)4583 void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
4584 if (expr->is_jsruntime()) {
4585 BAILOUT("call to a JavaScript runtime function");
4586 }
4587
4588 const Runtime::Function* function = expr->function();
4589 ASSERT(function != NULL);
4590 if (function->intrinsic_type == Runtime::INLINE) {
4591 ASSERT(expr->name()->length() > 0);
4592 ASSERT(expr->name()->Get(0) == '_');
4593 // Call to an inline function.
4594 int lookup_index = static_cast<int>(function->function_id) -
4595 static_cast<int>(Runtime::kFirstInlineFunction);
4596 ASSERT(lookup_index >= 0);
4597 ASSERT(static_cast<size_t>(lookup_index) <
4598 ARRAY_SIZE(kInlineFunctionGenerators));
4599 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index];
4600
4601 // Call the inline code generator using the pointer-to-member.
4602 (this->*generator)(expr);
4603 } else {
4604 ASSERT(function->intrinsic_type == Runtime::RUNTIME);
4605 VisitArgumentList(expr->arguments());
4606 CHECK_BAILOUT;
4607
4608 Handle<String> name = expr->name();
4609 int argument_count = expr->arguments()->length();
4610 HCallRuntime* call =
4611 new(zone()) HCallRuntime(name, function, argument_count);
4612 call->set_position(RelocInfo::kNoPosition);
4613 Drop(argument_count);
4614 ast_context()->ReturnInstruction(call, expr->id());
4615 }
4616 }
4617
4618
VisitUnaryOperation(UnaryOperation * expr)4619 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
4620 Token::Value op = expr->op();
4621 if (op == Token::VOID) {
4622 VISIT_FOR_EFFECT(expr->expression());
4623 ast_context()->ReturnValue(graph()->GetConstantUndefined());
4624 } else if (op == Token::DELETE) {
4625 Property* prop = expr->expression()->AsProperty();
4626 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
4627 if (prop == NULL && var == NULL) {
4628 // Result of deleting non-property, non-variable reference is true.
4629 // Evaluate the subexpression for side effects.
4630 VISIT_FOR_EFFECT(expr->expression());
4631 ast_context()->ReturnValue(graph()->GetConstantTrue());
4632 } else if (var != NULL &&
4633 !var->is_global() &&
4634 var->AsSlot() != NULL &&
4635 var->AsSlot()->type() != Slot::LOOKUP) {
4636 // Result of deleting non-global, non-dynamic variables is false.
4637 // The subexpression does not have side effects.
4638 ast_context()->ReturnValue(graph()->GetConstantFalse());
4639 } else if (prop != NULL) {
4640 if (prop->is_synthetic()) {
4641 // Result of deleting parameters is false, even when they rewrite
4642 // to accesses on the arguments object.
4643 ast_context()->ReturnValue(graph()->GetConstantFalse());
4644 } else {
4645 VISIT_FOR_VALUE(prop->obj());
4646 VISIT_FOR_VALUE(prop->key());
4647 HValue* key = Pop();
4648 HValue* obj = Pop();
4649 HDeleteProperty* instr = new(zone()) HDeleteProperty(obj, key);
4650 ast_context()->ReturnInstruction(instr, expr->id());
4651 }
4652 } else if (var->is_global()) {
4653 BAILOUT("delete with global variable");
4654 } else {
4655 BAILOUT("delete with non-global variable");
4656 }
4657 } else if (op == Token::NOT) {
4658 if (ast_context()->IsTest()) {
4659 TestContext* context = TestContext::cast(ast_context());
4660 VisitForControl(expr->expression(),
4661 context->if_false(),
4662 context->if_true());
4663 } else if (ast_context()->IsValue()) {
4664 HBasicBlock* materialize_false = graph()->CreateBasicBlock();
4665 HBasicBlock* materialize_true = graph()->CreateBasicBlock();
4666 VISIT_FOR_CONTROL(expr->expression(),
4667 materialize_false,
4668 materialize_true);
4669 materialize_false->SetJoinId(expr->expression()->id());
4670 materialize_true->SetJoinId(expr->expression()->id());
4671
4672 set_current_block(materialize_false);
4673 Push(graph()->GetConstantFalse());
4674 set_current_block(materialize_true);
4675 Push(graph()->GetConstantTrue());
4676
4677 HBasicBlock* join =
4678 CreateJoin(materialize_false, materialize_true, expr->id());
4679 set_current_block(join);
4680 ast_context()->ReturnValue(Pop());
4681 } else {
4682 ASSERT(ast_context()->IsEffect());
4683 VisitForEffect(expr->expression());
4684 }
4685
4686 } else if (op == Token::TYPEOF) {
4687 VisitForTypeOf(expr->expression());
4688 if (HasStackOverflow()) return;
4689 HValue* value = Pop();
4690 ast_context()->ReturnInstruction(new(zone()) HTypeof(value), expr->id());
4691
4692 } else {
4693 VISIT_FOR_VALUE(expr->expression());
4694 HValue* value = Pop();
4695 HInstruction* instr = NULL;
4696 switch (op) {
4697 case Token::BIT_NOT:
4698 instr = new(zone()) HBitNot(value);
4699 break;
4700 case Token::SUB:
4701 instr = new(zone()) HMul(value, graph_->GetConstantMinus1());
4702 break;
4703 case Token::ADD:
4704 instr = new(zone()) HMul(value, graph_->GetConstant1());
4705 break;
4706 default:
4707 BAILOUT("Value: unsupported unary operation");
4708 break;
4709 }
4710 ast_context()->ReturnInstruction(instr, expr->id());
4711 }
4712 }
4713
4714
BuildIncrement(HValue * value,bool increment)4715 HInstruction* HGraphBuilder::BuildIncrement(HValue* value, bool increment) {
4716 HConstant* delta = increment
4717 ? graph_->GetConstant1()
4718 : graph_->GetConstantMinus1();
4719 HInstruction* instr = new(zone()) HAdd(value, delta);
4720 AssumeRepresentation(instr, Representation::Integer32());
4721 return instr;
4722 }
4723
4724
VisitCountOperation(CountOperation * expr)4725 void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
4726 Expression* target = expr->expression();
4727 VariableProxy* proxy = target->AsVariableProxy();
4728 Variable* var = proxy->AsVariable();
4729 Property* prop = target->AsProperty();
4730 ASSERT(var == NULL || prop == NULL);
4731 bool inc = expr->op() == Token::INC;
4732
4733 if (var != NULL) {
4734 VISIT_FOR_VALUE(target);
4735
4736 // Match the full code generator stack by simulating an extra stack
4737 // element for postfix operations in a non-effect context.
4738 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect();
4739 HValue* before = has_extra ? Top() : Pop();
4740 HInstruction* after = BuildIncrement(before, inc);
4741 AddInstruction(after);
4742 Push(after);
4743
4744 if (var->is_global()) {
4745 HandleGlobalVariableAssignment(var,
4746 after,
4747 expr->position(),
4748 expr->AssignmentId());
4749 } else if (var->IsStackAllocated()) {
4750 Bind(var, after);
4751 } else if (var->IsContextSlot()) {
4752 HValue* context = BuildContextChainWalk(var);
4753 int index = var->AsSlot()->index();
4754 HStoreContextSlot* instr =
4755 new(zone()) HStoreContextSlot(context, index, after);
4756 AddInstruction(instr);
4757 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
4758 } else {
4759 BAILOUT("lookup variable in count operation");
4760 }
4761 Drop(has_extra ? 2 : 1);
4762 ast_context()->ReturnValue(expr->is_postfix() ? before : after);
4763
4764 } else if (prop != NULL) {
4765 prop->RecordTypeFeedback(oracle());
4766
4767 if (prop->key()->IsPropertyName()) {
4768 // Named property.
4769
4770 // Match the full code generator stack by simulating an extra stack
4771 // element for postfix operations in a non-effect context.
4772 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect();
4773 if (has_extra) Push(graph_->GetConstantUndefined());
4774
4775 VISIT_FOR_VALUE(prop->obj());
4776 HValue* obj = Top();
4777
4778 HInstruction* load = NULL;
4779 if (prop->IsMonomorphic()) {
4780 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
4781 Handle<Map> map = prop->GetReceiverTypes()->first();
4782 load = BuildLoadNamed(obj, prop, map, name);
4783 } else {
4784 load = BuildLoadNamedGeneric(obj, prop);
4785 }
4786 PushAndAdd(load);
4787 if (load->HasSideEffects()) AddSimulate(expr->CountId());
4788
4789 HValue* before = Pop();
4790 // There is no deoptimization to after the increment, so we don't need
4791 // to simulate the expression stack after this instruction.
4792 HInstruction* after = BuildIncrement(before, inc);
4793 AddInstruction(after);
4794
4795 HInstruction* store = BuildStoreNamed(obj, after, prop);
4796 AddInstruction(store);
4797
4798 // Overwrite the receiver in the bailout environment with the result
4799 // of the operation, and the placeholder with the original value if
4800 // necessary.
4801 environment()->SetExpressionStackAt(0, after);
4802 if (has_extra) environment()->SetExpressionStackAt(1, before);
4803 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId());
4804 Drop(has_extra ? 2 : 1);
4805
4806 ast_context()->ReturnValue(expr->is_postfix() ? before : after);
4807
4808 } else {
4809 // Keyed property.
4810
4811 // Match the full code generator stack by simulate an extra stack element
4812 // for postfix operations in a non-effect context.
4813 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect();
4814 if (has_extra) Push(graph_->GetConstantUndefined());
4815
4816 VISIT_FOR_VALUE(prop->obj());
4817 VISIT_FOR_VALUE(prop->key());
4818 HValue* obj = environment()->ExpressionStackAt(1);
4819 HValue* key = environment()->ExpressionStackAt(0);
4820
4821 HInstruction* load = BuildLoadKeyed(obj, key, prop);
4822 PushAndAdd(load);
4823 if (load->HasSideEffects()) AddSimulate(expr->CountId());
4824
4825 HValue* before = Pop();
4826 // There is no deoptimization to after the increment, so we don't need
4827 // to simulate the expression stack after this instruction.
4828 HInstruction* after = BuildIncrement(before, inc);
4829 AddInstruction(after);
4830
4831 expr->RecordTypeFeedback(oracle());
4832 HInstruction* store = BuildStoreKeyed(obj, key, after, expr);
4833 AddInstruction(store);
4834
4835 // Drop the key from the bailout environment. Overwrite the receiver
4836 // with the result of the operation, and the placeholder with the
4837 // original value if necessary.
4838 Drop(1);
4839 environment()->SetExpressionStackAt(0, after);
4840 if (has_extra) environment()->SetExpressionStackAt(1, before);
4841 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId());
4842 Drop(has_extra ? 2 : 1);
4843
4844 ast_context()->ReturnValue(expr->is_postfix() ? before : after);
4845 }
4846
4847 } else {
4848 BAILOUT("invalid lhs in count operation");
4849 }
4850 }
4851
4852
BuildStringCharCodeAt(HValue * string,HValue * index)4853 HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* string,
4854 HValue* index) {
4855 AddInstruction(new(zone()) HCheckNonSmi(string));
4856 AddInstruction(new(zone()) HCheckInstanceType(
4857 string, FIRST_STRING_TYPE, LAST_STRING_TYPE));
4858 HStringLength* length = new(zone()) HStringLength(string);
4859 AddInstruction(length);
4860 HInstruction* checked_index =
4861 AddInstruction(new(zone()) HBoundsCheck(index, length));
4862 return new(zone()) HStringCharCodeAt(string, checked_index);
4863 }
4864
4865
BuildBinaryOperation(BinaryOperation * expr,HValue * left,HValue * right)4866 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr,
4867 HValue* left,
4868 HValue* right) {
4869 HInstruction* instr = NULL;
4870 switch (expr->op()) {
4871 case Token::ADD:
4872 instr = new(zone()) HAdd(left, right);
4873 break;
4874 case Token::SUB:
4875 instr = new(zone()) HSub(left, right);
4876 break;
4877 case Token::MUL:
4878 instr = new(zone()) HMul(left, right);
4879 break;
4880 case Token::MOD:
4881 instr = new(zone()) HMod(left, right);
4882 break;
4883 case Token::DIV:
4884 instr = new(zone()) HDiv(left, right);
4885 break;
4886 case Token::BIT_XOR:
4887 instr = new(zone()) HBitXor(left, right);
4888 break;
4889 case Token::BIT_AND:
4890 instr = new(zone()) HBitAnd(left, right);
4891 break;
4892 case Token::BIT_OR:
4893 instr = new(zone()) HBitOr(left, right);
4894 break;
4895 case Token::SAR:
4896 instr = new(zone()) HSar(left, right);
4897 break;
4898 case Token::SHR:
4899 instr = new(zone()) HShr(left, right);
4900 break;
4901 case Token::SHL:
4902 instr = new(zone()) HShl(left, right);
4903 break;
4904 default:
4905 UNREACHABLE();
4906 }
4907 TypeInfo info = oracle()->BinaryType(expr);
4908 // If we hit an uninitialized binary op stub we will get type info
4909 // for a smi operation. If one of the operands is a constant string
4910 // do not generate code assuming it is a smi operation.
4911 if (info.IsSmi() &&
4912 ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) ||
4913 (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) {
4914 return instr;
4915 }
4916 if (FLAG_trace_representation) {
4917 PrintF("Info: %s/%s\n", info.ToString(), ToRepresentation(info).Mnemonic());
4918 }
4919 Representation rep = ToRepresentation(info);
4920 // We only generate either int32 or generic tagged bitwise operations.
4921 if (instr->IsBitwiseBinaryOperation() && rep.IsDouble()) {
4922 rep = Representation::Integer32();
4923 }
4924 AssumeRepresentation(instr, rep);
4925 return instr;
4926 }
4927
4928
4929 // Check for the form (%_ClassOf(foo) === 'BarClass').
IsClassOfTest(CompareOperation * expr)4930 static bool IsClassOfTest(CompareOperation* expr) {
4931 if (expr->op() != Token::EQ_STRICT) return false;
4932 CallRuntime* call = expr->left()->AsCallRuntime();
4933 if (call == NULL) return false;
4934 Literal* literal = expr->right()->AsLiteral();
4935 if (literal == NULL) return false;
4936 if (!literal->handle()->IsString()) return false;
4937 if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false;
4938 ASSERT(call->arguments()->length() == 1);
4939 return true;
4940 }
4941
4942
VisitBinaryOperation(BinaryOperation * expr)4943 void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
4944 if (expr->op() == Token::COMMA) {
4945 VISIT_FOR_EFFECT(expr->left());
4946 // Visit the right subexpression in the same AST context as the entire
4947 // expression.
4948 Visit(expr->right());
4949
4950 } else if (expr->op() == Token::AND || expr->op() == Token::OR) {
4951 bool is_logical_and = (expr->op() == Token::AND);
4952 if (ast_context()->IsTest()) {
4953 TestContext* context = TestContext::cast(ast_context());
4954 // Translate left subexpression.
4955 HBasicBlock* eval_right = graph()->CreateBasicBlock();
4956 if (is_logical_and) {
4957 VISIT_FOR_CONTROL(expr->left(), eval_right, context->if_false());
4958 } else {
4959 VISIT_FOR_CONTROL(expr->left(), context->if_true(), eval_right);
4960 }
4961 eval_right->SetJoinId(expr->RightId());
4962
4963 // Translate right subexpression by visiting it in the same AST
4964 // context as the entire expression.
4965 set_current_block(eval_right);
4966 Visit(expr->right());
4967
4968 } else if (ast_context()->IsValue()) {
4969 VISIT_FOR_VALUE(expr->left());
4970 ASSERT(current_block() != NULL);
4971
4972 // We need an extra block to maintain edge-split form.
4973 HBasicBlock* empty_block = graph()->CreateBasicBlock();
4974 HBasicBlock* eval_right = graph()->CreateBasicBlock();
4975 HTest* test = is_logical_and
4976 ? new(zone()) HTest(Top(), eval_right, empty_block)
4977 : new(zone()) HTest(Top(), empty_block, eval_right);
4978 current_block()->Finish(test);
4979
4980 set_current_block(eval_right);
4981 Drop(1); // Value of the left subexpression.
4982 VISIT_FOR_VALUE(expr->right());
4983
4984 HBasicBlock* join_block =
4985 CreateJoin(empty_block, current_block(), expr->id());
4986 set_current_block(join_block);
4987 ast_context()->ReturnValue(Pop());
4988
4989 } else {
4990 ASSERT(ast_context()->IsEffect());
4991 // In an effect context, we don't need the value of the left
4992 // subexpression, only its control flow and side effects. We need an
4993 // extra block to maintain edge-split form.
4994 HBasicBlock* empty_block = graph()->CreateBasicBlock();
4995 HBasicBlock* right_block = graph()->CreateBasicBlock();
4996 HBasicBlock* join_block = graph()->CreateBasicBlock();
4997 if (is_logical_and) {
4998 VISIT_FOR_CONTROL(expr->left(), right_block, empty_block);
4999 } else {
5000 VISIT_FOR_CONTROL(expr->left(), empty_block, right_block);
5001 }
5002 // TODO(kmillikin): Find a way to fix this. It's ugly that there are
5003 // actually two empty blocks (one here and one inserted by
5004 // TestContext::BuildBranch, and that they both have an HSimulate
5005 // though the second one is not a merge node, and that we really have
5006 // no good AST ID to put on that first HSimulate.
5007 empty_block->SetJoinId(expr->id());
5008 right_block->SetJoinId(expr->RightId());
5009 set_current_block(right_block);
5010 VISIT_FOR_EFFECT(expr->right());
5011
5012 empty_block->Goto(join_block);
5013 current_block()->Goto(join_block);
5014 join_block->SetJoinId(expr->id());
5015 set_current_block(join_block);
5016 // We did not materialize any value in the predecessor environments,
5017 // so there is no need to handle it here.
5018 }
5019
5020 } else {
5021 VISIT_FOR_VALUE(expr->left());
5022 VISIT_FOR_VALUE(expr->right());
5023
5024 HValue* right = Pop();
5025 HValue* left = Pop();
5026 HInstruction* instr = BuildBinaryOperation(expr, left, right);
5027 instr->set_position(expr->position());
5028 ast_context()->ReturnInstruction(instr, expr->id());
5029 }
5030 }
5031
5032
AssumeRepresentation(HValue * value,Representation r)5033 void HGraphBuilder::AssumeRepresentation(HValue* value, Representation r) {
5034 if (value->CheckFlag(HValue::kFlexibleRepresentation)) {
5035 if (FLAG_trace_representation) {
5036 PrintF("Assume representation for %s to be %s (%d)\n",
5037 value->Mnemonic(),
5038 r.Mnemonic(),
5039 graph_->GetMaximumValueID());
5040 }
5041 value->ChangeRepresentation(r);
5042 // The representation of the value is dictated by type feedback and
5043 // will not be changed later.
5044 value->ClearFlag(HValue::kFlexibleRepresentation);
5045 } else if (FLAG_trace_representation) {
5046 PrintF("No representation assumed\n");
5047 }
5048 }
5049
5050
ToRepresentation(TypeInfo info)5051 Representation HGraphBuilder::ToRepresentation(TypeInfo info) {
5052 if (info.IsSmi()) return Representation::Integer32();
5053 if (info.IsInteger32()) return Representation::Integer32();
5054 if (info.IsDouble()) return Representation::Double();
5055 if (info.IsNumber()) return Representation::Double();
5056 return Representation::Tagged();
5057 }
5058
5059
VisitCompareOperation(CompareOperation * expr)5060 void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
5061 if (IsClassOfTest(expr)) {
5062 CallRuntime* call = expr->left()->AsCallRuntime();
5063 VISIT_FOR_VALUE(call->arguments()->at(0));
5064 HValue* value = Pop();
5065 Literal* literal = expr->right()->AsLiteral();
5066 Handle<String> rhs = Handle<String>::cast(literal->handle());
5067 HInstruction* instr = new(zone()) HClassOfTest(value, rhs);
5068 instr->set_position(expr->position());
5069 ast_context()->ReturnInstruction(instr, expr->id());
5070 return;
5071 }
5072
5073 // Check for the pattern: typeof <expression> == <string literal>.
5074 UnaryOperation* left_unary = expr->left()->AsUnaryOperation();
5075 Literal* right_literal = expr->right()->AsLiteral();
5076 if ((expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT) &&
5077 left_unary != NULL && left_unary->op() == Token::TYPEOF &&
5078 right_literal != NULL && right_literal->handle()->IsString()) {
5079 VisitForTypeOf(left_unary->expression());
5080 if (HasStackOverflow()) return;
5081 HValue* left = Pop();
5082 HInstruction* instr = new(zone()) HTypeofIs(left,
5083 Handle<String>::cast(right_literal->handle()));
5084 instr->set_position(expr->position());
5085 ast_context()->ReturnInstruction(instr, expr->id());
5086 return;
5087 }
5088
5089 VISIT_FOR_VALUE(expr->left());
5090 VISIT_FOR_VALUE(expr->right());
5091
5092 HValue* right = Pop();
5093 HValue* left = Pop();
5094 Token::Value op = expr->op();
5095
5096 TypeInfo type_info = oracle()->CompareType(expr);
5097 HInstruction* instr = NULL;
5098 if (op == Token::INSTANCEOF) {
5099 // Check to see if the rhs of the instanceof is a global function not
5100 // residing in new space. If it is we assume that the function will stay the
5101 // same.
5102 Handle<JSFunction> target = Handle<JSFunction>::null();
5103 Variable* var = expr->right()->AsVariableProxy()->AsVariable();
5104 bool global_function = (var != NULL) && var->is_global() && !var->is_this();
5105 if (global_function &&
5106 info()->has_global_object() &&
5107 !info()->global_object()->IsAccessCheckNeeded()) {
5108 Handle<String> name = var->name();
5109 Handle<GlobalObject> global(info()->global_object());
5110 LookupResult lookup;
5111 global->Lookup(*name, &lookup);
5112 if (lookup.IsProperty() &&
5113 lookup.type() == NORMAL &&
5114 lookup.GetValue()->IsJSFunction()) {
5115 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue()));
5116 // If the function is in new space we assume it's more likely to
5117 // change and thus prefer the general IC code.
5118 if (!isolate()->heap()->InNewSpace(*candidate)) {
5119 target = candidate;
5120 }
5121 }
5122 }
5123
5124 // If the target is not null we have found a known global function that is
5125 // assumed to stay the same for this instanceof.
5126 if (target.is_null()) {
5127 HContext* context = new(zone()) HContext;
5128 AddInstruction(context);
5129 instr = new(zone()) HInstanceOf(context, left, right);
5130 } else {
5131 AddInstruction(new(zone()) HCheckFunction(right, target));
5132 instr = new(zone()) HInstanceOfKnownGlobal(left, target);
5133 }
5134 } else if (op == Token::IN) {
5135 BAILOUT("Unsupported comparison: in");
5136 } else if (type_info.IsNonPrimitive()) {
5137 switch (op) {
5138 case Token::EQ:
5139 case Token::EQ_STRICT: {
5140 AddInstruction(new(zone()) HCheckNonSmi(left));
5141 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left));
5142 AddInstruction(new(zone()) HCheckNonSmi(right));
5143 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right));
5144 instr = new(zone()) HCompareJSObjectEq(left, right);
5145 break;
5146 }
5147 default:
5148 BAILOUT("Unsupported non-primitive compare");
5149 break;
5150 }
5151 } else {
5152 HCompare* compare = new(zone()) HCompare(left, right, op);
5153 Representation r = ToRepresentation(type_info);
5154 compare->SetInputRepresentation(r);
5155 instr = compare;
5156 }
5157 instr->set_position(expr->position());
5158 ast_context()->ReturnInstruction(instr, expr->id());
5159 }
5160
5161
VisitCompareToNull(CompareToNull * expr)5162 void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) {
5163 VISIT_FOR_VALUE(expr->expression());
5164
5165 HValue* value = Pop();
5166 HIsNull* compare = new(zone()) HIsNull(value, expr->is_strict());
5167 ast_context()->ReturnInstruction(compare, expr->id());
5168 }
5169
5170
VisitThisFunction(ThisFunction * expr)5171 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) {
5172 BAILOUT("ThisFunction");
5173 }
5174
5175
VisitDeclaration(Declaration * decl)5176 void HGraphBuilder::VisitDeclaration(Declaration* decl) {
5177 // We allow only declarations that do not require code generation.
5178 // The following all require code generation: global variables and
5179 // functions, variables with slot type LOOKUP, declarations with
5180 // mode CONST, and functions.
5181 Variable* var = decl->proxy()->var();
5182 Slot* slot = var->AsSlot();
5183 if (var->is_global() ||
5184 (slot != NULL && slot->type() == Slot::LOOKUP) ||
5185 decl->mode() == Variable::CONST ||
5186 decl->fun() != NULL) {
5187 BAILOUT("unsupported declaration");
5188 }
5189 }
5190
5191
5192 // Generators for inline runtime functions.
5193 // Support for types.
GenerateIsSmi(CallRuntime * call)5194 void HGraphBuilder::GenerateIsSmi(CallRuntime* call) {
5195 ASSERT(call->arguments()->length() == 1);
5196 VISIT_FOR_VALUE(call->arguments()->at(0));
5197 HValue* value = Pop();
5198 HIsSmi* result = new(zone()) HIsSmi(value);
5199 ast_context()->ReturnInstruction(result, call->id());
5200 }
5201
5202
GenerateIsSpecObject(CallRuntime * call)5203 void HGraphBuilder::GenerateIsSpecObject(CallRuntime* call) {
5204 ASSERT(call->arguments()->length() == 1);
5205 VISIT_FOR_VALUE(call->arguments()->at(0));
5206 HValue* value = Pop();
5207 HHasInstanceType* result =
5208 new(zone()) HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE);
5209 ast_context()->ReturnInstruction(result, call->id());
5210 }
5211
5212
GenerateIsFunction(CallRuntime * call)5213 void HGraphBuilder::GenerateIsFunction(CallRuntime* call) {
5214 ASSERT(call->arguments()->length() == 1);
5215 VISIT_FOR_VALUE(call->arguments()->at(0));
5216 HValue* value = Pop();
5217 HHasInstanceType* result =
5218 new(zone()) HHasInstanceType(value, JS_FUNCTION_TYPE);
5219 ast_context()->ReturnInstruction(result, call->id());
5220 }
5221
5222
GenerateHasCachedArrayIndex(CallRuntime * call)5223 void HGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) {
5224 ASSERT(call->arguments()->length() == 1);
5225 VISIT_FOR_VALUE(call->arguments()->at(0));
5226 HValue* value = Pop();
5227 HHasCachedArrayIndex* result = new(zone()) HHasCachedArrayIndex(value);
5228 ast_context()->ReturnInstruction(result, call->id());
5229 }
5230
5231
GenerateIsArray(CallRuntime * call)5232 void HGraphBuilder::GenerateIsArray(CallRuntime* call) {
5233 ASSERT(call->arguments()->length() == 1);
5234 VISIT_FOR_VALUE(call->arguments()->at(0));
5235 HValue* value = Pop();
5236 HHasInstanceType* result = new(zone()) HHasInstanceType(value, JS_ARRAY_TYPE);
5237 ast_context()->ReturnInstruction(result, call->id());
5238 }
5239
5240
GenerateIsRegExp(CallRuntime * call)5241 void HGraphBuilder::GenerateIsRegExp(CallRuntime* call) {
5242 ASSERT(call->arguments()->length() == 1);
5243 VISIT_FOR_VALUE(call->arguments()->at(0));
5244 HValue* value = Pop();
5245 HHasInstanceType* result =
5246 new(zone()) HHasInstanceType(value, JS_REGEXP_TYPE);
5247 ast_context()->ReturnInstruction(result, call->id());
5248 }
5249
5250
GenerateIsObject(CallRuntime * call)5251 void HGraphBuilder::GenerateIsObject(CallRuntime* call) {
5252 ASSERT(call->arguments()->length() == 1);
5253 VISIT_FOR_VALUE(call->arguments()->at(0));
5254 HValue* value = Pop();
5255 HIsObject* test = new(zone()) HIsObject(value);
5256 ast_context()->ReturnInstruction(test, call->id());
5257 }
5258
5259
GenerateIsNonNegativeSmi(CallRuntime * call)5260 void HGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) {
5261 BAILOUT("inlined runtime function: IsNonNegativeSmi");
5262 }
5263
5264
GenerateIsUndetectableObject(CallRuntime * call)5265 void HGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) {
5266 BAILOUT("inlined runtime function: IsUndetectableObject");
5267 }
5268
5269
GenerateIsStringWrapperSafeForDefaultValueOf(CallRuntime * call)5270 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf(
5271 CallRuntime* call) {
5272 BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf");
5273 }
5274
5275
5276 // Support for construct call checks.
GenerateIsConstructCall(CallRuntime * call)5277 void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) {
5278 ASSERT(call->arguments()->length() == 0);
5279 if (function_state()->outer() != NULL) {
5280 // We are generating graph for inlined function. Currently
5281 // constructor inlining is not supported and we can just return
5282 // false from %_IsConstructCall().
5283 ast_context()->ReturnValue(graph()->GetConstantFalse());
5284 } else {
5285 ast_context()->ReturnInstruction(new(zone()) HIsConstructCall, call->id());
5286 }
5287 }
5288
5289
5290 // Support for arguments.length and arguments[?].
GenerateArgumentsLength(CallRuntime * call)5291 void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) {
5292 // Our implementation of arguments (based on this stack frame or an
5293 // adapter below it) does not work for inlined functions. This runtime
5294 // function is blacklisted by AstNode::IsInlineable.
5295 ASSERT(function_state()->outer() == NULL);
5296 ASSERT(call->arguments()->length() == 0);
5297 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
5298 HArgumentsLength* result = new(zone()) HArgumentsLength(elements);
5299 ast_context()->ReturnInstruction(result, call->id());
5300 }
5301
5302
GenerateArguments(CallRuntime * call)5303 void HGraphBuilder::GenerateArguments(CallRuntime* call) {
5304 // Our implementation of arguments (based on this stack frame or an
5305 // adapter below it) does not work for inlined functions. This runtime
5306 // function is blacklisted by AstNode::IsInlineable.
5307 ASSERT(function_state()->outer() == NULL);
5308 ASSERT(call->arguments()->length() == 1);
5309 VISIT_FOR_VALUE(call->arguments()->at(0));
5310 HValue* index = Pop();
5311 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
5312 HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements));
5313 HAccessArgumentsAt* result =
5314 new(zone()) HAccessArgumentsAt(elements, length, index);
5315 ast_context()->ReturnInstruction(result, call->id());
5316 }
5317
5318
5319 // Support for accessing the class and value fields of an object.
GenerateClassOf(CallRuntime * call)5320 void HGraphBuilder::GenerateClassOf(CallRuntime* call) {
5321 // The special form detected by IsClassOfTest is detected before we get here
5322 // and does not cause a bailout.
5323 BAILOUT("inlined runtime function: ClassOf");
5324 }
5325
5326
GenerateValueOf(CallRuntime * call)5327 void HGraphBuilder::GenerateValueOf(CallRuntime* call) {
5328 ASSERT(call->arguments()->length() == 1);
5329 VISIT_FOR_VALUE(call->arguments()->at(0));
5330 HValue* value = Pop();
5331 HValueOf* result = new(zone()) HValueOf(value);
5332 ast_context()->ReturnInstruction(result, call->id());
5333 }
5334
5335
GenerateSetValueOf(CallRuntime * call)5336 void HGraphBuilder::GenerateSetValueOf(CallRuntime* call) {
5337 BAILOUT("inlined runtime function: SetValueOf");
5338 }
5339
5340
5341 // Fast support for charCodeAt(n).
GenerateStringCharCodeAt(CallRuntime * call)5342 void HGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) {
5343 ASSERT(call->arguments()->length() == 2);
5344 VISIT_FOR_VALUE(call->arguments()->at(0));
5345 VISIT_FOR_VALUE(call->arguments()->at(1));
5346 HValue* index = Pop();
5347 HValue* string = Pop();
5348 HStringCharCodeAt* result = BuildStringCharCodeAt(string, index);
5349 ast_context()->ReturnInstruction(result, call->id());
5350 }
5351
5352
5353 // Fast support for string.charAt(n) and string[n].
GenerateStringCharFromCode(CallRuntime * call)5354 void HGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) {
5355 ASSERT(call->arguments()->length() == 1);
5356 VISIT_FOR_VALUE(call->arguments()->at(0));
5357 HValue* char_code = Pop();
5358 HStringCharFromCode* result = new(zone()) HStringCharFromCode(char_code);
5359 ast_context()->ReturnInstruction(result, call->id());
5360 }
5361
5362
5363 // Fast support for string.charAt(n) and string[n].
GenerateStringCharAt(CallRuntime * call)5364 void HGraphBuilder::GenerateStringCharAt(CallRuntime* call) {
5365 ASSERT(call->arguments()->length() == 2);
5366 VISIT_FOR_VALUE(call->arguments()->at(0));
5367 VISIT_FOR_VALUE(call->arguments()->at(1));
5368 HValue* index = Pop();
5369 HValue* string = Pop();
5370 HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index);
5371 AddInstruction(char_code);
5372 HStringCharFromCode* result = new(zone()) HStringCharFromCode(char_code);
5373 ast_context()->ReturnInstruction(result, call->id());
5374 }
5375
5376
5377 // Fast support for object equality testing.
GenerateObjectEquals(CallRuntime * call)5378 void HGraphBuilder::GenerateObjectEquals(CallRuntime* call) {
5379 ASSERT(call->arguments()->length() == 2);
5380 VISIT_FOR_VALUE(call->arguments()->at(0));
5381 VISIT_FOR_VALUE(call->arguments()->at(1));
5382 HValue* right = Pop();
5383 HValue* left = Pop();
5384 HCompareJSObjectEq* result = new(zone()) HCompareJSObjectEq(left, right);
5385 ast_context()->ReturnInstruction(result, call->id());
5386 }
5387
5388
GenerateLog(CallRuntime * call)5389 void HGraphBuilder::GenerateLog(CallRuntime* call) {
5390 // %_Log is ignored in optimized code.
5391 ast_context()->ReturnValue(graph()->GetConstantUndefined());
5392 }
5393
5394
5395 // Fast support for Math.random().
GenerateRandomHeapNumber(CallRuntime * call)5396 void HGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) {
5397 BAILOUT("inlined runtime function: RandomHeapNumber");
5398 }
5399
5400
5401 // Fast support for StringAdd.
GenerateStringAdd(CallRuntime * call)5402 void HGraphBuilder::GenerateStringAdd(CallRuntime* call) {
5403 ASSERT_EQ(2, call->arguments()->length());
5404 VisitArgumentList(call->arguments());
5405 CHECK_BAILOUT;
5406 HContext* context = new(zone()) HContext;
5407 AddInstruction(context);
5408 HCallStub* result = new(zone()) HCallStub(context, CodeStub::StringAdd, 2);
5409 Drop(2);
5410 ast_context()->ReturnInstruction(result, call->id());
5411 }
5412
5413
5414 // Fast support for SubString.
GenerateSubString(CallRuntime * call)5415 void HGraphBuilder::GenerateSubString(CallRuntime* call) {
5416 ASSERT_EQ(3, call->arguments()->length());
5417 VisitArgumentList(call->arguments());
5418 CHECK_BAILOUT;
5419 HContext* context = new(zone()) HContext;
5420 AddInstruction(context);
5421 HCallStub* result = new(zone()) HCallStub(context, CodeStub::SubString, 3);
5422 Drop(3);
5423 ast_context()->ReturnInstruction(result, call->id());
5424 }
5425
5426
5427 // Fast support for StringCompare.
GenerateStringCompare(CallRuntime * call)5428 void HGraphBuilder::GenerateStringCompare(CallRuntime* call) {
5429 ASSERT_EQ(2, call->arguments()->length());
5430 VisitArgumentList(call->arguments());
5431 CHECK_BAILOUT;
5432 HContext* context = new(zone()) HContext;
5433 AddInstruction(context);
5434 HCallStub* result =
5435 new(zone()) HCallStub(context, CodeStub::StringCompare, 2);
5436 Drop(2);
5437 ast_context()->ReturnInstruction(result, call->id());
5438 }
5439
5440
5441 // Support for direct calls from JavaScript to native RegExp code.
GenerateRegExpExec(CallRuntime * call)5442 void HGraphBuilder::GenerateRegExpExec(CallRuntime* call) {
5443 ASSERT_EQ(4, call->arguments()->length());
5444 VisitArgumentList(call->arguments());
5445 CHECK_BAILOUT;
5446 HContext* context = new(zone()) HContext;
5447 AddInstruction(context);
5448 HCallStub* result = new(zone()) HCallStub(context, CodeStub::RegExpExec, 4);
5449 Drop(4);
5450 ast_context()->ReturnInstruction(result, call->id());
5451 }
5452
5453
5454 // Construct a RegExp exec result with two in-object properties.
GenerateRegExpConstructResult(CallRuntime * call)5455 void HGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) {
5456 ASSERT_EQ(3, call->arguments()->length());
5457 VisitArgumentList(call->arguments());
5458 CHECK_BAILOUT;
5459 HContext* context = new(zone()) HContext;
5460 AddInstruction(context);
5461 HCallStub* result =
5462 new(zone()) HCallStub(context, CodeStub::RegExpConstructResult, 3);
5463 Drop(3);
5464 ast_context()->ReturnInstruction(result, call->id());
5465 }
5466
5467
5468 // Support for fast native caches.
GenerateGetFromCache(CallRuntime * call)5469 void HGraphBuilder::GenerateGetFromCache(CallRuntime* call) {
5470 BAILOUT("inlined runtime function: GetFromCache");
5471 }
5472
5473
5474 // Fast support for number to string.
GenerateNumberToString(CallRuntime * call)5475 void HGraphBuilder::GenerateNumberToString(CallRuntime* call) {
5476 ASSERT_EQ(1, call->arguments()->length());
5477 VisitArgumentList(call->arguments());
5478 CHECK_BAILOUT;
5479 HContext* context = new(zone()) HContext;
5480 AddInstruction(context);
5481 HCallStub* result =
5482 new(zone()) HCallStub(context, CodeStub::NumberToString, 1);
5483 Drop(1);
5484 ast_context()->ReturnInstruction(result, call->id());
5485 }
5486
5487
5488 // Fast swapping of elements. Takes three expressions, the object and two
5489 // indices. This should only be used if the indices are known to be
5490 // non-negative and within bounds of the elements array at the call site.
GenerateSwapElements(CallRuntime * call)5491 void HGraphBuilder::GenerateSwapElements(CallRuntime* call) {
5492 BAILOUT("inlined runtime function: SwapElements");
5493 }
5494
5495
5496 // Fast call for custom callbacks.
GenerateCallFunction(CallRuntime * call)5497 void HGraphBuilder::GenerateCallFunction(CallRuntime* call) {
5498 BAILOUT("inlined runtime function: CallFunction");
5499 }
5500
5501
5502 // Fast call to math functions.
GenerateMathPow(CallRuntime * call)5503 void HGraphBuilder::GenerateMathPow(CallRuntime* call) {
5504 ASSERT_EQ(2, call->arguments()->length());
5505 VISIT_FOR_VALUE(call->arguments()->at(0));
5506 VISIT_FOR_VALUE(call->arguments()->at(1));
5507 HValue* right = Pop();
5508 HValue* left = Pop();
5509 HPower* result = new(zone()) HPower(left, right);
5510 ast_context()->ReturnInstruction(result, call->id());
5511 }
5512
5513
GenerateMathSin(CallRuntime * call)5514 void HGraphBuilder::GenerateMathSin(CallRuntime* call) {
5515 ASSERT_EQ(1, call->arguments()->length());
5516 VisitArgumentList(call->arguments());
5517 CHECK_BAILOUT;
5518 HContext* context = new(zone()) HContext;
5519 AddInstruction(context);
5520 HCallStub* result =
5521 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
5522 result->set_transcendental_type(TranscendentalCache::SIN);
5523 Drop(1);
5524 ast_context()->ReturnInstruction(result, call->id());
5525 }
5526
5527
GenerateMathCos(CallRuntime * call)5528 void HGraphBuilder::GenerateMathCos(CallRuntime* call) {
5529 ASSERT_EQ(1, call->arguments()->length());
5530 VisitArgumentList(call->arguments());
5531 CHECK_BAILOUT;
5532 HContext* context = new(zone()) HContext;
5533 AddInstruction(context);
5534 HCallStub* result =
5535 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
5536 result->set_transcendental_type(TranscendentalCache::COS);
5537 Drop(1);
5538 ast_context()->ReturnInstruction(result, call->id());
5539 }
5540
5541
GenerateMathLog(CallRuntime * call)5542 void HGraphBuilder::GenerateMathLog(CallRuntime* call) {
5543 ASSERT_EQ(1, call->arguments()->length());
5544 VisitArgumentList(call->arguments());
5545 CHECK_BAILOUT;
5546 HContext* context = new(zone()) HContext;
5547 AddInstruction(context);
5548 HCallStub* result =
5549 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
5550 result->set_transcendental_type(TranscendentalCache::LOG);
5551 Drop(1);
5552 ast_context()->ReturnInstruction(result, call->id());
5553 }
5554
5555
GenerateMathSqrt(CallRuntime * call)5556 void HGraphBuilder::GenerateMathSqrt(CallRuntime* call) {
5557 BAILOUT("inlined runtime function: MathSqrt");
5558 }
5559
5560
5561 // Check whether two RegExps are equivalent
GenerateIsRegExpEquivalent(CallRuntime * call)5562 void HGraphBuilder::GenerateIsRegExpEquivalent(CallRuntime* call) {
5563 BAILOUT("inlined runtime function: IsRegExpEquivalent");
5564 }
5565
5566
GenerateGetCachedArrayIndex(CallRuntime * call)5567 void HGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) {
5568 ASSERT(call->arguments()->length() == 1);
5569 VISIT_FOR_VALUE(call->arguments()->at(0));
5570 HValue* value = Pop();
5571 HGetCachedArrayIndex* result = new(zone()) HGetCachedArrayIndex(value);
5572 ast_context()->ReturnInstruction(result, call->id());
5573 }
5574
5575
GenerateFastAsciiArrayJoin(CallRuntime * call)5576 void HGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) {
5577 BAILOUT("inlined runtime function: FastAsciiArrayJoin");
5578 }
5579
5580
5581 #undef BAILOUT
5582 #undef CHECK_BAILOUT
5583 #undef VISIT_FOR_EFFECT
5584 #undef VISIT_FOR_VALUE
5585 #undef ADD_TO_SUBGRAPH
5586
5587
HEnvironment(HEnvironment * outer,Scope * scope,Handle<JSFunction> closure)5588 HEnvironment::HEnvironment(HEnvironment* outer,
5589 Scope* scope,
5590 Handle<JSFunction> closure)
5591 : closure_(closure),
5592 values_(0),
5593 assigned_variables_(4),
5594 parameter_count_(0),
5595 local_count_(0),
5596 outer_(outer),
5597 pop_count_(0),
5598 push_count_(0),
5599 ast_id_(AstNode::kNoNumber) {
5600 Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0);
5601 }
5602
5603
HEnvironment(const HEnvironment * other)5604 HEnvironment::HEnvironment(const HEnvironment* other)
5605 : values_(0),
5606 assigned_variables_(0),
5607 parameter_count_(0),
5608 local_count_(0),
5609 outer_(NULL),
5610 pop_count_(0),
5611 push_count_(0),
5612 ast_id_(other->ast_id()) {
5613 Initialize(other);
5614 }
5615
5616
Initialize(int parameter_count,int local_count,int stack_height)5617 void HEnvironment::Initialize(int parameter_count,
5618 int local_count,
5619 int stack_height) {
5620 parameter_count_ = parameter_count;
5621 local_count_ = local_count;
5622
5623 // Avoid reallocating the temporaries' backing store on the first Push.
5624 int total = parameter_count + local_count + stack_height;
5625 values_.Initialize(total + 4);
5626 for (int i = 0; i < total; ++i) values_.Add(NULL);
5627 }
5628
5629
Initialize(const HEnvironment * other)5630 void HEnvironment::Initialize(const HEnvironment* other) {
5631 closure_ = other->closure();
5632 values_.AddAll(other->values_);
5633 assigned_variables_.AddAll(other->assigned_variables_);
5634 parameter_count_ = other->parameter_count_;
5635 local_count_ = other->local_count_;
5636 if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy.
5637 pop_count_ = other->pop_count_;
5638 push_count_ = other->push_count_;
5639 ast_id_ = other->ast_id_;
5640 }
5641
5642
AddIncomingEdge(HBasicBlock * block,HEnvironment * other)5643 void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) {
5644 ASSERT(!block->IsLoopHeader());
5645 ASSERT(values_.length() == other->values_.length());
5646
5647 int length = values_.length();
5648 for (int i = 0; i < length; ++i) {
5649 HValue* value = values_[i];
5650 if (value != NULL && value->IsPhi() && value->block() == block) {
5651 // There is already a phi for the i'th value.
5652 HPhi* phi = HPhi::cast(value);
5653 // Assert index is correct and that we haven't missed an incoming edge.
5654 ASSERT(phi->merged_index() == i);
5655 ASSERT(phi->OperandCount() == block->predecessors()->length());
5656 phi->AddInput(other->values_[i]);
5657 } else if (values_[i] != other->values_[i]) {
5658 // There is a fresh value on the incoming edge, a phi is needed.
5659 ASSERT(values_[i] != NULL && other->values_[i] != NULL);
5660 HPhi* phi = new(block->zone()) HPhi(i);
5661 HValue* old_value = values_[i];
5662 for (int j = 0; j < block->predecessors()->length(); j++) {
5663 phi->AddInput(old_value);
5664 }
5665 phi->AddInput(other->values_[i]);
5666 this->values_[i] = phi;
5667 block->AddPhi(phi);
5668 }
5669 }
5670 }
5671
5672
Bind(int index,HValue * value)5673 void HEnvironment::Bind(int index, HValue* value) {
5674 ASSERT(value != NULL);
5675 if (!assigned_variables_.Contains(index)) {
5676 assigned_variables_.Add(index);
5677 }
5678 values_[index] = value;
5679 }
5680
5681
HasExpressionAt(int index) const5682 bool HEnvironment::HasExpressionAt(int index) const {
5683 return index >= parameter_count_ + local_count_;
5684 }
5685
5686
ExpressionStackIsEmpty() const5687 bool HEnvironment::ExpressionStackIsEmpty() const {
5688 int first_expression = parameter_count() + local_count();
5689 ASSERT(length() >= first_expression);
5690 return length() == first_expression;
5691 }
5692
5693
SetExpressionStackAt(int index_from_top,HValue * value)5694 void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) {
5695 int count = index_from_top + 1;
5696 int index = values_.length() - count;
5697 ASSERT(HasExpressionAt(index));
5698 // The push count must include at least the element in question or else
5699 // the new value will not be included in this environment's history.
5700 if (push_count_ < count) {
5701 // This is the same effect as popping then re-pushing 'count' elements.
5702 pop_count_ += (count - push_count_);
5703 push_count_ = count;
5704 }
5705 values_[index] = value;
5706 }
5707
5708
Drop(int count)5709 void HEnvironment::Drop(int count) {
5710 for (int i = 0; i < count; ++i) {
5711 Pop();
5712 }
5713 }
5714
5715
Copy() const5716 HEnvironment* HEnvironment::Copy() const {
5717 return new(closure()->GetIsolate()->zone()) HEnvironment(this);
5718 }
5719
5720
CopyWithoutHistory() const5721 HEnvironment* HEnvironment::CopyWithoutHistory() const {
5722 HEnvironment* result = Copy();
5723 result->ClearHistory();
5724 return result;
5725 }
5726
5727
CopyAsLoopHeader(HBasicBlock * loop_header) const5728 HEnvironment* HEnvironment::CopyAsLoopHeader(HBasicBlock* loop_header) const {
5729 HEnvironment* new_env = Copy();
5730 for (int i = 0; i < values_.length(); ++i) {
5731 HPhi* phi = new(loop_header->zone()) HPhi(i);
5732 phi->AddInput(values_[i]);
5733 new_env->values_[i] = phi;
5734 loop_header->AddPhi(phi);
5735 }
5736 new_env->ClearHistory();
5737 return new_env;
5738 }
5739
5740
CopyForInlining(Handle<JSFunction> target,FunctionLiteral * function,bool is_speculative,HConstant * undefined) const5741 HEnvironment* HEnvironment::CopyForInlining(Handle<JSFunction> target,
5742 FunctionLiteral* function,
5743 bool is_speculative,
5744 HConstant* undefined) const {
5745 // Outer environment is a copy of this one without the arguments.
5746 int arity = function->scope()->num_parameters();
5747 HEnvironment* outer = Copy();
5748 outer->Drop(arity + 1); // Including receiver.
5749 outer->ClearHistory();
5750 Zone* zone = closure()->GetIsolate()->zone();
5751 HEnvironment* inner =
5752 new(zone) HEnvironment(outer, function->scope(), target);
5753 // Get the argument values from the original environment.
5754 if (is_speculative) {
5755 for (int i = 0; i <= arity; ++i) { // Include receiver.
5756 HValue* push = ExpressionStackAt(arity - i);
5757 inner->SetValueAt(i, push);
5758 }
5759 } else {
5760 for (int i = 0; i <= arity; ++i) { // Include receiver.
5761 inner->SetValueAt(i, ExpressionStackAt(arity - i));
5762 }
5763 }
5764
5765 // Initialize the stack-allocated locals to undefined.
5766 int local_base = arity + 1;
5767 int local_count = function->scope()->num_stack_slots();
5768 for (int i = 0; i < local_count; ++i) {
5769 inner->SetValueAt(local_base + i, undefined);
5770 }
5771
5772 inner->set_ast_id(AstNode::kFunctionEntryId);
5773 return inner;
5774 }
5775
5776
PrintTo(StringStream * stream)5777 void HEnvironment::PrintTo(StringStream* stream) {
5778 for (int i = 0; i < length(); i++) {
5779 if (i == 0) stream->Add("parameters\n");
5780 if (i == parameter_count()) stream->Add("locals\n");
5781 if (i == parameter_count() + local_count()) stream->Add("expressions");
5782 HValue* val = values_.at(i);
5783 stream->Add("%d: ", i);
5784 if (val != NULL) {
5785 val->PrintNameTo(stream);
5786 } else {
5787 stream->Add("NULL");
5788 }
5789 stream->Add("\n");
5790 }
5791 }
5792
5793
PrintToStd()5794 void HEnvironment::PrintToStd() {
5795 HeapStringAllocator string_allocator;
5796 StringStream trace(&string_allocator);
5797 PrintTo(&trace);
5798 PrintF("%s", *trace.ToCString());
5799 }
5800
5801
TraceCompilation(FunctionLiteral * function)5802 void HTracer::TraceCompilation(FunctionLiteral* function) {
5803 Tag tag(this, "compilation");
5804 Handle<String> name = function->debug_name();
5805 PrintStringProperty("name", *name->ToCString());
5806 PrintStringProperty("method", *name->ToCString());
5807 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis()));
5808 }
5809
5810
TraceLithium(const char * name,LChunk * chunk)5811 void HTracer::TraceLithium(const char* name, LChunk* chunk) {
5812 Trace(name, chunk->graph(), chunk);
5813 }
5814
5815
TraceHydrogen(const char * name,HGraph * graph)5816 void HTracer::TraceHydrogen(const char* name, HGraph* graph) {
5817 Trace(name, graph, NULL);
5818 }
5819
5820
Trace(const char * name,HGraph * graph,LChunk * chunk)5821 void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
5822 Tag tag(this, "cfg");
5823 PrintStringProperty("name", name);
5824 const ZoneList<HBasicBlock*>* blocks = graph->blocks();
5825 for (int i = 0; i < blocks->length(); i++) {
5826 HBasicBlock* current = blocks->at(i);
5827 Tag block_tag(this, "block");
5828 PrintBlockProperty("name", current->block_id());
5829 PrintIntProperty("from_bci", -1);
5830 PrintIntProperty("to_bci", -1);
5831
5832 if (!current->predecessors()->is_empty()) {
5833 PrintIndent();
5834 trace_.Add("predecessors");
5835 for (int j = 0; j < current->predecessors()->length(); ++j) {
5836 trace_.Add(" \"B%d\"", current->predecessors()->at(j)->block_id());
5837 }
5838 trace_.Add("\n");
5839 } else {
5840 PrintEmptyProperty("predecessors");
5841 }
5842
5843 if (current->end() == NULL || current->end()->FirstSuccessor() == NULL) {
5844 PrintEmptyProperty("successors");
5845 } else if (current->end()->SecondSuccessor() == NULL) {
5846 PrintBlockProperty("successors",
5847 current->end()->FirstSuccessor()->block_id());
5848 } else {
5849 PrintBlockProperty("successors",
5850 current->end()->FirstSuccessor()->block_id(),
5851 current->end()->SecondSuccessor()->block_id());
5852 }
5853
5854 PrintEmptyProperty("xhandlers");
5855 PrintEmptyProperty("flags");
5856
5857 if (current->dominator() != NULL) {
5858 PrintBlockProperty("dominator", current->dominator()->block_id());
5859 }
5860
5861 if (chunk != NULL) {
5862 int first_index = current->first_instruction_index();
5863 int last_index = current->last_instruction_index();
5864 PrintIntProperty(
5865 "first_lir_id",
5866 LifetimePosition::FromInstructionIndex(first_index).Value());
5867 PrintIntProperty(
5868 "last_lir_id",
5869 LifetimePosition::FromInstructionIndex(last_index).Value());
5870 }
5871
5872 {
5873 Tag states_tag(this, "states");
5874 Tag locals_tag(this, "locals");
5875 int total = current->phis()->length();
5876 trace_.Add("size %d\n", total);
5877 trace_.Add("method \"None\"");
5878 for (int j = 0; j < total; ++j) {
5879 HPhi* phi = current->phis()->at(j);
5880 trace_.Add("%d ", phi->merged_index());
5881 phi->PrintNameTo(&trace_);
5882 trace_.Add(" ");
5883 phi->PrintTo(&trace_);
5884 trace_.Add("\n");
5885 }
5886 }
5887
5888 {
5889 Tag HIR_tag(this, "HIR");
5890 HInstruction* instruction = current->first();
5891 while (instruction != NULL) {
5892 int bci = 0;
5893 int uses = instruction->uses()->length();
5894 trace_.Add("%d %d ", bci, uses);
5895 instruction->PrintNameTo(&trace_);
5896 trace_.Add(" ");
5897 instruction->PrintTo(&trace_);
5898 trace_.Add(" <|@\n");
5899 instruction = instruction->next();
5900 }
5901 }
5902
5903
5904 if (chunk != NULL) {
5905 Tag LIR_tag(this, "LIR");
5906 int first_index = current->first_instruction_index();
5907 int last_index = current->last_instruction_index();
5908 if (first_index != -1 && last_index != -1) {
5909 const ZoneList<LInstruction*>* instructions = chunk->instructions();
5910 for (int i = first_index; i <= last_index; ++i) {
5911 LInstruction* linstr = instructions->at(i);
5912 if (linstr != NULL) {
5913 trace_.Add("%d ",
5914 LifetimePosition::FromInstructionIndex(i).Value());
5915 linstr->PrintTo(&trace_);
5916 trace_.Add(" <|@\n");
5917 }
5918 }
5919 }
5920 }
5921 }
5922 }
5923
5924
TraceLiveRanges(const char * name,LAllocator * allocator)5925 void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) {
5926 Tag tag(this, "intervals");
5927 PrintStringProperty("name", name);
5928
5929 const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges();
5930 for (int i = 0; i < fixed_d->length(); ++i) {
5931 TraceLiveRange(fixed_d->at(i), "fixed");
5932 }
5933
5934 const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges();
5935 for (int i = 0; i < fixed->length(); ++i) {
5936 TraceLiveRange(fixed->at(i), "fixed");
5937 }
5938
5939 const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges();
5940 for (int i = 0; i < live_ranges->length(); ++i) {
5941 TraceLiveRange(live_ranges->at(i), "object");
5942 }
5943 }
5944
5945
TraceLiveRange(LiveRange * range,const char * type)5946 void HTracer::TraceLiveRange(LiveRange* range, const char* type) {
5947 if (range != NULL && !range->IsEmpty()) {
5948 trace_.Add("%d %s", range->id(), type);
5949 if (range->HasRegisterAssigned()) {
5950 LOperand* op = range->CreateAssignedOperand();
5951 int assigned_reg = op->index();
5952 if (op->IsDoubleRegister()) {
5953 trace_.Add(" \"%s\"",
5954 DoubleRegister::AllocationIndexToString(assigned_reg));
5955 } else {
5956 ASSERT(op->IsRegister());
5957 trace_.Add(" \"%s\"", Register::AllocationIndexToString(assigned_reg));
5958 }
5959 } else if (range->IsSpilled()) {
5960 LOperand* op = range->TopLevel()->GetSpillOperand();
5961 if (op->IsDoubleStackSlot()) {
5962 trace_.Add(" \"double_stack:%d\"", op->index());
5963 } else {
5964 ASSERT(op->IsStackSlot());
5965 trace_.Add(" \"stack:%d\"", op->index());
5966 }
5967 }
5968 int parent_index = -1;
5969 if (range->IsChild()) {
5970 parent_index = range->parent()->id();
5971 } else {
5972 parent_index = range->id();
5973 }
5974 LOperand* op = range->FirstHint();
5975 int hint_index = -1;
5976 if (op != NULL && op->IsUnallocated()) hint_index = op->VirtualRegister();
5977 trace_.Add(" %d %d", parent_index, hint_index);
5978 UseInterval* cur_interval = range->first_interval();
5979 while (cur_interval != NULL && range->Covers(cur_interval->start())) {
5980 trace_.Add(" [%d, %d[",
5981 cur_interval->start().Value(),
5982 cur_interval->end().Value());
5983 cur_interval = cur_interval->next();
5984 }
5985
5986 UsePosition* current_pos = range->first_pos();
5987 while (current_pos != NULL) {
5988 if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
5989 trace_.Add(" %d M", current_pos->pos().Value());
5990 }
5991 current_pos = current_pos->next();
5992 }
5993
5994 trace_.Add(" \"\"\n");
5995 }
5996 }
5997
5998
FlushToFile()5999 void HTracer::FlushToFile() {
6000 AppendChars(filename_, *trace_.ToCString(), trace_.length(), false);
6001 trace_.Reset();
6002 }
6003
6004
Initialize(CompilationInfo * info)6005 void HStatistics::Initialize(CompilationInfo* info) {
6006 source_size_ += info->shared_info()->SourceSize();
6007 }
6008
6009
Print()6010 void HStatistics::Print() {
6011 PrintF("Timing results:\n");
6012 int64_t sum = 0;
6013 for (int i = 0; i < timing_.length(); ++i) {
6014 sum += timing_[i];
6015 }
6016
6017 for (int i = 0; i < names_.length(); ++i) {
6018 PrintF("%30s", names_[i]);
6019 double ms = static_cast<double>(timing_[i]) / 1000;
6020 double percent = static_cast<double>(timing_[i]) * 100 / sum;
6021 PrintF(" - %7.3f ms / %4.1f %% ", ms, percent);
6022
6023 unsigned size = sizes_[i];
6024 double size_percent = static_cast<double>(size) * 100 / total_size_;
6025 PrintF(" %8u bytes / %4.1f %%\n", size, size_percent);
6026 }
6027 double source_size_in_kb = static_cast<double>(source_size_) / 1024;
6028 double normalized_time = source_size_in_kb > 0
6029 ? (static_cast<double>(sum) / 1000) / source_size_in_kb
6030 : 0;
6031 double normalized_bytes = source_size_in_kb > 0
6032 ? total_size_ / source_size_in_kb
6033 : 0;
6034 PrintF("%30s - %7.3f ms %7.3f bytes\n", "Sum",
6035 normalized_time, normalized_bytes);
6036 PrintF("---------------------------------------------------------------\n");
6037 PrintF("%30s - %7.3f ms (%.1f times slower than full code gen)\n",
6038 "Total",
6039 static_cast<double>(total_) / 1000,
6040 static_cast<double>(total_) / full_code_gen_);
6041 }
6042
6043
SaveTiming(const char * name,int64_t ticks,unsigned size)6044 void HStatistics::SaveTiming(const char* name, int64_t ticks, unsigned size) {
6045 if (name == HPhase::kFullCodeGen) {
6046 full_code_gen_ += ticks;
6047 } else if (name == HPhase::kTotal) {
6048 total_ += ticks;
6049 } else {
6050 total_size_ += size;
6051 for (int i = 0; i < names_.length(); ++i) {
6052 if (names_[i] == name) {
6053 timing_[i] += ticks;
6054 sizes_[i] += size;
6055 return;
6056 }
6057 }
6058 names_.Add(name);
6059 timing_.Add(ticks);
6060 sizes_.Add(size);
6061 }
6062 }
6063
6064
6065 const char* const HPhase::kFullCodeGen = "Full code generator";
6066 const char* const HPhase::kTotal = "Total";
6067
6068
Begin(const char * name,HGraph * graph,LChunk * chunk,LAllocator * allocator)6069 void HPhase::Begin(const char* name,
6070 HGraph* graph,
6071 LChunk* chunk,
6072 LAllocator* allocator) {
6073 name_ = name;
6074 graph_ = graph;
6075 chunk_ = chunk;
6076 allocator_ = allocator;
6077 if (allocator != NULL && chunk_ == NULL) {
6078 chunk_ = allocator->chunk();
6079 }
6080 if (FLAG_hydrogen_stats) start_ = OS::Ticks();
6081 start_allocation_size_ = Zone::allocation_size_;
6082 }
6083
6084
End() const6085 void HPhase::End() const {
6086 if (FLAG_hydrogen_stats) {
6087 int64_t end = OS::Ticks();
6088 unsigned size = Zone::allocation_size_ - start_allocation_size_;
6089 HStatistics::Instance()->SaveTiming(name_, end - start_, size);
6090 }
6091
6092 if (FLAG_trace_hydrogen) {
6093 if (graph_ != NULL) HTracer::Instance()->TraceHydrogen(name_, graph_);
6094 if (chunk_ != NULL) HTracer::Instance()->TraceLithium(name_, chunk_);
6095 if (allocator_ != NULL) {
6096 HTracer::Instance()->TraceLiveRanges(name_, allocator_);
6097 }
6098 }
6099
6100 #ifdef DEBUG
6101 if (graph_ != NULL) graph_->Verify();
6102 if (allocator_ != NULL) allocator_->Verify();
6103 #endif
6104 }
6105
6106 } } // namespace v8::internal
6107