The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / hydrogen.cc @ f230a1cf

History | View | Annotate | Download (339 KB)

1
// Copyright 2013 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 "hydrogen.h"
29

    
30
#include <algorithm>
31

    
32
#include "v8.h"
33
#include "allocation-site-scopes.h"
34
#include "codegen.h"
35
#include "full-codegen.h"
36
#include "hashmap.h"
37
#include "hydrogen-bce.h"
38
#include "hydrogen-bch.h"
39
#include "hydrogen-canonicalize.h"
40
#include "hydrogen-check-elimination.h"
41
#include "hydrogen-dce.h"
42
#include "hydrogen-dehoist.h"
43
#include "hydrogen-environment-liveness.h"
44
#include "hydrogen-escape-analysis.h"
45
#include "hydrogen-infer-representation.h"
46
#include "hydrogen-infer-types.h"
47
#include "hydrogen-load-elimination.h"
48
#include "hydrogen-gvn.h"
49
#include "hydrogen-mark-deoptimize.h"
50
#include "hydrogen-mark-unreachable.h"
51
#include "hydrogen-minus-zero.h"
52
#include "hydrogen-osr.h"
53
#include "hydrogen-range-analysis.h"
54
#include "hydrogen-redundant-phi.h"
55
#include "hydrogen-removable-simulates.h"
56
#include "hydrogen-representation-changes.h"
57
#include "hydrogen-sce.h"
58
#include "hydrogen-uint32-analysis.h"
59
#include "lithium-allocator.h"
60
#include "parser.h"
61
#include "scopeinfo.h"
62
#include "scopes.h"
63
#include "stub-cache.h"
64
#include "typing.h"
65

    
66
#if V8_TARGET_ARCH_IA32
67
#include "ia32/lithium-codegen-ia32.h"
68
#elif V8_TARGET_ARCH_X64
69
#include "x64/lithium-codegen-x64.h"
70
#elif V8_TARGET_ARCH_ARM
71
#include "arm/lithium-codegen-arm.h"
72
#elif V8_TARGET_ARCH_MIPS
73
#include "mips/lithium-codegen-mips.h"
74
#else
75
#error Unsupported target architecture.
76
#endif
77

    
78
namespace v8 {
79
namespace internal {
80

    
81
HBasicBlock::HBasicBlock(HGraph* graph)
82
    : block_id_(graph->GetNextBlockID()),
83
      graph_(graph),
84
      phis_(4, graph->zone()),
85
      first_(NULL),
86
      last_(NULL),
87
      end_(NULL),
88
      loop_information_(NULL),
89
      predecessors_(2, graph->zone()),
90
      dominator_(NULL),
91
      dominated_blocks_(4, graph->zone()),
92
      last_environment_(NULL),
93
      argument_count_(-1),
94
      first_instruction_index_(-1),
95
      last_instruction_index_(-1),
96
      deleted_phis_(4, graph->zone()),
97
      parent_loop_header_(NULL),
98
      inlined_entry_block_(NULL),
99
      is_inline_return_target_(false),
100
      is_reachable_(true),
101
      dominates_loop_successors_(false),
102
      is_osr_entry_(false) { }
103

    
104

    
105
Isolate* HBasicBlock::isolate() const {
106
  return graph_->isolate();
107
}
108

    
109

    
110
void HBasicBlock::MarkUnreachable() {
111
  is_reachable_ = false;
112
}
113

    
114

    
115
void HBasicBlock::AttachLoopInformation() {
116
  ASSERT(!IsLoopHeader());
117
  loop_information_ = new(zone()) HLoopInformation(this, zone());
118
}
119

    
120

    
121
void HBasicBlock::DetachLoopInformation() {
122
  ASSERT(IsLoopHeader());
123
  loop_information_ = NULL;
124
}
125

    
126

    
127
void HBasicBlock::AddPhi(HPhi* phi) {
128
  ASSERT(!IsStartBlock());
129
  phis_.Add(phi, zone());
130
  phi->SetBlock(this);
131
}
132

    
133

    
134
void HBasicBlock::RemovePhi(HPhi* phi) {
135
  ASSERT(phi->block() == this);
136
  ASSERT(phis_.Contains(phi));
137
  phi->Kill();
138
  phis_.RemoveElement(phi);
139
  phi->SetBlock(NULL);
140
}
141

    
142

    
143
void HBasicBlock::AddInstruction(HInstruction* instr, int position) {
144
  ASSERT(!IsStartBlock() || !IsFinished());
145
  ASSERT(!instr->IsLinked());
146
  ASSERT(!IsFinished());
147

    
148
  if (position != RelocInfo::kNoPosition) {
149
    instr->set_position(position);
150
  }
151
  if (first_ == NULL) {
152
    ASSERT(last_environment() != NULL);
153
    ASSERT(!last_environment()->ast_id().IsNone());
154
    HBlockEntry* entry = new(zone()) HBlockEntry();
155
    entry->InitializeAsFirst(this);
156
    if (position != RelocInfo::kNoPosition) {
157
      entry->set_position(position);
158
    } else {
159
      ASSERT(!FLAG_emit_opt_code_positions ||
160
             !graph()->info()->IsOptimizing());
161
    }
162
    first_ = last_ = entry;
163
  }
164
  instr->InsertAfter(last_);
165
}
166

    
167

    
168
HPhi* HBasicBlock::AddNewPhi(int merged_index) {
169
  if (graph()->IsInsideNoSideEffectsScope()) {
170
    merged_index = HPhi::kInvalidMergedIndex;
171
  }
172
  HPhi* phi = new(zone()) HPhi(merged_index, zone());
173
  AddPhi(phi);
174
  return phi;
175
}
176

    
177

    
178
HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id,
179
                                       RemovableSimulate removable) {
180
  ASSERT(HasEnvironment());
181
  HEnvironment* environment = last_environment();
182
  ASSERT(ast_id.IsNone() ||
183
         ast_id == BailoutId::StubEntry() ||
184
         environment->closure()->shared()->VerifyBailoutId(ast_id));
185

    
186
  int push_count = environment->push_count();
187
  int pop_count = environment->pop_count();
188

    
189
  HSimulate* instr =
190
      new(zone()) HSimulate(ast_id, pop_count, zone(), removable);
191
#ifdef DEBUG
192
  instr->set_closure(environment->closure());
193
#endif
194
  // Order of pushed values: newest (top of stack) first. This allows
195
  // HSimulate::MergeWith() to easily append additional pushed values
196
  // that are older (from further down the stack).
197
  for (int i = 0; i < push_count; ++i) {
198
    instr->AddPushedValue(environment->ExpressionStackAt(i));
199
  }
200
  for (GrowableBitVector::Iterator it(environment->assigned_variables(),
201
                                      zone());
202
       !it.Done();
203
       it.Advance()) {
204
    int index = it.Current();
205
    instr->AddAssignedValue(index, environment->Lookup(index));
206
  }
207
  environment->ClearHistory();
208
  return instr;
209
}
210

    
211

    
212
void HBasicBlock::Finish(HControlInstruction* end, int position) {
213
  ASSERT(!IsFinished());
214
  AddInstruction(end, position);
215
  end_ = end;
216
  for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
217
    it.Current()->RegisterPredecessor(this);
218
  }
219
}
220

    
221

    
222
void HBasicBlock::Goto(HBasicBlock* block,
223
                       int position,
224
                       FunctionState* state,
225
                       bool add_simulate) {
226
  bool drop_extra = state != NULL &&
227
      state->inlining_kind() == DROP_EXTRA_ON_RETURN;
228

    
229
  if (block->IsInlineReturnTarget()) {
230
    HEnvironment* env = last_environment();
231
    int argument_count = env->arguments_environment()->parameter_count();
232
    AddInstruction(new(zone())
233
                   HLeaveInlined(state->entry(), argument_count),
234
                   position);
235
    UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
236
  }
237

    
238
  if (add_simulate) AddNewSimulate(BailoutId::None(), position);
239
  HGoto* instr = new(zone()) HGoto(block);
240
  Finish(instr, position);
241
}
242

    
243

    
244
void HBasicBlock::AddLeaveInlined(HValue* return_value,
245
                                  FunctionState* state,
246
                                  int position) {
247
  HBasicBlock* target = state->function_return();
248
  bool drop_extra = state->inlining_kind() == DROP_EXTRA_ON_RETURN;
249

    
250
  ASSERT(target->IsInlineReturnTarget());
251
  ASSERT(return_value != NULL);
252
  HEnvironment* env = last_environment();
253
  int argument_count = env->arguments_environment()->parameter_count();
254
  AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count),
255
                 position);
256
  UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
257
  last_environment()->Push(return_value);
258
  AddNewSimulate(BailoutId::None(), position);
259
  HGoto* instr = new(zone()) HGoto(target);
260
  Finish(instr, position);
261
}
262

    
263

    
264
void HBasicBlock::SetInitialEnvironment(HEnvironment* env) {
265
  ASSERT(!HasEnvironment());
266
  ASSERT(first() == NULL);
267
  UpdateEnvironment(env);
268
}
269

    
270

    
271
void HBasicBlock::UpdateEnvironment(HEnvironment* env) {
272
  last_environment_ = env;
273
  graph()->update_maximum_environment_size(env->first_expression_index());
274
}
275

    
276

    
277
void HBasicBlock::SetJoinId(BailoutId ast_id) {
278
  int length = predecessors_.length();
279
  ASSERT(length > 0);
280
  for (int i = 0; i < length; i++) {
281
    HBasicBlock* predecessor = predecessors_[i];
282
    ASSERT(predecessor->end()->IsGoto());
283
    HSimulate* simulate = HSimulate::cast(predecessor->end()->previous());
284
    ASSERT(i != 0 ||
285
           (predecessor->last_environment()->closure().is_null() ||
286
            predecessor->last_environment()->closure()->shared()
287
              ->VerifyBailoutId(ast_id)));
288
    simulate->set_ast_id(ast_id);
289
    predecessor->last_environment()->set_ast_id(ast_id);
290
  }
291
}
292

    
293

    
294
bool HBasicBlock::Dominates(HBasicBlock* other) const {
295
  HBasicBlock* current = other->dominator();
296
  while (current != NULL) {
297
    if (current == this) return true;
298
    current = current->dominator();
299
  }
300
  return false;
301
}
302

    
303

    
304
int HBasicBlock::LoopNestingDepth() const {
305
  const HBasicBlock* current = this;
306
  int result  = (current->IsLoopHeader()) ? 1 : 0;
307
  while (current->parent_loop_header() != NULL) {
308
    current = current->parent_loop_header();
309
    result++;
310
  }
311
  return result;
312
}
313

    
314

    
315
void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) {
316
  ASSERT(IsLoopHeader());
317

    
318
  SetJoinId(stmt->EntryId());
319
  if (predecessors()->length() == 1) {
320
    // This is a degenerated loop.
321
    DetachLoopInformation();
322
    return;
323
  }
324

    
325
  // Only the first entry into the loop is from outside the loop. All other
326
  // entries must be back edges.
327
  for (int i = 1; i < predecessors()->length(); ++i) {
328
    loop_information()->RegisterBackEdge(predecessors()->at(i));
329
  }
330
}
331

    
332

    
333
void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) {
334
  if (HasPredecessor()) {
335
    // Only loop header blocks can have a predecessor added after
336
    // instructions have been added to the block (they have phis for all
337
    // values in the environment, these phis may be eliminated later).
338
    ASSERT(IsLoopHeader() || first_ == NULL);
339
    HEnvironment* incoming_env = pred->last_environment();
340
    if (IsLoopHeader()) {
341
      ASSERT(phis()->length() == incoming_env->length());
342
      for (int i = 0; i < phis_.length(); ++i) {
343
        phis_[i]->AddInput(incoming_env->values()->at(i));
344
      }
345
    } else {
346
      last_environment()->AddIncomingEdge(this, pred->last_environment());
347
    }
348
  } else if (!HasEnvironment() && !IsFinished()) {
349
    ASSERT(!IsLoopHeader());
350
    SetInitialEnvironment(pred->last_environment()->Copy());
351
  }
352

    
353
  predecessors_.Add(pred, zone());
354
}
355

    
356

    
357
void HBasicBlock::AddDominatedBlock(HBasicBlock* block) {
358
  ASSERT(!dominated_blocks_.Contains(block));
359
  // Keep the list of dominated blocks sorted such that if there is two
360
  // succeeding block in this list, the predecessor is before the successor.
361
  int index = 0;
362
  while (index < dominated_blocks_.length() &&
363
         dominated_blocks_[index]->block_id() < block->block_id()) {
364
    ++index;
365
  }
366
  dominated_blocks_.InsertAt(index, block, zone());
367
}
368

    
369

    
370
void HBasicBlock::AssignCommonDominator(HBasicBlock* other) {
371
  if (dominator_ == NULL) {
372
    dominator_ = other;
373
    other->AddDominatedBlock(this);
374
  } else if (other->dominator() != NULL) {
375
    HBasicBlock* first = dominator_;
376
    HBasicBlock* second = other;
377

    
378
    while (first != second) {
379
      if (first->block_id() > second->block_id()) {
380
        first = first->dominator();
381
      } else {
382
        second = second->dominator();
383
      }
384
      ASSERT(first != NULL && second != NULL);
385
    }
386

    
387
    if (dominator_ != first) {
388
      ASSERT(dominator_->dominated_blocks_.Contains(this));
389
      dominator_->dominated_blocks_.RemoveElement(this);
390
      dominator_ = first;
391
      first->AddDominatedBlock(this);
392
    }
393
  }
394
}
395

    
396

    
397
void HBasicBlock::AssignLoopSuccessorDominators() {
398
  // Mark blocks that dominate all subsequent reachable blocks inside their
399
  // loop. Exploit the fact that blocks are sorted in reverse post order. When
400
  // the loop is visited in increasing block id order, if the number of
401
  // non-loop-exiting successor edges at the dominator_candidate block doesn't
402
  // exceed the number of previously encountered predecessor edges, there is no
403
  // path from the loop header to any block with higher id that doesn't go
404
  // through the dominator_candidate block. In this case, the
405
  // dominator_candidate block is guaranteed to dominate all blocks reachable
406
  // from it with higher ids.
407
  HBasicBlock* last = loop_information()->GetLastBackEdge();
408
  int outstanding_successors = 1;  // one edge from the pre-header
409
  // Header always dominates everything.
410
  MarkAsLoopSuccessorDominator();
411
  for (int j = block_id(); j <= last->block_id(); ++j) {
412
    HBasicBlock* dominator_candidate = graph_->blocks()->at(j);
413
    for (HPredecessorIterator it(dominator_candidate); !it.Done();
414
         it.Advance()) {
415
      HBasicBlock* predecessor = it.Current();
416
      // Don't count back edges.
417
      if (predecessor->block_id() < dominator_candidate->block_id()) {
418
        outstanding_successors--;
419
      }
420
    }
421

    
422
    // If more successors than predecessors have been seen in the loop up to
423
    // now, it's not possible to guarantee that the current block dominates
424
    // all of the blocks with higher IDs. In this case, assume conservatively
425
    // that those paths through loop that don't go through the current block
426
    // contain all of the loop's dependencies. Also be careful to record
427
    // dominator information about the current loop that's being processed,
428
    // and not nested loops, which will be processed when
429
    // AssignLoopSuccessorDominators gets called on their header.
430
    ASSERT(outstanding_successors >= 0);
431
    HBasicBlock* parent_loop_header = dominator_candidate->parent_loop_header();
432
    if (outstanding_successors == 0 &&
433
        (parent_loop_header == this && !dominator_candidate->IsLoopHeader())) {
434
      dominator_candidate->MarkAsLoopSuccessorDominator();
435
    }
436
    HControlInstruction* end = dominator_candidate->end();
437
    for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
438
      HBasicBlock* successor = it.Current();
439
      // Only count successors that remain inside the loop and don't loop back
440
      // to a loop header.
441
      if (successor->block_id() > dominator_candidate->block_id() &&
442
          successor->block_id() <= last->block_id()) {
443
        // Backwards edges must land on loop headers.
444
        ASSERT(successor->block_id() > dominator_candidate->block_id() ||
445
               successor->IsLoopHeader());
446
        outstanding_successors++;
447
      }
448
    }
449
  }
450
}
451

    
452

    
453
int HBasicBlock::PredecessorIndexOf(HBasicBlock* predecessor) const {
454
  for (int i = 0; i < predecessors_.length(); ++i) {
455
    if (predecessors_[i] == predecessor) return i;
456
  }
457
  UNREACHABLE();
458
  return -1;
459
}
460

    
461

    
462
#ifdef DEBUG
463
void HBasicBlock::Verify() {
464
  // Check that every block is finished.
465
  ASSERT(IsFinished());
466
  ASSERT(block_id() >= 0);
467

    
468
  // Check that the incoming edges are in edge split form.
469
  if (predecessors_.length() > 1) {
470
    for (int i = 0; i < predecessors_.length(); ++i) {
471
      ASSERT(predecessors_[i]->end()->SecondSuccessor() == NULL);
472
    }
473
  }
474
}
475
#endif
476

    
477

    
478
void HLoopInformation::RegisterBackEdge(HBasicBlock* block) {
479
  this->back_edges_.Add(block, block->zone());
480
  AddBlock(block);
481
}
482

    
483

    
484
HBasicBlock* HLoopInformation::GetLastBackEdge() const {
485
  int max_id = -1;
486
  HBasicBlock* result = NULL;
487
  for (int i = 0; i < back_edges_.length(); ++i) {
488
    HBasicBlock* cur = back_edges_[i];
489
    if (cur->block_id() > max_id) {
490
      max_id = cur->block_id();
491
      result = cur;
492
    }
493
  }
494
  return result;
495
}
496

    
497

    
498
void HLoopInformation::AddBlock(HBasicBlock* block) {
499
  if (block == loop_header()) return;
500
  if (block->parent_loop_header() == loop_header()) return;
501
  if (block->parent_loop_header() != NULL) {
502
    AddBlock(block->parent_loop_header());
503
  } else {
504
    block->set_parent_loop_header(loop_header());
505
    blocks_.Add(block, block->zone());
506
    for (int i = 0; i < block->predecessors()->length(); ++i) {
507
      AddBlock(block->predecessors()->at(i));
508
    }
509
  }
510
}
511

    
512

    
513
#ifdef DEBUG
514

    
515
// Checks reachability of the blocks in this graph and stores a bit in
516
// the BitVector "reachable()" for every block that can be reached
517
// from the start block of the graph. If "dont_visit" is non-null, the given
518
// block is treated as if it would not be part of the graph. "visited_count()"
519
// returns the number of reachable blocks.
520
class ReachabilityAnalyzer BASE_EMBEDDED {
521
 public:
522
  ReachabilityAnalyzer(HBasicBlock* entry_block,
523
                       int block_count,
524
                       HBasicBlock* dont_visit)
525
      : visited_count_(0),
526
        stack_(16, entry_block->zone()),
527
        reachable_(block_count, entry_block->zone()),
528
        dont_visit_(dont_visit) {
529
    PushBlock(entry_block);
530
    Analyze();
531
  }
532

    
533
  int visited_count() const { return visited_count_; }
534
  const BitVector* reachable() const { return &reachable_; }
535

    
536
 private:
537
  void PushBlock(HBasicBlock* block) {
538
    if (block != NULL && block != dont_visit_ &&
539
        !reachable_.Contains(block->block_id())) {
540
      reachable_.Add(block->block_id());
541
      stack_.Add(block, block->zone());
542
      visited_count_++;
543
    }
544
  }
545

    
546
  void Analyze() {
547
    while (!stack_.is_empty()) {
548
      HControlInstruction* end = stack_.RemoveLast()->end();
549
      for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
550
        PushBlock(it.Current());
551
      }
552
    }
553
  }
554

    
555
  int visited_count_;
556
  ZoneList<HBasicBlock*> stack_;
557
  BitVector reachable_;
558
  HBasicBlock* dont_visit_;
559
};
560

    
561

    
562
void HGraph::Verify(bool do_full_verify) const {
563
  Heap::RelocationLock relocation_lock(isolate()->heap());
564
  AllowHandleDereference allow_deref;
565
  AllowDeferredHandleDereference allow_deferred_deref;
566
  for (int i = 0; i < blocks_.length(); i++) {
567
    HBasicBlock* block = blocks_.at(i);
568

    
569
    block->Verify();
570

    
571
    // Check that every block contains at least one node and that only the last
572
    // node is a control instruction.
573
    HInstruction* current = block->first();
574
    ASSERT(current != NULL && current->IsBlockEntry());
575
    while (current != NULL) {
576
      ASSERT((current->next() == NULL) == current->IsControlInstruction());
577
      ASSERT(current->block() == block);
578
      current->Verify();
579
      current = current->next();
580
    }
581

    
582
    // Check that successors are correctly set.
583
    HBasicBlock* first = block->end()->FirstSuccessor();
584
    HBasicBlock* second = block->end()->SecondSuccessor();
585
    ASSERT(second == NULL || first != NULL);
586

    
587
    // Check that the predecessor array is correct.
588
    if (first != NULL) {
589
      ASSERT(first->predecessors()->Contains(block));
590
      if (second != NULL) {
591
        ASSERT(second->predecessors()->Contains(block));
592
      }
593
    }
594

    
595
    // Check that phis have correct arguments.
596
    for (int j = 0; j < block->phis()->length(); j++) {
597
      HPhi* phi = block->phis()->at(j);
598
      phi->Verify();
599
    }
600

    
601
    // Check that all join blocks have predecessors that end with an
602
    // unconditional goto and agree on their environment node id.
603
    if (block->predecessors()->length() >= 2) {
604
      BailoutId id =
605
          block->predecessors()->first()->last_environment()->ast_id();
606
      for (int k = 0; k < block->predecessors()->length(); k++) {
607
        HBasicBlock* predecessor = block->predecessors()->at(k);
608
        ASSERT(predecessor->end()->IsGoto());
609
        ASSERT(predecessor->last_environment()->ast_id() == id);
610
      }
611
    }
612
  }
613

    
614
  // Check special property of first block to have no predecessors.
615
  ASSERT(blocks_.at(0)->predecessors()->is_empty());
616

    
617
  if (do_full_verify) {
618
    // Check that the graph is fully connected.
619
    ReachabilityAnalyzer analyzer(entry_block_, blocks_.length(), NULL);
620
    ASSERT(analyzer.visited_count() == blocks_.length());
621

    
622
    // Check that entry block dominator is NULL.
623
    ASSERT(entry_block_->dominator() == NULL);
624

    
625
    // Check dominators.
626
    for (int i = 0; i < blocks_.length(); ++i) {
627
      HBasicBlock* block = blocks_.at(i);
628
      if (block->dominator() == NULL) {
629
        // Only start block may have no dominator assigned to.
630
        ASSERT(i == 0);
631
      } else {
632
        // Assert that block is unreachable if dominator must not be visited.
633
        ReachabilityAnalyzer dominator_analyzer(entry_block_,
634
                                                blocks_.length(),
635
                                                block->dominator());
636
        ASSERT(!dominator_analyzer.reachable()->Contains(block->block_id()));
637
      }
638
    }
639
  }
640
}
641

    
642
#endif
643

    
644

    
645
HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer,
646
                               int32_t value) {
647
  if (!pointer->is_set()) {
648
    // Can't pass GetInvalidContext() to HConstant::New, because that will
649
    // recursively call GetConstant
650
    HConstant* constant = HConstant::New(zone(), NULL, value);
651
    constant->InsertAfter(entry_block()->first());
652
    pointer->set(constant);
653
    return constant;
654
  }
655
  return ReinsertConstantIfNecessary(pointer->get());
656
}
657

    
658

    
659
HConstant* HGraph::ReinsertConstantIfNecessary(HConstant* constant) {
660
  if (!constant->IsLinked()) {
661
    // The constant was removed from the graph. Reinsert.
662
    constant->ClearFlag(HValue::kIsDead);
663
    constant->InsertAfter(entry_block()->first());
664
  }
665
  return constant;
666
}
667

    
668

    
669
HConstant* HGraph::GetConstant0() {
670
  return GetConstant(&constant_0_, 0);
671
}
672

    
673

    
674
HConstant* HGraph::GetConstant1() {
675
  return GetConstant(&constant_1_, 1);
676
}
677

    
678

    
679
HConstant* HGraph::GetConstantMinus1() {
680
  return GetConstant(&constant_minus1_, -1);
681
}
682

    
683

    
684
#define DEFINE_GET_CONSTANT(Name, name, htype, boolean_value)                  \
685
HConstant* HGraph::GetConstant##Name() {                                       \
686
  if (!constant_##name##_.is_set()) {                                          \
687
    HConstant* constant = new(zone()) HConstant(                               \
688
        Unique<Object>::CreateImmovable(isolate()->factory()->name##_value()), \
689
        Representation::Tagged(),                                              \
690
        htype,                                                                 \
691
        false,                                                                 \
692
        true,                                                                  \
693
        false,                                                                 \
694
        boolean_value);                                                        \
695
    constant->InsertAfter(entry_block()->first());                             \
696
    constant_##name##_.set(constant);                                          \
697
  }                                                                            \
698
  return ReinsertConstantIfNecessary(constant_##name##_.get());                \
699
}
700

    
701

    
702
DEFINE_GET_CONSTANT(Undefined, undefined, HType::Tagged(), false)
703
DEFINE_GET_CONSTANT(True, true, HType::Boolean(), true)
704
DEFINE_GET_CONSTANT(False, false, HType::Boolean(), false)
705
DEFINE_GET_CONSTANT(Hole, the_hole, HType::Tagged(), false)
706
DEFINE_GET_CONSTANT(Null, null, HType::Tagged(), false)
707

    
708

    
709
#undef DEFINE_GET_CONSTANT
710

    
711

    
712
HConstant* HGraph::GetInvalidContext() {
713
  return GetConstant(&constant_invalid_context_, 0xFFFFC0C7);
714
}
715

    
716

    
717
bool HGraph::IsStandardConstant(HConstant* constant) {
718
  if (constant == GetConstantUndefined()) return true;
719
  if (constant == GetConstant0()) return true;
720
  if (constant == GetConstant1()) return true;
721
  if (constant == GetConstantMinus1()) return true;
722
  if (constant == GetConstantTrue()) return true;
723
  if (constant == GetConstantFalse()) return true;
724
  if (constant == GetConstantHole()) return true;
725
  if (constant == GetConstantNull()) return true;
726
  return false;
727
}
728

    
729

    
730
HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder)
731
    : builder_(builder),
732
      finished_(false),
733
      deopt_then_(false),
734
      deopt_else_(false),
735
      did_then_(false),
736
      did_else_(false),
737
      did_and_(false),
738
      did_or_(false),
739
      captured_(false),
740
      needs_compare_(true),
741
      split_edge_merge_block_(NULL),
742
      merge_block_(NULL) {
743
  HEnvironment* env = builder->environment();
744
  first_true_block_ = builder->CreateBasicBlock(env->Copy());
745
  last_true_block_ = NULL;
746
  first_false_block_ = builder->CreateBasicBlock(env->Copy());
747
}
748

    
749

    
750
HGraphBuilder::IfBuilder::IfBuilder(
751
    HGraphBuilder* builder,
752
    HIfContinuation* continuation)
753
    : builder_(builder),
754
      finished_(false),
755
      deopt_then_(false),
756
      deopt_else_(false),
757
      did_then_(false),
758
      did_else_(false),
759
      did_and_(false),
760
      did_or_(false),
761
      captured_(false),
762
      needs_compare_(false),
763
      first_true_block_(NULL),
764
      last_true_block_(NULL),
765
      first_false_block_(NULL),
766
      split_edge_merge_block_(NULL),
767
      merge_block_(NULL) {
768
  continuation->Continue(&first_true_block_,
769
                         &first_false_block_);
770
}
771

    
772

    
773
HControlInstruction* HGraphBuilder::IfBuilder::AddCompare(
774
    HControlInstruction* compare) {
775
  if (split_edge_merge_block_ != NULL) {
776
    HEnvironment* env = first_false_block_->last_environment();
777
    HBasicBlock* split_edge =
778
        builder_->CreateBasicBlock(env->Copy());
779
    if (did_or_) {
780
      compare->SetSuccessorAt(0, split_edge);
781
      compare->SetSuccessorAt(1, first_false_block_);
782
    } else {
783
      compare->SetSuccessorAt(0, first_true_block_);
784
      compare->SetSuccessorAt(1, split_edge);
785
    }
786
    builder_->GotoNoSimulate(split_edge, split_edge_merge_block_);
787
  } else {
788
    compare->SetSuccessorAt(0, first_true_block_);
789
    compare->SetSuccessorAt(1, first_false_block_);
790
  }
791
  builder_->FinishCurrentBlock(compare);
792
  needs_compare_ = false;
793
  return compare;
794
}
795

    
796

    
797
void HGraphBuilder::IfBuilder::Or() {
798
  ASSERT(!needs_compare_);
799
  ASSERT(!did_and_);
800
  did_or_ = true;
801
  HEnvironment* env = first_false_block_->last_environment();
802
  if (split_edge_merge_block_ == NULL) {
803
    split_edge_merge_block_ =
804
        builder_->CreateBasicBlock(env->Copy());
805
    builder_->GotoNoSimulate(first_true_block_, split_edge_merge_block_);
806
    first_true_block_ = split_edge_merge_block_;
807
  }
808
  builder_->set_current_block(first_false_block_);
809
  first_false_block_ = builder_->CreateBasicBlock(env->Copy());
810
}
811

    
812

    
813
void HGraphBuilder::IfBuilder::And() {
814
  ASSERT(!needs_compare_);
815
  ASSERT(!did_or_);
816
  did_and_ = true;
817
  HEnvironment* env = first_false_block_->last_environment();
818
  if (split_edge_merge_block_ == NULL) {
819
    split_edge_merge_block_ = builder_->CreateBasicBlock(env->Copy());
820
    builder_->GotoNoSimulate(first_false_block_, split_edge_merge_block_);
821
    first_false_block_ = split_edge_merge_block_;
822
  }
823
  builder_->set_current_block(first_true_block_);
824
  first_true_block_ = builder_->CreateBasicBlock(env->Copy());
825
}
826

    
827

    
828
void HGraphBuilder::IfBuilder::CaptureContinuation(
829
    HIfContinuation* continuation) {
830
  ASSERT(!finished_);
831
  ASSERT(!captured_);
832
  HBasicBlock* true_block = last_true_block_ == NULL
833
      ? first_true_block_
834
      : last_true_block_;
835
  HBasicBlock* false_block = did_else_ && (first_false_block_ != NULL)
836
      ? builder_->current_block()
837
      : first_false_block_;
838
  continuation->Capture(true_block, false_block);
839
  captured_ = true;
840
  End();
841
}
842

    
843

    
844
void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) {
845
  ASSERT(!finished_);
846
  ASSERT(!captured_);
847
  HBasicBlock* true_block = last_true_block_ == NULL
848
      ? first_true_block_
849
      : last_true_block_;
850
  HBasicBlock* false_block = did_else_ && (first_false_block_ != NULL)
851
      ? builder_->current_block()
852
      : first_false_block_;
853
  if (true_block != NULL && !true_block->IsFinished()) {
854
    ASSERT(continuation->IsTrueReachable());
855
    builder_->GotoNoSimulate(true_block, continuation->true_branch());
856
  }
857
  if (false_block != NULL && !false_block->IsFinished()) {
858
    ASSERT(continuation->IsFalseReachable());
859
    builder_->GotoNoSimulate(false_block, continuation->false_branch());
860
  }
861
  captured_ = true;
862
  End();
863
}
864

    
865

    
866
void HGraphBuilder::IfBuilder::Then() {
867
  ASSERT(!captured_);
868
  ASSERT(!finished_);
869
  did_then_ = true;
870
  if (needs_compare_) {
871
    // Handle if's without any expressions, they jump directly to the "else"
872
    // branch. However, we must pretend that the "then" branch is reachable,
873
    // so that the graph builder visits it and sees any live range extending
874
    // constructs within it.
875
    HConstant* constant_false = builder_->graph()->GetConstantFalse();
876
    ToBooleanStub::Types boolean_type = ToBooleanStub::Types();
877
    boolean_type.Add(ToBooleanStub::BOOLEAN);
878
    HBranch* branch = builder()->New<HBranch>(
879
        constant_false, boolean_type, first_true_block_, first_false_block_);
880
    builder_->FinishCurrentBlock(branch);
881
  }
882
  builder_->set_current_block(first_true_block_);
883
}
884

    
885

    
886
void HGraphBuilder::IfBuilder::Else() {
887
  ASSERT(did_then_);
888
  ASSERT(!captured_);
889
  ASSERT(!finished_);
890
  last_true_block_ = builder_->current_block();
891
  builder_->set_current_block(first_false_block_);
892
  did_else_ = true;
893
}
894

    
895

    
896
void HGraphBuilder::IfBuilder::Deopt(const char* reason) {
897
  ASSERT(did_then_);
898
  if (did_else_) {
899
    deopt_else_ = true;
900
  } else {
901
    deopt_then_ = true;
902
  }
903
  builder_->Add<HDeoptimize>(reason, Deoptimizer::EAGER);
904
}
905

    
906

    
907
void HGraphBuilder::IfBuilder::Return(HValue* value) {
908
  HValue* parameter_count = builder_->graph()->GetConstantMinus1();
909
  builder_->FinishExitCurrentBlock(
910
      builder_->New<HReturn>(value, parameter_count));
911
  if (did_else_) {
912
    first_false_block_ = NULL;
913
  } else {
914
    first_true_block_ = NULL;
915
  }
916
}
917

    
918

    
919
void HGraphBuilder::IfBuilder::End() {
920
  if (!captured_) {
921
    ASSERT(did_then_);
922
    if (!did_else_) {
923
      last_true_block_ = builder_->current_block();
924
    }
925
    if (last_true_block_ == NULL || last_true_block_->IsFinished()) {
926
      ASSERT(did_else_);
927
      // Return on true. Nothing to do, just continue the false block.
928
    } else if (first_false_block_ == NULL ||
929
               (did_else_ && builder_->current_block()->IsFinished())) {
930
      // Deopt on false. Nothing to do except switching to the true block.
931
      builder_->set_current_block(last_true_block_);
932
    } else {
933
      merge_block_ = builder_->graph()->CreateBasicBlock();
934
      ASSERT(!finished_);
935
      if (!did_else_) Else();
936
      ASSERT(!last_true_block_->IsFinished());
937
      HBasicBlock* last_false_block = builder_->current_block();
938
      ASSERT(!last_false_block->IsFinished());
939
      if (deopt_then_) {
940
        builder_->GotoNoSimulate(last_false_block, merge_block_);
941
        builder_->PadEnvironmentForContinuation(last_true_block_,
942
                                                merge_block_);
943
        builder_->GotoNoSimulate(last_true_block_, merge_block_);
944
      } else {
945
        builder_->GotoNoSimulate(last_true_block_, merge_block_);
946
        if (deopt_else_) {
947
          builder_->PadEnvironmentForContinuation(last_false_block,
948
                                                  merge_block_);
949
        }
950
        builder_->GotoNoSimulate(last_false_block, merge_block_);
951
      }
952
      builder_->set_current_block(merge_block_);
953
    }
954
  }
955
  finished_ = true;
956
}
957

    
958

    
959
HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder,
960
                                        HValue* context,
961
                                        LoopBuilder::Direction direction)
962
    : builder_(builder),
963
      context_(context),
964
      direction_(direction),
965
      finished_(false) {
966
  header_block_ = builder->CreateLoopHeaderBlock();
967
  body_block_ = NULL;
968
  exit_block_ = NULL;
969
  exit_trampoline_block_ = NULL;
970
  increment_amount_ = builder_->graph()->GetConstant1();
971
}
972

    
973

    
974
HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder,
975
                                        HValue* context,
976
                                        LoopBuilder::Direction direction,
977
                                        HValue* increment_amount)
978
    : builder_(builder),
979
      context_(context),
980
      direction_(direction),
981
      finished_(false) {
982
  header_block_ = builder->CreateLoopHeaderBlock();
983
  body_block_ = NULL;
984
  exit_block_ = NULL;
985
  exit_trampoline_block_ = NULL;
986
  increment_amount_ = increment_amount;
987
}
988

    
989

    
990
HValue* HGraphBuilder::LoopBuilder::BeginBody(
991
    HValue* initial,
992
    HValue* terminating,
993
    Token::Value token) {
994
  HEnvironment* env = builder_->environment();
995
  phi_ = header_block_->AddNewPhi(env->values()->length());
996
  phi_->AddInput(initial);
997
  env->Push(initial);
998
  builder_->GotoNoSimulate(header_block_);
999

    
1000
  HEnvironment* body_env = env->Copy();
1001
  HEnvironment* exit_env = env->Copy();
1002
  // Remove the phi from the expression stack
1003
  body_env->Pop();
1004
  exit_env->Pop();
1005
  body_block_ = builder_->CreateBasicBlock(body_env);
1006
  exit_block_ = builder_->CreateBasicBlock(exit_env);
1007

    
1008
  builder_->set_current_block(header_block_);
1009
  env->Pop();
1010
  builder_->FinishCurrentBlock(builder_->New<HCompareNumericAndBranch>(
1011
          phi_, terminating, token, body_block_, exit_block_));
1012

    
1013
  builder_->set_current_block(body_block_);
1014
  if (direction_ == kPreIncrement || direction_ == kPreDecrement) {
1015
    HValue* one = builder_->graph()->GetConstant1();
1016
    if (direction_ == kPreIncrement) {
1017
      increment_ = HAdd::New(zone(), context_, phi_, one);
1018
    } else {
1019
      increment_ = HSub::New(zone(), context_, phi_, one);
1020
    }
1021
    increment_->ClearFlag(HValue::kCanOverflow);
1022
    builder_->AddInstruction(increment_);
1023
    return increment_;
1024
  } else {
1025
    return phi_;
1026
  }
1027
}
1028

    
1029

    
1030
void HGraphBuilder::LoopBuilder::Break() {
1031
  if (exit_trampoline_block_ == NULL) {
1032
    // Its the first time we saw a break.
1033
    HEnvironment* env = exit_block_->last_environment()->Copy();
1034
    exit_trampoline_block_ = builder_->CreateBasicBlock(env);
1035
    builder_->GotoNoSimulate(exit_block_, exit_trampoline_block_);
1036
  }
1037

    
1038
  builder_->GotoNoSimulate(exit_trampoline_block_);
1039
}
1040

    
1041

    
1042
void HGraphBuilder::LoopBuilder::EndBody() {
1043
  ASSERT(!finished_);
1044

    
1045
  if (direction_ == kPostIncrement || direction_ == kPostDecrement) {
1046
    if (direction_ == kPostIncrement) {
1047
      increment_ = HAdd::New(zone(), context_, phi_, increment_amount_);
1048
    } else {
1049
      increment_ = HSub::New(zone(), context_, phi_, increment_amount_);
1050
    }
1051
    increment_->ClearFlag(HValue::kCanOverflow);
1052
    builder_->AddInstruction(increment_);
1053
  }
1054

    
1055
  // Push the new increment value on the expression stack to merge into the phi.
1056
  builder_->environment()->Push(increment_);
1057
  HBasicBlock* last_block = builder_->current_block();
1058
  builder_->GotoNoSimulate(last_block, header_block_);
1059
  header_block_->loop_information()->RegisterBackEdge(last_block);
1060

    
1061
  if (exit_trampoline_block_ != NULL) {
1062
    builder_->set_current_block(exit_trampoline_block_);
1063
  } else {
1064
    builder_->set_current_block(exit_block_);
1065
  }
1066
  finished_ = true;
1067
}
1068

    
1069

    
1070
HGraph* HGraphBuilder::CreateGraph() {
1071
  graph_ = new(zone()) HGraph(info_);
1072
  if (FLAG_hydrogen_stats) isolate()->GetHStatistics()->Initialize(info_);
1073
  CompilationPhase phase("H_Block building", info_);
1074
  set_current_block(graph()->entry_block());
1075
  if (!BuildGraph()) return NULL;
1076
  graph()->FinalizeUniqueness();
1077
  return graph_;
1078
}
1079

    
1080

    
1081
HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
1082
  ASSERT(current_block() != NULL);
1083
  ASSERT(!FLAG_emit_opt_code_positions ||
1084
         position_ != RelocInfo::kNoPosition || !info_->IsOptimizing());
1085
  current_block()->AddInstruction(instr, position_);
1086
  if (graph()->IsInsideNoSideEffectsScope()) {
1087
    instr->SetFlag(HValue::kHasNoObservableSideEffects);
1088
  }
1089
  return instr;
1090
}
1091

    
1092

    
1093
void HGraphBuilder::FinishCurrentBlock(HControlInstruction* last) {
1094
  ASSERT(!FLAG_emit_opt_code_positions || !info_->IsOptimizing() ||
1095
         position_ != RelocInfo::kNoPosition);
1096
  current_block()->Finish(last, position_);
1097
  if (last->IsReturn() || last->IsAbnormalExit()) {
1098
    set_current_block(NULL);
1099
  }
1100
}
1101

    
1102

    
1103
void HGraphBuilder::FinishExitCurrentBlock(HControlInstruction* instruction) {
1104
  ASSERT(!FLAG_emit_opt_code_positions || !info_->IsOptimizing() ||
1105
         position_ != RelocInfo::kNoPosition);
1106
  current_block()->FinishExit(instruction, position_);
1107
  if (instruction->IsReturn() || instruction->IsAbnormalExit()) {
1108
    set_current_block(NULL);
1109
  }
1110
}
1111

    
1112

    
1113
void HGraphBuilder::AddIncrementCounter(StatsCounter* counter) {
1114
  if (FLAG_native_code_counters && counter->Enabled()) {
1115
    HValue* reference = Add<HConstant>(ExternalReference(counter));
1116
    HValue* old_value = Add<HLoadNamedField>(reference,
1117
                                             HObjectAccess::ForCounter());
1118
    HValue* new_value = Add<HAdd>(old_value, graph()->GetConstant1());
1119
    new_value->ClearFlag(HValue::kCanOverflow);  // Ignore counter overflow
1120
    Add<HStoreNamedField>(reference, HObjectAccess::ForCounter(),
1121
                          new_value);
1122
  }
1123
}
1124

    
1125

    
1126
void HGraphBuilder::AddSimulate(BailoutId id,
1127
                                RemovableSimulate removable) {
1128
  ASSERT(current_block() != NULL);
1129
  ASSERT(!graph()->IsInsideNoSideEffectsScope());
1130
  current_block()->AddNewSimulate(id, removable);
1131
}
1132

    
1133

    
1134
HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) {
1135
  HBasicBlock* b = graph()->CreateBasicBlock();
1136
  b->SetInitialEnvironment(env);
1137
  return b;
1138
}
1139

    
1140

    
1141
HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
1142
  HBasicBlock* header = graph()->CreateBasicBlock();
1143
  HEnvironment* entry_env = environment()->CopyAsLoopHeader(header);
1144
  header->SetInitialEnvironment(entry_env);
1145
  header->AttachLoopInformation();
1146
  return header;
1147
}
1148

    
1149

    
1150
HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) {
1151
  if (obj->type().IsHeapObject()) return obj;
1152
  return Add<HCheckHeapObject>(obj);
1153
}
1154

    
1155

    
1156
void HGraphBuilder::FinishExitWithHardDeoptimization(
1157
    const char* reason, HBasicBlock* continuation) {
1158
  PadEnvironmentForContinuation(current_block(), continuation);
1159
  Add<HDeoptimize>(reason, Deoptimizer::EAGER);
1160
  if (graph()->IsInsideNoSideEffectsScope()) {
1161
    GotoNoSimulate(continuation);
1162
  } else {
1163
    Goto(continuation);
1164
  }
1165
}
1166

    
1167

    
1168
void HGraphBuilder::PadEnvironmentForContinuation(
1169
    HBasicBlock* from,
1170
    HBasicBlock* continuation) {
1171
  if (continuation->last_environment() != NULL) {
1172
    // When merging from a deopt block to a continuation, resolve differences in
1173
    // environment by pushing constant 0 and popping extra values so that the
1174
    // environments match during the join. Push 0 since it has the most specific
1175
    // representation, and will not influence representation inference of the
1176
    // phi.
1177
    int continuation_env_length = continuation->last_environment()->length();
1178
    while (continuation_env_length != from->last_environment()->length()) {
1179
      if (continuation_env_length > from->last_environment()->length()) {
1180
        from->last_environment()->Push(graph()->GetConstant0());
1181
      } else {
1182
        from->last_environment()->Pop();
1183
      }
1184
    }
1185
  } else {
1186
    ASSERT(continuation->predecessors()->length() == 0);
1187
  }
1188
}
1189

    
1190

    
1191
HValue* HGraphBuilder::BuildCheckMap(HValue* obj, Handle<Map> map) {
1192
  return Add<HCheckMaps>(obj, map, top_info());
1193
}
1194

    
1195

    
1196
HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* function) {
1197
  if (object->type().IsJSObject()) return object;
1198
  return Add<HWrapReceiver>(object, function);
1199
}
1200

    
1201

    
1202
HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object,
1203
                                                 HValue* elements,
1204
                                                 ElementsKind kind,
1205
                                                 HValue* length,
1206
                                                 HValue* key,
1207
                                                 bool is_js_array) {
1208
  IfBuilder length_checker(this);
1209

    
1210
  Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ;
1211
  length_checker.If<HCompareNumericAndBranch>(key, length, token);
1212

    
1213
  length_checker.Then();
1214

    
1215
  HValue* current_capacity = AddLoadFixedArrayLength(elements);
1216

    
1217
  IfBuilder capacity_checker(this);
1218

    
1219
  capacity_checker.If<HCompareNumericAndBranch>(key, current_capacity,
1220
                                                Token::GTE);
1221
  capacity_checker.Then();
1222

    
1223
  HValue* max_gap = Add<HConstant>(static_cast<int32_t>(JSObject::kMaxGap));
1224
  HValue* max_capacity = Add<HAdd>(current_capacity, max_gap);
1225
  IfBuilder key_checker(this);
1226
  key_checker.If<HCompareNumericAndBranch>(key, max_capacity, Token::LT);
1227
  key_checker.Then();
1228
  key_checker.ElseDeopt("Key out of capacity range");
1229
  key_checker.End();
1230

    
1231
  HValue* new_capacity = BuildNewElementsCapacity(key);
1232
  HValue* new_elements = BuildGrowElementsCapacity(object, elements,
1233
                                                   kind, kind, length,
1234
                                                   new_capacity);
1235

    
1236
  environment()->Push(new_elements);
1237
  capacity_checker.Else();
1238

    
1239
  environment()->Push(elements);
1240
  capacity_checker.End();
1241

    
1242
  if (is_js_array) {
1243
    HValue* new_length = AddUncasted<HAdd>(key, graph_->GetConstant1());
1244
    new_length->ClearFlag(HValue::kCanOverflow);
1245

    
1246
    Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(kind),
1247
                          new_length);
1248
  }
1249

    
1250
  length_checker.Else();
1251
  Add<HBoundsCheck>(key, length);
1252

    
1253
  environment()->Push(elements);
1254
  length_checker.End();
1255

    
1256
  return environment()->Pop();
1257
}
1258

    
1259

    
1260
HValue* HGraphBuilder::BuildCopyElementsOnWrite(HValue* object,
1261
                                                HValue* elements,
1262
                                                ElementsKind kind,
1263
                                                HValue* length) {
1264
  Factory* factory = isolate()->factory();
1265

    
1266
  IfBuilder cow_checker(this);
1267

    
1268
  cow_checker.If<HCompareMap>(elements, factory->fixed_cow_array_map());
1269
  cow_checker.Then();
1270

    
1271
  HValue* capacity = AddLoadFixedArrayLength(elements);
1272

    
1273
  HValue* new_elements = BuildGrowElementsCapacity(object, elements, kind,
1274
                                                   kind, length, capacity);
1275

    
1276
  environment()->Push(new_elements);
1277

    
1278
  cow_checker.Else();
1279

    
1280
  environment()->Push(elements);
1281

    
1282
  cow_checker.End();
1283

    
1284
  return environment()->Pop();
1285
}
1286

    
1287

    
1288
void HGraphBuilder::BuildTransitionElementsKind(HValue* object,
1289
                                                HValue* map,
1290
                                                ElementsKind from_kind,
1291
                                                ElementsKind to_kind,
1292
                                                bool is_jsarray) {
1293
  ASSERT(!IsFastHoleyElementsKind(from_kind) ||
1294
         IsFastHoleyElementsKind(to_kind));
1295

    
1296
  if (AllocationSite::GetMode(from_kind, to_kind) == TRACK_ALLOCATION_SITE) {
1297
    Add<HTrapAllocationMemento>(object);
1298
  }
1299

    
1300
  if (!IsSimpleMapChangeTransition(from_kind, to_kind)) {
1301
    HInstruction* elements = AddLoadElements(object);
1302

    
1303
    HInstruction* empty_fixed_array = Add<HConstant>(
1304
        isolate()->factory()->empty_fixed_array());
1305

    
1306
    IfBuilder if_builder(this);
1307

    
1308
    if_builder.IfNot<HCompareObjectEqAndBranch>(elements, empty_fixed_array);
1309

    
1310
    if_builder.Then();
1311

    
1312
    HInstruction* elements_length = AddLoadFixedArrayLength(elements);
1313

    
1314
    HInstruction* array_length = is_jsarray
1315
        ? Add<HLoadNamedField>(object, HObjectAccess::ForArrayLength(from_kind))
1316
        : elements_length;
1317

    
1318
    BuildGrowElementsCapacity(object, elements, from_kind, to_kind,
1319
                              array_length, elements_length);
1320

    
1321
    if_builder.End();
1322
  }
1323

    
1324
  Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map);
1325
}
1326

    
1327

    
1328
HValue* HGraphBuilder::BuildNumberToString(HValue* object,
1329
                                           Handle<Type> type) {
1330
  NoObservableSideEffectsScope scope(this);
1331

    
1332
  // Create a joinable continuation.
1333
  HIfContinuation found(graph()->CreateBasicBlock(),
1334
                        graph()->CreateBasicBlock());
1335

    
1336
  // Load the number string cache.
1337
  HValue* number_string_cache =
1338
      Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex);
1339

    
1340
  // Make the hash mask from the length of the number string cache. It
1341
  // contains two elements (number and string) for each cache entry.
1342
  HValue* mask = AddLoadFixedArrayLength(number_string_cache);
1343
  mask->set_type(HType::Smi());
1344
  mask = Add<HSar>(mask, graph()->GetConstant1());
1345
  mask = Add<HSub>(mask, graph()->GetConstant1());
1346

    
1347
  // Check whether object is a smi.
1348
  IfBuilder if_objectissmi(this);
1349
  if_objectissmi.If<HIsSmiAndBranch>(object);
1350
  if_objectissmi.Then();
1351
  {
1352
    // Compute hash for smi similar to smi_get_hash().
1353
    HValue* hash = Add<HBitwise>(Token::BIT_AND, object, mask);
1354

    
1355
    // Load the key.
1356
    HValue* key_index = Add<HShl>(hash, graph()->GetConstant1());
1357
    HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
1358
                                  static_cast<HValue*>(NULL),
1359
                                  FAST_ELEMENTS, ALLOW_RETURN_HOLE);
1360

    
1361
    // Check if object == key.
1362
    IfBuilder if_objectiskey(this);
1363
    if_objectiskey.If<HCompareObjectEqAndBranch>(object, key);
1364
    if_objectiskey.Then();
1365
    {
1366
      // Make the key_index available.
1367
      Push(key_index);
1368
    }
1369
    if_objectiskey.JoinContinuation(&found);
1370
  }
1371
  if_objectissmi.Else();
1372
  {
1373
    if (type->Is(Type::Smi())) {
1374
      if_objectissmi.Deopt("Excepted smi");
1375
    } else {
1376
      // Check if the object is a heap number.
1377
      IfBuilder if_objectisnumber(this);
1378
      if_objectisnumber.If<HCompareMap>(
1379
          object, isolate()->factory()->heap_number_map());
1380
      if_objectisnumber.Then();
1381
      {
1382
        // Compute hash for heap number similar to double_get_hash().
1383
        HValue* low = Add<HLoadNamedField>(
1384
            object, HObjectAccess::ForHeapNumberValueLowestBits());
1385
        HValue* high = Add<HLoadNamedField>(
1386
            object, HObjectAccess::ForHeapNumberValueHighestBits());
1387
        HValue* hash = Add<HBitwise>(Token::BIT_XOR, low, high);
1388
        hash = Add<HBitwise>(Token::BIT_AND, hash, mask);
1389

    
1390
        // Load the key.
1391
        HValue* key_index = Add<HShl>(hash, graph()->GetConstant1());
1392
        HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
1393
                                      static_cast<HValue*>(NULL),
1394
                                      FAST_ELEMENTS, ALLOW_RETURN_HOLE);
1395

    
1396
        // Check if key is a heap number (the number string cache contains only
1397
        // SMIs and heap number, so it is sufficient to do a SMI check here).
1398
        IfBuilder if_keyisnotsmi(this);
1399
        if_keyisnotsmi.IfNot<HIsSmiAndBranch>(key);
1400
        if_keyisnotsmi.Then();
1401
        {
1402
          // Check if values of key and object match.
1403
          IfBuilder if_keyeqobject(this);
1404
          if_keyeqobject.If<HCompareNumericAndBranch>(
1405
              Add<HLoadNamedField>(key, HObjectAccess::ForHeapNumberValue()),
1406
              Add<HLoadNamedField>(object, HObjectAccess::ForHeapNumberValue()),
1407
              Token::EQ);
1408
          if_keyeqobject.Then();
1409
          {
1410
            // Make the key_index available.
1411
            Push(key_index);
1412
          }
1413
          if_keyeqobject.JoinContinuation(&found);
1414
        }
1415
        if_keyisnotsmi.JoinContinuation(&found);
1416
      }
1417
      if_objectisnumber.Else();
1418
      {
1419
        if (type->Is(Type::Number())) {
1420
          if_objectisnumber.Deopt("Expected heap number");
1421
        }
1422
      }
1423
      if_objectisnumber.JoinContinuation(&found);
1424
    }
1425
  }
1426
  if_objectissmi.JoinContinuation(&found);
1427

    
1428
  // Check for cache hit.
1429
  IfBuilder if_found(this, &found);
1430
  if_found.Then();
1431
  {
1432
    // Count number to string operation in native code.
1433
    AddIncrementCounter(isolate()->counters()->number_to_string_native());
1434

    
1435
    // Load the value in case of cache hit.
1436
    HValue* key_index = Pop();
1437
    HValue* value_index = Add<HAdd>(key_index, graph()->GetConstant1());
1438
    Push(Add<HLoadKeyed>(number_string_cache, value_index,
1439
                         static_cast<HValue*>(NULL),
1440
                         FAST_ELEMENTS, ALLOW_RETURN_HOLE));
1441
  }
1442
  if_found.Else();
1443
  {
1444
    // Cache miss, fallback to runtime.
1445
    Add<HPushArgument>(object);
1446
    Push(Add<HCallRuntime>(
1447
            isolate()->factory()->empty_string(),
1448
            Runtime::FunctionForId(Runtime::kNumberToStringSkipCache),
1449
            1));
1450
  }
1451
  if_found.End();
1452

    
1453
  return Pop();
1454
}
1455

    
1456

    
1457
HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
1458
    HValue* checked_object,
1459
    HValue* key,
1460
    HValue* val,
1461
    bool is_js_array,
1462
    ElementsKind elements_kind,
1463
    bool is_store,
1464
    LoadKeyedHoleMode load_mode,
1465
    KeyedAccessStoreMode store_mode) {
1466
  ASSERT(!IsExternalArrayElementsKind(elements_kind) || !is_js_array);
1467
  // No GVNFlag is necessary for ElementsKind if there is an explicit dependency
1468
  // on a HElementsTransition instruction. The flag can also be removed if the
1469
  // map to check has FAST_HOLEY_ELEMENTS, since there can be no further
1470
  // ElementsKind transitions. Finally, the dependency can be removed for stores
1471
  // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the
1472
  // generated store code.
1473
  if ((elements_kind == FAST_HOLEY_ELEMENTS) ||
1474
      (elements_kind == FAST_ELEMENTS && is_store)) {
1475
    checked_object->ClearGVNFlag(kDependsOnElementsKind);
1476
  }
1477

    
1478
  bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind);
1479
  bool fast_elements = IsFastObjectElementsKind(elements_kind);
1480
  HValue* elements = AddLoadElements(checked_object);
1481
  if (is_store && (fast_elements || fast_smi_only_elements) &&
1482
      store_mode != STORE_NO_TRANSITION_HANDLE_COW) {
1483
    HCheckMaps* check_cow_map = Add<HCheckMaps>(
1484
        elements, isolate()->factory()->fixed_array_map(), top_info());
1485
    check_cow_map->ClearGVNFlag(kDependsOnElementsKind);
1486
  }
1487
  HInstruction* length = NULL;
1488
  if (is_js_array) {
1489
    length = Add<HLoadNamedField>(
1490
        checked_object, HObjectAccess::ForArrayLength(elements_kind));
1491
  } else {
1492
    length = AddLoadFixedArrayLength(elements);
1493
  }
1494
  length->set_type(HType::Smi());
1495
  HValue* checked_key = NULL;
1496
  if (IsExternalArrayElementsKind(elements_kind)) {
1497
    if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
1498
      NoObservableSideEffectsScope no_effects(this);
1499
       HLoadExternalArrayPointer* external_elements =
1500
           Add<HLoadExternalArrayPointer>(elements);
1501
      IfBuilder length_checker(this);
1502
      length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT);
1503
      length_checker.Then();
1504
      IfBuilder negative_checker(this);
1505
      HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>(
1506
          key, graph()->GetConstant0(), Token::GTE);
1507
      negative_checker.Then();
1508
      HInstruction* result = AddElementAccess(
1509
          external_elements, key, val, bounds_check, elements_kind, is_store);
1510
      negative_checker.ElseDeopt("Negative key encountered");
1511
      length_checker.End();
1512
      return result;
1513
    } else {
1514
      ASSERT(store_mode == STANDARD_STORE);
1515
      checked_key = Add<HBoundsCheck>(key, length);
1516
      HLoadExternalArrayPointer* external_elements =
1517
          Add<HLoadExternalArrayPointer>(elements);
1518
      return AddElementAccess(
1519
          external_elements, checked_key, val,
1520
          checked_object, elements_kind, is_store);
1521
    }
1522
  }
1523
  ASSERT(fast_smi_only_elements ||
1524
         fast_elements ||
1525
         IsFastDoubleElementsKind(elements_kind));
1526

    
1527
  // In case val is stored into a fast smi array, assure that the value is a smi
1528
  // before manipulating the backing store. Otherwise the actual store may
1529
  // deopt, leaving the backing store in an invalid state.
1530
  if (is_store && IsFastSmiElementsKind(elements_kind) &&
1531
      !val->type().IsSmi()) {
1532
    val = Add<HForceRepresentation>(val, Representation::Smi());
1533
  }
1534

    
1535
  if (IsGrowStoreMode(store_mode)) {
1536
    NoObservableSideEffectsScope no_effects(this);
1537
    elements = BuildCheckForCapacityGrow(checked_object, elements,
1538
                                         elements_kind, length, key,
1539
                                         is_js_array);
1540
    checked_key = key;
1541
  } else {
1542
    checked_key = Add<HBoundsCheck>(key, length);
1543

    
1544
    if (is_store && (fast_elements || fast_smi_only_elements)) {
1545
      if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) {
1546
        NoObservableSideEffectsScope no_effects(this);
1547
        elements = BuildCopyElementsOnWrite(checked_object, elements,
1548
                                            elements_kind, length);
1549
      } else {
1550
        HCheckMaps* check_cow_map = Add<HCheckMaps>(
1551
            elements, isolate()->factory()->fixed_array_map(), top_info());
1552
        check_cow_map->ClearGVNFlag(kDependsOnElementsKind);
1553
      }
1554
    }
1555
  }
1556
  return AddElementAccess(elements, checked_key, val, checked_object,
1557
                          elements_kind, is_store, load_mode);
1558
}
1559

    
1560

    
1561
HValue* HGraphBuilder::BuildAllocateElements(ElementsKind kind,
1562
                                             HValue* capacity) {
1563
  int elements_size;
1564
  InstanceType instance_type;
1565

    
1566
  if (IsFastDoubleElementsKind(kind)) {
1567
    elements_size = kDoubleSize;
1568
    instance_type = FIXED_DOUBLE_ARRAY_TYPE;
1569
  } else {
1570
    elements_size = kPointerSize;
1571
    instance_type = FIXED_ARRAY_TYPE;
1572
  }
1573

    
1574
  HConstant* elements_size_value = Add<HConstant>(elements_size);
1575
  HValue* mul = Add<HMul>(capacity, elements_size_value);
1576
  mul->ClearFlag(HValue::kCanOverflow);
1577

    
1578
  HConstant* header_size = Add<HConstant>(FixedArray::kHeaderSize);
1579
  HValue* total_size = Add<HAdd>(mul, header_size);
1580
  total_size->ClearFlag(HValue::kCanOverflow);
1581

    
1582
  return Add<HAllocate>(total_size, HType::JSArray(),
1583
      isolate()->heap()->GetPretenureMode(), instance_type);
1584
}
1585

    
1586

    
1587
void HGraphBuilder::BuildInitializeElementsHeader(HValue* elements,
1588
                                                  ElementsKind kind,
1589
                                                  HValue* capacity) {
1590
  Factory* factory = isolate()->factory();
1591
  Handle<Map> map = IsFastDoubleElementsKind(kind)
1592
      ? factory->fixed_double_array_map()
1593
      : factory->fixed_array_map();
1594

    
1595
  AddStoreMapConstant(elements, map);
1596
  Add<HStoreNamedField>(elements, HObjectAccess::ForFixedArrayLength(),
1597
                        capacity);
1598
}
1599

    
1600

    
1601
HValue* HGraphBuilder::BuildAllocateElementsAndInitializeElementsHeader(
1602
    ElementsKind kind,
1603
    HValue* capacity) {
1604
  // The HForceRepresentation is to prevent possible deopt on int-smi
1605
  // conversion after allocation but before the new object fields are set.
1606
  capacity = Add<HForceRepresentation>(capacity, Representation::Smi());
1607
  HValue* new_elements = BuildAllocateElements(kind, capacity);
1608
  BuildInitializeElementsHeader(new_elements, kind, capacity);
1609
  return new_elements;
1610
}
1611

    
1612

    
1613
HInnerAllocatedObject* HGraphBuilder::BuildJSArrayHeader(HValue* array,
1614
    HValue* array_map,
1615
    AllocationSiteMode mode,
1616
    ElementsKind elements_kind,
1617
    HValue* allocation_site_payload,
1618
    HValue* length_field) {
1619

    
1620
  Add<HStoreNamedField>(array, HObjectAccess::ForMap(), array_map);
1621

    
1622
  HConstant* empty_fixed_array =
1623
    Add<HConstant>(isolate()->factory()->empty_fixed_array());
1624

    
1625
  HObjectAccess access = HObjectAccess::ForPropertiesPointer();
1626
  Add<HStoreNamedField>(array, access, empty_fixed_array);
1627
  Add<HStoreNamedField>(array, HObjectAccess::ForArrayLength(elements_kind),
1628
                        length_field);
1629

    
1630
  if (mode == TRACK_ALLOCATION_SITE) {
1631
    BuildCreateAllocationMemento(array,
1632
                                 JSArray::kSize,
1633
                                 allocation_site_payload);
1634
  }
1635

    
1636
  int elements_location = JSArray::kSize;
1637
  if (mode == TRACK_ALLOCATION_SITE) {
1638
    elements_location += AllocationMemento::kSize;
1639
  }
1640

    
1641
  HValue* elements = Add<HInnerAllocatedObject>(array, elements_location);
1642
  Add<HStoreNamedField>(array, HObjectAccess::ForElementsPointer(), elements);
1643
  return static_cast<HInnerAllocatedObject*>(elements);
1644
}
1645

    
1646

    
1647
HInstruction* HGraphBuilder::AddElementAccess(
1648
    HValue* elements,
1649
    HValue* checked_key,
1650
    HValue* val,
1651
    HValue* dependency,
1652
    ElementsKind elements_kind,
1653
    bool is_store,
1654
    LoadKeyedHoleMode load_mode) {
1655
  if (is_store) {
1656
    ASSERT(val != NULL);
1657
    if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
1658
      val = Add<HClampToUint8>(val);
1659
    }
1660
    return Add<HStoreKeyed>(elements, checked_key, val, elements_kind);
1661
  }
1662

    
1663
  ASSERT(!is_store);
1664
  ASSERT(val == NULL);
1665
  HLoadKeyed* load = Add<HLoadKeyed>(
1666
      elements, checked_key, dependency, elements_kind, load_mode);
1667
  if (FLAG_opt_safe_uint32_operations &&
1668
      elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
1669
    graph()->RecordUint32Instruction(load);
1670
  }
1671
  return load;
1672
}
1673

    
1674

    
1675
HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object) {
1676
  return Add<HLoadNamedField>(object, HObjectAccess::ForElementsPointer());
1677
}
1678

    
1679

    
1680
HLoadNamedField* HGraphBuilder::AddLoadFixedArrayLength(HValue* object) {
1681
  return Add<HLoadNamedField>(object,
1682
                              HObjectAccess::ForFixedArrayLength());
1683
}
1684

    
1685

    
1686
HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* old_capacity) {
1687
  HValue* half_old_capacity = AddUncasted<HShr>(old_capacity,
1688
                                                graph_->GetConstant1());
1689

    
1690
  HValue* new_capacity = AddUncasted<HAdd>(half_old_capacity, old_capacity);
1691
  new_capacity->ClearFlag(HValue::kCanOverflow);
1692

    
1693
  HValue* min_growth = Add<HConstant>(16);
1694

    
1695
  new_capacity = AddUncasted<HAdd>(new_capacity, min_growth);
1696
  new_capacity->ClearFlag(HValue::kCanOverflow);
1697

    
1698
  return new_capacity;
1699
}
1700

    
1701

    
1702
void HGraphBuilder::BuildNewSpaceArrayCheck(HValue* length, ElementsKind kind) {
1703
  Heap* heap = isolate()->heap();
1704
  int element_size = IsFastDoubleElementsKind(kind) ? kDoubleSize
1705
                                                    : kPointerSize;
1706
  int max_size = heap->MaxRegularSpaceAllocationSize() / element_size;
1707
  max_size -= JSArray::kSize / element_size;
1708
  HConstant* max_size_constant = Add<HConstant>(max_size);
1709
  Add<HBoundsCheck>(length, max_size_constant);
1710
}
1711

    
1712

    
1713
HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object,
1714
                                                 HValue* elements,
1715
                                                 ElementsKind kind,
1716
                                                 ElementsKind new_kind,
1717
                                                 HValue* length,
1718
                                                 HValue* new_capacity) {
1719
  BuildNewSpaceArrayCheck(new_capacity, new_kind);
1720

    
1721
  HValue* new_elements = BuildAllocateElementsAndInitializeElementsHeader(
1722
      new_kind, new_capacity);
1723

    
1724
  BuildCopyElements(elements, kind,
1725
                    new_elements, new_kind,
1726
                    length, new_capacity);
1727

    
1728
  Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
1729
                        new_elements);
1730

    
1731
  return new_elements;
1732
}
1733

    
1734

    
1735
void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
1736
                                              ElementsKind elements_kind,
1737
                                              HValue* from,
1738
                                              HValue* to) {
1739
  // Fast elements kinds need to be initialized in case statements below cause
1740
  // a garbage collection.
1741
  Factory* factory = isolate()->factory();
1742

    
1743
  double nan_double = FixedDoubleArray::hole_nan_as_double();
1744
  HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind)
1745
      ? Add<HConstant>(factory->the_hole_value())
1746
      : Add<HConstant>(nan_double);
1747

    
1748
  // Special loop unfolding case
1749
  static const int kLoopUnfoldLimit = 4;
1750
  bool unfold_loop = false;
1751
  int initial_capacity = JSArray::kPreallocatedArrayElements;
1752
  if (from->IsConstant() && to->IsConstant() &&
1753
      initial_capacity <= kLoopUnfoldLimit) {
1754
    HConstant* constant_from = HConstant::cast(from);
1755
    HConstant* constant_to = HConstant::cast(to);
1756

    
1757
    if (constant_from->HasInteger32Value() &&
1758
        constant_from->Integer32Value() == 0 &&
1759
        constant_to->HasInteger32Value() &&
1760
        constant_to->Integer32Value() == initial_capacity) {
1761
      unfold_loop = true;
1762
    }
1763
  }
1764

    
1765
  // Since we're about to store a hole value, the store instruction below must
1766
  // assume an elements kind that supports heap object values.
1767
  if (IsFastSmiOrObjectElementsKind(elements_kind)) {
1768
    elements_kind = FAST_HOLEY_ELEMENTS;
1769
  }
1770

    
1771
  if (unfold_loop) {
1772
    for (int i = 0; i < initial_capacity; i++) {
1773
      HInstruction* key = Add<HConstant>(i);
1774
      Add<HStoreKeyed>(elements, key, hole, elements_kind);
1775
    }
1776
  } else {
1777
    LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
1778

    
1779
    HValue* key = builder.BeginBody(from, to, Token::LT);
1780

    
1781
    Add<HStoreKeyed>(elements, key, hole, elements_kind);
1782

    
1783
    builder.EndBody();
1784
  }
1785
}
1786

    
1787

    
1788
void HGraphBuilder::BuildCopyElements(HValue* from_elements,
1789
                                      ElementsKind from_elements_kind,
1790
                                      HValue* to_elements,
1791
                                      ElementsKind to_elements_kind,
1792
                                      HValue* length,
1793
                                      HValue* capacity) {
1794
  bool pre_fill_with_holes =
1795
      IsFastDoubleElementsKind(from_elements_kind) &&
1796
      IsFastObjectElementsKind(to_elements_kind);
1797

    
1798
  if (pre_fill_with_holes) {
1799
    // If the copy might trigger a GC, make sure that the FixedArray is
1800
    // pre-initialized with holes to make sure that it's always in a consistent
1801
    // state.
1802
    BuildFillElementsWithHole(to_elements, to_elements_kind,
1803
                              graph()->GetConstant0(), capacity);
1804
  }
1805

    
1806
  LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
1807

    
1808
  HValue* key = builder.BeginBody(graph()->GetConstant0(), length, Token::LT);
1809

    
1810
  HValue* element = Add<HLoadKeyed>(from_elements, key,
1811
                                    static_cast<HValue*>(NULL),
1812
                                    from_elements_kind,
1813
                                    ALLOW_RETURN_HOLE);
1814

    
1815
  ElementsKind kind = (IsHoleyElementsKind(from_elements_kind) &&
1816
                       IsFastSmiElementsKind(to_elements_kind))
1817
      ? FAST_HOLEY_ELEMENTS : to_elements_kind;
1818

    
1819
  if (IsHoleyElementsKind(from_elements_kind) &&
1820
      from_elements_kind != to_elements_kind) {
1821
    IfBuilder if_hole(this);
1822
    if_hole.If<HCompareHoleAndBranch>(element);
1823
    if_hole.Then();
1824
    HConstant* hole_constant = IsFastDoubleElementsKind(to_elements_kind)
1825
        ? Add<HConstant>(FixedDoubleArray::hole_nan_as_double())
1826
        : graph()->GetConstantHole();
1827
    Add<HStoreKeyed>(to_elements, key, hole_constant, kind);
1828
    if_hole.Else();
1829
    HStoreKeyed* store = Add<HStoreKeyed>(to_elements, key, element, kind);
1830
    store->SetFlag(HValue::kAllowUndefinedAsNaN);
1831
    if_hole.End();
1832
  } else {
1833
    HStoreKeyed* store = Add<HStoreKeyed>(to_elements, key, element, kind);
1834
    store->SetFlag(HValue::kAllowUndefinedAsNaN);
1835
  }
1836

    
1837
  builder.EndBody();
1838

    
1839
  if (!pre_fill_with_holes && length != capacity) {
1840
    // Fill unused capacity with the hole.
1841
    BuildFillElementsWithHole(to_elements, to_elements_kind,
1842
                              key, capacity);
1843
  }
1844
}
1845

    
1846

    
1847
HValue* HGraphBuilder::BuildCloneShallowArray(HValue* boilerplate,
1848
                                              HValue* allocation_site,
1849
                                              AllocationSiteMode mode,
1850
                                              ElementsKind kind,
1851
                                              int length) {
1852
  NoObservableSideEffectsScope no_effects(this);
1853

    
1854
  // All sizes here are multiples of kPointerSize.
1855
  int size = JSArray::kSize;
1856
  if (mode == TRACK_ALLOCATION_SITE) {
1857
    size += AllocationMemento::kSize;
1858
  }
1859

    
1860
  HValue* size_in_bytes = Add<HConstant>(size);
1861
  HInstruction* object = Add<HAllocate>(size_in_bytes,
1862
                                        HType::JSObject(),
1863
                                        NOT_TENURED,
1864
                                        JS_OBJECT_TYPE);
1865

    
1866
  // Copy the JS array part.
1867
  for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
1868
    if ((i != JSArray::kElementsOffset) || (length == 0)) {
1869
      HObjectAccess access = HObjectAccess::ForJSArrayOffset(i);
1870
      Add<HStoreNamedField>(object, access,
1871
                            Add<HLoadNamedField>(boilerplate, access));
1872
    }
1873
  }
1874

    
1875
  // Create an allocation site info if requested.
1876
  if (mode == TRACK_ALLOCATION_SITE) {
1877
    BuildCreateAllocationMemento(object, JSArray::kSize, allocation_site);
1878
  }
1879

    
1880
  if (length > 0) {
1881
    HValue* boilerplate_elements = AddLoadElements(boilerplate);
1882
    HValue* object_elements;
1883
    if (IsFastDoubleElementsKind(kind)) {
1884
      HValue* elems_size = Add<HConstant>(FixedDoubleArray::SizeFor(length));
1885
      object_elements = Add<HAllocate>(elems_size, HType::JSArray(),
1886
          NOT_TENURED, FIXED_DOUBLE_ARRAY_TYPE);
1887
    } else {
1888
      HValue* elems_size = Add<HConstant>(FixedArray::SizeFor(length));
1889
      object_elements = Add<HAllocate>(elems_size, HType::JSArray(),
1890
          NOT_TENURED, FIXED_ARRAY_TYPE);
1891
    }
1892
    Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
1893
                          object_elements);
1894

    
1895
    // Copy the elements array header.
1896
    for (int i = 0; i < FixedArrayBase::kHeaderSize; i += kPointerSize) {
1897
      HObjectAccess access = HObjectAccess::ForFixedArrayHeader(i);
1898
      Add<HStoreNamedField>(object_elements, access,
1899
                            Add<HLoadNamedField>(boilerplate_elements, access));
1900
    }
1901

    
1902
    // Copy the elements array contents.
1903
    // TODO(mstarzinger): Teach HGraphBuilder::BuildCopyElements to unfold
1904
    // copying loops with constant length up to a given boundary and use this
1905
    // helper here instead.
1906
    for (int i = 0; i < length; i++) {
1907
      HValue* key_constant = Add<HConstant>(i);
1908
      HInstruction* value = Add<HLoadKeyed>(boilerplate_elements, key_constant,
1909
                                            static_cast<HValue*>(NULL), kind);
1910
      Add<HStoreKeyed>(object_elements, key_constant, value, kind);
1911
    }
1912
  }
1913

    
1914
  return object;
1915
}
1916

    
1917

    
1918
void HGraphBuilder::BuildCompareNil(
1919
    HValue* value,
1920
    Handle<Type> type,
1921
    HIfContinuation* continuation) {
1922
  IfBuilder if_nil(this);
1923
  bool some_case_handled = false;
1924
  bool some_case_missing = false;
1925

    
1926
  if (type->Maybe(Type::Null())) {
1927
    if (some_case_handled) if_nil.Or();
1928
    if_nil.If<HCompareObjectEqAndBranch>(value, graph()->GetConstantNull());
1929
    some_case_handled = true;
1930
  } else {
1931
    some_case_missing = true;
1932
  }
1933

    
1934
  if (type->Maybe(Type::Undefined())) {
1935
    if (some_case_handled) if_nil.Or();
1936
    if_nil.If<HCompareObjectEqAndBranch>(value,
1937
                                         graph()->GetConstantUndefined());
1938
    some_case_handled = true;
1939
  } else {
1940
    some_case_missing = true;
1941
  }
1942

    
1943
  if (type->Maybe(Type::Undetectable())) {
1944
    if (some_case_handled) if_nil.Or();
1945
    if_nil.If<HIsUndetectableAndBranch>(value);
1946
    some_case_handled = true;
1947
  } else {
1948
    some_case_missing = true;
1949
  }
1950

    
1951
  if (some_case_missing) {
1952
    if_nil.Then();
1953
    if_nil.Else();
1954
    if (type->NumClasses() == 1) {
1955
      BuildCheckHeapObject(value);
1956
      // For ICs, the map checked below is a sentinel map that gets replaced by
1957
      // the monomorphic map when the code is used as a template to generate a
1958
      // new IC. For optimized functions, there is no sentinel map, the map
1959
      // emitted below is the actual monomorphic map.
1960
      BuildCheckMap(value, type->Classes().Current());
1961
    } else {
1962
      if_nil.Deopt("Too many undetectable types");
1963
    }
1964
  }
1965

    
1966
  if_nil.CaptureContinuation(continuation);
1967
}
1968

    
1969

    
1970
HValue* HGraphBuilder::BuildCreateAllocationMemento(HValue* previous_object,
1971
                                                    int previous_object_size,
1972
                                                    HValue* alloc_site) {
1973
  ASSERT(alloc_site != NULL);
1974
  HInnerAllocatedObject* alloc_memento = Add<HInnerAllocatedObject>(
1975
      previous_object, previous_object_size);
1976
  Handle<Map> alloc_memento_map =
1977
      isolate()->factory()->allocation_memento_map();
1978
  AddStoreMapConstant(alloc_memento, alloc_memento_map);
1979
  HObjectAccess access = HObjectAccess::ForAllocationMementoSite();
1980
  Add<HStoreNamedField>(alloc_memento, access, alloc_site);
1981
  return alloc_memento;
1982
}
1983

    
1984

    
1985
HInstruction* HGraphBuilder::BuildGetNativeContext() {
1986
  // Get the global context, then the native context
1987
  HInstruction* global_object = Add<HGlobalObject>();
1988
  HObjectAccess access = HObjectAccess::ForJSObjectOffset(
1989
      GlobalObject::kNativeContextOffset);
1990
  return Add<HLoadNamedField>(global_object, access);
1991
}
1992

    
1993

    
1994
HInstruction* HGraphBuilder::BuildGetArrayFunction() {
1995
  HInstruction* native_context = BuildGetNativeContext();
1996
  HInstruction* index =
1997
      Add<HConstant>(static_cast<int32_t>(Context::ARRAY_FUNCTION_INDEX));
1998
  return Add<HLoadKeyed>(
1999
      native_context, index, static_cast<HValue*>(NULL), FAST_ELEMENTS);
2000
}
2001

    
2002

    
2003
HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder,
2004
    ElementsKind kind,
2005
    HValue* allocation_site_payload,
2006
    HValue* constructor_function,
2007
    AllocationSiteOverrideMode override_mode) :
2008
        builder_(builder),
2009
        kind_(kind),
2010
        allocation_site_payload_(allocation_site_payload),
2011
        constructor_function_(constructor_function) {
2012
  mode_ = override_mode == DISABLE_ALLOCATION_SITES
2013
      ? DONT_TRACK_ALLOCATION_SITE
2014
      : AllocationSite::GetMode(kind);
2015
}
2016

    
2017

    
2018
HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder,
2019
                                              ElementsKind kind,
2020
                                              HValue* constructor_function) :
2021
    builder_(builder),
2022
    kind_(kind),
2023
    mode_(DONT_TRACK_ALLOCATION_SITE),
2024
    allocation_site_payload_(NULL),
2025
    constructor_function_(constructor_function) {
2026
}
2027

    
2028

    
2029
HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode() {
2030
  if (kind_ == GetInitialFastElementsKind()) {
2031
    // No need for a context lookup if the kind_ matches the initial
2032
    // map, because we can just load the map in that case.
2033
    HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap();
2034
    return builder()->AddLoadNamedField(constructor_function_, access);
2035
  }
2036

    
2037
  HInstruction* native_context = builder()->BuildGetNativeContext();
2038
  HInstruction* index = builder()->Add<HConstant>(
2039
      static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX));
2040

    
2041
  HInstruction* map_array = builder()->Add<HLoadKeyed>(
2042
      native_context, index, static_cast<HValue*>(NULL), FAST_ELEMENTS);
2043

    
2044
  HInstruction* kind_index = builder()->Add<HConstant>(kind_);
2045

    
2046
  return builder()->Add<HLoadKeyed>(
2047
      map_array, kind_index, static_cast<HValue*>(NULL), FAST_ELEMENTS);
2048
}
2049

    
2050

    
2051
HValue* HGraphBuilder::JSArrayBuilder::EmitInternalMapCode() {
2052
  // Find the map near the constructor function
2053
  HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap();
2054
  return builder()->AddLoadNamedField(constructor_function_, access);
2055
}
2056

    
2057

    
2058
HValue* HGraphBuilder::JSArrayBuilder::EstablishAllocationSize(
2059
    HValue* length_node) {
2060
  ASSERT(length_node != NULL);
2061

    
2062
  int base_size = JSArray::kSize;
2063
  if (mode_ == TRACK_ALLOCATION_SITE) {
2064
    base_size += AllocationMemento::kSize;
2065
  }
2066

    
2067
  STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize);
2068
  base_size += FixedArray::kHeaderSize;
2069

    
2070
  HInstruction* elements_size_value =
2071
      builder()->Add<HConstant>(elements_size());
2072
  HInstruction* mul = builder()->Add<HMul>(length_node, elements_size_value);
2073
  mul->ClearFlag(HValue::kCanOverflow);
2074

    
2075
  HInstruction* base = builder()->Add<HConstant>(base_size);
2076
  HInstruction* total_size = builder()->Add<HAdd>(base, mul);
2077
  total_size->ClearFlag(HValue::kCanOverflow);
2078
  return total_size;
2079
}
2080

    
2081

    
2082
HValue* HGraphBuilder::JSArrayBuilder::EstablishEmptyArrayAllocationSize() {
2083
  int base_size = JSArray::kSize;
2084
  if (mode_ == TRACK_ALLOCATION_SITE) {
2085
    base_size += AllocationMemento::kSize;
2086
  }
2087

    
2088
  base_size += IsFastDoubleElementsKind(kind_)
2089
      ? FixedDoubleArray::SizeFor(initial_capacity())
2090
      : FixedArray::SizeFor(initial_capacity());
2091

    
2092
  return builder()->Add<HConstant>(base_size);
2093
}
2094

    
2095

    
2096
HValue* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() {
2097
  HValue* size_in_bytes = EstablishEmptyArrayAllocationSize();
2098
  HConstant* capacity = builder()->Add<HConstant>(initial_capacity());
2099
  return AllocateArray(size_in_bytes,
2100
                       capacity,
2101
                       builder()->graph()->GetConstant0(),
2102
                       true);
2103
}
2104

    
2105

    
2106
HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* capacity,
2107
                                                     HValue* length_field,
2108
                                                     bool fill_with_hole) {
2109
  HValue* size_in_bytes = EstablishAllocationSize(capacity);
2110
  return AllocateArray(size_in_bytes, capacity, length_field, fill_with_hole);
2111
}
2112

    
2113

    
2114
HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes,
2115
                                                     HValue* capacity,
2116
                                                     HValue* length_field,
2117
                                                     bool fill_with_hole) {
2118
  // These HForceRepresentations are because we store these as fields in the
2119
  // objects we construct, and an int32-to-smi HChange could deopt. Accept
2120
  // the deopt possibility now, before allocation occurs.
2121
  capacity = builder()->Add<HForceRepresentation>(capacity,
2122
                                                  Representation::Smi());
2123
  length_field = builder()->Add<HForceRepresentation>(length_field,
2124
                                                      Representation::Smi());
2125
  // Allocate (dealing with failure appropriately)
2126
  HAllocate* new_object = builder()->Add<HAllocate>(size_in_bytes,
2127
      HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE);
2128

    
2129
  // Folded array allocation should be aligned if it has fast double elements.
2130
  if (IsFastDoubleElementsKind(kind_)) {
2131
     new_object->MakeDoubleAligned();
2132
  }
2133

    
2134
  // Fill in the fields: map, properties, length
2135
  HValue* map;
2136
  if (allocation_site_payload_ == NULL) {
2137
    map = EmitInternalMapCode();
2138
  } else {
2139
    map = EmitMapCode();
2140
  }
2141
  elements_location_ = builder()->BuildJSArrayHeader(new_object,
2142
                                                     map,
2143
                                                     mode_,
2144
                                                     kind_,
2145
                                                     allocation_site_payload_,
2146
                                                     length_field);
2147

    
2148
  // Initialize the elements
2149
  builder()->BuildInitializeElementsHeader(elements_location_, kind_, capacity);
2150

    
2151
  if (fill_with_hole) {
2152
    builder()->BuildFillElementsWithHole(elements_location_, kind_,
2153
                                         graph()->GetConstant0(), capacity);
2154
  }
2155

    
2156
  return new_object;
2157
}
2158

    
2159

    
2160
HStoreNamedField* HGraphBuilder::AddStoreMapConstant(HValue *object,
2161
                                                     Handle<Map> map) {
2162
  return Add<HStoreNamedField>(object, HObjectAccess::ForMap(),
2163
                               Add<HConstant>(map));
2164
}
2165

    
2166

    
2167
HValue* HGraphBuilder::AddLoadJSBuiltin(Builtins::JavaScript builtin) {
2168
  HGlobalObject* global_object = Add<HGlobalObject>();
2169
  HObjectAccess access = HObjectAccess::ForJSObjectOffset(
2170
      GlobalObject::kBuiltinsOffset);
2171
  HValue* builtins = Add<HLoadNamedField>(global_object, access);
2172
  HObjectAccess function_access = HObjectAccess::ForJSObjectOffset(
2173
      JSBuiltinsObject::OffsetOfFunctionWithId(builtin));
2174
  return Add<HLoadNamedField>(builtins, function_access);
2175
}
2176

    
2177

    
2178
HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info)
2179
    : HGraphBuilder(info),
2180
      function_state_(NULL),
2181
      initial_function_state_(this, info, NORMAL_RETURN),
2182
      ast_context_(NULL),
2183
      break_scope_(NULL),
2184
      inlined_count_(0),
2185
      globals_(10, info->zone()),
2186
      inline_bailout_(false),
2187
      osr_(new(info->zone()) HOsrBuilder(this)) {
2188
  // This is not initialized in the initializer list because the
2189
  // constructor for the initial state relies on function_state_ == NULL
2190
  // to know it's the initial state.
2191
  function_state_= &initial_function_state_;
2192
  InitializeAstVisitor(info->isolate());
2193
  if (FLAG_emit_opt_code_positions) {
2194
    SetSourcePosition(info->shared_info()->start_position());
2195
  }
2196
}
2197

    
2198

    
2199
HBasicBlock* HOptimizedGraphBuilder::CreateJoin(HBasicBlock* first,
2200
                                                HBasicBlock* second,
2201
                                                BailoutId join_id) {
2202
  if (first == NULL) {
2203
    return second;
2204
  } else if (second == NULL) {
2205
    return first;
2206
  } else {
2207
    HBasicBlock* join_block = graph()->CreateBasicBlock();
2208
    Goto(first, join_block);
2209
    Goto(second, join_block);
2210
    join_block->SetJoinId(join_id);
2211
    return join_block;
2212
  }
2213
}
2214

    
2215

    
2216
HBasicBlock* HOptimizedGraphBuilder::JoinContinue(IterationStatement* statement,
2217
                                                  HBasicBlock* exit_block,
2218
                                                  HBasicBlock* continue_block) {
2219
  if (continue_block != NULL) {
2220
    if (exit_block != NULL) Goto(exit_block, continue_block);
2221
    continue_block->SetJoinId(statement->ContinueId());
2222
    return continue_block;
2223
  }
2224
  return exit_block;
2225
}
2226

    
2227

    
2228
HBasicBlock* HOptimizedGraphBuilder::CreateLoop(IterationStatement* statement,
2229
                                                HBasicBlock* loop_entry,
2230
                                                HBasicBlock* body_exit,
2231
                                                HBasicBlock* loop_successor,
2232
                                                HBasicBlock* break_block) {
2233
  if (body_exit != NULL) Goto(body_exit, loop_entry);
2234
  loop_entry->PostProcessLoopHeader(statement);
2235
  if (break_block != NULL) {
2236
    if (loop_successor != NULL) Goto(loop_successor, break_block);
2237
    break_block->SetJoinId(statement->ExitId());
2238
    return break_block;
2239
  }
2240
  return loop_successor;
2241
}
2242

    
2243

    
2244
// Build a new loop header block and set it as the current block.
2245
HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry() {
2246
  HBasicBlock* loop_entry = CreateLoopHeaderBlock();
2247
  Goto(loop_entry);
2248
  set_current_block(loop_entry);
2249
  return loop_entry;
2250
}
2251

    
2252

    
2253
HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry(
2254
    IterationStatement* statement) {
2255
  HBasicBlock* loop_entry = osr()->HasOsrEntryAt(statement)
2256
      ? osr()->BuildOsrLoopEntry(statement)
2257
      : BuildLoopEntry();
2258
  return loop_entry;
2259
}
2260

    
2261

    
2262
void HBasicBlock::FinishExit(HControlInstruction* instruction, int position) {
2263
  Finish(instruction, position);
2264
  ClearEnvironment();
2265
}
2266

    
2267

    
2268
HGraph::HGraph(CompilationInfo* info)
2269
    : isolate_(info->isolate()),
2270
      next_block_id_(0),
2271
      entry_block_(NULL),
2272
      blocks_(8, info->zone()),
2273
      values_(16, info->zone()),
2274
      phi_list_(NULL),
2275
      uint32_instructions_(NULL),
2276
      osr_(NULL),
2277
      info_(info),
2278
      zone_(info->zone()),
2279
      is_recursive_(false),
2280
      use_optimistic_licm_(false),
2281
      depends_on_empty_array_proto_elements_(false),
2282
      type_change_checksum_(0),
2283
      maximum_environment_size_(0),
2284
      no_side_effects_scope_count_(0) {
2285
  if (info->IsStub()) {
2286
    HydrogenCodeStub* stub = info->code_stub();
2287
    CodeStubInterfaceDescriptor* descriptor =
2288
        stub->GetInterfaceDescriptor(isolate_);
2289
    start_environment_ =
2290
        new(zone_) HEnvironment(zone_, descriptor->environment_length());
2291
  } else {
2292
    start_environment_ =
2293
        new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_);
2294
  }
2295
  start_environment_->set_ast_id(BailoutId::FunctionEntry());
2296
  entry_block_ = CreateBasicBlock();
2297
  entry_block_->SetInitialEnvironment(start_environment_);
2298
}
2299

    
2300

    
2301
HBasicBlock* HGraph::CreateBasicBlock() {
2302
  HBasicBlock* result = new(zone()) HBasicBlock(this);
2303
  blocks_.Add(result, zone());
2304
  return result;
2305
}
2306

    
2307

    
2308
void HGraph::FinalizeUniqueness() {
2309
  DisallowHeapAllocation no_gc;
2310
  ASSERT(!isolate()->optimizing_compiler_thread()->IsOptimizerThread());
2311
  for (int i = 0; i < blocks()->length(); ++i) {
2312
    for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) {
2313
      it.Current()->FinalizeUniqueness();
2314
    }
2315
  }
2316
}
2317

    
2318

    
2319
// Block ordering was implemented with two mutually recursive methods,
2320
// HGraph::Postorder and HGraph::PostorderLoopBlocks.
2321
// The recursion could lead to stack overflow so the algorithm has been
2322
// implemented iteratively.
2323
// At a high level the algorithm looks like this:
2324
//
2325
// Postorder(block, loop_header) : {
2326
//   if (block has already been visited or is of another loop) return;
2327
//   mark block as visited;
2328
//   if (block is a loop header) {
2329
//     VisitLoopMembers(block, loop_header);
2330
//     VisitSuccessorsOfLoopHeader(block);
2331
//   } else {
2332
//     VisitSuccessors(block)
2333
//   }
2334
//   put block in result list;
2335
// }
2336
//
2337
// VisitLoopMembers(block, outer_loop_header) {
2338
//   foreach (block b in block loop members) {
2339
//     VisitSuccessorsOfLoopMember(b, outer_loop_header);
2340
//     if (b is loop header) VisitLoopMembers(b);
2341
//   }
2342
// }
2343
//
2344
// VisitSuccessorsOfLoopMember(block, outer_loop_header) {
2345
//   foreach (block b in block successors) Postorder(b, outer_loop_header)
2346
// }
2347
//
2348
// VisitSuccessorsOfLoopHeader(block) {
2349
//   foreach (block b in block successors) Postorder(b, block)
2350
// }
2351
//
2352
// VisitSuccessors(block, loop_header) {
2353
//   foreach (block b in block successors) Postorder(b, loop_header)
2354
// }
2355
//
2356
// The ordering is started calling Postorder(entry, NULL).
2357
//
2358
// Each instance of PostorderProcessor represents the "stack frame" of the
2359
// recursion, and particularly keeps the state of the loop (iteration) of the
2360
// "Visit..." function it represents.
2361
// To recycle memory we keep all the frames in a double linked list but
2362
// this means that we cannot use constructors to initialize the frames.
2363
//
2364
class PostorderProcessor : public ZoneObject {
2365
 public:
2366
  // Back link (towards the stack bottom).
2367
  PostorderProcessor* parent() {return father_; }
2368
  // Forward link (towards the stack top).
2369
  PostorderProcessor* child() {return child_; }
2370
  HBasicBlock* block() { return block_; }
2371
  HLoopInformation* loop() { return loop_; }
2372
  HBasicBlock* loop_header() { return loop_header_; }
2373

    
2374
  static PostorderProcessor* CreateEntryProcessor(Zone* zone,
2375
                                                  HBasicBlock* block,
2376
                                                  BitVector* visited) {
2377
    PostorderProcessor* result = new(zone) PostorderProcessor(NULL);
2378
    return result->SetupSuccessors(zone, block, NULL, visited);
2379
  }
2380

    
2381
  PostorderProcessor* PerformStep(Zone* zone,
2382
                                  BitVector* visited,
2383
                                  ZoneList<HBasicBlock*>* order) {
2384
    PostorderProcessor* next =
2385
        PerformNonBacktrackingStep(zone, visited, order);
2386
    if (next != NULL) {
2387
      return next;
2388
    } else {
2389
      return Backtrack(zone, visited, order);
2390
    }
2391
  }
2392

    
2393
 private:
2394
  explicit PostorderProcessor(PostorderProcessor* father)
2395
      : father_(father), child_(NULL), successor_iterator(NULL) { }
2396

    
2397
  // Each enum value states the cycle whose state is kept by this instance.
2398
  enum LoopKind {
2399
    NONE,
2400
    SUCCESSORS,
2401
    SUCCESSORS_OF_LOOP_HEADER,
2402
    LOOP_MEMBERS,
2403
    SUCCESSORS_OF_LOOP_MEMBER
2404
  };
2405

    
2406
  // Each "Setup..." method is like a constructor for a cycle state.
2407
  PostorderProcessor* SetupSuccessors(Zone* zone,
2408
                                      HBasicBlock* block,
2409
                                      HBasicBlock* loop_header,
2410
                                      BitVector* visited) {
2411
    if (block == NULL || visited->Contains(block->block_id()) ||
2412
        block->parent_loop_header() != loop_header) {
2413
      kind_ = NONE;
2414
      block_ = NULL;
2415
      loop_ = NULL;
2416
      loop_header_ = NULL;
2417
      return this;
2418
    } else {
2419
      block_ = block;
2420
      loop_ = NULL;
2421
      visited->Add(block->block_id());
2422

    
2423
      if (block->IsLoopHeader()) {
2424
        kind_ = SUCCESSORS_OF_LOOP_HEADER;
2425
        loop_header_ = block;
2426
        InitializeSuccessors();
2427
        PostorderProcessor* result = Push(zone);
2428
        return result->SetupLoopMembers(zone, block, block->loop_information(),
2429
                                        loop_header);
2430
      } else {
2431
        ASSERT(block->IsFinished());
2432
        kind_ = SUCCESSORS;
2433
        loop_header_ = loop_header;
2434
        InitializeSuccessors();
2435
        return this;
2436
      }
2437
    }
2438
  }
2439

    
2440
  PostorderProcessor* SetupLoopMembers(Zone* zone,
2441
                                       HBasicBlock* block,
2442
                                       HLoopInformation* loop,
2443
                                       HBasicBlock* loop_header) {
2444
    kind_ = LOOP_MEMBERS;
2445
    block_ = block;
2446
    loop_ = loop;
2447
    loop_header_ = loop_header;
2448
    InitializeLoopMembers();
2449
    return this;
2450
  }
2451

    
2452
  PostorderProcessor* SetupSuccessorsOfLoopMember(
2453
      HBasicBlock* block,
2454
      HLoopInformation* loop,
2455
      HBasicBlock* loop_header) {
2456
    kind_ = SUCCESSORS_OF_LOOP_MEMBER;
2457
    block_ = block;
2458
    loop_ = loop;
2459
    loop_header_ = loop_header;
2460
    InitializeSuccessors();
2461
    return this;
2462
  }
2463

    
2464
  // This method "allocates" a new stack frame.
2465
  PostorderProcessor* Push(Zone* zone) {
2466
    if (child_ == NULL) {
2467
      child_ = new(zone) PostorderProcessor(this);
2468
    }
2469
    return child_;
2470
  }
2471

    
2472
  void ClosePostorder(ZoneList<HBasicBlock*>* order, Zone* zone) {
2473
    ASSERT(block_->end()->FirstSuccessor() == NULL ||
2474
           order->Contains(block_->end()->FirstSuccessor()) ||
2475
           block_->end()->FirstSuccessor()->IsLoopHeader());
2476
    ASSERT(block_->end()->SecondSuccessor() == NULL ||
2477
           order->Contains(block_->end()->SecondSuccessor()) ||
2478
           block_->end()->SecondSuccessor()->IsLoopHeader());
2479
    order->Add(block_, zone);
2480
  }
2481

    
2482
  // This method is the basic block to walk up the stack.
2483
  PostorderProcessor* Pop(Zone* zone,
2484
                          BitVector* visited,
2485
                          ZoneList<HBasicBlock*>* order) {
2486
    switch (kind_) {
2487
      case SUCCESSORS:
2488
      case SUCCESSORS_OF_LOOP_HEADER:
2489
        ClosePostorder(order, zone);
2490
        return father_;
2491
      case LOOP_MEMBERS:
2492
        return father_;
2493
      case SUCCESSORS_OF_LOOP_MEMBER:
2494
        if (block()->IsLoopHeader() && block() != loop_->loop_header()) {
2495
          // In this case we need to perform a LOOP_MEMBERS cycle so we
2496
          // initialize it and return this instead of father.
2497
          return SetupLoopMembers(zone, block(),
2498
                                  block()->loop_information(), loop_header_);
2499
        } else {
2500
          return father_;
2501
        }
2502
      case NONE:
2503
        return father_;
2504
    }
2505
    UNREACHABLE();
2506
    return NULL;
2507
  }
2508

    
2509
  // Walks up the stack.
2510
  PostorderProcessor* Backtrack(Zone* zone,
2511
                                BitVector* visited,
2512
                                ZoneList<HBasicBlock*>* order) {
2513
    PostorderProcessor* parent = Pop(zone, visited, order);
2514
    while (parent != NULL) {
2515
      PostorderProcessor* next =
2516
          parent->PerformNonBacktrackingStep(zone, visited, order);
2517
      if (next != NULL) {
2518
        return next;
2519
      } else {
2520
        parent = parent->Pop(zone, visited, order);
2521
      }
2522
    }
2523
    return NULL;
2524
  }
2525

    
2526
  PostorderProcessor* PerformNonBacktrackingStep(
2527
      Zone* zone,
2528
      BitVector* visited,
2529
      ZoneList<HBasicBlock*>* order) {
2530
    HBasicBlock* next_block;
2531
    switch (kind_) {
2532
      case SUCCESSORS:
2533
        next_block = AdvanceSuccessors();
2534
        if (next_block != NULL) {
2535
          PostorderProcessor* result = Push(zone);
2536
          return result->SetupSuccessors(zone, next_block,
2537
                                         loop_header_, visited);
2538
        }
2539
        break;
2540
      case SUCCESSORS_OF_LOOP_HEADER:
2541
        next_block = AdvanceSuccessors();
2542
        if (next_block != NULL) {
2543
          PostorderProcessor* result = Push(zone);
2544
          return result->SetupSuccessors(zone, next_block,
2545
                                         block(), visited);
2546
        }
2547
        break;
2548
      case LOOP_MEMBERS:
2549
        next_block = AdvanceLoopMembers();
2550
        if (next_block != NULL) {
2551
          PostorderProcessor* result = Push(zone);
2552
          return result->SetupSuccessorsOfLoopMember(next_block,
2553
                                                     loop_, loop_header_);
2554
        }
2555
        break;
2556
      case SUCCESSORS_OF_LOOP_MEMBER:
2557
        next_block = AdvanceSuccessors();
2558
        if (next_block != NULL) {
2559
          PostorderProcessor* result = Push(zone);
2560
          return result->SetupSuccessors(zone, next_block,
2561
                                         loop_header_, visited);
2562
        }
2563
        break;
2564
      case NONE:
2565
        return NULL;
2566
    }
2567
    return NULL;
2568
  }
2569

    
2570
  // The following two methods implement a "foreach b in successors" cycle.
2571
  void InitializeSuccessors() {
2572
    loop_index = 0;
2573
    loop_length = 0;
2574
    successor_iterator = HSuccessorIterator(block_->end());
2575
  }
2576

    
2577
  HBasicBlock* AdvanceSuccessors() {
2578
    if (!successor_iterator.Done()) {
2579
      HBasicBlock* result = successor_iterator.Current();
2580
      successor_iterator.Advance();
2581
      return result;
2582
    }
2583
    return NULL;
2584
  }
2585

    
2586
  // The following two methods implement a "foreach b in loop members" cycle.
2587
  void InitializeLoopMembers() {
2588
    loop_index = 0;
2589
    loop_length = loop_->blocks()->length();
2590
  }
2591

    
2592
  HBasicBlock* AdvanceLoopMembers() {
2593
    if (loop_index < loop_length) {
2594
      HBasicBlock* result = loop_->blocks()->at(loop_index);
2595
      loop_index++;
2596
      return result;
2597
    } else {
2598
      return NULL;
2599
    }
2600
  }
2601

    
2602
  LoopKind kind_;
2603
  PostorderProcessor* father_;
2604
  PostorderProcessor* child_;
2605
  HLoopInformation* loop_;
2606
  HBasicBlock* block_;
2607
  HBasicBlock* loop_header_;
2608
  int loop_index;
2609
  int loop_length;
2610
  HSuccessorIterator successor_iterator;
2611
};
2612

    
2613

    
2614
void HGraph::OrderBlocks() {
2615
  CompilationPhase phase("H_Block ordering", info());
2616
  BitVector visited(blocks_.length(), zone());
2617

    
2618
  ZoneList<HBasicBlock*> reverse_result(8, zone());
2619
  HBasicBlock* start = blocks_[0];
2620
  PostorderProcessor* postorder =
2621
      PostorderProcessor::CreateEntryProcessor(zone(), start, &visited);
2622
  while (postorder != NULL) {
2623
    postorder = postorder->PerformStep(zone(), &visited, &reverse_result);
2624
  }
2625
  blocks_.Rewind(0);
2626
  int index = 0;
2627
  for (int i = reverse_result.length() - 1; i >= 0; --i) {
2628
    HBasicBlock* b = reverse_result[i];
2629
    blocks_.Add(b, zone());
2630
    b->set_block_id(index++);
2631
  }
2632
}
2633

    
2634

    
2635
void HGraph::AssignDominators() {
2636
  HPhase phase("H_Assign dominators", this);
2637
  for (int i = 0; i < blocks_.length(); ++i) {
2638
    HBasicBlock* block = blocks_[i];
2639
    if (block->IsLoopHeader()) {
2640
      // Only the first predecessor of a loop header is from outside the loop.
2641
      // All others are back edges, and thus cannot dominate the loop header.
2642
      block->AssignCommonDominator(block->predecessors()->first());
2643
      block->AssignLoopSuccessorDominators();
2644
    } else {
2645
      for (int j = blocks_[i]->predecessors()->length() - 1; j >= 0; --j) {
2646
        blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j));
2647
      }
2648
    }
2649
  }
2650
}
2651

    
2652

    
2653
bool HGraph::CheckArgumentsPhiUses() {
2654
  int block_count = blocks_.length();
2655
  for (int i = 0; i < block_count; ++i) {
2656
    for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
2657
      HPhi* phi = blocks_[i]->phis()->at(j);
2658
      // We don't support phi uses of arguments for now.
2659
      if (phi->CheckFlag(HValue::kIsArguments)) return false;
2660
    }
2661
  }
2662
  return true;
2663
}
2664

    
2665

    
2666
bool HGraph::CheckConstPhiUses() {
2667
  int block_count = blocks_.length();
2668
  for (int i = 0; i < block_count; ++i) {
2669
    for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
2670
      HPhi* phi = blocks_[i]->phis()->at(j);
2671
      // Check for the hole value (from an uninitialized const).
2672
      for (int k = 0; k < phi->OperandCount(); k++) {
2673
        if (phi->OperandAt(k) == GetConstantHole()) return false;
2674
      }
2675
    }
2676
  }
2677
  return true;
2678
}
2679

    
2680

    
2681
void HGraph::CollectPhis() {
2682
  int block_count = blocks_.length();
2683
  phi_list_ = new(zone()) ZoneList<HPhi*>(block_count, zone());
2684
  for (int i = 0; i < block_count; ++i) {
2685
    for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
2686
      HPhi* phi = blocks_[i]->phis()->at(j);
2687
      phi_list_->Add(phi, zone());
2688
    }
2689
  }
2690
}
2691

    
2692

    
2693
// Implementation of utility class to encapsulate the translation state for
2694
// a (possibly inlined) function.
2695
FunctionState::FunctionState(HOptimizedGraphBuilder* owner,
2696
                             CompilationInfo* info,
2697
                             InliningKind inlining_kind)
2698
    : owner_(owner),
2699
      compilation_info_(info),
2700
      call_context_(NULL),
2701
      inlining_kind_(inlining_kind),
2702
      function_return_(NULL),
2703
      test_context_(NULL),
2704
      entry_(NULL),
2705
      arguments_object_(NULL),
2706
      arguments_elements_(NULL),
2707
      outer_(owner->function_state()) {
2708
  if (outer_ != NULL) {
2709
    // State for an inline function.
2710
    if (owner->ast_context()->IsTest()) {
2711
      HBasicBlock* if_true = owner->graph()->CreateBasicBlock();
2712
      HBasicBlock* if_false = owner->graph()->CreateBasicBlock();
2713
      if_true->MarkAsInlineReturnTarget(owner->current_block());
2714
      if_false->MarkAsInlineReturnTarget(owner->current_block());
2715
      TestContext* outer_test_context = TestContext::cast(owner->ast_context());
2716
      Expression* cond = outer_test_context->condition();
2717
      // The AstContext constructor pushed on the context stack.  This newed
2718
      // instance is the reason that AstContext can't be BASE_EMBEDDED.
2719
      test_context_ = new TestContext(owner, cond, if_true, if_false);
2720
    } else {
2721
      function_return_ = owner->graph()->CreateBasicBlock();
2722
      function_return()->MarkAsInlineReturnTarget(owner->current_block());
2723
    }
2724
    // Set this after possibly allocating a new TestContext above.
2725
    call_context_ = owner->ast_context();
2726
  }
2727

    
2728
  // Push on the state stack.
2729
  owner->set_function_state(this);
2730
}
2731

    
2732

    
2733
FunctionState::~FunctionState() {
2734
  delete test_context_;
2735
  owner_->set_function_state(outer_);
2736
}
2737

    
2738

    
2739
// Implementation of utility classes to represent an expression's context in
2740
// the AST.
2741
AstContext::AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind)
2742
    : owner_(owner),
2743
      kind_(kind),
2744
      outer_(owner->ast_context()),
2745
      for_typeof_(false) {
2746
  owner->set_ast_context(this);  // Push.
2747
#ifdef DEBUG
2748
  ASSERT(owner->environment()->frame_type() == JS_FUNCTION);
2749
  original_length_ = owner->environment()->length();
2750
#endif
2751
}
2752

    
2753

    
2754
AstContext::~AstContext() {
2755
  owner_->set_ast_context(outer_);  // Pop.
2756
}
2757

    
2758

    
2759
EffectContext::~EffectContext() {
2760
  ASSERT(owner()->HasStackOverflow() ||
2761
         owner()->current_block() == NULL ||
2762
         (owner()->environment()->length() == original_length_ &&
2763
          owner()->environment()->frame_type() == JS_FUNCTION));
2764
}
2765

    
2766

    
2767
ValueContext::~ValueContext() {
2768
  ASSERT(owner()->HasStackOverflow() ||
2769
         owner()->current_block() == NULL ||
2770
         (owner()->environment()->length() == original_length_ + 1 &&
2771
          owner()->environment()->frame_type() == JS_FUNCTION));
2772
}
2773

    
2774

    
2775
void EffectContext::ReturnValue(HValue* value) {
2776
  // The value is simply ignored.
2777
}
2778

    
2779

    
2780
void ValueContext::ReturnValue(HValue* value) {
2781
  // The value is tracked in the bailout environment, and communicated
2782
  // through the environment as the result of the expression.
2783
  if (!arguments_allowed() && value->CheckFlag(HValue::kIsArguments)) {
2784
    owner()->Bailout(kBadValueContextForArgumentsValue);
2785
  }
2786
  owner()->Push(value);
2787
}
2788

    
2789

    
2790
void TestContext::ReturnValue(HValue* value) {
2791
  BuildBranch(value);
2792
}
2793

    
2794

    
2795
void EffectContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
2796
  ASSERT(!instr->IsControlInstruction());
2797
  owner()->AddInstruction(instr);
2798
  if (instr->HasObservableSideEffects()) {
2799
    owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
2800
  }
2801
}
2802

    
2803

    
2804
void EffectContext::ReturnControl(HControlInstruction* instr,
2805
                                  BailoutId ast_id) {
2806
  ASSERT(!instr->HasObservableSideEffects());
2807
  HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
2808
  HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
2809
  instr->SetSuccessorAt(0, empty_true);
2810
  instr->SetSuccessorAt(1, empty_false);
2811
  owner()->FinishCurrentBlock(instr);
2812
  HBasicBlock* join = owner()->CreateJoin(empty_true, empty_false, ast_id);
2813
  owner()->set_current_block(join);
2814
}
2815

    
2816

    
2817
void EffectContext::ReturnContinuation(HIfContinuation* continuation,
2818
                                       BailoutId ast_id) {
2819
  HBasicBlock* true_branch = NULL;
2820
  HBasicBlock* false_branch = NULL;
2821
  continuation->Continue(&true_branch, &false_branch);
2822
  if (!continuation->IsTrueReachable()) {
2823
    owner()->set_current_block(false_branch);
2824
  } else if (!continuation->IsFalseReachable()) {
2825
    owner()->set_current_block(true_branch);
2826
  } else {
2827
    HBasicBlock* join = owner()->CreateJoin(true_branch, false_branch, ast_id);
2828
    owner()->set_current_block(join);
2829
  }
2830
}
2831

    
2832

    
2833
void ValueContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
2834
  ASSERT(!instr->IsControlInstruction());
2835
  if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
2836
    return owner()->Bailout(kBadValueContextForArgumentsObjectValue);
2837
  }
2838
  owner()->AddInstruction(instr);
2839
  owner()->Push(instr);
2840
  if (instr->HasObservableSideEffects()) {
2841
    owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
2842
  }
2843
}
2844

    
2845

    
2846
void ValueContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
2847
  ASSERT(!instr->HasObservableSideEffects());
2848
  if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
2849
    return owner()->Bailout(kBadValueContextForArgumentsObjectValue);
2850
  }
2851
  HBasicBlock* materialize_false = owner()->graph()->CreateBasicBlock();
2852
  HBasicBlock* materialize_true = owner()->graph()->CreateBasicBlock();
2853
  instr->SetSuccessorAt(0, materialize_true);
2854
  instr->SetSuccessorAt(1, materialize_false);
2855
  owner()->FinishCurrentBlock(instr);
2856
  owner()->set_current_block(materialize_true);
2857
  owner()->Push(owner()->graph()->GetConstantTrue());
2858
  owner()->set_current_block(materialize_false);
2859
  owner()->Push(owner()->graph()->GetConstantFalse());
2860
  HBasicBlock* join =
2861
    owner()->CreateJoin(materialize_true, materialize_false, ast_id);
2862
  owner()->set_current_block(join);
2863
}
2864

    
2865

    
2866
void ValueContext::ReturnContinuation(HIfContinuation* continuation,
2867
                                      BailoutId ast_id) {
2868
  HBasicBlock* materialize_true = NULL;
2869
  HBasicBlock* materialize_false = NULL;
2870
  continuation->Continue(&materialize_true, &materialize_false);
2871
  if (continuation->IsTrueReachable()) {
2872
    owner()->set_current_block(materialize_true);
2873
    owner()->Push(owner()->graph()->GetConstantTrue());
2874
    owner()->set_current_block(materialize_true);
2875
  }
2876
  if (continuation->IsFalseReachable()) {
2877
    owner()->set_current_block(materialize_false);
2878
    owner()->Push(owner()->graph()->GetConstantFalse());
2879
    owner()->set_current_block(materialize_false);
2880
  }
2881
  if (continuation->TrueAndFalseReachable()) {
2882
    HBasicBlock* join =
2883
        owner()->CreateJoin(materialize_true, materialize_false, ast_id);
2884
    owner()->set_current_block(join);
2885
  }
2886
}
2887

    
2888

    
2889
void TestContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
2890
  ASSERT(!instr->IsControlInstruction());
2891
  HOptimizedGraphBuilder* builder = owner();
2892
  builder->AddInstruction(instr);
2893
  // We expect a simulate after every expression with side effects, though
2894
  // this one isn't actually needed (and wouldn't work if it were targeted).
2895
  if (instr->HasObservableSideEffects()) {
2896
    builder->Push(instr);
2897
    builder->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
2898
    builder->Pop();
2899
  }
2900
  BuildBranch(instr);
2901
}
2902

    
2903

    
2904
void TestContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
2905
  ASSERT(!instr->HasObservableSideEffects());
2906
  HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
2907
  HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
2908
  instr->SetSuccessorAt(0, empty_true);
2909
  instr->SetSuccessorAt(1, empty_false);
2910
  owner()->FinishCurrentBlock(instr);
2911
  owner()->Goto(empty_true, if_true(), owner()->function_state());
2912
  owner()->Goto(empty_false, if_false(), owner()->function_state());
2913
  owner()->set_current_block(NULL);
2914
}
2915

    
2916

    
2917
void TestContext::ReturnContinuation(HIfContinuation* continuation,
2918
                                     BailoutId ast_id) {
2919
  HBasicBlock* true_branch = NULL;
2920
  HBasicBlock* false_branch = NULL;
2921
  continuation->Continue(&true_branch, &false_branch);
2922
  if (continuation->IsTrueReachable()) {
2923
    owner()->Goto(true_branch, if_true(), owner()->function_state());
2924
  }
2925
  if (continuation->IsFalseReachable()) {
2926
    owner()->Goto(false_branch, if_false(), owner()->function_state());
2927
  }
2928
  owner()->set_current_block(NULL);
2929
}
2930

    
2931

    
2932
void TestContext::BuildBranch(HValue* value) {
2933
  // We expect the graph to be in edge-split form: there is no edge that
2934
  // connects a branch node to a join node.  We conservatively ensure that
2935
  // property by always adding an empty block on the outgoing edges of this
2936
  // branch.
2937
  HOptimizedGraphBuilder* builder = owner();
2938
  if (value != NULL && value->CheckFlag(HValue::kIsArguments)) {
2939
    builder->Bailout(kArgumentsObjectValueInATestContext);
2940
  }
2941
  HBasicBlock* empty_true = builder->graph()->CreateBasicBlock();
2942
  HBasicBlock* empty_false = builder->graph()->CreateBasicBlock();
2943
  ToBooleanStub::Types expected(condition()->to_boolean_types());
2944
  builder->FinishCurrentBlock(builder->New<HBranch>(
2945
          value, expected, empty_true, empty_false));
2946

    
2947
  owner()->Goto(empty_true, if_true(), builder->function_state());
2948
  owner()->Goto(empty_false , if_false(), builder->function_state());
2949
  builder->set_current_block(NULL);
2950
}
2951

    
2952

    
2953
// HOptimizedGraphBuilder infrastructure for bailing out and checking bailouts.
2954
#define CHECK_BAILOUT(call)                     \
2955
  do {                                          \
2956
    call;                                       \
2957
    if (HasStackOverflow()) return;             \
2958
  } while (false)
2959

    
2960

    
2961
#define CHECK_ALIVE(call)                                       \
2962
  do {                                                          \
2963
    call;                                                       \
2964
    if (HasStackOverflow() || current_block() == NULL) return;  \
2965
  } while (false)
2966

    
2967

    
2968
#define CHECK_ALIVE_OR_RETURN(call, value)                            \
2969
  do {                                                                \
2970
    call;                                                             \
2971
    if (HasStackOverflow() || current_block() == NULL) return value;  \
2972
  } while (false)
2973

    
2974

    
2975
void HOptimizedGraphBuilder::Bailout(BailoutReason reason) {
2976
  current_info()->set_bailout_reason(reason);
2977
  SetStackOverflow();
2978
}
2979

    
2980

    
2981
void HOptimizedGraphBuilder::VisitForEffect(Expression* expr) {
2982
  EffectContext for_effect(this);
2983
  Visit(expr);
2984
}
2985

    
2986

    
2987
void HOptimizedGraphBuilder::VisitForValue(Expression* expr,
2988
                                           ArgumentsAllowedFlag flag) {
2989
  ValueContext for_value(this, flag);
2990
  Visit(expr);
2991
}
2992

    
2993

    
2994
void HOptimizedGraphBuilder::VisitForTypeOf(Expression* expr) {
2995
  ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
2996
  for_value.set_for_typeof(true);
2997
  Visit(expr);
2998
}
2999

    
3000

    
3001

    
3002
void HOptimizedGraphBuilder::VisitForControl(Expression* expr,
3003
                                             HBasicBlock* true_block,
3004
                                             HBasicBlock* false_block) {
3005
  TestContext for_test(this, expr, true_block, false_block);
3006
  Visit(expr);
3007
}
3008

    
3009

    
3010
void HOptimizedGraphBuilder::VisitArgument(Expression* expr) {
3011
  CHECK_ALIVE(VisitForValue(expr));
3012
  Push(Add<HPushArgument>(Pop()));
3013
}
3014

    
3015

    
3016
void HOptimizedGraphBuilder::VisitArgumentList(
3017
    ZoneList<Expression*>* arguments) {
3018
  for (int i = 0; i < arguments->length(); i++) {
3019
    CHECK_ALIVE(VisitArgument(arguments->at(i)));
3020
  }
3021
}
3022

    
3023

    
3024
void HOptimizedGraphBuilder::VisitExpressions(
3025
    ZoneList<Expression*>* exprs) {
3026
  for (int i = 0; i < exprs->length(); ++i) {
3027
    CHECK_ALIVE(VisitForValue(exprs->at(i)));
3028
  }
3029
}
3030

    
3031

    
3032
bool HOptimizedGraphBuilder::BuildGraph() {
3033
  if (current_info()->function()->is_generator()) {
3034
    Bailout(kFunctionIsAGenerator);
3035
    return false;
3036
  }
3037
  Scope* scope = current_info()->scope();
3038
  if (scope->HasIllegalRedeclaration()) {
3039
    Bailout(kFunctionWithIllegalRedeclaration);
3040
    return false;
3041
  }
3042
  if (scope->calls_eval()) {
3043
    Bailout(kFunctionCallsEval);
3044
    return false;
3045
  }
3046
  SetUpScope(scope);
3047

    
3048
  // Add an edge to the body entry.  This is warty: the graph's start
3049
  // environment will be used by the Lithium translation as the initial
3050
  // environment on graph entry, but it has now been mutated by the
3051
  // Hydrogen translation of the instructions in the start block.  This
3052
  // environment uses values which have not been defined yet.  These
3053
  // Hydrogen instructions will then be replayed by the Lithium
3054
  // translation, so they cannot have an environment effect.  The edge to
3055
  // the body's entry block (along with some special logic for the start
3056
  // block in HInstruction::InsertAfter) seals the start block from
3057
  // getting unwanted instructions inserted.
3058
  //
3059
  // TODO(kmillikin): Fix this.  Stop mutating the initial environment.
3060
  // Make the Hydrogen instructions in the initial block into Hydrogen
3061
  // values (but not instructions), present in the initial environment and
3062
  // not replayed by the Lithium translation.
3063
  HEnvironment* initial_env = environment()->CopyWithoutHistory();
3064
  HBasicBlock* body_entry = CreateBasicBlock(initial_env);
3065
  Goto(body_entry);
3066
  body_entry->SetJoinId(BailoutId::FunctionEntry());
3067
  set_current_block(body_entry);
3068

    
3069
  // Handle implicit declaration of the function name in named function
3070
  // expressions before other declarations.
3071
  if (scope->is_function_scope() && scope->function() != NULL) {
3072
    VisitVariableDeclaration(scope->function());
3073
  }
3074
  VisitDeclarations(scope->declarations());
3075
  Add<HSimulate>(BailoutId::Declarations());
3076

    
3077
  Add<HStackCheck>(HStackCheck::kFunctionEntry);
3078

    
3079
  VisitStatements(current_info()->function()->body());
3080
  if (HasStackOverflow()) return false;
3081

    
3082
  if (current_block() != NULL) {
3083
    Add<HReturn>(graph()->GetConstantUndefined());
3084
    set_current_block(NULL);
3085
  }
3086

    
3087
  // If the checksum of the number of type info changes is the same as the
3088
  // last time this function was compiled, then this recompile is likely not
3089
  // due to missing/inadequate type feedback, but rather too aggressive
3090
  // optimization. Disable optimistic LICM in that case.
3091
  Handle<Code> unoptimized_code(current_info()->shared_info()->code());
3092
  ASSERT(unoptimized_code->kind() == Code::FUNCTION);
3093
  Handle<TypeFeedbackInfo> type_info(
3094
      TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info()));
3095
  int checksum = type_info->own_type_change_checksum();
3096
  int composite_checksum = graph()->update_type_change_checksum(checksum);
3097
  graph()->set_use_optimistic_licm(
3098
      !type_info->matches_inlined_type_change_checksum(composite_checksum));
3099
  type_info->set_inlined_type_change_checksum(composite_checksum);
3100

    
3101
  // Perform any necessary OSR-specific cleanups or changes to the graph.
3102
  osr()->FinishGraph();
3103

    
3104
  return true;
3105
}
3106

    
3107

    
3108
bool HGraph::Optimize(BailoutReason* bailout_reason) {
3109
  OrderBlocks();
3110
  AssignDominators();
3111

    
3112
  // We need to create a HConstant "zero" now so that GVN will fold every
3113
  // zero-valued constant in the graph together.
3114
  // The constant is needed to make idef-based bounds check work: the pass
3115
  // evaluates relations with "zero" and that zero cannot be created after GVN.
3116
  GetConstant0();
3117

    
3118
#ifdef DEBUG
3119
  // Do a full verify after building the graph and computing dominators.
3120
  Verify(true);
3121
#endif
3122

    
3123
  if (FLAG_analyze_environment_liveness && maximum_environment_size() != 0) {
3124
    Run<HEnvironmentLivenessAnalysisPhase>();
3125
  }
3126

    
3127
  if (!CheckConstPhiUses()) {
3128
    *bailout_reason = kUnsupportedPhiUseOfConstVariable;
3129
    return false;
3130
  }
3131
  Run<HRedundantPhiEliminationPhase>();
3132
  if (!CheckArgumentsPhiUses()) {
3133
    *bailout_reason = kUnsupportedPhiUseOfArguments;
3134
    return false;
3135
  }
3136

    
3137
  // Find and mark unreachable code to simplify optimizations, especially gvn,
3138
  // where unreachable code could unnecessarily defeat LICM.
3139
  Run<HMarkUnreachableBlocksPhase>();
3140

    
3141
  if (FLAG_check_elimination) Run<HCheckEliminationPhase>();
3142
  if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>();
3143
  if (FLAG_use_escape_analysis) Run<HEscapeAnalysisPhase>();
3144

    
3145
  if (FLAG_load_elimination) Run<HLoadEliminationPhase>();
3146

    
3147
  CollectPhis();
3148

    
3149
  if (has_osr()) osr()->FinishOsrValues();
3150

    
3151
  Run<HInferRepresentationPhase>();
3152

    
3153
  // Remove HSimulate instructions that have turned out not to be needed
3154
  // after all by folding them into the following HSimulate.
3155
  // This must happen after inferring representations.
3156
  Run<HMergeRemovableSimulatesPhase>();
3157

    
3158
  Run<HMarkDeoptimizeOnUndefinedPhase>();
3159
  Run<HRepresentationChangesPhase>();
3160

    
3161
  Run<HInferTypesPhase>();
3162

    
3163
  // Must be performed before canonicalization to ensure that Canonicalize
3164
  // will not remove semantically meaningful ToInt32 operations e.g. BIT_OR with
3165
  // zero.
3166
  if (FLAG_opt_safe_uint32_operations) Run<HUint32AnalysisPhase>();
3167

    
3168
  if (FLAG_use_canonicalizing) Run<HCanonicalizePhase>();
3169

    
3170
  if (FLAG_use_gvn) Run<HGlobalValueNumberingPhase>();
3171

    
3172
  if (FLAG_use_range) Run<HRangeAnalysisPhase>();
3173

    
3174
  Run<HComputeChangeUndefinedToNaN>();
3175
  Run<HComputeMinusZeroChecksPhase>();
3176

    
3177
  // Eliminate redundant stack checks on backwards branches.
3178
  Run<HStackCheckEliminationPhase>();
3179

    
3180
  if (FLAG_array_bounds_checks_elimination) Run<HBoundsCheckEliminationPhase>();
3181
  if (FLAG_array_bounds_checks_hoisting) Run<HBoundsCheckHoistingPhase>();
3182
  if (FLAG_array_index_dehoisting) Run<HDehoistIndexComputationsPhase>();
3183
  if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>();
3184

    
3185
  RestoreActualValues();
3186

    
3187
  // Find unreachable code a second time, GVN and other optimizations may have
3188
  // made blocks unreachable that were previously reachable.
3189
  Run<HMarkUnreachableBlocksPhase>();
3190

    
3191
  return true;
3192
}
3193

    
3194

    
3195
void HGraph::RestoreActualValues() {
3196
  HPhase phase("H_Restore actual values", this);
3197

    
3198
  for (int block_index = 0; block_index < blocks()->length(); block_index++) {
3199
    HBasicBlock* block = blocks()->at(block_index);
3200

    
3201
#ifdef DEBUG
3202
    for (int i = 0; i < block->phis()->length(); i++) {
3203
      HPhi* phi = block->phis()->at(i);
3204
      ASSERT(phi->ActualValue() == phi);
3205
    }
3206
#endif
3207

    
3208
    for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
3209
      HInstruction* instruction = it.Current();
3210
      if (instruction->ActualValue() != instruction) {
3211
        ASSERT(instruction->IsInformativeDefinition());
3212
        if (instruction->IsPurelyInformativeDefinition()) {
3213
          instruction->DeleteAndReplaceWith(instruction->RedefinedOperand());
3214
        } else {
3215
          instruction->ReplaceAllUsesWith(instruction->ActualValue());
3216
        }
3217
      }
3218
    }
3219
  }
3220
}
3221

    
3222

    
3223
template <class Instruction>
3224
HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) {
3225
  int count = call->argument_count();
3226
  ZoneList<HValue*> arguments(count, zone());
3227
  for (int i = 0; i < count; ++i) {
3228
    arguments.Add(Pop(), zone());
3229
  }
3230

    
3231
  while (!arguments.is_empty()) {
3232
    Add<HPushArgument>(arguments.RemoveLast());
3233
  }
3234
  return call;
3235
}
3236

    
3237

    
3238
void HOptimizedGraphBuilder::SetUpScope(Scope* scope) {
3239
  // First special is HContext.
3240
  HInstruction* context = Add<HContext>();
3241
  environment()->BindContext(context);
3242

    
3243
  // Create an arguments object containing the initial parameters.  Set the
3244
  // initial values of parameters including "this" having parameter index 0.
3245
  ASSERT_EQ(scope->num_parameters() + 1, environment()->parameter_count());
3246
  HArgumentsObject* arguments_object =
3247
      New<HArgumentsObject>(environment()->parameter_count());
3248
  for (int i = 0; i < environment()->parameter_count(); ++i) {
3249
    HInstruction* parameter = Add<HParameter>(i);
3250
    arguments_object->AddArgument(parameter, zone());
3251
    environment()->Bind(i, parameter);
3252
  }
3253
  AddInstruction(arguments_object);
3254
  graph()->SetArgumentsObject(arguments_object);
3255

    
3256
  HConstant* undefined_constant = graph()->GetConstantUndefined();
3257
  // Initialize specials and locals to undefined.
3258
  for (int i = environment()->parameter_count() + 1;
3259
       i < environment()->length();
3260
       ++i) {
3261
    environment()->Bind(i, undefined_constant);
3262
  }
3263

    
3264
  // Handle the arguments and arguments shadow variables specially (they do
3265
  // not have declarations).
3266
  if (scope->arguments() != NULL) {
3267
    if (!scope->arguments()->IsStackAllocated()) {
3268
      return Bailout(kContextAllocatedArguments);
3269
    }
3270

    
3271
    environment()->Bind(scope->arguments(),
3272
                        graph()->GetArgumentsObject());
3273
  }
3274
}
3275

    
3276

    
3277
void HOptimizedGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) {
3278
  for (int i = 0; i < statements->length(); i++) {
3279
    Statement* stmt = statements->at(i);
3280
    CHECK_ALIVE(Visit(stmt));
3281
    if (stmt->IsJump()) break;
3282
  }
3283
}
3284

    
3285

    
3286
void HOptimizedGraphBuilder::VisitBlock(Block* stmt) {
3287
  ASSERT(!HasStackOverflow());
3288
  ASSERT(current_block() != NULL);
3289
  ASSERT(current_block()->HasPredecessor());
3290
  if (stmt->scope() != NULL) {
3291
    return Bailout(kScopedBlock);
3292
  }
3293
  BreakAndContinueInfo break_info(stmt);
3294
  { BreakAndContinueScope push(&break_info, this);
3295
    CHECK_BAILOUT(VisitStatements(stmt->statements()));
3296
  }
3297
  HBasicBlock* break_block = break_info.break_block();
3298
  if (break_block != NULL) {
3299
    if (current_block() != NULL) Goto(break_block);
3300
    break_block->SetJoinId(stmt->ExitId());
3301
    set_current_block(break_block);
3302
  }
3303
}
3304

    
3305

    
3306
void HOptimizedGraphBuilder::VisitExpressionStatement(
3307
    ExpressionStatement* stmt) {
3308
  ASSERT(!HasStackOverflow());
3309
  ASSERT(current_block() != NULL);
3310
  ASSERT(current_block()->HasPredecessor());
3311
  VisitForEffect(stmt->expression());
3312
}
3313

    
3314

    
3315
void HOptimizedGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
3316
  ASSERT(!HasStackOverflow());
3317
  ASSERT(current_block() != NULL);
3318
  ASSERT(current_block()->HasPredecessor());
3319
}
3320

    
3321

    
3322
void HOptimizedGraphBuilder::VisitIfStatement(IfStatement* stmt) {
3323
  ASSERT(!HasStackOverflow());
3324
  ASSERT(current_block() != NULL);
3325
  ASSERT(current_block()->HasPredecessor());
3326
  if (stmt->condition()->ToBooleanIsTrue()) {
3327
    Add<HSimulate>(stmt->ThenId());
3328
    Visit(stmt->then_statement());
3329
  } else if (stmt->condition()->ToBooleanIsFalse()) {
3330
    Add<HSimulate>(stmt->ElseId());
3331
    Visit(stmt->else_statement());
3332
  } else {
3333
    HBasicBlock* cond_true = graph()->CreateBasicBlock();
3334
    HBasicBlock* cond_false = graph()->CreateBasicBlock();
3335
    CHECK_BAILOUT(VisitForControl(stmt->condition(), cond_true, cond_false));
3336

    
3337
    if (cond_true->HasPredecessor()) {
3338
      cond_true->SetJoinId(stmt->ThenId());
3339
      set_current_block(cond_true);
3340
      CHECK_BAILOUT(Visit(stmt->then_statement()));
3341
      cond_true = current_block();
3342
    } else {
3343
      cond_true = NULL;
3344
    }
3345

    
3346
    if (cond_false->HasPredecessor()) {
3347
      cond_false->SetJoinId(stmt->ElseId());
3348
      set_current_block(cond_false);
3349
      CHECK_BAILOUT(Visit(stmt->else_statement()));
3350
      cond_false = current_block();
3351
    } else {
3352
      cond_false = NULL;
3353
    }
3354

    
3355
    HBasicBlock* join = CreateJoin(cond_true, cond_false, stmt->IfId());
3356
    set_current_block(join);
3357
  }
3358
}
3359

    
3360

    
3361
HBasicBlock* HOptimizedGraphBuilder::BreakAndContinueScope::Get(
3362
    BreakableStatement* stmt,
3363
    BreakType type,
3364
    int* drop_extra) {
3365
  *drop_extra = 0;
3366
  BreakAndContinueScope* current = this;
3367
  while (current != NULL && current->info()->target() != stmt) {
3368
    *drop_extra += current->info()->drop_extra();
3369
    current = current->next();
3370
  }
3371
  ASSERT(current != NULL);  // Always found (unless stack is malformed).
3372

    
3373
  if (type == BREAK) {
3374
    *drop_extra += current->info()->drop_extra();
3375
  }
3376

    
3377
  HBasicBlock* block = NULL;
3378
  switch (type) {
3379
    case BREAK:
3380
      block = current->info()->break_block();
3381
      if (block == NULL) {
3382
        block = current->owner()->graph()->CreateBasicBlock();
3383
        current->info()->set_break_block(block);
3384
      }
3385
      break;
3386

    
3387
    case CONTINUE:
3388
      block = current->info()->continue_block();
3389
      if (block == NULL) {
3390
        block = current->owner()->graph()->CreateBasicBlock();
3391
        current->info()->set_continue_block(block);
3392
      }
3393
      break;
3394
  }
3395

    
3396
  return block;
3397
}
3398

    
3399

    
3400
void HOptimizedGraphBuilder::VisitContinueStatement(
3401
    ContinueStatement* stmt) {
3402
  ASSERT(!HasStackOverflow());
3403
  ASSERT(current_block() != NULL);
3404
  ASSERT(current_block()->HasPredecessor());
3405
  int drop_extra = 0;
3406
  HBasicBlock* continue_block = break_scope()->Get(
3407
      stmt->target(), BreakAndContinueScope::CONTINUE, &drop_extra);
3408
  Drop(drop_extra);
3409
  Goto(continue_block);
3410
  set_current_block(NULL);
3411
}
3412

    
3413

    
3414
void HOptimizedGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
3415
  ASSERT(!HasStackOverflow());
3416
  ASSERT(current_block() != NULL);
3417
  ASSERT(current_block()->HasPredecessor());
3418
  int drop_extra = 0;
3419
  HBasicBlock* break_block = break_scope()->Get(
3420
      stmt->target(), BreakAndContinueScope::BREAK, &drop_extra);
3421
  Drop(drop_extra);
3422
  Goto(break_block);
3423
  set_current_block(NULL);
3424
}
3425

    
3426

    
3427
void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
3428
  ASSERT(!HasStackOverflow());
3429
  ASSERT(current_block() != NULL);
3430
  ASSERT(current_block()->HasPredecessor());
3431
  FunctionState* state = function_state();
3432
  AstContext* context = call_context();
3433
  if (context == NULL) {
3434
    // Not an inlined return, so an actual one.
3435
    CHECK_ALIVE(VisitForValue(stmt->expression()));
3436
    HValue* result = environment()->Pop();
3437
    Add<HReturn>(result);
3438
  } else if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) {
3439
    // Return from an inlined construct call. In a test context the return value
3440
    // will always evaluate to true, in a value context the return value needs
3441
    // to be a JSObject.
3442
    if (context->IsTest()) {
3443
      TestContext* test = TestContext::cast(context);
3444
      CHECK_ALIVE(VisitForEffect(stmt->expression()));
3445
      Goto(test->if_true(), state);
3446
    } else if (context->IsEffect()) {
3447
      CHECK_ALIVE(VisitForEffect(stmt->expression()));
3448
      Goto(function_return(), state);
3449
    } else {
3450
      ASSERT(context->IsValue());
3451
      CHECK_ALIVE(VisitForValue(stmt->expression()));
3452
      HValue* return_value = Pop();
3453
      HValue* receiver = environment()->arguments_environment()->Lookup(0);
3454
      HHasInstanceTypeAndBranch* typecheck =
3455
          New<HHasInstanceTypeAndBranch>(return_value,
3456
                                         FIRST_SPEC_OBJECT_TYPE,
3457
                                         LAST_SPEC_OBJECT_TYPE);
3458
      HBasicBlock* if_spec_object = graph()->CreateBasicBlock();
3459
      HBasicBlock* not_spec_object = graph()->CreateBasicBlock();
3460
      typecheck->SetSuccessorAt(0, if_spec_object);
3461
      typecheck->SetSuccessorAt(1, not_spec_object);
3462
      FinishCurrentBlock(typecheck);
3463
      AddLeaveInlined(if_spec_object, return_value, state);
3464
      AddLeaveInlined(not_spec_object, receiver, state);
3465
    }
3466
  } else if (state->inlining_kind() == SETTER_CALL_RETURN) {
3467
    // Return from an inlined setter call. The returned value is never used, the
3468
    // value of an assignment is always the value of the RHS of the assignment.
3469
    CHECK_ALIVE(VisitForEffect(stmt->expression()));
3470
    if (context->IsTest()) {
3471
      HValue* rhs = environment()->arguments_environment()->Lookup(1);
3472
      context->ReturnValue(rhs);
3473
    } else if (context->IsEffect()) {
3474
      Goto(function_return(), state);
3475
    } else {
3476
      ASSERT(context->IsValue());
3477
      HValue* rhs = environment()->arguments_environment()->Lookup(1);
3478
      AddLeaveInlined(rhs, state);
3479
    }
3480
  } else {
3481
    // Return from a normal inlined function. Visit the subexpression in the
3482
    // expression context of the call.
3483
    if (context->IsTest()) {
3484
      TestContext* test = TestContext::cast(context);
3485
      VisitForControl(stmt->expression(), test->if_true(), test->if_false());
3486
    } else if (context->IsEffect()) {
3487
      CHECK_ALIVE(VisitForEffect(stmt->expression()));
3488
      Goto(function_return(), state);
3489
    } else {
3490
      ASSERT(context->IsValue());
3491
      CHECK_ALIVE(VisitForValue(stmt->expression()));
3492
      AddLeaveInlined(Pop(), state);
3493
    }
3494
  }
3495
  set_current_block(NULL);
3496
}
3497

    
3498

    
3499
void HOptimizedGraphBuilder::VisitWithStatement(WithStatement* stmt) {
3500
  ASSERT(!HasStackOverflow());
3501
  ASSERT(current_block() != NULL);
3502
  ASSERT(current_block()->HasPredecessor());
3503
  return Bailout(kWithStatement);
3504
}
3505

    
3506

    
3507
void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
3508
  ASSERT(!HasStackOverflow());
3509
  ASSERT(current_block() != NULL);
3510
  ASSERT(current_block()->HasPredecessor());
3511

    
3512
  // We only optimize switch statements with smi-literal smi comparisons,
3513
  // with a bounded number of clauses.
3514
  const int kCaseClauseLimit = 128;
3515
  ZoneList<CaseClause*>* clauses = stmt->cases();
3516
  int clause_count = clauses->length();
3517
  if (clause_count > kCaseClauseLimit) {
3518
    return Bailout(kSwitchStatementTooManyClauses);
3519
  }
3520

    
3521
  ASSERT(stmt->switch_type() != SwitchStatement::UNKNOWN_SWITCH);
3522
  if (stmt->switch_type() == SwitchStatement::GENERIC_SWITCH) {
3523
    return Bailout(kSwitchStatementMixedOrNonLiteralSwitchLabels);
3524
  }
3525

    
3526
  CHECK_ALIVE(VisitForValue(stmt->tag()));
3527
  Add<HSimulate>(stmt->EntryId());
3528
  HValue* tag_value = Pop();
3529
  HBasicBlock* first_test_block = current_block();
3530

    
3531
  HUnaryControlInstruction* string_check = NULL;
3532
  HBasicBlock* not_string_block = NULL;
3533

    
3534
  // Test switch's tag value if all clauses are string literals
3535
  if (stmt->switch_type() == SwitchStatement::STRING_SWITCH) {
3536
    first_test_block = graph()->CreateBasicBlock();
3537
    not_string_block = graph()->CreateBasicBlock();
3538
    string_check = New<HIsStringAndBranch>(
3539
        tag_value, first_test_block, not_string_block);
3540
    FinishCurrentBlock(string_check);
3541

    
3542
    set_current_block(first_test_block);
3543
  }
3544

    
3545
  // 1. Build all the tests, with dangling true branches
3546
  BailoutId default_id = BailoutId::None();
3547
  for (int i = 0; i < clause_count; ++i) {
3548
    CaseClause* clause = clauses->at(i);
3549
    if (clause->is_default()) {
3550
      default_id = clause->EntryId();
3551
      continue;
3552
    }
3553

    
3554
    // Generate a compare and branch.
3555
    CHECK_ALIVE(VisitForValue(clause->label()));
3556
    HValue* label_value = Pop();
3557

    
3558
    HBasicBlock* next_test_block = graph()->CreateBasicBlock();
3559
    HBasicBlock* body_block = graph()->CreateBasicBlock();
3560

    
3561
    HControlInstruction* compare;
3562

    
3563
    if (stmt->switch_type() == SwitchStatement::SMI_SWITCH) {
3564
      if (!clause->compare_type()->Is(Type::Smi())) {
3565
        Add<HDeoptimize>("Non-smi switch type", Deoptimizer::SOFT);
3566
      }
3567

    
3568
      HCompareNumericAndBranch* compare_ =
3569
          New<HCompareNumericAndBranch>(tag_value,
3570
                                        label_value,
3571
                                        Token::EQ_STRICT);
3572
      compare_->set_observed_input_representation(
3573
          Representation::Smi(), Representation::Smi());
3574
      compare = compare_;
3575
    } else {
3576
      compare = New<HStringCompareAndBranch>(tag_value,
3577
                                             label_value,
3578
                                             Token::EQ_STRICT);
3579
    }
3580

    
3581
    compare->SetSuccessorAt(0, body_block);
3582
    compare->SetSuccessorAt(1, next_test_block);
3583
    FinishCurrentBlock(compare);
3584

    
3585
    set_current_block(next_test_block);
3586
  }
3587

    
3588
  // Save the current block to use for the default or to join with the
3589
  // exit.
3590
  HBasicBlock* last_block = current_block();
3591

    
3592
  if (not_string_block != NULL) {
3593
    BailoutId join_id = !default_id.IsNone() ? default_id : stmt->ExitId();
3594
    last_block = CreateJoin(last_block, not_string_block, join_id);
3595
  }
3596

    
3597
  // 2. Loop over the clauses and the linked list of tests in lockstep,
3598
  // translating the clause bodies.
3599
  HBasicBlock* curr_test_block = first_test_block;
3600
  HBasicBlock* fall_through_block = NULL;
3601

    
3602
  BreakAndContinueInfo break_info(stmt);
3603
  { BreakAndContinueScope push(&break_info, this);
3604
    for (int i = 0; i < clause_count; ++i) {
3605
      CaseClause* clause = clauses->at(i);
3606

    
3607
      // Identify the block where normal (non-fall-through) control flow
3608
      // goes to.
3609
      HBasicBlock* normal_block = NULL;
3610
      if (clause->is_default()) {
3611
        if (last_block != NULL) {
3612
          normal_block = last_block;
3613
          last_block = NULL;  // Cleared to indicate we've handled it.
3614
        }
3615
      } else {
3616
        // If the current test block is deoptimizing due to an unhandled clause
3617
        // of the switch, the test instruction is in the next block since the
3618
        // deopt must end the current block.
3619
        if (curr_test_block->IsDeoptimizing()) {
3620
          ASSERT(curr_test_block->end()->SecondSuccessor() == NULL);
3621
          curr_test_block = curr_test_block->end()->FirstSuccessor();
3622
        }
3623
        normal_block = curr_test_block->end()->FirstSuccessor();
3624
        curr_test_block = curr_test_block->end()->SecondSuccessor();
3625
      }
3626

    
3627
      // Identify a block to emit the body into.
3628
      if (normal_block == NULL) {
3629
        if (fall_through_block == NULL) {
3630
          // (a) Unreachable.
3631
          if (clause->is_default()) {
3632
            continue;  // Might still be reachable clause bodies.
3633
          } else {
3634
            break;
3635
          }
3636
        } else {
3637
          // (b) Reachable only as fall through.
3638
          set_current_block(fall_through_block);
3639
        }
3640
      } else if (fall_through_block == NULL) {
3641
        // (c) Reachable only normally.
3642
        set_current_block(normal_block);
3643
      } else {
3644
        // (d) Reachable both ways.
3645
        HBasicBlock* join = CreateJoin(fall_through_block,
3646
                                       normal_block,
3647
                                       clause->EntryId());
3648
        set_current_block(join);
3649
      }
3650

    
3651
      CHECK_BAILOUT(VisitStatements(clause->statements()));
3652
      fall_through_block = current_block();
3653
    }
3654
  }
3655

    
3656
  // Create an up-to-3-way join.  Use the break block if it exists since
3657
  // it's already a join block.
3658
  HBasicBlock* break_block = break_info.break_block();
3659
  if (break_block == NULL) {
3660
    set_current_block(CreateJoin(fall_through_block,
3661
                                 last_block,
3662
                                 stmt->ExitId()));
3663
  } else {
3664
    if (fall_through_block != NULL) Goto(fall_through_block, break_block);
3665
    if (last_block != NULL) Goto(last_block, break_block);
3666
    break_block->SetJoinId(stmt->ExitId());
3667
    set_current_block(break_block);
3668
  }
3669
}
3670

    
3671

    
3672
void HOptimizedGraphBuilder::VisitLoopBody(IterationStatement* stmt,
3673
                                           HBasicBlock* loop_entry,
3674
                                           BreakAndContinueInfo* break_info) {
3675
  BreakAndContinueScope push(break_info, this);
3676
  Add<HSimulate>(stmt->StackCheckId());
3677
  HStackCheck* stack_check =
3678
      HStackCheck::cast(Add<HStackCheck>(HStackCheck::kBackwardsBranch));
3679
  ASSERT(loop_entry->IsLoopHeader());
3680
  loop_entry->loop_information()->set_stack_check(stack_check);
3681
  CHECK_BAILOUT(Visit(stmt->body()));
3682
}
3683

    
3684

    
3685
void HOptimizedGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
3686
  ASSERT(!HasStackOverflow());
3687
  ASSERT(current_block() != NULL);
3688
  ASSERT(current_block()->HasPredecessor());
3689
  ASSERT(current_block() != NULL);
3690
  HBasicBlock* loop_entry = BuildLoopEntry(stmt);
3691

    
3692
  BreakAndContinueInfo break_info(stmt);
3693
  CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
3694
  HBasicBlock* body_exit =
3695
      JoinContinue(stmt, current_block(), break_info.continue_block());
3696
  HBasicBlock* loop_successor = NULL;
3697
  if (body_exit != NULL && !stmt->cond()->ToBooleanIsTrue()) {
3698
    set_current_block(body_exit);
3699
    // The block for a true condition, the actual predecessor block of the
3700
    // back edge.
3701
    body_exit = graph()->CreateBasicBlock();
3702
    loop_successor = graph()->CreateBasicBlock();
3703
    CHECK_BAILOUT(VisitForControl(stmt->cond(), body_exit, loop_successor));
3704
    if (body_exit->HasPredecessor()) {
3705
      body_exit->SetJoinId(stmt->BackEdgeId());
3706
    } else {
3707
      body_exit = NULL;
3708
    }
3709
    if (loop_successor->HasPredecessor()) {
3710
      loop_successor->SetJoinId(stmt->ExitId());
3711
    } else {
3712
      loop_successor = NULL;
3713
    }
3714
  }
3715
  HBasicBlock* loop_exit = CreateLoop(stmt,
3716
                                      loop_entry,
3717
                                      body_exit,
3718
                                      loop_successor,
3719
                                      break_info.break_block());
3720
  set_current_block(loop_exit);
3721
}
3722

    
3723

    
3724
void HOptimizedGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
3725
  ASSERT(!HasStackOverflow());
3726
  ASSERT(current_block() != NULL);
3727
  ASSERT(current_block()->HasPredecessor());
3728
  ASSERT(current_block() != NULL);
3729
  HBasicBlock* loop_entry = BuildLoopEntry(stmt);
3730

    
3731
  // If the condition is constant true, do not generate a branch.
3732
  HBasicBlock* loop_successor = NULL;
3733
  if (!stmt->cond()->ToBooleanIsTrue()) {
3734
    HBasicBlock* body_entry = graph()->CreateBasicBlock();
3735
    loop_successor = graph()->CreateBasicBlock();
3736
    CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor));
3737
    if (body_entry->HasPredecessor()) {
3738
      body_entry->SetJoinId(stmt->BodyId());
3739
      set_current_block(body_entry);
3740
    }
3741
    if (loop_successor->HasPredecessor()) {
3742
      loop_successor->SetJoinId(stmt->ExitId());
3743
    } else {
3744
      loop_successor = NULL;
3745
    }
3746
  }
3747

    
3748
  BreakAndContinueInfo break_info(stmt);
3749
  if (current_block() != NULL) {
3750
    CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
3751
  }
3752
  HBasicBlock* body_exit =
3753
      JoinContinue(stmt, current_block(), break_info.continue_block());
3754
  HBasicBlock* loop_exit = CreateLoop(stmt,
3755
                                      loop_entry,
3756
                                      body_exit,
3757
                                      loop_successor,
3758
                                      break_info.break_block());
3759
  set_current_block(loop_exit);
3760
}
3761

    
3762

    
3763
void HOptimizedGraphBuilder::VisitForStatement(ForStatement* stmt) {
3764
  ASSERT(!HasStackOverflow());
3765
  ASSERT(current_block() != NULL);
3766
  ASSERT(current_block()->HasPredecessor());
3767
  if (stmt->init() != NULL) {
3768
    CHECK_ALIVE(Visit(stmt->init()));
3769
  }
3770
  ASSERT(current_block() != NULL);
3771
  HBasicBlock* loop_entry = BuildLoopEntry(stmt);
3772

    
3773
  HBasicBlock* loop_successor = NULL;
3774
  if (stmt->cond() != NULL) {
3775
    HBasicBlock* body_entry = graph()->CreateBasicBlock();
3776
    loop_successor = graph()->CreateBasicBlock();
3777
    CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor));
3778
    if (body_entry->HasPredecessor()) {
3779
      body_entry->SetJoinId(stmt->BodyId());
3780
      set_current_block(body_entry);
3781
    }
3782
    if (loop_successor->HasPredecessor()) {
3783
      loop_successor->SetJoinId(stmt->ExitId());
3784
    } else {
3785
      loop_successor = NULL;
3786
    }
3787
  }
3788

    
3789
  BreakAndContinueInfo break_info(stmt);
3790
  if (current_block() != NULL) {
3791
    CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
3792
  }
3793
  HBasicBlock* body_exit =
3794
      JoinContinue(stmt, current_block(), break_info.continue_block());
3795

    
3796
  if (stmt->next() != NULL && body_exit != NULL) {
3797
    set_current_block(body_exit);
3798
    CHECK_BAILOUT(Visit(stmt->next()));
3799
    body_exit = current_block();
3800
  }
3801

    
3802
  HBasicBlock* loop_exit = CreateLoop(stmt,
3803
                                      loop_entry,
3804
                                      body_exit,
3805
                                      loop_successor,
3806
                                      break_info.break_block());
3807
  set_current_block(loop_exit);
3808
}
3809

    
3810

    
3811
void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
3812
  ASSERT(!HasStackOverflow());
3813
  ASSERT(current_block() != NULL);
3814
  ASSERT(current_block()->HasPredecessor());
3815

    
3816
  if (!FLAG_optimize_for_in) {
3817
    return Bailout(kForInStatementOptimizationIsDisabled);
3818
  }
3819

    
3820
  if (stmt->for_in_type() != ForInStatement::FAST_FOR_IN) {
3821
    return Bailout(kForInStatementIsNotFastCase);
3822
  }
3823

    
3824
  if (!stmt->each()->IsVariableProxy() ||
3825
      !stmt->each()->AsVariableProxy()->var()->IsStackLocal()) {
3826
    return Bailout(kForInStatementWithNonLocalEachVariable);
3827
  }
3828

    
3829
  Variable* each_var = stmt->each()->AsVariableProxy()->var();
3830

    
3831
  CHECK_ALIVE(VisitForValue(stmt->enumerable()));
3832
  HValue* enumerable = Top();  // Leave enumerable at the top.
3833

    
3834
  HInstruction* map = Add<HForInPrepareMap>(enumerable);
3835
  Add<HSimulate>(stmt->PrepareId());
3836

    
3837
  HInstruction* array = Add<HForInCacheArray>(
3838
      enumerable, map, DescriptorArray::kEnumCacheBridgeCacheIndex);
3839

    
3840
  HInstruction* enum_length = Add<HMapEnumLength>(map);
3841

    
3842
  HInstruction* start_index = Add<HConstant>(0);
3843

    
3844
  Push(map);
3845
  Push(array);
3846
  Push(enum_length);
3847
  Push(start_index);
3848

    
3849
  HInstruction* index_cache = Add<HForInCacheArray>(
3850
      enumerable, map, DescriptorArray::kEnumCacheBridgeIndicesCacheIndex);
3851
  HForInCacheArray::cast(array)->set_index_cache(
3852
      HForInCacheArray::cast(index_cache));
3853

    
3854
  HBasicBlock* loop_entry = BuildLoopEntry(stmt);
3855

    
3856
  HValue* index = environment()->ExpressionStackAt(0);
3857
  HValue* limit = environment()->ExpressionStackAt(1);
3858

    
3859
  // Check that we still have more keys.
3860
  HCompareNumericAndBranch* compare_index =
3861
      New<HCompareNumericAndBranch>(index, limit, Token::LT);
3862
  compare_index->set_observed_input_representation(
3863
      Representation::Smi(), Representation::Smi());
3864

    
3865
  HBasicBlock* loop_body = graph()->CreateBasicBlock();
3866
  HBasicBlock* loop_successor = graph()->CreateBasicBlock();
3867

    
3868
  compare_index->SetSuccessorAt(0, loop_body);
3869
  compare_index->SetSuccessorAt(1, loop_successor);
3870
  FinishCurrentBlock(compare_index);
3871

    
3872
  set_current_block(loop_successor);
3873
  Drop(5);
3874

    
3875
  set_current_block(loop_body);
3876

    
3877
  HValue* key = Add<HLoadKeyed>(
3878
      environment()->ExpressionStackAt(2),  // Enum cache.
3879
      environment()->ExpressionStackAt(0),  // Iteration index.
3880
      environment()->ExpressionStackAt(0),
3881
      FAST_ELEMENTS);
3882

    
3883
  // Check if the expected map still matches that of the enumerable.
3884
  // If not just deoptimize.
3885
  Add<HCheckMapValue>(environment()->ExpressionStackAt(4),
3886
                      environment()->ExpressionStackAt(3));
3887

    
3888
  Bind(each_var, key);
3889

    
3890
  BreakAndContinueInfo break_info(stmt, 5);
3891
  CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
3892

    
3893
  HBasicBlock* body_exit =
3894
      JoinContinue(stmt, current_block(), break_info.continue_block());
3895

    
3896
  if (body_exit != NULL) {
3897
    set_current_block(body_exit);
3898

    
3899
    HValue* current_index = Pop();
3900
    Push(Add<HAdd>(current_index, graph()->GetConstant1()));
3901
    body_exit = current_block();
3902
  }
3903

    
3904
  HBasicBlock* loop_exit = CreateLoop(stmt,
3905
                                      loop_entry,
3906
                                      body_exit,
3907
                                      loop_successor,
3908
                                      break_info.break_block());
3909

    
3910
  set_current_block(loop_exit);
3911
}
3912

    
3913

    
3914
void HOptimizedGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) {
3915
  ASSERT(!HasStackOverflow());
3916
  ASSERT(current_block() != NULL);
3917
  ASSERT(current_block()->HasPredecessor());
3918
  return Bailout(kForOfStatement);
3919
}
3920

    
3921

    
3922
void HOptimizedGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
3923
  ASSERT(!HasStackOverflow());
3924
  ASSERT(current_block() != NULL);
3925
  ASSERT(current_block()->HasPredecessor());
3926
  return Bailout(kTryCatchStatement);
3927
}
3928

    
3929

    
3930
void HOptimizedGraphBuilder::VisitTryFinallyStatement(
3931
    TryFinallyStatement* stmt) {
3932
  ASSERT(!HasStackOverflow());
3933
  ASSERT(current_block() != NULL);
3934
  ASSERT(current_block()->HasPredecessor());
3935
  return Bailout(kTryFinallyStatement);
3936
}
3937

    
3938

    
3939
void HOptimizedGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
3940
  ASSERT(!HasStackOverflow());
3941
  ASSERT(current_block() != NULL);
3942
  ASSERT(current_block()->HasPredecessor());
3943
  return Bailout(kDebuggerStatement);
3944
}
3945

    
3946

    
3947
void HOptimizedGraphBuilder::VisitCaseClause(CaseClause* clause) {
3948
  UNREACHABLE();
3949
}
3950

    
3951

    
3952
static Handle<SharedFunctionInfo> SearchSharedFunctionInfo(
3953
    Code* unoptimized_code, FunctionLiteral* expr) {
3954
  int start_position = expr->start_position();
3955
  for (RelocIterator it(unoptimized_code); !it.done(); it.next()) {
3956
    RelocInfo* rinfo = it.rinfo();
3957
    if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue;
3958
    Object* obj = rinfo->target_object();
3959
    if (obj->IsSharedFunctionInfo()) {
3960
      SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
3961
      if (shared->start_position() == start_position) {
3962
        return Handle<SharedFunctionInfo>(shared);
3963
      }
3964
    }
3965
  }
3966

    
3967
  return Handle<SharedFunctionInfo>();
3968
}
3969

    
3970

    
3971
void HOptimizedGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
3972
  ASSERT(!HasStackOverflow());
3973
  ASSERT(current_block() != NULL);
3974
  ASSERT(current_block()->HasPredecessor());
3975
  Handle<SharedFunctionInfo> shared_info =
3976
      SearchSharedFunctionInfo(current_info()->shared_info()->code(), expr);
3977
  if (shared_info.is_null()) {
3978
    shared_info = Compiler::BuildFunctionInfo(expr, current_info()->script());
3979
  }
3980
  // We also have a stack overflow if the recursive compilation did.
3981
  if (HasStackOverflow()) return;
3982
  HFunctionLiteral* instr =
3983
      New<HFunctionLiteral>(shared_info, expr->pretenure());
3984
  return ast_context()->ReturnInstruction(instr, expr->id());
3985
}
3986

    
3987

    
3988
void HOptimizedGraphBuilder::VisitNativeFunctionLiteral(
3989
    NativeFunctionLiteral* expr) {
3990
  ASSERT(!HasStackOverflow());
3991
  ASSERT(current_block() != NULL);
3992
  ASSERT(current_block()->HasPredecessor());
3993
  return Bailout(kNativeFunctionLiteral);
3994
}
3995

    
3996

    
3997
void HOptimizedGraphBuilder::VisitConditional(Conditional* expr) {
3998
  ASSERT(!HasStackOverflow());
3999
  ASSERT(current_block() != NULL);
4000
  ASSERT(current_block()->HasPredecessor());
4001
  HBasicBlock* cond_true = graph()->CreateBasicBlock();
4002
  HBasicBlock* cond_false = graph()->CreateBasicBlock();
4003
  CHECK_BAILOUT(VisitForControl(expr->condition(), cond_true, cond_false));
4004

    
4005
  // Visit the true and false subexpressions in the same AST context as the
4006
  // whole expression.
4007
  if (cond_true->HasPredecessor()) {
4008
    cond_true->SetJoinId(expr->ThenId());
4009
    set_current_block(cond_true);
4010
    CHECK_BAILOUT(Visit(expr->then_expression()));
4011
    cond_true = current_block();
4012
  } else {
4013
    cond_true = NULL;
4014
  }
4015

    
4016
  if (cond_false->HasPredecessor()) {
4017
    cond_false->SetJoinId(expr->ElseId());
4018
    set_current_block(cond_false);
4019
    CHECK_BAILOUT(Visit(expr->else_expression()));
4020
    cond_false = current_block();
4021
  } else {
4022
    cond_false = NULL;
4023
  }
4024

    
4025
  if (!ast_context()->IsTest()) {
4026
    HBasicBlock* join = CreateJoin(cond_true, cond_false, expr->id());
4027
    set_current_block(join);
4028
    if (join != NULL && !ast_context()->IsEffect()) {
4029
      return ast_context()->ReturnValue(Pop());
4030
    }
4031
  }
4032
}
4033

    
4034

    
4035
HOptimizedGraphBuilder::GlobalPropertyAccess
4036
    HOptimizedGraphBuilder::LookupGlobalProperty(
4037
        Variable* var, LookupResult* lookup, bool is_store) {
4038
  if (var->is_this() || !current_info()->has_global_object()) {
4039
    return kUseGeneric;
4040
  }
4041
  Handle<GlobalObject> global(current_info()->global_object());
4042
  global->Lookup(*var->name(), lookup);
4043
  if (!lookup->IsNormal() ||
4044
      (is_store && lookup->IsReadOnly()) ||
4045
      lookup->holder() != *global) {
4046
    return kUseGeneric;
4047
  }
4048

    
4049
  return kUseCell;
4050
}
4051

    
4052

    
4053
HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) {
4054
  ASSERT(var->IsContextSlot());
4055
  HValue* context = environment()->context();
4056
  int length = current_info()->scope()->ContextChainLength(var->scope());
4057
  while (length-- > 0) {
4058
    context = Add<HOuterContext>(context);
4059
  }
4060
  return context;
4061
}
4062

    
4063

    
4064
void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
4065
  ASSERT(!HasStackOverflow());
4066
  ASSERT(current_block() != NULL);
4067
  ASSERT(current_block()->HasPredecessor());
4068
  Variable* variable = expr->var();
4069
  switch (variable->location()) {
4070
    case Variable::UNALLOCATED: {
4071
      if (IsLexicalVariableMode(variable->mode())) {
4072
        // TODO(rossberg): should this be an ASSERT?
4073
        return Bailout(kReferenceToGlobalLexicalVariable);
4074
      }
4075
      // Handle known global constants like 'undefined' specially to avoid a
4076
      // load from a global cell for them.
4077
      Handle<Object> constant_value =
4078
          isolate()->factory()->GlobalConstantFor(variable->name());
4079
      if (!constant_value.is_null()) {
4080
        HConstant* instr = New<HConstant>(constant_value);
4081
        return ast_context()->ReturnInstruction(instr, expr->id());
4082
      }
4083

    
4084
      LookupResult lookup(isolate());
4085
      GlobalPropertyAccess type =
4086
          LookupGlobalProperty(variable, &lookup, false);
4087

    
4088
      if (type == kUseCell &&
4089
          current_info()->global_object()->IsAccessCheckNeeded()) {
4090
        type = kUseGeneric;
4091
      }
4092

    
4093
      if (type == kUseCell) {
4094
        Handle<GlobalObject> global(current_info()->global_object());
4095
        Handle<PropertyCell> cell(global->GetPropertyCell(&lookup));
4096
        if (cell->type()->IsConstant()) {
4097
          cell->AddDependentCompilationInfo(top_info());
4098
          Handle<Object> constant_object = cell->type()->AsConstant();
4099
          if (constant_object->IsConsString()) {
4100
            constant_object =
4101
                FlattenGetString(Handle<String>::cast(constant_object));
4102
          }
4103
          HConstant* constant = New<HConstant>(constant_object);
4104
          return ast_context()->ReturnInstruction(constant, expr->id());
4105
        } else {
4106
          HLoadGlobalCell* instr =
4107
              New<HLoadGlobalCell>(cell, lookup.GetPropertyDetails());
4108
          return ast_context()->ReturnInstruction(instr, expr->id());
4109
        }
4110
      } else {
4111
        HGlobalObject* global_object = Add<HGlobalObject>();
4112
        HLoadGlobalGeneric* instr =
4113
            New<HLoadGlobalGeneric>(global_object,
4114
                                    variable->name(),
4115
                                    ast_context()->is_for_typeof());
4116
        return ast_context()->ReturnInstruction(instr, expr->id());
4117
      }
4118
    }
4119

    
4120
    case Variable::PARAMETER:
4121
    case Variable::LOCAL: {
4122
      HValue* value = LookupAndMakeLive(variable);
4123
      if (value == graph()->GetConstantHole()) {
4124
        ASSERT(IsDeclaredVariableMode(variable->mode()) &&
4125
               variable->mode() != VAR);
4126
        return Bailout(kReferenceToUninitializedVariable);
4127
      }
4128
      return ast_context()->ReturnValue(value);
4129
    }
4130

    
4131
    case Variable::CONTEXT: {
4132
      HValue* context = BuildContextChainWalk(variable);
4133
      HLoadContextSlot* instr = new(zone()) HLoadContextSlot(context, variable);
4134
      return ast_context()->ReturnInstruction(instr, expr->id());
4135
    }
4136

    
4137
    case Variable::LOOKUP:
4138
      return Bailout(kReferenceToAVariableWhichRequiresDynamicLookup);
4139
  }
4140
}
4141

    
4142

    
4143
void HOptimizedGraphBuilder::VisitLiteral(Literal* expr) {
4144
  ASSERT(!HasStackOverflow());
4145
  ASSERT(current_block() != NULL);
4146
  ASSERT(current_block()->HasPredecessor());
4147
  HConstant* instr = New<HConstant>(expr->value());
4148
  return ast_context()->ReturnInstruction(instr, expr->id());
4149
}
4150

    
4151

    
4152
void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
4153
  ASSERT(!HasStackOverflow());
4154
  ASSERT(current_block() != NULL);
4155
  ASSERT(current_block()->HasPredecessor());
4156
  Handle<JSFunction> closure = function_state()->compilation_info()->closure();
4157
  Handle<FixedArray> literals(closure->literals());
4158
  HRegExpLiteral* instr = New<HRegExpLiteral>(literals,
4159
                                              expr->pattern(),
4160
                                              expr->flags(),
4161
                                              expr->literal_index());
4162
  return ast_context()->ReturnInstruction(instr, expr->id());
4163
}
4164

    
4165

    
4166
static bool CanInlinePropertyAccess(Map* type) {
4167
  return type->IsJSObjectMap() &&
4168
      !type->is_dictionary_map() &&
4169
      !type->has_named_interceptor();
4170
}
4171

    
4172

    
4173
static void LookupInPrototypes(Handle<Map> map,
4174
                               Handle<String> name,
4175
                               LookupResult* lookup) {
4176
  while (map->prototype()->IsJSObject()) {
4177
    Handle<JSObject> holder(JSObject::cast(map->prototype()));
4178
    map = Handle<Map>(holder->map());
4179
    if (!CanInlinePropertyAccess(*map)) break;
4180
    map->LookupDescriptor(*holder, *name, lookup);
4181
    if (lookup->IsFound()) return;
4182
  }
4183
  lookup->NotFound();
4184
}
4185

    
4186

    
4187
// Tries to find a JavaScript accessor of the given name in the prototype chain
4188
// starting at the given map. Return true iff there is one, including the
4189
// corresponding AccessorPair plus its holder (which could be null when the
4190
// accessor is found directly in the given map).
4191
static bool LookupAccessorPair(Handle<Map> map,
4192
                               Handle<String> name,
4193
                               Handle<AccessorPair>* accessors,
4194
                               Handle<JSObject>* holder) {
4195
  Isolate* isolate = map->GetIsolate();
4196
  LookupResult lookup(isolate);
4197

    
4198
  // Check for a JavaScript accessor directly in the map.
4199
  map->LookupDescriptor(NULL, *name, &lookup);
4200
  if (lookup.IsPropertyCallbacks()) {
4201
    Handle<Object> callback(lookup.GetValueFromMap(*map), isolate);
4202
    if (!callback->IsAccessorPair()) return false;
4203
    *accessors = Handle<AccessorPair>::cast(callback);
4204
    *holder = Handle<JSObject>();
4205
    return true;
4206
  }
4207

    
4208
  // Everything else, e.g. a field, can't be an accessor call.
4209
  if (lookup.IsFound()) return false;
4210

    
4211
  // Check for a JavaScript accessor somewhere in the proto chain.
4212
  LookupInPrototypes(map, name, &lookup);
4213
  if (lookup.IsPropertyCallbacks()) {
4214
    Handle<Object> callback(lookup.GetValue(), isolate);
4215
    if (!callback->IsAccessorPair()) return false;
4216
    *accessors = Handle<AccessorPair>::cast(callback);
4217
    *holder = Handle<JSObject>(lookup.holder());
4218
    return true;
4219
  }
4220

    
4221
  // We haven't found a JavaScript accessor anywhere.
4222
  return false;
4223
}
4224

    
4225

    
4226
static bool LookupSetter(Handle<Map> map,
4227
                         Handle<String> name,
4228
                         Handle<JSFunction>* setter,
4229
                         Handle<JSObject>* holder) {
4230
  Handle<AccessorPair> accessors;
4231
  if (LookupAccessorPair(map, name, &accessors, holder) &&
4232
      accessors->setter()->IsJSFunction()) {
4233
    Handle<JSFunction> func(JSFunction::cast(accessors->setter()));
4234
    CallOptimization call_optimization(func);
4235
    // TODO(dcarney): temporary hack unless crankshaft can handle api calls.
4236
    if (call_optimization.is_simple_api_call()) return false;
4237
    *setter = func;
4238
    return true;
4239
  }
4240
  return false;
4241
}
4242

    
4243

    
4244
// Determines whether the given array or object literal boilerplate satisfies
4245
// all limits to be considered for fast deep-copying and computes the total
4246
// size of all objects that are part of the graph.
4247
static bool IsFastLiteral(Handle<JSObject> boilerplate,
4248
                          int max_depth,
4249
                          int* max_properties) {
4250
  if (boilerplate->map()->is_deprecated()) {
4251
    Handle<Object> result = JSObject::TryMigrateInstance(boilerplate);
4252
    if (result.is_null()) return false;
4253
  }
4254

    
4255
  ASSERT(max_depth >= 0 && *max_properties >= 0);
4256
  if (max_depth == 0) return false;
4257

    
4258
  Isolate* isolate = boilerplate->GetIsolate();
4259
  Handle<FixedArrayBase> elements(boilerplate->elements());
4260
  if (elements->length() > 0 &&
4261
      elements->map() != isolate->heap()->fixed_cow_array_map()) {
4262
    if (boilerplate->HasFastObjectElements()) {
4263
      Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
4264
      int length = elements->length();
4265
      for (int i = 0; i < length; i++) {
4266
        if ((*max_properties)-- == 0) return false;
4267
        Handle<Object> value(fast_elements->get(i), isolate);
4268
        if (value->IsJSObject()) {
4269
          Handle<JSObject> value_object = Handle<JSObject>::cast(value);
4270
          if (!IsFastLiteral(value_object,
4271
                             max_depth - 1,
4272
                             max_properties)) {
4273
            return false;
4274
          }
4275
        }
4276
      }
4277
    } else if (!boilerplate->HasFastDoubleElements()) {
4278
      return false;
4279
    }
4280
  }
4281

    
4282
  Handle<FixedArray> properties(boilerplate->properties());
4283
  if (properties->length() > 0) {
4284
    return false;
4285
  } else {
4286
    Handle<DescriptorArray> descriptors(
4287
        boilerplate->map()->instance_descriptors());
4288
    int limit = boilerplate->map()->NumberOfOwnDescriptors();
4289
    for (int i = 0; i < limit; i++) {
4290
      PropertyDetails details = descriptors->GetDetails(i);
4291
      if (details.type() != FIELD) continue;
4292
      int index = descriptors->GetFieldIndex(i);
4293
      if ((*max_properties)-- == 0) return false;
4294
      Handle<Object> value(boilerplate->InObjectPropertyAt(index), isolate);
4295
      if (value->IsJSObject()) {
4296
        Handle<JSObject> value_object = Handle<JSObject>::cast(value);
4297
        if (!IsFastLiteral(value_object,
4298
                           max_depth - 1,
4299
                           max_properties)) {
4300
          return false;
4301
        }
4302
      }
4303
    }
4304
  }
4305
  return true;
4306
}
4307

    
4308

    
4309
void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
4310
  ASSERT(!HasStackOverflow());
4311
  ASSERT(current_block() != NULL);
4312
  ASSERT(current_block()->HasPredecessor());
4313
  Handle<JSFunction> closure = function_state()->compilation_info()->closure();
4314
  HInstruction* literal;
4315

    
4316
  // Check whether to use fast or slow deep-copying for boilerplate.
4317
  int max_properties = kMaxFastLiteralProperties;
4318
  Handle<Object> literals_cell(closure->literals()->get(expr->literal_index()),
4319
                               isolate());
4320
  Handle<AllocationSite> site;
4321
  Handle<JSObject> boilerplate;
4322
  if (!literals_cell->IsUndefined()) {
4323
    // Retrieve the boilerplate
4324
    site = Handle<AllocationSite>::cast(literals_cell);
4325
    boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()),
4326
                                   isolate());
4327
  }
4328

    
4329
  if (!boilerplate.is_null() &&
4330
      IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) {
4331
    AllocationSiteUsageContext usage_context(isolate(), site, false);
4332
    usage_context.EnterNewScope();
4333
    literal = BuildFastLiteral(boilerplate, &usage_context);
4334
    usage_context.ExitScope(site, boilerplate);
4335
  } else {
4336
    NoObservableSideEffectsScope no_effects(this);
4337
    Handle<FixedArray> closure_literals(closure->literals(), isolate());
4338
    Handle<FixedArray> constant_properties = expr->constant_properties();
4339
    int literal_index = expr->literal_index();
4340
    int flags = expr->fast_elements()
4341
        ? ObjectLiteral::kFastElements : ObjectLiteral::kNoFlags;
4342
    flags |= expr->has_function()
4343
        ? ObjectLiteral::kHasFunction : ObjectLiteral::kNoFlags;
4344

    
4345
    Add<HPushArgument>(Add<HConstant>(closure_literals));
4346
    Add<HPushArgument>(Add<HConstant>(literal_index));
4347
    Add<HPushArgument>(Add<HConstant>(constant_properties));
4348
    Add<HPushArgument>(Add<HConstant>(flags));
4349

    
4350
    // TODO(mvstanton): Add a flag to turn off creation of any
4351
    // AllocationMementos for this call: we are in crankshaft and should have
4352
    // learned enough about transition behavior to stop emitting mementos.
4353
    Runtime::FunctionId function_id = Runtime::kCreateObjectLiteral;
4354
    literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
4355
                                Runtime::FunctionForId(function_id),
4356
                                4);
4357
  }
4358

    
4359
  // The object is expected in the bailout environment during computation
4360
  // of the property values and is the value of the entire expression.
4361
  Push(literal);
4362

    
4363
  expr->CalculateEmitStore(zone());
4364

    
4365
  for (int i = 0; i < expr->properties()->length(); i++) {
4366
    ObjectLiteral::Property* property = expr->properties()->at(i);
4367
    if (property->IsCompileTimeValue()) continue;
4368

    
4369
    Literal* key = property->key();
4370
    Expression* value = property->value();
4371

    
4372
    switch (property->kind()) {
4373
      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
4374
        ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
4375
        // Fall through.
4376
      case ObjectLiteral::Property::COMPUTED:
4377
        if (key->value()->IsInternalizedString()) {
4378
          if (property->emit_store()) {
4379
            CHECK_ALIVE(VisitForValue(value));
4380
            HValue* value = Pop();
4381
            Handle<Map> map = property->GetReceiverType();
4382
            Handle<String> name = property->key()->AsPropertyName();
4383
            HInstruction* store;
4384
            if (map.is_null()) {
4385
              // If we don't know the monomorphic type, do a generic store.
4386
              CHECK_ALIVE(store = BuildStoreNamedGeneric(literal, name, value));
4387
            } else {
4388
#if DEBUG
4389
              Handle<JSFunction> setter;
4390
              Handle<JSObject> holder;
4391
              ASSERT(!LookupSetter(map, name, &setter, &holder));
4392
#endif
4393
              CHECK_ALIVE(store = BuildStoreNamedMonomorphic(literal,
4394
                                                             name,
4395
                                                             value,
4396
                                                             map));
4397
            }
4398
            AddInstruction(store);
4399
            if (store->HasObservableSideEffects()) {
4400
              Add<HSimulate>(key->id(), REMOVABLE_SIMULATE);
4401
            }
4402
          } else {
4403
            CHECK_ALIVE(VisitForEffect(value));
4404
          }
4405
          break;
4406
        }
4407
        // Fall through.
4408
      case ObjectLiteral::Property::PROTOTYPE:
4409
      case ObjectLiteral::Property::SETTER:
4410
      case ObjectLiteral::Property::GETTER:
4411
        return Bailout(kObjectLiteralWithComplexProperty);
4412
      default: UNREACHABLE();
4413
    }
4414
  }
4415

    
4416
  if (expr->has_function()) {
4417
    // Return the result of the transformation to fast properties
4418
    // instead of the original since this operation changes the map
4419
    // of the object. This makes sure that the original object won't
4420
    // be used by other optimized code before it is transformed
4421
    // (e.g. because of code motion).
4422
    HToFastProperties* result = Add<HToFastProperties>(Pop());
4423
    return ast_context()->ReturnValue(result);
4424
  } else {
4425
    return ast_context()->ReturnValue(Pop());
4426
  }
4427
}
4428

    
4429

    
4430
void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
4431
  ASSERT(!HasStackOverflow());
4432
  ASSERT(current_block() != NULL);
4433
  ASSERT(current_block()->HasPredecessor());
4434
  ZoneList<Expression*>* subexprs = expr->values();
4435
  int length = subexprs->length();
4436
  HInstruction* literal;
4437

    
4438
  Handle<AllocationSite> site;
4439
  Handle<FixedArray> literals(environment()->closure()->literals(), isolate());
4440
  bool uninitialized = false;
4441
  Handle<Object> literals_cell(literals->get(expr->literal_index()),
4442
                               isolate());
4443
  Handle<JSObject> boilerplate_object;
4444
  if (literals_cell->IsUndefined()) {
4445
    uninitialized = true;
4446
    Handle<Object> raw_boilerplate = Runtime::CreateArrayLiteralBoilerplate(
4447
        isolate(), literals, expr->constant_elements());
4448
    if (raw_boilerplate.is_null()) {
4449
      return Bailout(kArrayBoilerplateCreationFailed);
4450
    }
4451

    
4452
    boilerplate_object = Handle<JSObject>::cast(raw_boilerplate);
4453
    AllocationSiteCreationContext creation_context(isolate());
4454
    site = creation_context.EnterNewScope();
4455
    if (JSObject::DeepWalk(boilerplate_object, &creation_context).is_null()) {
4456
      return Bailout(kArrayBoilerplateCreationFailed);
4457
    }
4458
    creation_context.ExitScope(site, boilerplate_object);
4459
    literals->set(expr->literal_index(), *site);
4460

    
4461
    if (boilerplate_object->elements()->map() ==
4462
        isolate()->heap()->fixed_cow_array_map()) {
4463
      isolate()->counters()->cow_arrays_created_runtime()->Increment();
4464
    }
4465
  } else {
4466
    ASSERT(literals_cell->IsAllocationSite());
4467
    site = Handle<AllocationSite>::cast(literals_cell);
4468
    boilerplate_object = Handle<JSObject>(
4469
        JSObject::cast(site->transition_info()), isolate());
4470
  }
4471

    
4472
  ASSERT(!boilerplate_object.is_null());
4473
  ASSERT(site->SitePointsToLiteral());
4474

    
4475
  ElementsKind boilerplate_elements_kind =
4476
      boilerplate_object->GetElementsKind();
4477

    
4478
  // Check whether to use fast or slow deep-copying for boilerplate.
4479
  int max_properties = kMaxFastLiteralProperties;
4480
  if (IsFastLiteral(boilerplate_object,
4481
                    kMaxFastLiteralDepth,
4482
                    &max_properties)) {
4483
    AllocationSiteUsageContext usage_context(isolate(), site, false);
4484
    usage_context.EnterNewScope();
4485
    literal = BuildFastLiteral(boilerplate_object, &usage_context);
4486
    usage_context.ExitScope(site, boilerplate_object);
4487
  } else {
4488
    NoObservableSideEffectsScope no_effects(this);
4489
    // Boilerplate already exists and constant elements are never accessed,
4490
    // pass an empty fixed array to the runtime function instead.
4491
    Handle<FixedArray> constants = isolate()->factory()->empty_fixed_array();
4492
    int literal_index = expr->literal_index();
4493

    
4494
    Add<HPushArgument>(Add<HConstant>(literals));
4495
    Add<HPushArgument>(Add<HConstant>(literal_index));
4496
    Add<HPushArgument>(Add<HConstant>(constants));
4497

    
4498
    // TODO(mvstanton): Consider a flag to turn off creation of any
4499
    // AllocationMementos for this call: we are in crankshaft and should have
4500
    // learned enough about transition behavior to stop emitting mementos.
4501
    Runtime::FunctionId function_id = (expr->depth() > 1)
4502
        ? Runtime::kCreateArrayLiteral : Runtime::kCreateArrayLiteralShallow;
4503
    literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
4504
                                Runtime::FunctionForId(function_id),
4505
                                3);
4506

    
4507
    // De-opt if elements kind changed from boilerplate_elements_kind.
4508
    Handle<Map> map = Handle<Map>(boilerplate_object->map(), isolate());
4509
    literal = Add<HCheckMaps>(literal, map, top_info());
4510
  }
4511

    
4512
  // The array is expected in the bailout environment during computation
4513
  // of the property values and is the value of the entire expression.
4514
  Push(literal);
4515
  // The literal index is on the stack, too.
4516
  Push(Add<HConstant>(expr->literal_index()));
4517

    
4518
  HInstruction* elements = NULL;
4519

    
4520
  for (int i = 0; i < length; i++) {
4521
    Expression* subexpr = subexprs->at(i);
4522
    // If the subexpression is a literal or a simple materialized literal it
4523
    // is already set in the cloned array.
4524
    if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
4525

    
4526
    CHECK_ALIVE(VisitForValue(subexpr));
4527
    HValue* value = Pop();
4528
    if (!Smi::IsValid(i)) return Bailout(kNonSmiKeyInArrayLiteral);
4529

    
4530
    elements = AddLoadElements(literal);
4531

    
4532
    HValue* key = Add<HConstant>(i);
4533

    
4534
    switch (boilerplate_elements_kind) {
4535
      case FAST_SMI_ELEMENTS:
4536
      case FAST_HOLEY_SMI_ELEMENTS:
4537
      case FAST_ELEMENTS:
4538
      case FAST_HOLEY_ELEMENTS:
4539
      case FAST_DOUBLE_ELEMENTS:
4540
      case FAST_HOLEY_DOUBLE_ELEMENTS: {
4541
        HStoreKeyed* instr = Add<HStoreKeyed>(elements, key, value,
4542
                                              boilerplate_elements_kind);
4543
        instr->SetUninitialized(uninitialized);
4544
        break;
4545
      }
4546
      default:
4547
        UNREACHABLE();
4548
        break;
4549
    }
4550

    
4551
    Add<HSimulate>(expr->GetIdForElement(i));
4552
  }
4553

    
4554
  Drop(1);  // array literal index
4555
  return ast_context()->ReturnValue(Pop());
4556
}
4557

    
4558

    
4559
HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object,
4560
                                                Handle<Map> map) {
4561
  BuildCheckHeapObject(object);
4562
  return Add<HCheckMaps>(object, map, top_info());
4563
}
4564

    
4565

    
4566
HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
4567
    HValue* checked_object,
4568
    Handle<String> name,
4569
    HValue* value,
4570
    Handle<Map> map,
4571
    LookupResult* lookup) {
4572
  ASSERT(lookup->IsFound());
4573
  // If the property does not exist yet, we have to check that it wasn't made
4574
  // readonly or turned into a setter by some meanwhile modifications on the
4575
  // prototype chain.
4576
  if (!lookup->IsProperty() && map->prototype()->IsJSReceiver()) {
4577
    Object* proto = map->prototype();
4578
    // First check that the prototype chain isn't affected already.
4579
    LookupResult proto_result(isolate());
4580
    proto->Lookup(*name, &proto_result);
4581
    if (proto_result.IsProperty()) {
4582
      // If the inherited property could induce readonly-ness, bail out.
4583
      if (proto_result.IsReadOnly() || !proto_result.IsCacheable()) {
4584
        Bailout(kImproperObjectOnPrototypeChainForStore);
4585
        return NULL;
4586
      }
4587
      // We only need to check up to the preexisting property.
4588
      proto = proto_result.holder();
4589
    } else {
4590
      // Otherwise, find the top prototype.
4591
      while (proto->GetPrototype(isolate())->IsJSObject()) {
4592
        proto = proto->GetPrototype(isolate());
4593
      }
4594
      ASSERT(proto->GetPrototype(isolate())->IsNull());
4595
    }
4596
    ASSERT(proto->IsJSObject());
4597
    BuildCheckPrototypeMaps(
4598
        Handle<JSObject>(JSObject::cast(map->prototype())),
4599
        Handle<JSObject>(JSObject::cast(proto)));
4600
  }
4601

    
4602
  HObjectAccess field_access = HObjectAccess::ForField(map, lookup, name);
4603
  bool transition_to_field = lookup->IsTransitionToField(*map);
4604

    
4605
  HStoreNamedField *instr;
4606
  if (FLAG_track_double_fields && field_access.representation().IsDouble()) {
4607
    HObjectAccess heap_number_access =
4608
        field_access.WithRepresentation(Representation::Tagged());
4609
    if (transition_to_field) {
4610
      // The store requires a mutable HeapNumber to be allocated.
4611
      NoObservableSideEffectsScope no_side_effects(this);
4612
      HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize);
4613
      HInstruction* heap_number = Add<HAllocate>(heap_number_size,
4614
          HType::HeapNumber(), isolate()->heap()->GetPretenureMode(),
4615
          HEAP_NUMBER_TYPE);
4616
      AddStoreMapConstant(heap_number, isolate()->factory()->heap_number_map());
4617
      Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(),
4618
                            value);
4619
      instr = New<HStoreNamedField>(checked_object->ActualValue(),
4620
                                    heap_number_access,
4621
                                    heap_number);
4622
    } else {
4623
      // Already holds a HeapNumber; load the box and write its value field.
4624
      HInstruction* heap_number = Add<HLoadNamedField>(checked_object,
4625
                                                       heap_number_access);
4626
      heap_number->set_type(HType::HeapNumber());
4627
      instr = New<HStoreNamedField>(heap_number,
4628
                                    HObjectAccess::ForHeapNumberValue(),
4629
                                    value);
4630
    }
4631
  } else {
4632
    // This is a normal store.
4633
    instr = New<HStoreNamedField>(checked_object->ActualValue(),
4634
                                  field_access,
4635
                                  value);
4636
  }
4637

    
4638
  if (transition_to_field) {
4639
    Handle<Map> transition(lookup->GetTransitionMapFromMap(*map));
4640
    HConstant* transition_constant = Add<HConstant>(transition);
4641
    instr->SetTransition(transition_constant, top_info());
4642
    // TODO(fschneider): Record the new map type of the object in the IR to
4643
    // enable elimination of redundant checks after the transition store.
4644
    instr->SetGVNFlag(kChangesMaps);
4645
  }
4646
  return instr;
4647
}
4648

    
4649

    
4650
HInstruction* HOptimizedGraphBuilder::BuildStoreNamedGeneric(
4651
    HValue* object,
4652
    Handle<String> name,
4653
    HValue* value) {
4654
  return New<HStoreNamedGeneric>(
4655
                         object,
4656
                         name,
4657
                         value,
4658
                         function_strict_mode_flag());
4659
}
4660

    
4661

    
4662
// Sets the lookup result and returns true if the load/store can be inlined.
4663
static bool ComputeStoreField(Handle<Map> type,
4664
                              Handle<String> name,
4665
                              LookupResult* lookup,
4666
                              bool lookup_transition = true) {
4667
  ASSERT(!type->is_observed());
4668
  if (!CanInlinePropertyAccess(*type)) {
4669
    lookup->NotFound();
4670
    return false;
4671
  }
4672
  // If we directly find a field, the access can be inlined.
4673
  type->LookupDescriptor(NULL, *name, lookup);
4674
  if (lookup->IsField()) return true;
4675

    
4676
  if (!lookup_transition) return false;
4677

    
4678
  type->LookupTransition(NULL, *name, lookup);
4679
  return lookup->IsTransitionToField(*type) &&
4680
      (type->unused_property_fields() > 0);
4681
}
4682

    
4683

    
4684
HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic(
4685
    HValue* object,
4686
    Handle<String> name,
4687
    HValue* value,
4688
    Handle<Map> map) {
4689
  // Handle a store to a known field.
4690
  LookupResult lookup(isolate());
4691
  if (ComputeStoreField(map, name, &lookup)) {
4692
    HCheckMaps* checked_object = AddCheckMap(object, map);
4693
    return BuildStoreNamedField(checked_object, name, value, map, &lookup);
4694
  }
4695

    
4696
  // No luck, do a generic store.
4697
  return BuildStoreNamedGeneric(object, name, value);
4698
}
4699

    
4700

    
4701
bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad(
4702
    PropertyAccessInfo* info) {
4703
  if (!CanInlinePropertyAccess(*map_)) return false;
4704

    
4705
  if (!LookupDescriptor()) return false;
4706

    
4707
  if (!lookup_.IsFound()) {
4708
    return (!info->lookup_.IsFound() || info->has_holder()) &&
4709
        map_->prototype() == info->map_->prototype();
4710
  }
4711

    
4712
  // Mismatch if the other access info found the property in the prototype
4713
  // chain.
4714
  if (info->has_holder()) return false;
4715

    
4716
  if (lookup_.IsPropertyCallbacks()) {
4717
    return accessor_.is_identical_to(info->accessor_);
4718
  }
4719

    
4720
  if (lookup_.IsConstant()) {
4721
    return constant_.is_identical_to(info->constant_);
4722
  }
4723

    
4724
  ASSERT(lookup_.IsField());
4725
  if (!info->lookup_.IsField()) return false;
4726

    
4727
  Representation r = access_.representation();
4728
  if (!info->access_.representation().IsCompatibleForLoad(r)) return false;
4729
  if (info->access_.offset() != access_.offset()) return false;
4730
  if (info->access_.IsInobject() != access_.IsInobject()) return false;
4731
  info->GeneralizeRepresentation(r);
4732
  return true;
4733
}
4734

    
4735

    
4736
bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() {
4737
  map_->LookupDescriptor(NULL, *name_, &lookup_);
4738
  return LoadResult(map_);
4739
}
4740

    
4741

    
4742
bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) {
4743
  if (lookup_.IsField()) {
4744
    access_ = HObjectAccess::ForField(map, &lookup_, name_);
4745
  } else if (lookup_.IsPropertyCallbacks()) {
4746
    Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate());
4747
    if (!callback->IsAccessorPair()) return false;
4748
    Object* getter = Handle<AccessorPair>::cast(callback)->getter();
4749
    if (!getter->IsJSFunction()) return false;
4750
    Handle<JSFunction> accessor = handle(JSFunction::cast(getter));
4751
    CallOptimization call_optimization(accessor);
4752
    // TODO(dcarney): temporary hack unless crankshaft can handle api calls.
4753
    if (call_optimization.is_simple_api_call()) return false;
4754
    accessor_ = accessor;
4755
  } else if (lookup_.IsConstant()) {
4756
    constant_ = handle(lookup_.GetConstantFromMap(*map), isolate());
4757
  }
4758

    
4759
  return true;
4760
}
4761

    
4762

    
4763
bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
4764
  Handle<Map> map = map_;
4765
  while (map->prototype()->IsJSObject()) {
4766
    holder_ = handle(JSObject::cast(map->prototype()));
4767
    if (holder_->map()->is_deprecated()) {
4768
      JSObject::TryMigrateInstance(holder_);
4769
    }
4770
    map = Handle<Map>(holder_->map());
4771
    if (!CanInlinePropertyAccess(*map)) {
4772
      lookup_.NotFound();
4773
      return false;
4774
    }
4775
    map->LookupDescriptor(*holder_, *name_, &lookup_);
4776
    if (lookup_.IsFound()) return LoadResult(map);
4777
  }
4778
  lookup_.NotFound();
4779
  return true;
4780
}
4781

    
4782

    
4783
bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() {
4784
  if (!CanInlinePropertyAccess(*map_)) return IsStringLength();
4785
  if (IsJSObjectFieldAccessor()) return true;
4786
  if (!LookupDescriptor()) return false;
4787
  if (lookup_.IsFound()) return true;
4788
  return LookupInPrototypes();
4789
}
4790

    
4791

    
4792
bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
4793
    SmallMapList* types) {
4794
  ASSERT(map_.is_identical_to(types->first()));
4795
  if (!CanLoadMonomorphic()) return false;
4796
  if (types->length() > kMaxLoadPolymorphism) return false;
4797

    
4798
  if (IsStringLength()) {
4799
    for (int i = 1; i < types->length(); ++i) {
4800
      if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
4801
    }
4802
    return true;
4803
  }
4804

    
4805
  if (IsArrayLength()) {
4806
    bool is_fast = IsFastElementsKind(map_->elements_kind());
4807
    for (int i = 1; i < types->length(); ++i) {
4808
      Handle<Map> test_map = types->at(i);
4809
      if (test_map->instance_type() != JS_ARRAY_TYPE) return false;
4810
      if (IsFastElementsKind(test_map->elements_kind()) != is_fast) {
4811
        return false;
4812
      }
4813
    }
4814
    return true;
4815
  }
4816

    
4817
  if (IsJSObjectFieldAccessor()) {
4818
    InstanceType instance_type = map_->instance_type();
4819
    for (int i = 1; i < types->length(); ++i) {
4820
      if (types->at(i)->instance_type() != instance_type) return false;
4821
    }
4822
    return true;
4823
  }
4824

    
4825
  for (int i = 1; i < types->length(); ++i) {
4826
    PropertyAccessInfo test_info(isolate(), types->at(i), name_);
4827
    if (!test_info.IsCompatibleForLoad(this)) return false;
4828
  }
4829

    
4830
  return true;
4831
}
4832

    
4833

    
4834
HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic(
4835
    PropertyAccessInfo* info,
4836
    HValue* object,
4837
    HInstruction* checked_object,
4838
    BailoutId ast_id,
4839
    BailoutId return_id,
4840
    bool can_inline_accessor) {
4841

    
4842
  HObjectAccess access = HObjectAccess::ForMap();  // bogus default
4843
  if (info->GetJSObjectFieldAccess(&access)) {
4844
    return New<HLoadNamedField>(checked_object, access);
4845
  }
4846

    
4847
  HValue* checked_holder = checked_object;
4848
  if (info->has_holder()) {
4849
    Handle<JSObject> prototype(JSObject::cast(info->map()->prototype()));
4850
    checked_holder = BuildCheckPrototypeMaps(prototype, info->holder());
4851
  }
4852

    
4853
  if (!info->lookup()->IsFound()) return graph()->GetConstantUndefined();
4854

    
4855
  if (info->lookup()->IsField()) {
4856
    return BuildLoadNamedField(checked_holder, info->access());
4857
  }
4858

    
4859
  if (info->lookup()->IsPropertyCallbacks()) {
4860
    Push(checked_object);
4861
    if (FLAG_inline_accessors &&
4862
        can_inline_accessor &&
4863
        TryInlineGetter(info->accessor(), ast_id, return_id)) {
4864
      return NULL;
4865
    }
4866
    Add<HPushArgument>(Pop());
4867
    return New<HCallConstantFunction>(info->accessor(), 1);
4868
  }
4869

    
4870
  ASSERT(info->lookup()->IsConstant());
4871
  return New<HConstant>(info->constant());
4872
}
4873

    
4874

    
4875
void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
4876
    BailoutId ast_id,
4877
    BailoutId return_id,
4878
    HValue* object,
4879
    SmallMapList* types,
4880
    Handle<String> name) {
4881
  // Something did not match; must use a polymorphic load.
4882
  int count = 0;
4883
  HBasicBlock* join = NULL;
4884
  for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
4885
    PropertyAccessInfo info(isolate(), types->at(i), name);
4886
    if (info.CanLoadMonomorphic()) {
4887
      if (count == 0) {
4888
        BuildCheckHeapObject(object);
4889
        join = graph()->CreateBasicBlock();
4890
      }
4891
      ++count;
4892
      HBasicBlock* if_true = graph()->CreateBasicBlock();
4893
      HBasicBlock* if_false = graph()->CreateBasicBlock();
4894
      HCompareMap* compare = New<HCompareMap>(
4895
          object, info.map(),  if_true, if_false);
4896
      FinishCurrentBlock(compare);
4897

    
4898
      set_current_block(if_true);
4899

    
4900
      HInstruction* load = BuildLoadMonomorphic(
4901
          &info, object, compare, ast_id, return_id, FLAG_polymorphic_inlining);
4902
      if (load == NULL) {
4903
        if (HasStackOverflow()) return;
4904
      } else {
4905
        if (!load->IsLinked()) {
4906
          AddInstruction(load);
4907
        }
4908
        if (!ast_context()->IsEffect()) Push(load);
4909
      }
4910

    
4911
      if (current_block() != NULL) Goto(join);
4912
      set_current_block(if_false);
4913
    }
4914
  }
4915

    
4916
  // Finish up.  Unconditionally deoptimize if we've handled all the maps we
4917
  // know about and do not want to handle ones we've never seen.  Otherwise
4918
  // use a generic IC.
4919
  if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
4920
    // Because the deopt may be the only path in the polymorphic load, make sure
4921
    // that the environment stack matches the depth on deopt that it otherwise
4922
    // would have had after a successful load.
4923
    if (!ast_context()->IsEffect()) Push(graph()->GetConstant0());
4924
    FinishExitWithHardDeoptimization("Unknown map in polymorphic load", join);
4925
  } else {
4926
    HInstruction* load = Add<HLoadNamedGeneric>(object, name);
4927
    if (!ast_context()->IsEffect()) Push(load);
4928

    
4929
    if (join != NULL) {
4930
      Goto(join);
4931
    } else {
4932
      Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
4933
      if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
4934
      return;
4935
    }
4936
  }
4937

    
4938
  ASSERT(join != NULL);
4939
  join->SetJoinId(ast_id);
4940
  set_current_block(join);
4941
  if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
4942
}
4943

    
4944

    
4945
bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic(
4946
    BailoutId assignment_id,
4947
    HValue* object,
4948
    HValue* value,
4949
    SmallMapList* types,
4950
    Handle<String> name) {
4951
  // Use monomorphic store if property lookup results in the same field index
4952
  // for all maps. Requires special map check on the set of all handled maps.
4953
  if (types->length() > kMaxStorePolymorphism) return false;
4954

    
4955
  LookupResult lookup(isolate());
4956
  int count;
4957
  Representation representation = Representation::None();
4958
  HObjectAccess access = HObjectAccess::ForMap();  // initial value unused.
4959
  for (count = 0; count < types->length(); ++count) {
4960
    Handle<Map> map = types->at(count);
4961
    // Pass false to ignore transitions.
4962
    if (!ComputeStoreField(map, name, &lookup, false)) break;
4963
    ASSERT(!map->is_observed());
4964

    
4965
    HObjectAccess new_access = HObjectAccess::ForField(map, &lookup, name);
4966
    Representation new_representation = new_access.representation();
4967

    
4968
    if (count == 0) {
4969
      // First time through the loop; set access and representation.
4970
      access = new_access;
4971
      representation = new_representation;
4972
    } else if (!representation.IsCompatibleForStore(new_representation)) {
4973
      // Representations did not match.
4974
      break;
4975
    } else if (access.offset() != new_access.offset()) {
4976
      // Offsets did not match.
4977
      break;
4978
    } else if (access.IsInobject() != new_access.IsInobject()) {
4979
      // In-objectness did not match.
4980
      break;
4981
    }
4982
  }
4983

    
4984
  if (count != types->length()) return false;
4985

    
4986
  // Everything matched; can use monomorphic store.
4987
  BuildCheckHeapObject(object);
4988
  HCheckMaps* checked_object = Add<HCheckMaps>(object, types);
4989
  HInstruction* store;
4990
  CHECK_ALIVE_OR_RETURN(
4991
      store = BuildStoreNamedField(
4992
          checked_object, name, value, types->at(count - 1), &lookup),
4993
      true);
4994
  if (!ast_context()->IsEffect()) Push(value);
4995
  AddInstruction(store);
4996
  Add<HSimulate>(assignment_id);
4997
  if (!ast_context()->IsEffect()) Drop(1);
4998
  ast_context()->ReturnValue(value);
4999
  return true;
5000
}
5001

    
5002

    
5003
void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField(
5004
    BailoutId assignment_id,
5005
    HValue* object,
5006
    HValue* value,
5007
    SmallMapList* types,
5008
    Handle<String> name) {
5009
  if (TryStorePolymorphicAsMonomorphic(
5010
          assignment_id, object, value, types, name)) {
5011
    return;
5012
  }
5013

    
5014
  // TODO(ager): We should recognize when the prototype chains for different
5015
  // maps are identical. In that case we can avoid repeatedly generating the
5016
  // same prototype map checks.
5017
  int count = 0;
5018
  HBasicBlock* join = NULL;
5019
  for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) {
5020
    Handle<Map> map = types->at(i);
5021
    LookupResult lookup(isolate());
5022
    if (ComputeStoreField(map, name, &lookup)) {
5023
      if (count == 0) {
5024
        BuildCheckHeapObject(object);
5025
        join = graph()->CreateBasicBlock();
5026
      }
5027
      ++count;
5028
      HBasicBlock* if_true = graph()->CreateBasicBlock();
5029
      HBasicBlock* if_false = graph()->CreateBasicBlock();
5030
      HCompareMap* compare = New<HCompareMap>(object, map,  if_true, if_false);
5031
      FinishCurrentBlock(compare);
5032

    
5033
      set_current_block(if_true);
5034
      HInstruction* instr;
5035
      CHECK_ALIVE(instr = BuildStoreNamedField(
5036
          compare, name, value, map, &lookup));
5037
      // Goto will add the HSimulate for the store.
5038
      AddInstruction(instr);
5039
      if (!ast_context()->IsEffect()) Push(value);
5040
      Goto(join);
5041

    
5042
      set_current_block(if_false);
5043
    }
5044
  }
5045

    
5046
  // Finish up.  Unconditionally deoptimize if we've handled all the maps we
5047
  // know about and do not want to handle ones we've never seen.  Otherwise
5048
  // use a generic IC.
5049
  if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
5050
    FinishExitWithHardDeoptimization("Unknown map in polymorphic store", join);
5051
  } else {
5052
    HInstruction* instr = BuildStoreNamedGeneric(object, name, value);
5053
    AddInstruction(instr);
5054

    
5055
    if (join != NULL) {
5056
      if (!ast_context()->IsEffect()) {
5057
        Push(value);
5058
      }
5059
      Goto(join);
5060
    } else {
5061
      // The HSimulate for the store should not see the stored value in
5062
      // effect contexts (it is not materialized at expr->id() in the
5063
      // unoptimized code).
5064
      if (instr->HasObservableSideEffects()) {
5065
        if (ast_context()->IsEffect()) {
5066
          Add<HSimulate>(assignment_id, REMOVABLE_SIMULATE);
5067
        } else {
5068
          Push(value);
5069
          Add<HSimulate>(assignment_id, REMOVABLE_SIMULATE);
5070
          Drop(1);
5071
        }
5072
      }
5073
      return ast_context()->ReturnValue(value);
5074
    }
5075
  }
5076

    
5077
  ASSERT(join != NULL);
5078
  join->SetJoinId(assignment_id);
5079
  set_current_block(join);
5080
  if (!ast_context()->IsEffect()) {
5081
    ast_context()->ReturnValue(Pop());
5082
  }
5083
}
5084

    
5085

    
5086
static bool ComputeReceiverTypes(Expression* expr,
5087
                                 HValue* receiver,
5088
                                 SmallMapList** t) {
5089
  SmallMapList* types = expr->GetReceiverTypes();
5090
  *t = types;
5091
  bool monomorphic = expr->IsMonomorphic();
5092
  if (types != NULL && receiver->HasMonomorphicJSObjectType()) {
5093
    Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap();
5094
    types->FilterForPossibleTransitions(root_map);
5095
    monomorphic = types->length() == 1;
5096
  }
5097
  return monomorphic && CanInlinePropertyAccess(*types->first());
5098
}
5099

    
5100

    
5101
void HOptimizedGraphBuilder::BuildStore(Expression* expr,
5102
                                        Property* prop,
5103
                                        BailoutId ast_id,
5104
                                        BailoutId return_id,
5105
                                        bool is_uninitialized) {
5106
  HValue* value = environment()->ExpressionStackAt(0);
5107

    
5108
  if (!prop->key()->IsPropertyName()) {
5109
    // Keyed store.
5110
    HValue* key = environment()->ExpressionStackAt(1);
5111
    HValue* object = environment()->ExpressionStackAt(2);
5112
    bool has_side_effects = false;
5113
    HandleKeyedElementAccess(object, key, value, expr,
5114
                             true,  // is_store
5115
                             &has_side_effects);
5116
    Drop(3);
5117
    Push(value);
5118
    Add<HSimulate>(return_id, REMOVABLE_SIMULATE);
5119
    return ast_context()->ReturnValue(Pop());
5120
  }
5121

    
5122
  // Named store.
5123
  HValue* object = environment()->ExpressionStackAt(1);
5124

    
5125
  if (is_uninitialized) {
5126
    Add<HDeoptimize>("Insufficient type feedback for property assignment",
5127
                     Deoptimizer::SOFT);
5128
  }
5129

    
5130
  Literal* key = prop->key()->AsLiteral();
5131
  Handle<String> name = Handle<String>::cast(key->value());
5132
  ASSERT(!name.is_null());
5133

    
5134
  HInstruction* instr = NULL;
5135

    
5136
  SmallMapList* types;
5137
  bool monomorphic = ComputeReceiverTypes(expr, object, &types);
5138

    
5139
  if (monomorphic) {
5140
    Handle<Map> map = types->first();
5141
    Handle<JSFunction> setter;
5142
    Handle<JSObject> holder;
5143
    if (LookupSetter(map, name, &setter, &holder)) {
5144
      AddCheckConstantFunction(holder, object, map);
5145
      if (FLAG_inline_accessors &&
5146
          TryInlineSetter(setter, ast_id, return_id, value)) {
5147
        return;
5148
      }
5149
      Drop(2);
5150
      Add<HPushArgument>(object);
5151
      Add<HPushArgument>(value);
5152
      instr = New<HCallConstantFunction>(setter, 2);
5153
    } else {
5154
      Drop(2);
5155
      CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object,
5156
                                                     name,
5157
                                                     value,
5158
                                                     map));
5159
    }
5160
  } else if (types != NULL && types->length() > 1) {
5161
    Drop(2);
5162
    return HandlePolymorphicStoreNamedField(ast_id, object, value, types, name);
5163
  } else {
5164
    Drop(2);
5165
    instr = BuildStoreNamedGeneric(object, name, value);
5166
  }
5167

    
5168
  if (!ast_context()->IsEffect()) Push(value);
5169
  AddInstruction(instr);
5170
  if (instr->HasObservableSideEffects()) {
5171
    Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
5172
  }
5173
  if (!ast_context()->IsEffect()) Drop(1);
5174
  return ast_context()->ReturnValue(value);
5175
}
5176

    
5177

    
5178
void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
5179
  Property* prop = expr->target()->AsProperty();
5180
  ASSERT(prop != NULL);
5181
  CHECK_ALIVE(VisitForValue(prop->obj()));
5182
  if (!prop->key()->IsPropertyName()) {
5183
    CHECK_ALIVE(VisitForValue(prop->key()));
5184
  }
5185
  CHECK_ALIVE(VisitForValue(expr->value()));
5186
  BuildStore(expr, prop, expr->id(),
5187
             expr->AssignmentId(), expr->IsUninitialized());
5188
}
5189

    
5190

    
5191
// Because not every expression has a position and there is not common
5192
// superclass of Assignment and CountOperation, we cannot just pass the
5193
// owning expression instead of position and ast_id separately.
5194
void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
5195
    Variable* var,
5196
    HValue* value,
5197
    BailoutId ast_id) {
5198
  LookupResult lookup(isolate());
5199
  GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true);
5200
  if (type == kUseCell) {
5201
    Handle<GlobalObject> global(current_info()->global_object());
5202
    Handle<PropertyCell> cell(global->GetPropertyCell(&lookup));
5203
    if (cell->type()->IsConstant()) {
5204
      IfBuilder builder(this);
5205
      HValue* constant = Add<HConstant>(cell->type()->AsConstant());
5206
      if (cell->type()->AsConstant()->IsNumber()) {
5207
        builder.If<HCompareNumericAndBranch>(value, constant, Token::EQ);
5208
      } else {
5209
        builder.If<HCompareObjectEqAndBranch>(value, constant);
5210
      }
5211
      builder.Then();
5212
      builder.Else();
5213
      Add<HDeoptimize>("Constant global variable assignment",
5214
                       Deoptimizer::EAGER);
5215
      builder.End();
5216
    }
5217
    HInstruction* instr =
5218
        Add<HStoreGlobalCell>(value, cell, lookup.GetPropertyDetails());
5219
    if (instr->HasObservableSideEffects()) {
5220
      Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
5221
    }
5222
  } else {
5223
    HGlobalObject* global_object = Add<HGlobalObject>();
5224
    HStoreGlobalGeneric* instr =
5225
        Add<HStoreGlobalGeneric>(global_object, var->name(),
5226
                                 value, function_strict_mode_flag());
5227
    USE(instr);
5228
    ASSERT(instr->HasObservableSideEffects());
5229
    Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
5230
  }
5231
}
5232

    
5233

    
5234
void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
5235
  Expression* target = expr->target();
5236
  VariableProxy* proxy = target->AsVariableProxy();
5237
  Property* prop = target->AsProperty();
5238
  ASSERT(proxy == NULL || prop == NULL);
5239

    
5240
  // We have a second position recorded in the FullCodeGenerator to have
5241
  // type feedback for the binary operation.
5242
  BinaryOperation* operation = expr->binary_operation();
5243

    
5244
  if (proxy != NULL) {
5245
    Variable* var = proxy->var();
5246
    if (var->mode() == LET)  {
5247
      return Bailout(kUnsupportedLetCompoundAssignment);
5248
    }
5249

    
5250
    CHECK_ALIVE(VisitForValue(operation));
5251

    
5252
    switch (var->location()) {
5253
      case Variable::UNALLOCATED:
5254
        HandleGlobalVariableAssignment(var,
5255
                                       Top(),
5256
                                       expr->AssignmentId());
5257
        break;
5258

    
5259
      case Variable::PARAMETER:
5260
      case Variable::LOCAL:
5261
        if (var->mode() == CONST)  {
5262
          return Bailout(kUnsupportedConstCompoundAssignment);
5263
        }
5264
        BindIfLive(var, Top());
5265
        break;
5266

    
5267
      case Variable::CONTEXT: {
5268
        // Bail out if we try to mutate a parameter value in a function
5269
        // using the arguments object.  We do not (yet) correctly handle the
5270
        // arguments property of the function.
5271
        if (current_info()->scope()->arguments() != NULL) {
5272
          // Parameters will be allocated to context slots.  We have no
5273
          // direct way to detect that the variable is a parameter so we do
5274
          // a linear search of the parameter variables.
5275
          int count = current_info()->scope()->num_parameters();
5276
          for (int i = 0; i < count; ++i) {
5277
            if (var == current_info()->scope()->parameter(i)) {
5278
              Bailout(kAssignmentToParameterFunctionUsesArgumentsObject);
5279
            }
5280
          }
5281
        }
5282

    
5283
        HStoreContextSlot::Mode mode;
5284

    
5285
        switch (var->mode()) {
5286
          case LET:
5287
            mode = HStoreContextSlot::kCheckDeoptimize;
5288
            break;
5289
          case CONST:
5290
            return ast_context()->ReturnValue(Pop());
5291
          case CONST_HARMONY:
5292
            // This case is checked statically so no need to
5293
            // perform checks here
5294
            UNREACHABLE();
5295
          default:
5296
            mode = HStoreContextSlot::kNoCheck;
5297
        }
5298

    
5299
        HValue* context = BuildContextChainWalk(var);
5300
        HStoreContextSlot* instr = Add<HStoreContextSlot>(
5301
            context, var->index(), mode, Top());
5302
        if (instr->HasObservableSideEffects()) {
5303
          Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
5304
        }
5305
        break;
5306
      }
5307

    
5308
      case Variable::LOOKUP:
5309
        return Bailout(kCompoundAssignmentToLookupSlot);
5310
    }
5311
    return ast_context()->ReturnValue(Pop());
5312

    
5313
  } else if (prop != NULL) {
5314
    CHECK_ALIVE(VisitForValue(prop->obj()));
5315
    HValue* object = Top();
5316
    HValue* key = NULL;
5317
    if ((!prop->IsFunctionPrototype() && !prop->key()->IsPropertyName()) ||
5318
        prop->IsStringAccess()) {
5319
      CHECK_ALIVE(VisitForValue(prop->key()));
5320
      key = Top();
5321
    }
5322

    
5323
    CHECK_ALIVE(PushLoad(prop, object, key));
5324

    
5325
    CHECK_ALIVE(VisitForValue(expr->value()));
5326
    HValue* right = Pop();
5327
    HValue* left = Pop();
5328

    
5329
    HInstruction* instr = BuildBinaryOperation(operation, left, right);
5330
    AddInstruction(instr);
5331
    Push(instr);
5332
    if (instr->HasObservableSideEffects()) {
5333
      Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE);
5334
    }
5335
    BuildStore(expr, prop, expr->id(),
5336
               expr->AssignmentId(), expr->IsUninitialized());
5337
  } else {
5338
    return Bailout(kInvalidLhsInCompoundAssignment);
5339
  }
5340
}
5341

    
5342

    
5343
void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
5344
  ASSERT(!HasStackOverflow());
5345
  ASSERT(current_block() != NULL);
5346
  ASSERT(current_block()->HasPredecessor());
5347
  VariableProxy* proxy = expr->target()->AsVariableProxy();
5348
  Property* prop = expr->target()->AsProperty();
5349
  ASSERT(proxy == NULL || prop == NULL);
5350

    
5351
  if (expr->is_compound()) {
5352
    HandleCompoundAssignment(expr);
5353
    return;
5354
  }
5355

    
5356
  if (prop != NULL) {
5357
    HandlePropertyAssignment(expr);
5358
  } else if (proxy != NULL) {
5359
    Variable* var = proxy->var();
5360

    
5361
    if (var->mode() == CONST) {
5362
      if (expr->op() != Token::INIT_CONST) {
5363
        CHECK_ALIVE(VisitForValue(expr->value()));
5364
        return ast_context()->ReturnValue(Pop());
5365
      }
5366

    
5367
      if (var->IsStackAllocated()) {
5368
        // We insert a use of the old value to detect unsupported uses of const
5369
        // variables (e.g. initialization inside a loop).
5370
        HValue* old_value = environment()->Lookup(var);
5371
        Add<HUseConst>(old_value);
5372
      }
5373
    } else if (var->mode() == CONST_HARMONY) {
5374
      if (expr->op() != Token::INIT_CONST_HARMONY) {
5375
        return Bailout(kNonInitializerAssignmentToConst);
5376
      }
5377
    }
5378

    
5379
    if (proxy->IsArguments()) return Bailout(kAssignmentToArguments);
5380

    
5381
    // Handle the assignment.
5382
    switch (var->location()) {
5383
      case Variable::UNALLOCATED:
5384
        CHECK_ALIVE(VisitForValue(expr->value()));
5385
        HandleGlobalVariableAssignment(var,
5386
                                       Top(),
5387
                                       expr->AssignmentId());
5388
        return ast_context()->ReturnValue(Pop());
5389

    
5390
      case Variable::PARAMETER:
5391
      case Variable::LOCAL: {
5392
        // Perform an initialization check for let declared variables
5393
        // or parameters.
5394
        if (var->mode() == LET && expr->op() == Token::ASSIGN) {
5395
          HValue* env_value = environment()->Lookup(var);
5396
          if (env_value == graph()->GetConstantHole()) {
5397
            return Bailout(kAssignmentToLetVariableBeforeInitialization);
5398
          }
5399
        }
5400
        // We do not allow the arguments object to occur in a context where it
5401
        // may escape, but assignments to stack-allocated locals are
5402
        // permitted.
5403
        CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED));
5404
        HValue* value = Pop();
5405
        BindIfLive(var, value);
5406
        return ast_context()->ReturnValue(value);
5407
      }
5408

    
5409
      case Variable::CONTEXT: {
5410
        // Bail out if we try to mutate a parameter value in a function using
5411
        // the arguments object.  We do not (yet) correctly handle the
5412
        // arguments property of the function.
5413
        if (current_info()->scope()->arguments() != NULL) {
5414
          // Parameters will rewrite to context slots.  We have no direct way
5415
          // to detect that the variable is a parameter.
5416
          int count = current_info()->scope()->num_parameters();
5417
          for (int i = 0; i < count; ++i) {
5418
            if (var == current_info()->scope()->parameter(i)) {
5419
              return Bailout(kAssignmentToParameterInArgumentsObject);
5420
            }
5421
          }
5422
        }
5423

    
5424
        CHECK_ALIVE(VisitForValue(expr->value()));
5425
        HStoreContextSlot::Mode mode;
5426
        if (expr->op() == Token::ASSIGN) {
5427
          switch (var->mode()) {
5428
            case LET:
5429
              mode = HStoreContextSlot::kCheckDeoptimize;
5430
              break;
5431
            case CONST:
5432
              return ast_context()->ReturnValue(Pop());
5433
            case CONST_HARMONY:
5434
              // This case is checked statically so no need to
5435
              // perform checks here
5436
              UNREACHABLE();
5437
            default:
5438
              mode = HStoreContextSlot::kNoCheck;
5439
          }
5440
        } else if (expr->op() == Token::INIT_VAR ||
5441
                   expr->op() == Token::INIT_LET ||
5442
                   expr->op() == Token::INIT_CONST_HARMONY) {
5443
          mode = HStoreContextSlot::kNoCheck;
5444
        } else {
5445
          ASSERT(expr->op() == Token::INIT_CONST);
5446

    
5447
          mode = HStoreContextSlot::kCheckIgnoreAssignment;
5448
        }
5449

    
5450
        HValue* context = BuildContextChainWalk(var);
5451
        HStoreContextSlot* instr = Add<HStoreContextSlot>(
5452
            context, var->index(), mode, Top());
5453
        if (instr->HasObservableSideEffects()) {
5454
          Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
5455
        }
5456
        return ast_context()->ReturnValue(Pop());
5457
      }
5458

    
5459
      case Variable::LOOKUP:
5460
        return Bailout(kAssignmentToLOOKUPVariable);
5461
    }
5462
  } else {
5463
    return Bailout(kInvalidLeftHandSideInAssignment);
5464
  }
5465
}
5466

    
5467

    
5468
void HOptimizedGraphBuilder::VisitYield(Yield* expr) {
5469
  // Generators are not optimized, so we should never get here.
5470
  UNREACHABLE();
5471
}
5472

    
5473

    
5474
void HOptimizedGraphBuilder::VisitThrow(Throw* expr) {
5475
  ASSERT(!HasStackOverflow());
5476
  ASSERT(current_block() != NULL);
5477
  ASSERT(current_block()->HasPredecessor());
5478
  // We don't optimize functions with invalid left-hand sides in
5479
  // assignments, count operations, or for-in.  Consequently throw can
5480
  // currently only occur in an effect context.
5481
  ASSERT(ast_context()->IsEffect());
5482
  CHECK_ALIVE(VisitForValue(expr->exception()));
5483

    
5484
  HValue* value = environment()->Pop();
5485
  if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
5486
  Add<HThrow>(value);
5487
  Add<HSimulate>(expr->id());
5488

    
5489
  // If the throw definitely exits the function, we can finish with a dummy
5490
  // control flow at this point.  This is not the case if the throw is inside
5491
  // an inlined function which may be replaced.
5492
  if (call_context() == NULL) {
5493
    FinishExitCurrentBlock(New<HAbnormalExit>());
5494
  }
5495
}
5496

    
5497

    
5498
HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object,
5499
                                                    HObjectAccess access) {
5500
  if (FLAG_track_double_fields && access.representation().IsDouble()) {
5501
    // load the heap number
5502
    HLoadNamedField* heap_number = Add<HLoadNamedField>(
5503
        object, access.WithRepresentation(Representation::Tagged()));
5504
    heap_number->set_type(HType::HeapNumber());
5505
    // load the double value from it
5506
    return New<HLoadNamedField>(
5507
        heap_number, HObjectAccess::ForHeapNumberValue());
5508
  }
5509
  return New<HLoadNamedField>(object, access);
5510
}
5511

    
5512

    
5513
HInstruction* HGraphBuilder::AddLoadNamedField(HValue* object,
5514
                                               HObjectAccess access) {
5515
  return AddInstruction(BuildLoadNamedField(object, access));
5516
}
5517

    
5518

    
5519
HInstruction* HGraphBuilder::BuildLoadStringLength(HValue* object,
5520
                                                   HValue* checked_string) {
5521
  if (FLAG_fold_constants && object->IsConstant()) {
5522
    HConstant* constant = HConstant::cast(object);
5523
    if (constant->HasStringValue()) {
5524
      return New<HConstant>(constant->StringValue()->length());
5525
    }
5526
  }
5527
  return BuildLoadNamedField(checked_string, HObjectAccess::ForStringLength());
5528
}
5529

    
5530

    
5531
HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric(
5532
    HValue* object,
5533
    Handle<String> name,
5534
    Property* expr) {
5535
  if (expr->IsUninitialized()) {
5536
    Add<HDeoptimize>("Insufficient type feedback for generic named load",
5537
                     Deoptimizer::SOFT);
5538
  }
5539
  return New<HLoadNamedGeneric>(object, name);
5540
}
5541

    
5542

    
5543

    
5544
HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
5545
                                                            HValue* key) {
5546
  return New<HLoadKeyedGeneric>(object, key);
5547
}
5548

    
5549

    
5550
LoadKeyedHoleMode HOptimizedGraphBuilder::BuildKeyedHoleMode(Handle<Map> map) {
5551
  // Loads from a "stock" fast holey double arrays can elide the hole check.
5552
  LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE;
5553
  if (*map == isolate()->get_initial_js_array_map(FAST_HOLEY_DOUBLE_ELEMENTS) &&
5554
      isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
5555
    Handle<JSObject> prototype(JSObject::cast(map->prototype()), isolate());
5556
    Handle<JSObject> object_prototype = isolate()->initial_object_prototype();
5557
    BuildCheckPrototypeMaps(prototype, object_prototype);
5558
    load_mode = ALLOW_RETURN_HOLE;
5559
    graph()->MarkDependsOnEmptyArrayProtoElements();
5560
  }
5561

    
5562
  return load_mode;
5563
}
5564

    
5565

    
5566
HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess(
5567
    HValue* object,
5568
    HValue* key,
5569
    HValue* val,
5570
    HValue* dependency,
5571
    Handle<Map> map,
5572
    bool is_store,
5573
    KeyedAccessStoreMode store_mode) {
5574
  HCheckMaps* checked_object = Add<HCheckMaps>(object, map, top_info(),
5575
                                               dependency);
5576
  if (dependency) {
5577
    checked_object->ClearGVNFlag(kDependsOnElementsKind);
5578
  }
5579

    
5580
  LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map);
5581
  return BuildUncheckedMonomorphicElementAccess(
5582
      checked_object, key, val,
5583
      map->instance_type() == JS_ARRAY_TYPE,
5584
      map->elements_kind(), is_store,
5585
      load_mode, store_mode);
5586
}
5587

    
5588

    
5589
HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad(
5590
    HValue* object,
5591
    HValue* key,
5592
    HValue* val,
5593
    SmallMapList* maps) {
5594
  // For polymorphic loads of similar elements kinds (i.e. all tagged or all
5595
  // double), always use the "worst case" code without a transition.  This is
5596
  // much faster than transitioning the elements to the worst case, trading a
5597
  // HTransitionElements for a HCheckMaps, and avoiding mutation of the array.
5598
  bool has_double_maps = false;
5599
  bool has_smi_or_object_maps = false;
5600
  bool has_js_array_access = false;
5601
  bool has_non_js_array_access = false;
5602
  bool has_seen_holey_elements = false;
5603
  Handle<Map> most_general_consolidated_map;
5604
  for (int i = 0; i < maps->length(); ++i) {
5605
    Handle<Map> map = maps->at(i);
5606
    if (!map->IsJSObjectMap()) return NULL;
5607
    // Don't allow mixing of JSArrays with JSObjects.
5608
    if (map->instance_type() == JS_ARRAY_TYPE) {
5609
      if (has_non_js_array_access) return NULL;
5610
      has_js_array_access = true;
5611
    } else if (has_js_array_access) {
5612
      return NULL;
5613
    } else {
5614
      has_non_js_array_access = true;
5615
    }
5616
    // Don't allow mixed, incompatible elements kinds.
5617
    if (map->has_fast_double_elements()) {
5618
      if (has_smi_or_object_maps) return NULL;
5619
      has_double_maps = true;
5620
    } else if (map->has_fast_smi_or_object_elements()) {
5621
      if (has_double_maps) return NULL;
5622
      has_smi_or_object_maps = true;
5623
    } else {
5624
      return NULL;
5625
    }
5626
    // Remember if we've ever seen holey elements.
5627
    if (IsHoleyElementsKind(map->elements_kind())) {
5628
      has_seen_holey_elements = true;
5629
    }
5630
    // Remember the most general elements kind, the code for its load will
5631
    // properly handle all of the more specific cases.
5632
    if ((i == 0) || IsMoreGeneralElementsKindTransition(
5633
            most_general_consolidated_map->elements_kind(),
5634
            map->elements_kind())) {
5635
      most_general_consolidated_map = map;
5636
    }
5637
  }
5638
  if (!has_double_maps && !has_smi_or_object_maps) return NULL;
5639

    
5640
  HCheckMaps* checked_object = Add<HCheckMaps>(object, maps);
5641
  // FAST_ELEMENTS is considered more general than FAST_HOLEY_SMI_ELEMENTS.
5642
  // If we've seen both, the consolidated load must use FAST_HOLEY_ELEMENTS.
5643
  ElementsKind consolidated_elements_kind = has_seen_holey_elements
5644
      ? GetHoleyElementsKind(most_general_consolidated_map->elements_kind())
5645
      : most_general_consolidated_map->elements_kind();
5646
  HInstruction* instr = BuildUncheckedMonomorphicElementAccess(
5647
      checked_object, key, val,
5648
      most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE,
5649
      consolidated_elements_kind,
5650
      false, NEVER_RETURN_HOLE, STANDARD_STORE);
5651
  return instr;
5652
}
5653

    
5654

    
5655
HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
5656
    HValue* object,
5657
    HValue* key,
5658
    HValue* val,
5659
    SmallMapList* maps,
5660
    bool is_store,
5661
    KeyedAccessStoreMode store_mode,
5662
    bool* has_side_effects) {
5663
  *has_side_effects = false;
5664
  BuildCheckHeapObject(object);
5665

    
5666
  if (!is_store) {
5667
    HInstruction* consolidated_load =
5668
        TryBuildConsolidatedElementLoad(object, key, val, maps);
5669
    if (consolidated_load != NULL) {
5670
      *has_side_effects |= consolidated_load->HasObservableSideEffects();
5671
      return consolidated_load;
5672
    }
5673
  }
5674

    
5675
  // Elements_kind transition support.
5676
  MapHandleList transition_target(maps->length());
5677
  // Collect possible transition targets.
5678
  MapHandleList possible_transitioned_maps(maps->length());
5679
  for (int i = 0; i < maps->length(); ++i) {
5680
    Handle<Map> map = maps->at(i);
5681
    ElementsKind elements_kind = map->elements_kind();
5682
    if (IsFastElementsKind(elements_kind) &&
5683
        elements_kind != GetInitialFastElementsKind()) {
5684
      possible_transitioned_maps.Add(map);
5685
    }
5686
  }
5687
  // Get transition target for each map (NULL == no transition).
5688
  for (int i = 0; i < maps->length(); ++i) {
5689
    Handle<Map> map = maps->at(i);
5690
    Handle<Map> transitioned_map =
5691
        map->FindTransitionedMap(&possible_transitioned_maps);
5692
    transition_target.Add(transitioned_map);
5693
  }
5694

    
5695
  MapHandleList untransitionable_maps(maps->length());
5696
  HTransitionElementsKind* transition = NULL;
5697
  for (int i = 0; i < maps->length(); ++i) {
5698
    Handle<Map> map = maps->at(i);
5699
    ASSERT(map->IsMap());
5700
    if (!transition_target.at(i).is_null()) {
5701
      ASSERT(Map::IsValidElementsTransition(
5702
          map->elements_kind(),
5703
          transition_target.at(i)->elements_kind()));
5704
      transition = Add<HTransitionElementsKind>(object, map,
5705
                                                transition_target.at(i));
5706
    } else {
5707
      untransitionable_maps.Add(map);
5708
    }
5709
  }
5710

    
5711
  // If only one map is left after transitioning, handle this case
5712
  // monomorphically.
5713
  ASSERT(untransitionable_maps.length() >= 1);
5714
  if (untransitionable_maps.length() == 1) {
5715
    Handle<Map> untransitionable_map = untransitionable_maps[0];
5716
    HInstruction* instr = NULL;
5717
    if (untransitionable_map->has_slow_elements_kind() ||
5718
        !untransitionable_map->IsJSObjectMap()) {
5719
      instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val)
5720
                                      : BuildLoadKeyedGeneric(object, key));
5721
    } else {
5722
      instr = BuildMonomorphicElementAccess(
5723
          object, key, val, transition, untransitionable_map, is_store,
5724
          store_mode);
5725
    }
5726
    *has_side_effects |= instr->HasObservableSideEffects();
5727
    return is_store ? NULL : instr;
5728
  }
5729

    
5730
  HBasicBlock* join = graph()->CreateBasicBlock();
5731

    
5732
  for (int i = 0; i < untransitionable_maps.length(); ++i) {
5733
    Handle<Map> map = untransitionable_maps[i];
5734
    if (!map->IsJSObjectMap()) continue;
5735
    ElementsKind elements_kind = map->elements_kind();
5736
    HBasicBlock* this_map = graph()->CreateBasicBlock();
5737
    HBasicBlock* other_map = graph()->CreateBasicBlock();
5738
    HCompareMap* mapcompare =
5739
        New<HCompareMap>(object, map, this_map, other_map);
5740
    FinishCurrentBlock(mapcompare);
5741

    
5742
    set_current_block(this_map);
5743
    HInstruction* access = NULL;
5744
    if (IsDictionaryElementsKind(elements_kind)) {
5745
      access = is_store
5746
          ? AddInstruction(BuildStoreKeyedGeneric(object, key, val))
5747
          : AddInstruction(BuildLoadKeyedGeneric(object, key));
5748
    } else {
5749
      ASSERT(IsFastElementsKind(elements_kind) ||
5750
             IsExternalArrayElementsKind(elements_kind));
5751
      LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map);
5752
      // Happily, mapcompare is a checked object.
5753
      access = BuildUncheckedMonomorphicElementAccess(
5754
          mapcompare, key, val,
5755
          map->instance_type() == JS_ARRAY_TYPE,
5756
          elements_kind, is_store,
5757
          load_mode,
5758
          store_mode);
5759
    }
5760
    *has_side_effects |= access->HasObservableSideEffects();
5761
    // The caller will use has_side_effects and add a correct Simulate.
5762
    access->SetFlag(HValue::kHasNoObservableSideEffects);
5763
    if (!is_store) {
5764
      Push(access);
5765
    }
5766
    NoObservableSideEffectsScope scope(this);
5767
    GotoNoSimulate(join);
5768
    set_current_block(other_map);
5769
  }
5770

    
5771
  // Deopt if none of the cases matched.
5772
  NoObservableSideEffectsScope scope(this);
5773
  FinishExitWithHardDeoptimization("Unknown map in polymorphic element access",
5774
                                   join);
5775
  set_current_block(join);
5776
  return is_store ? NULL : Pop();
5777
}
5778

    
5779

    
5780
HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
5781
    HValue* obj,
5782
    HValue* key,
5783
    HValue* val,
5784
    Expression* expr,
5785
    bool is_store,
5786
    bool* has_side_effects) {
5787
  ASSERT(!expr->IsPropertyName());
5788
  HInstruction* instr = NULL;
5789

    
5790
  SmallMapList* types;
5791
  bool monomorphic = ComputeReceiverTypes(expr, obj, &types);
5792

    
5793
  if (monomorphic) {
5794
    Handle<Map> map = types->first();
5795
    if (map->has_slow_elements_kind()) {
5796
      instr = is_store ? BuildStoreKeyedGeneric(obj, key, val)
5797
                       : BuildLoadKeyedGeneric(obj, key);
5798
      AddInstruction(instr);
5799
    } else {
5800
      BuildCheckHeapObject(obj);
5801
      instr = BuildMonomorphicElementAccess(
5802
          obj, key, val, NULL, map, is_store, expr->GetStoreMode());
5803
    }
5804
  } else if (types != NULL && !types->is_empty()) {
5805
    return HandlePolymorphicElementAccess(
5806
        obj, key, val, types, is_store,
5807
        expr->GetStoreMode(), has_side_effects);
5808
  } else {
5809
    if (is_store) {
5810
      if (expr->IsAssignment() &&
5811
          expr->AsAssignment()->HasNoTypeInformation()) {
5812
        Add<HDeoptimize>("Insufficient type feedback for keyed store",
5813
                         Deoptimizer::SOFT);
5814
      }
5815
      instr = BuildStoreKeyedGeneric(obj, key, val);
5816
    } else {
5817
      if (expr->AsProperty()->HasNoTypeInformation()) {
5818
        Add<HDeoptimize>("Insufficient type feedback for keyed load",
5819
                         Deoptimizer::SOFT);
5820
      }
5821
      instr = BuildLoadKeyedGeneric(obj, key);
5822
    }
5823
    AddInstruction(instr);
5824
  }
5825
  *has_side_effects = instr->HasObservableSideEffects();
5826
  return instr;
5827
}
5828

    
5829

    
5830
HInstruction* HOptimizedGraphBuilder::BuildStoreKeyedGeneric(
5831
    HValue* object,
5832
    HValue* key,
5833
    HValue* value) {
5834
  return New<HStoreKeyedGeneric>(
5835
                         object,
5836
                         key,
5837
                         value,
5838
                         function_strict_mode_flag());
5839
}
5840

    
5841

    
5842
void HOptimizedGraphBuilder::EnsureArgumentsArePushedForAccess() {
5843
  // Outermost function already has arguments on the stack.
5844
  if (function_state()->outer() == NULL) return;
5845

    
5846
  if (function_state()->arguments_pushed()) return;
5847

    
5848
  // Push arguments when entering inlined function.
5849
  HEnterInlined* entry = function_state()->entry();
5850
  entry->set_arguments_pushed();
5851

    
5852
  HArgumentsObject* arguments = entry->arguments_object();
5853
  const ZoneList<HValue*>* arguments_values = arguments->arguments_values();
5854

    
5855
  HInstruction* insert_after = entry;
5856
  for (int i = 0; i < arguments_values->length(); i++) {
5857
    HValue* argument = arguments_values->at(i);
5858
    HInstruction* push_argument = New<HPushArgument>(argument);
5859
    push_argument->InsertAfter(insert_after);
5860
    insert_after = push_argument;
5861
  }
5862

    
5863
  HArgumentsElements* arguments_elements = New<HArgumentsElements>(true);
5864
  arguments_elements->ClearFlag(HValue::kUseGVN);
5865
  arguments_elements->InsertAfter(insert_after);
5866
  function_state()->set_arguments_elements(arguments_elements);
5867
}
5868

    
5869

    
5870
bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) {
5871
  VariableProxy* proxy = expr->obj()->AsVariableProxy();
5872
  if (proxy == NULL) return false;
5873
  if (!proxy->var()->IsStackAllocated()) return false;
5874
  if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) {
5875
    return false;
5876
  }
5877

    
5878
  HInstruction* result = NULL;
5879
  if (expr->key()->IsPropertyName()) {
5880
    Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
5881
    if (!name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("length"))) return false;
5882

    
5883
    if (function_state()->outer() == NULL) {
5884
      HInstruction* elements = Add<HArgumentsElements>(false);
5885
      result = New<HArgumentsLength>(elements);
5886
    } else {
5887
      // Number of arguments without receiver.
5888
      int argument_count = environment()->
5889
          arguments_environment()->parameter_count() - 1;
5890
      result = New<HConstant>(argument_count);
5891
    }
5892
  } else {
5893
    Push(graph()->GetArgumentsObject());
5894
    CHECK_ALIVE_OR_RETURN(VisitForValue(expr->key()), true);
5895
    HValue* key = Pop();
5896
    Drop(1);  // Arguments object.
5897
    if (function_state()->outer() == NULL) {
5898
      HInstruction* elements = Add<HArgumentsElements>(false);
5899
      HInstruction* length = Add<HArgumentsLength>(elements);
5900
      HInstruction* checked_key = Add<HBoundsCheck>(key, length);
5901
      result = New<HAccessArgumentsAt>(elements, length, checked_key);
5902
    } else {
5903
      EnsureArgumentsArePushedForAccess();
5904

    
5905
      // Number of arguments without receiver.
5906
      HInstruction* elements = function_state()->arguments_elements();
5907
      int argument_count = environment()->
5908
          arguments_environment()->parameter_count() - 1;
5909
      HInstruction* length = Add<HConstant>(argument_count);
5910
      HInstruction* checked_key = Add<HBoundsCheck>(key, length);
5911
      result = New<HAccessArgumentsAt>(elements, length, checked_key);
5912
    }
5913
  }
5914
  ast_context()->ReturnInstruction(result, expr->id());
5915
  return true;
5916
}
5917

    
5918

    
5919
void HOptimizedGraphBuilder::PushLoad(Property* expr,
5920
                                      HValue* object,
5921
                                      HValue* key) {
5922
  ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
5923
  Push(object);
5924
  if (key != NULL) Push(key);
5925
  BuildLoad(expr, expr->LoadId());
5926
}
5927

    
5928

    
5929
static bool AreStringTypes(SmallMapList* types) {
5930
  for (int i = 0; i < types->length(); i++) {
5931
    if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
5932
  }
5933
  return true;
5934
}
5935

    
5936

    
5937
void HOptimizedGraphBuilder::BuildLoad(Property* expr,
5938
                                       BailoutId ast_id) {
5939
  HInstruction* instr = NULL;
5940
  if (expr->IsStringAccess()) {
5941
    HValue* index = Pop();
5942
    HValue* string = Pop();
5943
    HInstruction* char_code = BuildStringCharCodeAt(string, index);
5944
    AddInstruction(char_code);
5945
    instr = NewUncasted<HStringCharFromCode>(char_code);
5946

    
5947
  } else if (expr->IsFunctionPrototype()) {
5948
    HValue* function = Pop();
5949
    BuildCheckHeapObject(function);
5950
    instr = New<HLoadFunctionPrototype>(function);
5951

    
5952
  } else if (expr->key()->IsPropertyName()) {
5953
    Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
5954
    HValue* object = Pop();
5955

    
5956
    SmallMapList* types;
5957
    ComputeReceiverTypes(expr, object, &types);
5958
    ASSERT(types != NULL);
5959

    
5960
    if (types->length() > 0) {
5961
      PropertyAccessInfo info(isolate(), types->first(), name);
5962
      if (!info.CanLoadAsMonomorphic(types)) {
5963
        return HandlePolymorphicLoadNamedField(
5964
            ast_id, expr->LoadId(), object, types, name);
5965
      }
5966

    
5967
      BuildCheckHeapObject(object);
5968
      HInstruction* checked_object;
5969
      if (AreStringTypes(types)) {
5970
        checked_object =
5971
            Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING);
5972
      } else {
5973
        checked_object = Add<HCheckMaps>(object, types);
5974
      }
5975
      instr = BuildLoadMonomorphic(
5976
          &info, object, checked_object, ast_id, expr->LoadId());
5977
      if (instr == NULL) return;
5978
      if (instr->IsLinked()) return ast_context()->ReturnValue(instr);
5979
    } else {
5980
      instr = BuildLoadNamedGeneric(object, name, expr);
5981
    }
5982

    
5983
  } else {
5984
    HValue* key = Pop();
5985
    HValue* obj = Pop();
5986

    
5987
    bool has_side_effects = false;
5988
    HValue* load = HandleKeyedElementAccess(
5989
        obj, key, NULL, expr,
5990
        false,  // is_store
5991
        &has_side_effects);
5992
    if (has_side_effects) {
5993
      if (ast_context()->IsEffect()) {
5994
        Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
5995
      } else {
5996
        Push(load);
5997
        Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
5998
        Drop(1);
5999
      }
6000
    }
6001
    return ast_context()->ReturnValue(load);
6002
  }
6003
  return ast_context()->ReturnInstruction(instr, ast_id);
6004
}
6005

    
6006

    
6007
void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
6008
  ASSERT(!HasStackOverflow());
6009
  ASSERT(current_block() != NULL);
6010
  ASSERT(current_block()->HasPredecessor());
6011

    
6012
  if (TryArgumentsAccess(expr)) return;
6013

    
6014
  CHECK_ALIVE(VisitForValue(expr->obj()));
6015
  if ((!expr->IsFunctionPrototype() && !expr->key()->IsPropertyName()) ||
6016
      expr->IsStringAccess()) {
6017
    CHECK_ALIVE(VisitForValue(expr->key()));
6018
  }
6019

    
6020
  BuildLoad(expr, expr->id());
6021
}
6022

    
6023

    
6024
HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant,
6025
                                                   CompilationInfo* info) {
6026
  HConstant* constant_value = New<HConstant>(constant);
6027

    
6028
  if (constant->map()->CanOmitMapChecks()) {
6029
    constant->map()->AddDependentCompilationInfo(
6030
        DependentCode::kPrototypeCheckGroup, info);
6031
    return constant_value;
6032
  }
6033

    
6034
  AddInstruction(constant_value);
6035
  HCheckMaps* check =
6036
      Add<HCheckMaps>(constant_value, handle(constant->map()), info);
6037
  check->ClearGVNFlag(kDependsOnElementsKind);
6038
  return check;
6039
}
6040

    
6041

    
6042
HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype,
6043
                                                     Handle<JSObject> holder) {
6044
  while (!prototype.is_identical_to(holder)) {
6045
    BuildConstantMapCheck(prototype, top_info());
6046
    prototype = handle(JSObject::cast(prototype->GetPrototype()));
6047
  }
6048

    
6049
  HInstruction* checked_object = BuildConstantMapCheck(prototype, top_info());
6050
  if (!checked_object->IsLinked()) AddInstruction(checked_object);
6051
  return checked_object;
6052
}
6053

    
6054

    
6055
void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder,
6056
                                                   Handle<Map> receiver_map) {
6057
  if (!holder.is_null()) {
6058
    Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
6059
    BuildCheckPrototypeMaps(prototype, holder);
6060
  }
6061
}
6062

    
6063

    
6064
void HOptimizedGraphBuilder::AddCheckConstantFunction(
6065
    Handle<JSObject> holder,
6066
    HValue* receiver,
6067
    Handle<Map> receiver_map) {
6068
  // Constant functions have the nice property that the map will change if they
6069
  // are overwritten.  Therefore it is enough to check the map of the holder and
6070
  // its prototypes.
6071
  AddCheckMap(receiver, receiver_map);
6072
  AddCheckPrototypeMaps(holder, receiver_map);
6073
}
6074

    
6075

    
6076
class FunctionSorter {
6077
 public:
6078
  FunctionSorter() : index_(0), ticks_(0), ast_length_(0), src_length_(0) { }
6079
  FunctionSorter(int index, int ticks, int ast_length, int src_length)
6080
      : index_(index),
6081
        ticks_(ticks),
6082
        ast_length_(ast_length),
6083
        src_length_(src_length) { }
6084

    
6085
  int index() const { return index_; }
6086
  int ticks() const { return ticks_; }
6087
  int ast_length() const { return ast_length_; }
6088
  int src_length() const { return src_length_; }
6089

    
6090
 private:
6091
  int index_;
6092
  int ticks_;
6093
  int ast_length_;
6094
  int src_length_;
6095
};
6096

    
6097

    
6098
inline bool operator<(const FunctionSorter& lhs, const FunctionSorter& rhs) {
6099
  int diff = lhs.ticks() - rhs.ticks();
6100
  if (diff != 0) return diff > 0;
6101
  diff = lhs.ast_length() - rhs.ast_length();
6102
  if (diff != 0) return diff < 0;
6103
  return lhs.src_length() < rhs.src_length();
6104
}
6105

    
6106

    
6107
bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic(
6108
    Call* expr,
6109
    HValue* receiver,
6110
    SmallMapList* types,
6111
    Handle<String> name) {
6112
  if (types->length() > kMaxCallPolymorphism) return false;
6113

    
6114
  PropertyAccessInfo info(isolate(), types->at(0), name);
6115
  if (!info.CanLoadAsMonomorphic(types)) return false;
6116
  if (!expr->ComputeTarget(info.map(), name)) return false;
6117

    
6118
  BuildCheckHeapObject(receiver);
6119
  Add<HCheckMaps>(receiver, types);
6120
  AddCheckPrototypeMaps(expr->holder(), info.map());
6121
  if (FLAG_trace_inlining) {
6122
    Handle<JSFunction> caller = current_info()->closure();
6123
    SmartArrayPointer<char> caller_name =
6124
        caller->shared()->DebugName()->ToCString();
6125
    PrintF("Trying to inline the polymorphic call to %s from %s\n",
6126
           *name->ToCString(), *caller_name);
6127
  }
6128

    
6129
  if (!TryInlineCall(expr)) {
6130
    int argument_count = expr->arguments()->length() + 1;  // Includes receiver.
6131
    HCallConstantFunction* call =
6132
      New<HCallConstantFunction>(expr->target(), argument_count);
6133
    PreProcessCall(call);
6134
    AddInstruction(call);
6135
    if (!ast_context()->IsEffect()) Push(call);
6136
    Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
6137
    if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
6138
  }
6139

    
6140
  return true;
6141
}
6142

    
6143

    
6144
void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
6145
    Call* expr,
6146
    HValue* receiver,
6147
    SmallMapList* types,
6148
    Handle<String> name) {
6149
  if (TryCallPolymorphicAsMonomorphic(expr, receiver, types, name)) return;
6150

    
6151
  int argument_count = expr->arguments()->length() + 1;  // Includes receiver.
6152
  HBasicBlock* join = NULL;
6153
  FunctionSorter order[kMaxCallPolymorphism];
6154
  int ordered_functions = 0;
6155

    
6156
  Handle<Map> initial_string_map(
6157
      isolate()->native_context()->string_function()->initial_map());
6158
  Handle<Map> string_marker_map(
6159
      JSObject::cast(initial_string_map->prototype())->map());
6160
  Handle<Map> initial_number_map(
6161
      isolate()->native_context()->number_function()->initial_map());
6162
  Handle<Map> number_marker_map(
6163
      JSObject::cast(initial_number_map->prototype())->map());
6164
  Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
6165

    
6166
  bool handle_smi = false;
6167

    
6168
  for (int i = 0;
6169
       i < types->length() && ordered_functions < kMaxCallPolymorphism;
6170
       ++i) {
6171
    Handle<Map> map = types->at(i);
6172
    if (expr->ComputeTarget(map, name)) {
6173
      if (map.is_identical_to(number_marker_map)) handle_smi = true;
6174
      order[ordered_functions++] =
6175
          FunctionSorter(i,
6176
                         expr->target()->shared()->profiler_ticks(),
6177
                         InliningAstSize(expr->target()),
6178
                         expr->target()->shared()->SourceSize());
6179
    }
6180
  }
6181

    
6182
  std::sort(order, order + ordered_functions);
6183

    
6184
  HBasicBlock* number_block = NULL;
6185

    
6186
  for (int fn = 0; fn < ordered_functions; ++fn) {
6187
    int i = order[fn].index();
6188
    Handle<Map> map = types->at(i);
6189
    if (fn == 0) {
6190
      // Only needed once.
6191
      join = graph()->CreateBasicBlock();
6192
      if (handle_smi) {
6193
        HBasicBlock* empty_smi_block = graph()->CreateBasicBlock();
6194
        HBasicBlock* not_smi_block = graph()->CreateBasicBlock();
6195
        number_block = graph()->CreateBasicBlock();
6196
        FinishCurrentBlock(New<HIsSmiAndBranch>(
6197
                receiver, empty_smi_block, not_smi_block));
6198
        Goto(empty_smi_block, number_block);
6199
        set_current_block(not_smi_block);
6200
      } else {
6201
        BuildCheckHeapObject(receiver);
6202
      }
6203
    }
6204
    HBasicBlock* if_true = graph()->CreateBasicBlock();
6205
    HBasicBlock* if_false = graph()->CreateBasicBlock();
6206
    HUnaryControlInstruction* compare;
6207

    
6208
    if (handle_smi && map.is_identical_to(number_marker_map)) {
6209
      compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false);
6210
      map = initial_number_map;
6211
      expr->set_number_check(
6212
          Handle<JSObject>(JSObject::cast(map->prototype())));
6213
    } else if (map.is_identical_to(string_marker_map)) {
6214
      compare = New<HIsStringAndBranch>(receiver, if_true, if_false);
6215
      map = initial_string_map;
6216
      expr->set_string_check(
6217
          Handle<JSObject>(JSObject::cast(map->prototype())));
6218
    } else {
6219
      compare = New<HCompareMap>(receiver, map, if_true, if_false);
6220
      expr->set_map_check();
6221
    }
6222

    
6223
    FinishCurrentBlock(compare);
6224

    
6225
    if (expr->check_type() == NUMBER_CHECK) {
6226
      Goto(if_true, number_block);
6227
      if_true = number_block;
6228
      number_block->SetJoinId(expr->id());
6229
    }
6230
    set_current_block(if_true);
6231

    
6232
    expr->ComputeTarget(map, name);
6233
    AddCheckPrototypeMaps(expr->holder(), map);
6234
    if (FLAG_trace_inlining && FLAG_polymorphic_inlining) {
6235
      Handle<JSFunction> caller = current_info()->closure();
6236
      SmartArrayPointer<char> caller_name =
6237
          caller->shared()->DebugName()->ToCString();
6238
      PrintF("Trying to inline the polymorphic call to %s from %s\n",
6239
             *name->ToCString(),
6240
             *caller_name);
6241
    }
6242
    if (FLAG_polymorphic_inlining && TryInlineCall(expr)) {
6243
      // Trying to inline will signal that we should bailout from the
6244
      // entire compilation by setting stack overflow on the visitor.
6245
      if (HasStackOverflow()) return;
6246
    } else {
6247
      HCallConstantFunction* call =
6248
          New<HCallConstantFunction>(expr->target(), argument_count);
6249
      PreProcessCall(call);
6250
      AddInstruction(call);
6251
      if (!ast_context()->IsEffect()) Push(call);
6252
    }
6253

    
6254
    if (current_block() != NULL) Goto(join);
6255
    set_current_block(if_false);
6256
  }
6257

    
6258
  // Finish up.  Unconditionally deoptimize if we've handled all the maps we
6259
  // know about and do not want to handle ones we've never seen.  Otherwise
6260
  // use a generic IC.
6261
  if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) {
6262
    // Because the deopt may be the only path in the polymorphic call, make sure
6263
    // that the environment stack matches the depth on deopt that it otherwise
6264
    // would have had after a successful call.
6265
    Drop(argument_count);
6266
    if (!ast_context()->IsEffect()) Push(graph()->GetConstant0());
6267
    FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join);
6268
  } else {
6269
    HCallNamed* call = New<HCallNamed>(name, argument_count);
6270
    PreProcessCall(call);
6271

    
6272
    if (join != NULL) {
6273
      AddInstruction(call);
6274
      if (!ast_context()->IsEffect()) Push(call);
6275
      Goto(join);
6276
    } else {
6277
      return ast_context()->ReturnInstruction(call, expr->id());
6278
    }
6279
  }
6280

    
6281
  // We assume that control flow is always live after an expression.  So
6282
  // even without predecessors to the join block, we set it as the exit
6283
  // block and continue by adding instructions there.
6284
  ASSERT(join != NULL);
6285
  if (join->HasPredecessor()) {
6286
    set_current_block(join);
6287
    join->SetJoinId(expr->id());
6288
    if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop());
6289
  } else {
6290
    set_current_block(NULL);
6291
  }
6292
}
6293

    
6294

    
6295
void HOptimizedGraphBuilder::TraceInline(Handle<JSFunction> target,
6296
                                         Handle<JSFunction> caller,
6297
                                         const char* reason) {
6298
  if (FLAG_trace_inlining) {
6299
    SmartArrayPointer<char> target_name =
6300
        target->shared()->DebugName()->ToCString();
6301
    SmartArrayPointer<char> caller_name =
6302
        caller->shared()->DebugName()->ToCString();
6303
    if (reason == NULL) {
6304
      PrintF("Inlined %s called from %s.\n", *target_name, *caller_name);
6305
    } else {
6306
      PrintF("Did not inline %s called from %s (%s).\n",
6307
             *target_name, *caller_name, reason);
6308
    }
6309
  }
6310
}
6311

    
6312

    
6313
static const int kNotInlinable = 1000000000;
6314

    
6315

    
6316
int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) {
6317
  if (!FLAG_use_inlining) return kNotInlinable;
6318

    
6319
  // Precondition: call is monomorphic and we have found a target with the
6320
  // appropriate arity.
6321
  Handle<JSFunction> caller = current_info()->closure();
6322
  Handle<SharedFunctionInfo> target_shared(target->shared());
6323

    
6324
  // Do a quick check on source code length to avoid parsing large
6325
  // inlining candidates.
6326
  if (target_shared->SourceSize() >
6327
      Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) {
6328
    TraceInline(target, caller, "target text too big");
6329
    return kNotInlinable;
6330
  }
6331

    
6332
  // Target must be inlineable.
6333
  if (!target->IsInlineable()) {
6334
    TraceInline(target, caller, "target not inlineable");
6335
    return kNotInlinable;
6336
  }
6337
  if (target_shared->dont_inline() || target_shared->dont_optimize()) {
6338
    TraceInline(target, caller, "target contains unsupported syntax [early]");
6339
    return kNotInlinable;
6340
  }
6341

    
6342
  int nodes_added = target_shared->ast_node_count();
6343
  return nodes_added;
6344
}
6345

    
6346

    
6347
bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
6348
                                       Handle<JSFunction> target,
6349
                                       int arguments_count,
6350
                                       HValue* implicit_return_value,
6351
                                       BailoutId ast_id,
6352
                                       BailoutId return_id,
6353
                                       InliningKind inlining_kind) {
6354
  int nodes_added = InliningAstSize(target);
6355
  if (nodes_added == kNotInlinable) return false;
6356

    
6357
  Handle<JSFunction> caller = current_info()->closure();
6358

    
6359
  if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
6360
    TraceInline(target, caller, "target AST is too large [early]");
6361
    return false;
6362
  }
6363

    
6364
#if !V8_TARGET_ARCH_IA32 && !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_MIPS
6365
  // Target must be able to use caller's context.
6366
  CompilationInfo* outer_info = current_info();
6367
  if (target->context() != outer_info->closure()->context() ||
6368
      outer_info->scope()->contains_with() ||
6369
      outer_info->scope()->num_heap_slots() > 0) {
6370
    TraceInline(target, caller, "target requires context change");
6371
    return false;
6372
  }
6373
#endif
6374

    
6375

    
6376
  // Don't inline deeper than the maximum number of inlining levels.
6377
  HEnvironment* env = environment();
6378
  int current_level = 1;
6379
  while (env->outer() != NULL) {
6380
    if (current_level == FLAG_max_inlining_levels) {
6381
      TraceInline(target, caller, "inline depth limit reached");
6382
      return false;
6383
    }
6384
    if (env->outer()->frame_type() == JS_FUNCTION) {
6385
      current_level++;
6386
    }
6387
    env = env->outer();
6388
  }
6389

    
6390
  // Don't inline recursive functions.
6391
  for (FunctionState* state = function_state();
6392
       state != NULL;
6393
       state = state->outer()) {
6394
    if (*state->compilation_info()->closure() == *target) {
6395
      TraceInline(target, caller, "target is recursive");
6396
      return false;
6397
    }
6398
  }
6399

    
6400
  // We don't want to add more than a certain number of nodes from inlining.
6401
  if (inlined_count_ > Min(FLAG_max_inlined_nodes_cumulative,
6402
                           kUnlimitedMaxInlinedNodesCumulative)) {
6403
    TraceInline(target, caller, "cumulative AST node limit reached");
6404
    return false;
6405
  }
6406

    
6407
  // Parse and allocate variables.
6408
  CompilationInfo target_info(target, zone());
6409
  Handle<SharedFunctionInfo> target_shared(target->shared());
6410
  if (!Parser::Parse(&target_info) || !Scope::Analyze(&target_info)) {
6411
    if (target_info.isolate()->has_pending_exception()) {
6412
      // Parse or scope error, never optimize this function.
6413
      SetStackOverflow();
6414
      target_shared->DisableOptimization(kParseScopeError);
6415
    }
6416
    TraceInline(target, caller, "parse failure");
6417
    return false;
6418
  }
6419

    
6420
  if (target_info.scope()->num_heap_slots() > 0) {
6421
    TraceInline(target, caller, "target has context-allocated variables");
6422
    return false;
6423
  }
6424
  FunctionLiteral* function = target_info.function();
6425

    
6426
  // The following conditions must be checked again after re-parsing, because
6427
  // earlier the information might not have been complete due to lazy parsing.
6428
  nodes_added = function->ast_node_count();
6429
  if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
6430
    TraceInline(target, caller, "target AST is too large [late]");
6431
    return false;
6432
  }
6433
  AstProperties::Flags* flags(function->flags());
6434
  if (flags->Contains(kDontInline) || function->dont_optimize()) {
6435
    TraceInline(target, caller, "target contains unsupported syntax [late]");
6436
    return false;
6437
  }
6438

    
6439
  // If the function uses the arguments object check that inlining of functions
6440
  // with arguments object is enabled and the arguments-variable is
6441
  // stack allocated.
6442
  if (function->scope()->arguments() != NULL) {
6443
    if (!FLAG_inline_arguments) {
6444
      TraceInline(target, caller, "target uses arguments object");
6445
      return false;
6446
    }
6447

    
6448
    if (!function->scope()->arguments()->IsStackAllocated()) {
6449
      TraceInline(target,
6450
                  caller,
6451
                  "target uses non-stackallocated arguments object");
6452
      return false;
6453
    }
6454
  }
6455

    
6456
  // All declarations must be inlineable.
6457
  ZoneList<Declaration*>* decls = target_info.scope()->declarations();
6458
  int decl_count = decls->length();
6459
  for (int i = 0; i < decl_count; ++i) {
6460
    if (!decls->at(i)->IsInlineable()) {
6461
      TraceInline(target, caller, "target has non-trivial declaration");
6462
      return false;
6463
    }
6464
  }
6465

    
6466
  // Generate the deoptimization data for the unoptimized version of
6467
  // the target function if we don't already have it.
6468
  if (!target_shared->has_deoptimization_support()) {
6469
    // Note that we compile here using the same AST that we will use for
6470
    // generating the optimized inline code.
6471
    target_info.EnableDeoptimizationSupport();
6472
    if (!FullCodeGenerator::MakeCode(&target_info)) {
6473
      TraceInline(target, caller, "could not generate deoptimization info");
6474
      return false;
6475
    }
6476
    if (target_shared->scope_info() == ScopeInfo::Empty(isolate())) {
6477
      // The scope info might not have been set if a lazily compiled
6478
      // function is inlined before being called for the first time.
6479
      Handle<ScopeInfo> target_scope_info =
6480
          ScopeInfo::Create(target_info.scope(), zone());
6481
      target_shared->set_scope_info(*target_scope_info);
6482
    }
6483
    target_shared->EnableDeoptimizationSupport(*target_info.code());
6484
    Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG,
6485
                                        &target_info,
6486
                                        target_shared);
6487
  }
6488

    
6489
  // ----------------------------------------------------------------
6490
  // After this point, we've made a decision to inline this function (so
6491
  // TryInline should always return true).
6492

    
6493
  // Type-check the inlined function.
6494
  ASSERT(target_shared->has_deoptimization_support());
6495
  AstTyper::Run(&target_info);
6496

    
6497
  // Save the pending call context. Set up new one for the inlined function.
6498
  // The function state is new-allocated because we need to delete it
6499
  // in two different places.
6500
  FunctionState* target_state = new FunctionState(
6501
      this, &target_info, inlining_kind);
6502

    
6503
  HConstant* undefined = graph()->GetConstantUndefined();
6504
  bool undefined_receiver = HEnvironment::UseUndefinedReceiver(
6505
      target, function, call_kind, inlining_kind);
6506
  HEnvironment* inner_env =
6507
      environment()->CopyForInlining(target,
6508
                                     arguments_count,
6509
                                     function,
6510
                                     undefined,
6511
                                     function_state()->inlining_kind(),
6512
                                     undefined_receiver);
6513
#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
6514
  // IA32, ARM and MIPS only, overwrite the caller's context in the
6515
  // deoptimization environment with the correct one.
6516
  //
6517
  // TODO(kmillikin): implement the same inlining on other platforms so we
6518
  // can remove the unsightly ifdefs in this function.
6519
  HConstant* context = Add<HConstant>(Handle<Context>(target->context()));
6520
  inner_env->BindContext(context);
6521
#endif
6522

    
6523
  Add<HSimulate>(return_id);
6524
  current_block()->UpdateEnvironment(inner_env);
6525
  HArgumentsObject* arguments_object = NULL;
6526

    
6527
  // If the function uses arguments object create and bind one, also copy
6528
  // current arguments values to use them for materialization.
6529
  if (function->scope()->arguments() != NULL) {
6530
    ASSERT(function->scope()->arguments()->IsStackAllocated());
6531
    HEnvironment* arguments_env = inner_env->arguments_environment();
6532
    int arguments_count = arguments_env->parameter_count();
6533
    arguments_object = Add<HArgumentsObject>(arguments_count);
6534
    inner_env->Bind(function->scope()->arguments(), arguments_object);
6535
    for (int i = 0; i < arguments_count; i++) {
6536
      arguments_object->AddArgument(arguments_env->Lookup(i), zone());
6537
    }
6538
  }
6539

    
6540
  HEnterInlined* enter_inlined =
6541
      Add<HEnterInlined>(target, arguments_count, function,
6542
                         function_state()->inlining_kind(),
6543
                         function->scope()->arguments(),
6544
                         arguments_object, undefined_receiver);
6545
  function_state()->set_entry(enter_inlined);
6546

    
6547
  VisitDeclarations(target_info.scope()->declarations());
6548
  VisitStatements(function->body());
6549
  if (HasStackOverflow()) {
6550
    // Bail out if the inline function did, as we cannot residualize a call
6551
    // instead.
6552
    TraceInline(target, caller, "inline graph construction failed");
6553
    target_shared->DisableOptimization(kInliningBailedOut);
6554
    inline_bailout_ = true;
6555
    delete target_state;
6556
    return true;
6557
  }
6558

    
6559
  // Update inlined nodes count.
6560
  inlined_count_ += nodes_added;
6561

    
6562
  Handle<Code> unoptimized_code(target_shared->code());
6563
  ASSERT(unoptimized_code->kind() == Code::FUNCTION);
6564
  Handle<TypeFeedbackInfo> type_info(
6565
      TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info()));
6566
  graph()->update_type_change_checksum(type_info->own_type_change_checksum());
6567

    
6568
  TraceInline(target, caller, NULL);
6569

    
6570
  if (current_block() != NULL) {
6571
    FunctionState* state = function_state();
6572
    if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) {
6573
      // Falling off the end of an inlined construct call. In a test context the
6574
      // return value will always evaluate to true, in a value context the
6575
      // return value is the newly allocated receiver.
6576
      if (call_context()->IsTest()) {
6577
        Goto(inlined_test_context()->if_true(), state);
6578
      } else if (call_context()->IsEffect()) {
6579
        Goto(function_return(), state);
6580
      } else {
6581
        ASSERT(call_context()->IsValue());
6582
        AddLeaveInlined(implicit_return_value, state);
6583
      }
6584
    } else if (state->inlining_kind() == SETTER_CALL_RETURN) {
6585
      // Falling off the end of an inlined setter call. The returned value is
6586
      // never used, the value of an assignment is always the value of the RHS
6587
      // of the assignment.
6588
      if (call_context()->IsTest()) {
6589
        inlined_test_context()->ReturnValue(implicit_return_value);
6590
      } else if (call_context()->IsEffect()) {
6591
        Goto(function_return(), state);
6592
      } else {
6593
        ASSERT(call_context()->IsValue());
6594
        AddLeaveInlined(implicit_return_value, state);
6595
      }
6596
    } else {
6597
      // Falling off the end of a normal inlined function. This basically means
6598
      // returning undefined.
6599
      if (call_context()->IsTest()) {
6600
        Goto(inlined_test_context()->if_false(), state);
6601
      } else if (call_context()->IsEffect()) {
6602
        Goto(function_return(), state);
6603
      } else {
6604
        ASSERT(call_context()->IsValue());
6605
        AddLeaveInlined(undefined, state);
6606
      }
6607
    }
6608
  }
6609

    
6610
  // Fix up the function exits.
6611
  if (inlined_test_context() != NULL) {
6612
    HBasicBlock* if_true = inlined_test_context()->if_true();
6613
    HBasicBlock* if_false = inlined_test_context()->if_false();
6614

    
6615
    HEnterInlined* entry = function_state()->entry();
6616

    
6617
    // Pop the return test context from the expression context stack.
6618
    ASSERT(ast_context() == inlined_test_context());
6619
    ClearInlinedTestContext();
6620
    delete target_state;
6621

    
6622
    // Forward to the real test context.
6623
    if (if_true->HasPredecessor()) {
6624
      entry->RegisterReturnTarget(if_true, zone());
6625
      if_true->SetJoinId(ast_id);
6626
      HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
6627
      Goto(if_true, true_target, function_state());
6628
    }
6629
    if (if_false->HasPredecessor()) {
6630
      entry->RegisterReturnTarget(if_false, zone());
6631
      if_false->SetJoinId(ast_id);
6632
      HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
6633
      Goto(if_false, false_target, function_state());
6634
    }
6635
    set_current_block(NULL);
6636
    return true;
6637

    
6638
  } else if (function_return()->HasPredecessor()) {
6639
    function_state()->entry()->RegisterReturnTarget(function_return(), zone());
6640
    function_return()->SetJoinId(ast_id);
6641
    set_current_block(function_return());
6642
  } else {
6643
    set_current_block(NULL);
6644
  }
6645
  delete target_state;
6646
  return true;
6647
}
6648

    
6649

    
6650
bool HOptimizedGraphBuilder::TryInlineCall(Call* expr, bool drop_extra) {
6651
  // The function call we are inlining is a method call if the call
6652
  // is a property call.
6653
  CallKind call_kind = (expr->expression()->AsProperty() == NULL)
6654
      ? CALL_AS_FUNCTION
6655
      : CALL_AS_METHOD;
6656

    
6657
  return TryInline(call_kind,
6658
                   expr->target(),
6659
                   expr->arguments()->length(),
6660
                   NULL,
6661
                   expr->id(),
6662
                   expr->ReturnId(),
6663
                   drop_extra ? DROP_EXTRA_ON_RETURN : NORMAL_RETURN);
6664
}
6665

    
6666

    
6667
bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr,
6668
                                                HValue* implicit_return_value) {
6669
  return TryInline(CALL_AS_FUNCTION,
6670
                   expr->target(),
6671
                   expr->arguments()->length(),
6672
                   implicit_return_value,
6673
                   expr->id(),
6674
                   expr->ReturnId(),
6675
                   CONSTRUCT_CALL_RETURN);
6676
}
6677

    
6678

    
6679
bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter,
6680
                                             BailoutId ast_id,
6681
                                             BailoutId return_id) {
6682
  return TryInline(CALL_AS_METHOD,
6683
                   getter,
6684
                   0,
6685
                   NULL,
6686
                   ast_id,
6687
                   return_id,
6688
                   GETTER_CALL_RETURN);
6689
}
6690

    
6691

    
6692
bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter,
6693
                                             BailoutId id,
6694
                                             BailoutId assignment_id,
6695
                                             HValue* implicit_return_value) {
6696
  return TryInline(CALL_AS_METHOD,
6697
                   setter,
6698
                   1,
6699
                   implicit_return_value,
6700
                   id, assignment_id,
6701
                   SETTER_CALL_RETURN);
6702
}
6703

    
6704

    
6705
bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function,
6706
                                            Call* expr,
6707
                                            int arguments_count) {
6708
  return TryInline(CALL_AS_METHOD,
6709
                   function,
6710
                   arguments_count,
6711
                   NULL,
6712
                   expr->id(),
6713
                   expr->ReturnId(),
6714
                   NORMAL_RETURN);
6715
}
6716

    
6717

    
6718
bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr,
6719
                                                          bool drop_extra) {
6720
  if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
6721
  BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
6722
  switch (id) {
6723
    case kMathExp:
6724
      if (!FLAG_fast_math) break;
6725
      // Fall through if FLAG_fast_math.
6726
    case kMathRound:
6727
    case kMathFloor:
6728
    case kMathAbs:
6729
    case kMathSqrt:
6730
    case kMathLog:
6731
    case kMathSin:
6732
    case kMathCos:
6733
    case kMathTan:
6734
      if (expr->arguments()->length() == 1) {
6735
        HValue* argument = Pop();
6736
        Drop(1);  // Receiver.
6737
        HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id);
6738
        if (drop_extra) Drop(1);  // Optionally drop the function.
6739
        ast_context()->ReturnInstruction(op, expr->id());
6740
        return true;
6741
      }
6742
      break;
6743
    case kMathImul:
6744
      if (expr->arguments()->length() == 2) {
6745
        HValue* right = Pop();
6746
        HValue* left = Pop();
6747
        Drop(1);  // Receiver.
6748
        HInstruction* op = HMul::NewImul(zone(), context(), left, right);
6749
        if (drop_extra) Drop(1);  // Optionally drop the function.
6750
        ast_context()->ReturnInstruction(op, expr->id());
6751
        return true;
6752
      }
6753
      break;
6754
    default:
6755
      // Not supported for inlining yet.
6756
      break;
6757
  }
6758
  return false;
6759
}
6760

    
6761

    
6762
bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
6763
    Call* expr,
6764
    HValue* receiver,
6765
    Handle<Map> receiver_map,
6766
    CheckType check_type) {
6767
  ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null());
6768
  // Try to inline calls like Math.* as operations in the calling function.
6769
  if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
6770
  BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
6771
  int argument_count = expr->arguments()->length() + 1;  // Plus receiver.
6772
  switch (id) {
6773
    case kStringCharCodeAt:
6774
    case kStringCharAt:
6775
      if (argument_count == 2 && check_type == STRING_CHECK) {
6776
        HValue* index = Pop();
6777
        HValue* string = Pop();
6778
        ASSERT(!expr->holder().is_null());
6779
        BuildCheckPrototypeMaps(Call::GetPrototypeForPrimitiveCheck(
6780
                STRING_CHECK, expr->holder()->GetIsolate()),
6781
            expr->holder());
6782
        HInstruction* char_code =
6783
            BuildStringCharCodeAt(string, index);
6784
        if (id == kStringCharCodeAt) {
6785
          ast_context()->ReturnInstruction(char_code, expr->id());
6786
          return true;
6787
        }
6788
        AddInstruction(char_code);
6789
        HInstruction* result = NewUncasted<HStringCharFromCode>(char_code);
6790
        ast_context()->ReturnInstruction(result, expr->id());
6791
        return true;
6792
      }
6793
      break;
6794
    case kStringFromCharCode:
6795
      if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
6796
        AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
6797
        HValue* argument = Pop();
6798
        Drop(1);  // Receiver.
6799
        HInstruction* result = NewUncasted<HStringCharFromCode>(argument);
6800
        ast_context()->ReturnInstruction(result, expr->id());
6801
        return true;
6802
      }
6803
      break;
6804
    case kMathExp:
6805
      if (!FLAG_fast_math) break;
6806
      // Fall through if FLAG_fast_math.
6807
    case kMathRound:
6808
    case kMathFloor:
6809
    case kMathAbs:
6810
    case kMathSqrt:
6811
    case kMathLog:
6812
    case kMathSin:
6813
    case kMathCos:
6814
    case kMathTan:
6815
      if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
6816
        AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
6817
        HValue* argument = Pop();
6818
        Drop(1);  // Receiver.
6819
        HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id);
6820
        ast_context()->ReturnInstruction(op, expr->id());
6821
        return true;
6822
      }
6823
      break;
6824
    case kMathPow:
6825
      if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
6826
        AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
6827
        HValue* right = Pop();
6828
        HValue* left = Pop();
6829
        Pop();  // Pop receiver.
6830
        HInstruction* result = NULL;
6831
        // Use sqrt() if exponent is 0.5 or -0.5.
6832
        if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) {
6833
          double exponent = HConstant::cast(right)->DoubleValue();
6834
          if (exponent == 0.5) {
6835
            result = NewUncasted<HUnaryMathOperation>(left, kMathPowHalf);
6836
          } else if (exponent == -0.5) {
6837
            HValue* one = graph()->GetConstant1();
6838
            HInstruction* sqrt = AddUncasted<HUnaryMathOperation>(
6839
                left, kMathPowHalf);
6840
            // MathPowHalf doesn't have side effects so there's no need for
6841
            // an environment simulation here.
6842
            ASSERT(!sqrt->HasObservableSideEffects());
6843
            result = NewUncasted<HDiv>(one, sqrt);
6844
          } else if (exponent == 2.0) {
6845
            result = NewUncasted<HMul>(left, left);
6846
          }
6847
        }
6848

    
6849
        if (result == NULL) {
6850
          result = NewUncasted<HPower>(left, right);
6851
        }
6852
        ast_context()->ReturnInstruction(result, expr->id());
6853
        return true;
6854
      }
6855
      break;
6856
    case kMathRandom:
6857
      if (argument_count == 1 && check_type == RECEIVER_MAP_CHECK) {
6858
        AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
6859
        Drop(1);  // Receiver.
6860
        HGlobalObject* global_object = Add<HGlobalObject>();
6861
        HRandom* result = New<HRandom>(global_object);
6862
        ast_context()->ReturnInstruction(result, expr->id());
6863
        return true;
6864
      }
6865
      break;
6866
    case kMathMax:
6867
    case kMathMin:
6868
      if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
6869
        AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
6870
        HValue* right = Pop();
6871
        HValue* left = Pop();
6872
        Drop(1);  // Receiver.
6873
        HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin
6874
                                                     : HMathMinMax::kMathMax;
6875
        HInstruction* result = NewUncasted<HMathMinMax>(left, right, op);
6876
        ast_context()->ReturnInstruction(result, expr->id());
6877
        return true;
6878
      }
6879
      break;
6880
    case kMathImul:
6881
      if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
6882
        AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
6883
        HValue* right = Pop();
6884
        HValue* left = Pop();
6885
        Drop(1);  // Receiver.
6886
        HInstruction* result = HMul::NewImul(zone(), context(), left, right);
6887
        ast_context()->ReturnInstruction(result, expr->id());
6888
        return true;
6889
      }
6890
      break;
6891
    default:
6892
      // Not yet supported for inlining.
6893
      break;
6894
  }
6895
  return false;
6896
}
6897

    
6898

    
6899
bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
6900
  Expression* callee = expr->expression();
6901
  Property* prop = callee->AsProperty();
6902
  ASSERT(prop != NULL);
6903

    
6904
  if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) {
6905
    return false;
6906
  }
6907
  Handle<Map> function_map = expr->GetReceiverTypes()->first();
6908
  if (function_map->instance_type() != JS_FUNCTION_TYPE ||
6909
      !expr->target()->shared()->HasBuiltinFunctionId() ||
6910
      expr->target()->shared()->builtin_function_id() != kFunctionApply) {
6911
    return false;
6912
  }
6913

    
6914
  if (current_info()->scope()->arguments() == NULL) return false;
6915

    
6916
  ZoneList<Expression*>* args = expr->arguments();
6917
  if (args->length() != 2) return false;
6918

    
6919
  VariableProxy* arg_two = args->at(1)->AsVariableProxy();
6920
  if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
6921
  HValue* arg_two_value = LookupAndMakeLive(arg_two->var());
6922
  if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
6923

    
6924
  // Found pattern f.apply(receiver, arguments).
6925
  CHECK_ALIVE_OR_RETURN(VisitForValue(prop->obj()), true);
6926
  HValue* function = Top();
6927
  AddCheckConstantFunction(expr->holder(), function, function_map);
6928
  Drop(1);
6929

    
6930
  CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true);
6931
  HValue* receiver = Pop();
6932

    
6933
  if (function_state()->outer() == NULL) {
6934
    HInstruction* elements = Add<HArgumentsElements>(false);
6935
    HInstruction* length = Add<HArgumentsLength>(elements);
6936
    HValue* wrapped_receiver = BuildWrapReceiver(receiver, function);
6937
    HInstruction* result = New<HApplyArguments>(function,
6938
                                                wrapped_receiver,
6939
                                                length,
6940
                                                elements);
6941
    ast_context()->ReturnInstruction(result, expr->id());
6942
    return true;
6943
  } else {
6944
    // We are inside inlined function and we know exactly what is inside
6945
    // arguments object. But we need to be able to materialize at deopt.
6946
    ASSERT_EQ(environment()->arguments_environment()->parameter_count(),
6947
              function_state()->entry()->arguments_object()->arguments_count());
6948
    HArgumentsObject* args = function_state()->entry()->arguments_object();
6949
    const ZoneList<HValue*>* arguments_values = args->arguments_values();
6950
    int arguments_count = arguments_values->length();
6951
    Push(BuildWrapReceiver(receiver, function));
6952
    for (int i = 1; i < arguments_count; i++) {
6953
      Push(arguments_values->at(i));
6954
    }
6955

    
6956
    Handle<JSFunction> known_function;
6957
    if (function->IsConstant()) {
6958
      HConstant* constant_function = HConstant::cast(function);
6959
      known_function = Handle<JSFunction>::cast(
6960
          constant_function->handle(isolate()));
6961
      int args_count = arguments_count - 1;  // Excluding receiver.
6962
      if (TryInlineApply(known_function, expr, args_count)) return true;
6963
    }
6964

    
6965
    Drop(arguments_count - 1);
6966
    Push(Add<HPushArgument>(Pop()));
6967
    for (int i = 1; i < arguments_count; i++) {
6968
      Push(Add<HPushArgument>(arguments_values->at(i)));
6969
    }
6970

    
6971
    HInvokeFunction* call = New<HInvokeFunction>(function,
6972
                                                 known_function,
6973
                                                 arguments_count);
6974
    Drop(arguments_count);
6975
    ast_context()->ReturnInstruction(call, expr->id());
6976
    return true;
6977
  }
6978
}
6979

    
6980

    
6981
void HOptimizedGraphBuilder::VisitCall(Call* expr) {
6982
  ASSERT(!HasStackOverflow());
6983
  ASSERT(current_block() != NULL);
6984
  ASSERT(current_block()->HasPredecessor());
6985
  Expression* callee = expr->expression();
6986
  int argument_count = expr->arguments()->length() + 1;  // Plus receiver.
6987
  HInstruction* call = NULL;
6988

    
6989
  Property* prop = callee->AsProperty();
6990
  if (prop != NULL) {
6991
    if (!prop->key()->IsPropertyName()) {
6992
      // Keyed function call.
6993
      CHECK_ALIVE(VisitArgument(prop->obj()));
6994

    
6995
      CHECK_ALIVE(VisitForValue(prop->key()));
6996
      // Push receiver and key like the non-optimized code generator expects it.
6997
      HValue* key = Pop();
6998
      HValue* receiver = Pop();
6999
      Push(key);
7000
      Push(receiver);
7001

    
7002
      CHECK_ALIVE(VisitArgumentList(expr->arguments()));
7003

    
7004
      call = New<HCallKeyed>(key, argument_count);
7005
      Drop(argument_count + 1);  // 1 is the key.
7006
      return ast_context()->ReturnInstruction(call, expr->id());
7007
    }
7008

    
7009
    // Named function call.
7010
    if (TryCallApply(expr)) return;
7011

    
7012
    CHECK_ALIVE(VisitForValue(prop->obj()));
7013
    CHECK_ALIVE(VisitExpressions(expr->arguments()));
7014

    
7015
    Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
7016
    HValue* receiver =
7017
        environment()->ExpressionStackAt(expr->arguments()->length());
7018

    
7019
    SmallMapList* types;
7020
    bool was_monomorphic = expr->IsMonomorphic();
7021
    bool monomorphic = ComputeReceiverTypes(expr, receiver, &types);
7022
    if (!was_monomorphic && monomorphic) {
7023
      monomorphic = expr->ComputeTarget(types->first(), name);
7024
    }
7025

    
7026
    if (monomorphic) {
7027
      Handle<Map> map = types->first();
7028
      if (TryInlineBuiltinMethodCall(expr, receiver, map, expr->check_type())) {
7029
        if (FLAG_trace_inlining) {
7030
          PrintF("Inlining builtin ");
7031
          expr->target()->ShortPrint();
7032
          PrintF("\n");
7033
        }
7034
        return;
7035
      }
7036

    
7037
      if (CallStubCompiler::HasCustomCallGenerator(expr->target()) ||
7038
          expr->check_type() != RECEIVER_MAP_CHECK) {
7039
        // When the target has a custom call IC generator, use the IC,
7040
        // because it is likely to generate better code.  Also use the IC
7041
        // when a primitive receiver check is required.
7042
        call = PreProcessCall(New<HCallNamed>(name, argument_count));
7043
      } else {
7044
        AddCheckConstantFunction(expr->holder(), receiver, map);
7045

    
7046
        if (TryInlineCall(expr)) return;
7047
        call = PreProcessCall(
7048
            New<HCallConstantFunction>(expr->target(), argument_count));
7049
      }
7050
    } else if (types != NULL && types->length() > 1) {
7051
      ASSERT(expr->check_type() == RECEIVER_MAP_CHECK);
7052
      HandlePolymorphicCallNamed(expr, receiver, types, name);
7053
      return;
7054

    
7055
    } else {
7056
      call = PreProcessCall(New<HCallNamed>(name, argument_count));
7057
    }
7058
  } else {
7059
    VariableProxy* proxy = expr->expression()->AsVariableProxy();
7060
    if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) {
7061
      return Bailout(kPossibleDirectCallToEval);
7062
    }
7063

    
7064
    bool global_call = proxy != NULL && proxy->var()->IsUnallocated();
7065
    if (global_call) {
7066
      Variable* var = proxy->var();
7067
      bool known_global_function = false;
7068
      // If there is a global property cell for the name at compile time and
7069
      // access check is not enabled we assume that the function will not change
7070
      // and generate optimized code for calling the function.
7071
      LookupResult lookup(isolate());
7072
      GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false);
7073
      if (type == kUseCell &&
7074
          !current_info()->global_object()->IsAccessCheckNeeded()) {
7075
        Handle<GlobalObject> global(current_info()->global_object());
7076
        known_global_function = expr->ComputeGlobalTarget(global, &lookup);
7077
      }
7078
      if (known_global_function) {
7079
        // Push the global object instead of the global receiver because
7080
        // code generated by the full code generator expects it.
7081
        HGlobalObject* global_object = Add<HGlobalObject>();
7082
        Push(global_object);
7083
        CHECK_ALIVE(VisitExpressions(expr->arguments()));
7084

    
7085
        CHECK_ALIVE(VisitForValue(expr->expression()));
7086
        HValue* function = Pop();
7087
        Add<HCheckValue>(function, expr->target());
7088

    
7089
        // Replace the global object with the global receiver.
7090
        HGlobalReceiver* global_receiver = Add<HGlobalReceiver>(global_object);
7091
        // Index of the receiver from the top of the expression stack.
7092
        const int receiver_index = argument_count - 1;
7093
        ASSERT(environment()->ExpressionStackAt(receiver_index)->
7094
               IsGlobalObject());
7095
        environment()->SetExpressionStackAt(receiver_index, global_receiver);
7096

    
7097
        if (TryInlineBuiltinFunctionCall(expr, false)) {  // Nothing to drop.
7098
          if (FLAG_trace_inlining) {
7099
            PrintF("Inlining builtin ");
7100
            expr->target()->ShortPrint();
7101
            PrintF("\n");
7102
          }
7103
          return;
7104
        }
7105
        if (TryInlineCall(expr)) return;
7106

    
7107
        if (expr->target().is_identical_to(current_info()->closure())) {
7108
          graph()->MarkRecursive();
7109
        }
7110

    
7111
        if (CallStubCompiler::HasCustomCallGenerator(expr->target())) {
7112
          // When the target has a custom call IC generator, use the IC,
7113
          // because it is likely to generate better code.
7114
          call = PreProcessCall(New<HCallNamed>(var->name(), argument_count));
7115
        } else {
7116
          call = PreProcessCall(New<HCallKnownGlobal>(
7117
              expr->target(), argument_count));
7118
        }
7119
      } else {
7120
        HGlobalObject* receiver = Add<HGlobalObject>();
7121
        Push(Add<HPushArgument>(receiver));
7122
        CHECK_ALIVE(VisitArgumentList(expr->arguments()));
7123

    
7124
        call = New<HCallGlobal>(var->name(), argument_count);
7125
        Drop(argument_count);
7126
      }
7127

    
7128
    } else if (expr->IsMonomorphic()) {
7129
      // The function is on the stack in the unoptimized code during
7130
      // evaluation of the arguments.
7131
      CHECK_ALIVE(VisitForValue(expr->expression()));
7132
      HValue* function = Top();
7133
      HGlobalObject* global = Add<HGlobalObject>();
7134
      HGlobalReceiver* receiver = Add<HGlobalReceiver>(global);
7135
      Push(receiver);
7136
      CHECK_ALIVE(VisitExpressions(expr->arguments()));
7137
      Add<HCheckValue>(function, expr->target());
7138

    
7139
      if (TryInlineBuiltinFunctionCall(expr, true)) {  // Drop the function.
7140
        if (FLAG_trace_inlining) {
7141
          PrintF("Inlining builtin ");
7142
          expr->target()->ShortPrint();
7143
          PrintF("\n");
7144
        }
7145
        return;
7146
      }
7147

    
7148
      if (TryInlineCall(expr, true)) {   // Drop function from environment.
7149
        return;
7150
      } else {
7151
        call = PreProcessCall(New<HInvokeFunction>(function, expr->target(),
7152
                                                   argument_count));
7153
        Drop(1);  // The function.
7154
      }
7155

    
7156
    } else {
7157
      CHECK_ALIVE(VisitForValue(expr->expression()));
7158
      HValue* function = Top();
7159
      HGlobalObject* global_object = Add<HGlobalObject>();
7160
      HGlobalReceiver* receiver = Add<HGlobalReceiver>(global_object);
7161
      Push(Add<HPushArgument>(receiver));
7162
      CHECK_ALIVE(VisitArgumentList(expr->arguments()));
7163

    
7164
      call = New<HCallFunction>(function, argument_count);
7165
      Drop(argument_count + 1);
7166
    }
7167
  }
7168

    
7169
  return ast_context()->ReturnInstruction(call, expr->id());
7170
}
7171

    
7172

    
7173
// Checks whether allocation using the given constructor can be inlined.
7174
static bool IsAllocationInlineable(Handle<JSFunction> constructor) {
7175
  return constructor->has_initial_map() &&
7176
      constructor->initial_map()->instance_type() == JS_OBJECT_TYPE &&
7177
      constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize &&
7178
      constructor->initial_map()->InitialPropertiesLength() == 0;
7179
}
7180

    
7181

    
7182
void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
7183
  ASSERT(!HasStackOverflow());
7184
  ASSERT(current_block() != NULL);
7185
  ASSERT(current_block()->HasPredecessor());
7186
  if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
7187
  int argument_count = expr->arguments()->length() + 1;  // Plus constructor.
7188
  Factory* factory = isolate()->factory();
7189

    
7190
  if (FLAG_inline_construct &&
7191
      expr->IsMonomorphic() &&
7192
      IsAllocationInlineable(expr->target())) {
7193
    // The constructor function is on the stack in the unoptimized code
7194
    // during evaluation of the arguments.
7195
    CHECK_ALIVE(VisitForValue(expr->expression()));
7196
    HValue* function = Top();
7197
    CHECK_ALIVE(VisitExpressions(expr->arguments()));
7198
    Handle<JSFunction> constructor = expr->target();
7199
    HValue* check = Add<HCheckValue>(function, constructor);
7200

    
7201
    // Force completion of inobject slack tracking before generating
7202
    // allocation code to finalize instance size.
7203
    if (constructor->shared()->IsInobjectSlackTrackingInProgress()) {
7204
      constructor->shared()->CompleteInobjectSlackTracking();
7205
    }
7206

    
7207
    // Calculate instance size from initial map of constructor.
7208
    ASSERT(constructor->has_initial_map());
7209
    Handle<Map> initial_map(constructor->initial_map());
7210
    int instance_size = initial_map->instance_size();
7211
    ASSERT(initial_map->InitialPropertiesLength() == 0);
7212

    
7213
    // Allocate an instance of the implicit receiver object.
7214
    HValue* size_in_bytes = Add<HConstant>(instance_size);
7215
    PretenureFlag pretenure_flag =
7216
        (FLAG_pretenuring_call_new &&
7217
            isolate()->heap()->GetPretenureMode() == TENURED)
7218
                ? TENURED : NOT_TENURED;
7219
    HAllocate* receiver =
7220
        Add<HAllocate>(size_in_bytes, HType::JSObject(), pretenure_flag,
7221
        JS_OBJECT_TYPE);
7222
    receiver->set_known_initial_map(initial_map);
7223

    
7224
    // Load the initial map from the constructor.
7225
    HValue* constructor_value = Add<HConstant>(constructor);
7226
    HValue* initial_map_value =
7227
      Add<HLoadNamedField>(constructor_value, HObjectAccess::ForJSObjectOffset(
7228
            JSFunction::kPrototypeOrInitialMapOffset));
7229

    
7230
    // Initialize map and fields of the newly allocated object.
7231
    { NoObservableSideEffectsScope no_effects(this);
7232
      ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE);
7233
      Add<HStoreNamedField>(receiver,
7234
          HObjectAccess::ForJSObjectOffset(JSObject::kMapOffset),
7235
          initial_map_value);
7236
      HValue* empty_fixed_array = Add<HConstant>(factory->empty_fixed_array());
7237
      Add<HStoreNamedField>(receiver,
7238
          HObjectAccess::ForJSObjectOffset(JSObject::kPropertiesOffset),
7239
          empty_fixed_array);
7240
      Add<HStoreNamedField>(receiver,
7241
          HObjectAccess::ForJSObjectOffset(JSObject::kElementsOffset),
7242
          empty_fixed_array);
7243
      if (initial_map->inobject_properties() != 0) {
7244
        HConstant* undefined = graph()->GetConstantUndefined();
7245
        for (int i = 0; i < initial_map->inobject_properties(); i++) {
7246
          int property_offset = JSObject::kHeaderSize + i * kPointerSize;
7247
          Add<HStoreNamedField>(receiver,
7248
              HObjectAccess::ForJSObjectOffset(property_offset),
7249
              undefined);
7250
        }
7251
      }
7252
    }
7253

    
7254
    // Replace the constructor function with a newly allocated receiver using
7255
    // the index of the receiver from the top of the expression stack.
7256
    const int receiver_index = argument_count - 1;
7257
    ASSERT(environment()->ExpressionStackAt(receiver_index) == function);
7258
    environment()->SetExpressionStackAt(receiver_index, receiver);
7259

    
7260
    if (TryInlineConstruct(expr, receiver)) return;
7261

    
7262
    // TODO(mstarzinger): For now we remove the previous HAllocate and all
7263
    // corresponding instructions and instead add HPushArgument for the
7264
    // arguments in case inlining failed.  What we actually should do is for
7265
    // inlining to try to build a subgraph without mutating the parent graph.
7266
    HInstruction* instr = current_block()->last();
7267
    while (instr != initial_map_value) {
7268
      HInstruction* prev_instr = instr->previous();
7269
      instr->DeleteAndReplaceWith(NULL);
7270
      instr = prev_instr;
7271
    }
7272
    initial_map_value->DeleteAndReplaceWith(NULL);
7273
    receiver->DeleteAndReplaceWith(NULL);
7274
    check->DeleteAndReplaceWith(NULL);
7275
    environment()->SetExpressionStackAt(receiver_index, function);
7276
    HInstruction* call =
7277
      PreProcessCall(New<HCallNew>(function, argument_count));
7278
    return ast_context()->ReturnInstruction(call, expr->id());
7279
  } else {
7280
    // The constructor function is both an operand to the instruction and an
7281
    // argument to the construct call.
7282
    Handle<JSFunction> array_function(
7283
        isolate()->global_context()->array_function(), isolate());
7284
    CHECK_ALIVE(VisitArgument(expr->expression()));
7285
    HValue* constructor = HPushArgument::cast(Top())->argument();
7286
    CHECK_ALIVE(VisitArgumentList(expr->arguments()));
7287
    HBinaryCall* call;
7288
    if (expr->target().is_identical_to(array_function)) {
7289
      Handle<Cell> cell = expr->allocation_info_cell();
7290
      Add<HCheckValue>(constructor, array_function);
7291
      call = New<HCallNewArray>(constructor, argument_count,
7292
                                cell, expr->elements_kind());
7293
    } else {
7294
      call = New<HCallNew>(constructor, argument_count);
7295
    }
7296
    Drop(argument_count);
7297
    return ast_context()->ReturnInstruction(call, expr->id());
7298
  }
7299
}
7300

    
7301

    
7302
// Support for generating inlined runtime functions.
7303

    
7304
// Lookup table for generators for runtime calls that are generated inline.
7305
// Elements of the table are member pointers to functions of
7306
// HOptimizedGraphBuilder.
7307
#define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize)  \
7308
    &HOptimizedGraphBuilder::Generate##Name,
7309

    
7310
const HOptimizedGraphBuilder::InlineFunctionGenerator
7311
    HOptimizedGraphBuilder::kInlineFunctionGenerators[] = {
7312
        INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
7313
        INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
7314
};
7315
#undef INLINE_FUNCTION_GENERATOR_ADDRESS
7316

    
7317

    
7318
void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
7319
  ASSERT(!HasStackOverflow());
7320
  ASSERT(current_block() != NULL);
7321
  ASSERT(current_block()->HasPredecessor());
7322
  if (expr->is_jsruntime()) {
7323
    return Bailout(kCallToAJavaScriptRuntimeFunction);
7324
  }
7325

    
7326
  const Runtime::Function* function = expr->function();
7327
  ASSERT(function != NULL);
7328
  if (function->intrinsic_type == Runtime::INLINE) {
7329
    ASSERT(expr->name()->length() > 0);
7330
    ASSERT(expr->name()->Get(0) == '_');
7331
    // Call to an inline function.
7332
    int lookup_index = static_cast<int>(function->function_id) -
7333
        static_cast<int>(Runtime::kFirstInlineFunction);
7334
    ASSERT(lookup_index >= 0);
7335
    ASSERT(static_cast<size_t>(lookup_index) <
7336
           ARRAY_SIZE(kInlineFunctionGenerators));
7337
    InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index];
7338

    
7339
    // Call the inline code generator using the pointer-to-member.
7340
    (this->*generator)(expr);
7341
  } else {
7342
    ASSERT(function->intrinsic_type == Runtime::RUNTIME);
7343
    CHECK_ALIVE(VisitArgumentList(expr->arguments()));
7344

    
7345
    Handle<String> name = expr->name();
7346
    int argument_count = expr->arguments()->length();
7347
    HCallRuntime* call = New<HCallRuntime>(name, function,
7348
                                           argument_count);
7349
    Drop(argument_count);
7350
    return ast_context()->ReturnInstruction(call, expr->id());
7351
  }
7352
}
7353

    
7354

    
7355
void HOptimizedGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
7356
  ASSERT(!HasStackOverflow());
7357
  ASSERT(current_block() != NULL);
7358
  ASSERT(current_block()->HasPredecessor());
7359
  switch (expr->op()) {
7360
    case Token::DELETE: return VisitDelete(expr);
7361
    case Token::VOID: return VisitVoid(expr);
7362
    case Token::TYPEOF: return VisitTypeof(expr);
7363
    case Token::NOT: return VisitNot(expr);
7364
    default: UNREACHABLE();
7365
  }
7366
}
7367

    
7368

    
7369
void HOptimizedGraphBuilder::VisitDelete(UnaryOperation* expr) {
7370
  Property* prop = expr->expression()->AsProperty();
7371
  VariableProxy* proxy = expr->expression()->AsVariableProxy();
7372
  if (prop != NULL) {
7373
    CHECK_ALIVE(VisitForValue(prop->obj()));
7374
    CHECK_ALIVE(VisitForValue(prop->key()));
7375
    HValue* key = Pop();
7376
    HValue* obj = Pop();
7377
    HValue* function = AddLoadJSBuiltin(Builtins::DELETE);
7378
    Add<HPushArgument>(obj);
7379
    Add<HPushArgument>(key);
7380
    Add<HPushArgument>(Add<HConstant>(function_strict_mode_flag()));
7381
    // TODO(olivf) InvokeFunction produces a check for the parameter count,
7382
    // even though we are certain to pass the correct number of arguments here.
7383
    HInstruction* instr = New<HInvokeFunction>(function, 3);
7384
    return ast_context()->ReturnInstruction(instr, expr->id());
7385
  } else if (proxy != NULL) {
7386
    Variable* var = proxy->var();
7387
    if (var->IsUnallocated()) {
7388
      Bailout(kDeleteWithGlobalVariable);
7389
    } else if (var->IsStackAllocated() || var->IsContextSlot()) {
7390
      // Result of deleting non-global variables is false.  'this' is not
7391
      // really a variable, though we implement it as one.  The
7392
      // subexpression does not have side effects.
7393
      HValue* value = var->is_this()
7394
          ? graph()->GetConstantTrue()
7395
          : graph()->GetConstantFalse();
7396
      return ast_context()->ReturnValue(value);
7397
    } else {
7398
      Bailout(kDeleteWithNonGlobalVariable);
7399
    }
7400
  } else {
7401
    // Result of deleting non-property, non-variable reference is true.
7402
    // Evaluate the subexpression for side effects.
7403
    CHECK_ALIVE(VisitForEffect(expr->expression()));
7404
    return ast_context()->ReturnValue(graph()->GetConstantTrue());
7405
  }
7406
}
7407

    
7408

    
7409
void HOptimizedGraphBuilder::VisitVoid(UnaryOperation* expr) {
7410
  CHECK_ALIVE(VisitForEffect(expr->expression()));
7411
  return ast_context()->ReturnValue(graph()->GetConstantUndefined());
7412
}
7413

    
7414

    
7415
void HOptimizedGraphBuilder::VisitTypeof(UnaryOperation* expr) {
7416
  CHECK_ALIVE(VisitForTypeOf(expr->expression()));
7417
  HValue* value = Pop();
7418
  HInstruction* instr = New<HTypeof>(value);
7419
  return ast_context()->ReturnInstruction(instr, expr->id());
7420
}
7421

    
7422

    
7423
void HOptimizedGraphBuilder::VisitNot(UnaryOperation* expr) {
7424
  if (ast_context()->IsTest()) {
7425
    TestContext* context = TestContext::cast(ast_context());
7426
    VisitForControl(expr->expression(),
7427
                    context->if_false(),
7428
                    context->if_true());
7429
    return;
7430
  }
7431

    
7432
  if (ast_context()->IsEffect()) {
7433
    VisitForEffect(expr->expression());
7434
    return;
7435
  }
7436

    
7437
  ASSERT(ast_context()->IsValue());
7438
  HBasicBlock* materialize_false = graph()->CreateBasicBlock();
7439
  HBasicBlock* materialize_true = graph()->CreateBasicBlock();
7440
  CHECK_BAILOUT(VisitForControl(expr->expression(),
7441
                                materialize_false,
7442
                                materialize_true));
7443

    
7444
  if (materialize_false->HasPredecessor()) {
7445
    materialize_false->SetJoinId(expr->MaterializeFalseId());
7446
    set_current_block(materialize_false);
7447
    Push(graph()->GetConstantFalse());
7448
  } else {
7449
    materialize_false = NULL;
7450
  }
7451

    
7452
  if (materialize_true->HasPredecessor()) {
7453
    materialize_true->SetJoinId(expr->MaterializeTrueId());
7454
    set_current_block(materialize_true);
7455
    Push(graph()->GetConstantTrue());
7456
  } else {
7457
    materialize_true = NULL;
7458
  }
7459

    
7460
  HBasicBlock* join =
7461
    CreateJoin(materialize_false, materialize_true, expr->id());
7462
  set_current_block(join);
7463
  if (join != NULL) return ast_context()->ReturnValue(Pop());
7464
}
7465

    
7466

    
7467
HInstruction* HOptimizedGraphBuilder::BuildIncrement(
7468
    bool returns_original_input,
7469
    CountOperation* expr) {
7470
  // The input to the count operation is on top of the expression stack.
7471
  Handle<Type> info = expr->type();
7472
  Representation rep = Representation::FromType(info);
7473
  if (rep.IsNone() || rep.IsTagged()) {
7474
    rep = Representation::Smi();
7475
  }
7476

    
7477
  if (returns_original_input) {
7478
    // We need an explicit HValue representing ToNumber(input).  The
7479
    // actual HChange instruction we need is (sometimes) added in a later
7480
    // phase, so it is not available now to be used as an input to HAdd and
7481
    // as the return value.
7482
    HInstruction* number_input = Add<HForceRepresentation>(Pop(), rep);
7483
    if (!rep.IsDouble()) {
7484
      number_input->SetFlag(HInstruction::kFlexibleRepresentation);
7485
      number_input->SetFlag(HInstruction::kCannotBeTagged);
7486
    }
7487
    Push(number_input);
7488
  }
7489

    
7490
  // The addition has no side effects, so we do not need
7491
  // to simulate the expression stack after this instruction.
7492
  // Any later failures deopt to the load of the input or earlier.
7493
  HConstant* delta = (expr->op() == Token::INC)
7494
      ? graph()->GetConstant1()
7495
      : graph()->GetConstantMinus1();
7496
  HInstruction* instr = AddUncasted<HAdd>(Top(), delta);
7497
  if (instr->IsAdd()) {
7498
    HAdd* add = HAdd::cast(instr);
7499
    add->set_observed_input_representation(1, rep);
7500
    add->set_observed_input_representation(2, Representation::Smi());
7501
  }
7502
  instr->SetFlag(HInstruction::kCannotBeTagged);
7503
  instr->ClearAllSideEffects();
7504
  return instr;
7505
}
7506

    
7507

    
7508
void HOptimizedGraphBuilder::BuildStoreForEffect(Expression* expr,
7509
                                                 Property* prop,
7510
                                                 BailoutId ast_id,
7511
                                                 BailoutId return_id,
7512
                                                 HValue* object,
7513
                                                 HValue* key,
7514
                                                 HValue* value) {
7515
  EffectContext for_effect(this);
7516
  Push(object);
7517
  if (key != NULL) Push(key);
7518
  Push(value);
7519
  BuildStore(expr, prop, ast_id, return_id);
7520
}
7521

    
7522

    
7523
void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
7524
  ASSERT(!HasStackOverflow());
7525
  ASSERT(current_block() != NULL);
7526
  ASSERT(current_block()->HasPredecessor());
7527
  if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
7528
  Expression* target = expr->expression();
7529
  VariableProxy* proxy = target->AsVariableProxy();
7530
  Property* prop = target->AsProperty();
7531
  if (proxy == NULL && prop == NULL) {
7532
    return Bailout(kInvalidLhsInCountOperation);
7533
  }
7534

    
7535
  // Match the full code generator stack by simulating an extra stack
7536
  // element for postfix operations in a non-effect context.  The return
7537
  // value is ToNumber(input).
7538
  bool returns_original_input =
7539
      expr->is_postfix() && !ast_context()->IsEffect();
7540
  HValue* input = NULL;  // ToNumber(original_input).
7541
  HValue* after = NULL;  // The result after incrementing or decrementing.
7542

    
7543
  if (proxy != NULL) {
7544
    Variable* var = proxy->var();
7545
    if (var->mode() == CONST)  {
7546
      return Bailout(kUnsupportedCountOperationWithConst);
7547
    }
7548
    // Argument of the count operation is a variable, not a property.
7549
    ASSERT(prop == NULL);
7550
    CHECK_ALIVE(VisitForValue(target));
7551

    
7552
    after = BuildIncrement(returns_original_input, expr);
7553
    input = returns_original_input ? Top() : Pop();
7554
    Push(after);
7555

    
7556
    switch (var->location()) {
7557
      case Variable::UNALLOCATED:
7558
        HandleGlobalVariableAssignment(var,
7559
                                       after,
7560
                                       expr->AssignmentId());
7561
        break;
7562

    
7563
      case Variable::PARAMETER:
7564
      case Variable::LOCAL:
7565
        BindIfLive(var, after);
7566
        break;
7567

    
7568
      case Variable::CONTEXT: {
7569
        // Bail out if we try to mutate a parameter value in a function
7570
        // using the arguments object.  We do not (yet) correctly handle the
7571
        // arguments property of the function.
7572
        if (current_info()->scope()->arguments() != NULL) {
7573
          // Parameters will rewrite to context slots.  We have no direct
7574
          // way to detect that the variable is a parameter so we use a
7575
          // linear search of the parameter list.
7576
          int count = current_info()->scope()->num_parameters();
7577
          for (int i = 0; i < count; ++i) {
7578
            if (var == current_info()->scope()->parameter(i)) {
7579
              return Bailout(kAssignmentToParameterInArgumentsObject);
7580
            }
7581
          }
7582
        }
7583

    
7584
        HValue* context = BuildContextChainWalk(var);
7585
        HStoreContextSlot::Mode mode = IsLexicalVariableMode(var->mode())
7586
            ? HStoreContextSlot::kCheckDeoptimize : HStoreContextSlot::kNoCheck;
7587
        HStoreContextSlot* instr = Add<HStoreContextSlot>(context, var->index(),
7588
                                                          mode, after);
7589
        if (instr->HasObservableSideEffects()) {
7590
          Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
7591
        }
7592
        break;
7593
      }
7594

    
7595
      case Variable::LOOKUP:
7596
        return Bailout(kLookupVariableInCountOperation);
7597
    }
7598

    
7599
    Drop(returns_original_input ? 2 : 1);
7600
    return ast_context()->ReturnValue(expr->is_postfix() ? input : after);
7601
  }
7602

    
7603
  // Argument of the count operation is a property.
7604
  ASSERT(prop != NULL);
7605
  if (returns_original_input) Push(graph()->GetConstantUndefined());
7606

    
7607
  CHECK_ALIVE(VisitForValue(prop->obj()));
7608
  HValue* object = Top();
7609

    
7610
  HValue* key = NULL;
7611
  if ((!prop->IsFunctionPrototype() && !prop->key()->IsPropertyName()) ||
7612
      prop->IsStringAccess()) {
7613
    CHECK_ALIVE(VisitForValue(prop->key()));
7614
    key = Top();
7615
  }
7616

    
7617
  CHECK_ALIVE(PushLoad(prop, object, key));
7618

    
7619
  after = BuildIncrement(returns_original_input, expr);
7620

    
7621
  if (returns_original_input) {
7622
    input = Pop();
7623
    // Drop object and key to push it again in the effect context below.
7624
    Drop(key == NULL ? 1 : 2);
7625
    environment()->SetExpressionStackAt(0, input);
7626
    CHECK_ALIVE(BuildStoreForEffect(
7627
        expr, prop, expr->id(), expr->AssignmentId(), object, key, after));
7628
    return ast_context()->ReturnValue(Pop());
7629
  }
7630

    
7631
  environment()->SetExpressionStackAt(0, after);
7632
  return BuildStore(expr, prop, expr->id(), expr->AssignmentId());
7633
}
7634

    
7635

    
7636
HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt(
7637
    HValue* string,
7638
    HValue* index) {
7639
  if (string->IsConstant() && index->IsConstant()) {
7640
    HConstant* c_string = HConstant::cast(string);
7641
    HConstant* c_index = HConstant::cast(index);
7642
    if (c_string->HasStringValue() && c_index->HasNumberValue()) {
7643
      int32_t i = c_index->NumberValueAsInteger32();
7644
      Handle<String> s = c_string->StringValue();
7645
      if (i < 0 || i >= s->length()) {
7646
        return New<HConstant>(OS::nan_value());
7647
      }
7648
      return New<HConstant>(s->Get(i));
7649
    }
7650
  }
7651
  BuildCheckHeapObject(string);
7652
  HValue* checkstring =
7653
      Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING);
7654
  HInstruction* length = BuildLoadStringLength(string, checkstring);
7655
  AddInstruction(length);
7656
  HInstruction* checked_index = Add<HBoundsCheck>(index, length);
7657
  return New<HStringCharCodeAt>(string, checked_index);
7658
}
7659

    
7660

    
7661
// Checks if the given shift amounts have following forms:
7662
// (N1) and (N2) with N1 + N2 = 32; (sa) and (32 - sa).
7663
static bool ShiftAmountsAllowReplaceByRotate(HValue* sa,
7664
                                             HValue* const32_minus_sa) {
7665
  if (sa->IsConstant() && const32_minus_sa->IsConstant()) {
7666
    const HConstant* c1 = HConstant::cast(sa);
7667
    const HConstant* c2 = HConstant::cast(const32_minus_sa);
7668
    return c1->HasInteger32Value() && c2->HasInteger32Value() &&
7669
        (c1->Integer32Value() + c2->Integer32Value() == 32);
7670
  }
7671
  if (!const32_minus_sa->IsSub()) return false;
7672
  HSub* sub = HSub::cast(const32_minus_sa);
7673
  if (sa != sub->right()) return false;
7674
  HValue* const32 = sub->left();
7675
  if (!const32->IsConstant() ||
7676
      HConstant::cast(const32)->Integer32Value() != 32) {
7677
    return false;
7678
  }
7679
  return (sub->right() == sa);
7680
}
7681

    
7682

    
7683
// Checks if the left and the right are shift instructions with the oposite
7684
// directions that can be replaced by one rotate right instruction or not.
7685
// Returns the operand and the shift amount for the rotate instruction in the
7686
// former case.
7687
bool HGraphBuilder::MatchRotateRight(HValue* left,
7688
                                     HValue* right,
7689
                                     HValue** operand,
7690
                                     HValue** shift_amount) {
7691
  HShl* shl;
7692
  HShr* shr;
7693
  if (left->IsShl() && right->IsShr()) {
7694
    shl = HShl::cast(left);
7695
    shr = HShr::cast(right);
7696
  } else if (left->IsShr() && right->IsShl()) {
7697
    shl = HShl::cast(right);
7698
    shr = HShr::cast(left);
7699
  } else {
7700
    return false;
7701
  }
7702
  if (shl->left() != shr->left()) return false;
7703

    
7704
  if (!ShiftAmountsAllowReplaceByRotate(shl->right(), shr->right()) &&
7705
      !ShiftAmountsAllowReplaceByRotate(shr->right(), shl->right())) {
7706
    return false;
7707
  }
7708
  *operand= shr->left();
7709
  *shift_amount = shr->right();
7710
  return true;
7711
}
7712

    
7713

    
7714
bool CanBeZero(HValue* right) {
7715
  if (right->IsConstant()) {
7716
    HConstant* right_const = HConstant::cast(right);
7717
    if (right_const->HasInteger32Value() &&
7718
       (right_const->Integer32Value() & 0x1f) != 0) {
7719
      return false;
7720
    }
7721
  }
7722
  return true;
7723
}
7724

    
7725

    
7726
HValue* HGraphBuilder::EnforceNumberType(HValue* number,
7727
                                         Handle<Type> expected) {
7728
  if (expected->Is(Type::Smi())) {
7729
    return Add<HForceRepresentation>(number, Representation::Smi());
7730
  }
7731
  if (expected->Is(Type::Signed32())) {
7732
    return Add<HForceRepresentation>(number, Representation::Integer32());
7733
  }
7734
  return number;
7735
}
7736

    
7737

    
7738
HValue* HGraphBuilder::TruncateToNumber(HValue* value, Handle<Type>* expected) {
7739
  if (value->IsConstant()) {
7740
    HConstant* constant = HConstant::cast(value);
7741
    Maybe<HConstant*> number = constant->CopyToTruncatedNumber(zone());
7742
    if (number.has_value) {
7743
      *expected = handle(Type::Number(), isolate());
7744
      return AddInstruction(number.value);
7745
    }
7746
  }
7747

    
7748
  // We put temporary values on the stack, which don't correspond to anything
7749
  // in baseline code. Since nothing is observable we avoid recording those
7750
  // pushes with a NoObservableSideEffectsScope.
7751
  NoObservableSideEffectsScope no_effects(this);
7752

    
7753
  Handle<Type> expected_type = *expected;
7754

    
7755
  // Separate the number type from the rest.
7756
  Handle<Type> expected_obj = handle(Type::Intersect(
7757
      expected_type, handle(Type::NonNumber(), isolate())), isolate());
7758
  Handle<Type> expected_number = handle(Type::Intersect(
7759
      expected_type, handle(Type::Number(), isolate())), isolate());
7760

    
7761
  // We expect to get a number.
7762
  // (We need to check first, since Type::None->Is(Type::Any()) == true.
7763
  if (expected_obj->Is(Type::None())) {
7764
    ASSERT(!expected_number->Is(Type::None()));
7765
    return value;
7766
  }
7767

    
7768
  if (expected_obj->Is(Type::Undefined())) {
7769
    // This is already done by HChange.
7770
    *expected = handle(Type::Union(
7771
          expected_number, handle(Type::Double(), isolate())), isolate());
7772
    return value;
7773
  }
7774

    
7775
  return value;
7776
}
7777

    
7778

    
7779
HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation(
7780
    BinaryOperation* expr,
7781
    HValue* left,
7782
    HValue* right) {
7783
  Handle<Type> left_type = expr->left()->bounds().lower;
7784
  Handle<Type> right_type = expr->right()->bounds().lower;
7785
  Handle<Type> result_type = expr->bounds().lower;
7786
  Maybe<int> fixed_right_arg = expr->fixed_right_arg();
7787

    
7788
  return HGraphBuilder::BuildBinaryOperation(expr->op(), left, right,
7789
      left_type, right_type, result_type, fixed_right_arg);
7790
}
7791

    
7792

    
7793
HInstruction* HGraphBuilder::BuildBinaryOperation(
7794
    Token::Value op,
7795
    HValue* left,
7796
    HValue* right,
7797
    Handle<Type> left_type,
7798
    Handle<Type> right_type,
7799
    Handle<Type> result_type,
7800
    Maybe<int> fixed_right_arg,
7801
    bool binop_stub) {
7802

    
7803
  Representation left_rep = Representation::FromType(left_type);
7804
  Representation right_rep = Representation::FromType(right_type);
7805

    
7806
  bool maybe_string_add = op == Token::ADD &&
7807
                          (left_type->Maybe(Type::String()) ||
7808
                           right_type->Maybe(Type::String()));
7809

    
7810
  if (left_type->Is(Type::None())) {
7811
    Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation",
7812
                     Deoptimizer::SOFT);
7813
    // TODO(rossberg): we should be able to get rid of non-continuous
7814
    // defaults.
7815
    left_type = handle(Type::Any(), isolate());
7816
  } else {
7817
    if (!maybe_string_add) left = TruncateToNumber(left, &left_type);
7818
    left_rep = Representation::FromType(left_type);
7819
  }
7820

    
7821
  if (right_type->Is(Type::None())) {
7822
    Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation",
7823
                     Deoptimizer::SOFT);
7824
    right_type = handle(Type::Any(), isolate());
7825
  } else {
7826
    if (!maybe_string_add) right = TruncateToNumber(right, &right_type);
7827
    right_rep = Representation::FromType(right_type);
7828
  }
7829

    
7830
  // Special case for string addition here.
7831
  if (op == Token::ADD &&
7832
      (left_type->Is(Type::String()) || right_type->Is(Type::String()))) {
7833
    if (left_type->Is(Type::String())) {
7834
      IfBuilder if_isstring(this);
7835
      if_isstring.If<HIsStringAndBranch>(left);
7836
      if_isstring.Then();
7837
      if_isstring.ElseDeopt("Expected string for LHS of binary operation");
7838
    } else if (left_type->Is(Type::Number())) {
7839
      left = BuildNumberToString(left, left_type);
7840
    } else {
7841
      ASSERT(right_type->Is(Type::String()));
7842
      HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_RIGHT);
7843
      Add<HPushArgument>(left);
7844
      Add<HPushArgument>(right);
7845
      return NewUncasted<HInvokeFunction>(function, 2);
7846
    }
7847

    
7848
    if (right_type->Is(Type::String())) {
7849
      IfBuilder if_isstring(this);
7850
      if_isstring.If<HIsStringAndBranch>(right);
7851
      if_isstring.Then();
7852
      if_isstring.ElseDeopt("Expected string for RHS of binary operation");
7853
    } else if (right_type->Is(Type::Number())) {
7854
      right = BuildNumberToString(right, right_type);
7855
    } else {
7856
      ASSERT(left_type->Is(Type::String()));
7857
      HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT);
7858
      Add<HPushArgument>(left);
7859
      Add<HPushArgument>(right);
7860
      return NewUncasted<HInvokeFunction>(function, 2);
7861
    }
7862

    
7863
    return NewUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_NONE);
7864
  }
7865

    
7866
  if (binop_stub) {
7867
    left = EnforceNumberType(left, left_type);
7868
    right = EnforceNumberType(right, right_type);
7869
  }
7870

    
7871
  Representation result_rep = Representation::FromType(result_type);
7872

    
7873
  bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) ||
7874
                          (right_rep.IsTagged() && !right_rep.IsSmi());
7875

    
7876
  HInstruction* instr = NULL;
7877
  // Only the stub is allowed to call into the runtime, since otherwise we would
7878
  // inline several instructions (including the two pushes) for every tagged
7879
  // operation in optimized code, which is more expensive, than a stub call.
7880
  if (binop_stub && is_non_primitive) {
7881
    HValue* function = AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op));
7882
    Add<HPushArgument>(left);
7883
    Add<HPushArgument>(right);
7884
    instr = NewUncasted<HInvokeFunction>(function, 2);
7885
  } else {
7886
    switch (op) {
7887
      case Token::ADD:
7888
        instr = NewUncasted<HAdd>(left, right);
7889
        break;
7890
      case Token::SUB:
7891
        instr = NewUncasted<HSub>(left, right);
7892
        break;
7893
      case Token::MUL:
7894
        instr = NewUncasted<HMul>(left, right);
7895
        break;
7896
      case Token::MOD:
7897
        instr = NewUncasted<HMod>(left, right, fixed_right_arg);
7898
        break;
7899
      case Token::DIV:
7900
        instr = NewUncasted<HDiv>(left, right);
7901
        break;
7902
      case Token::BIT_XOR:
7903
      case Token::BIT_AND:
7904
        instr = NewUncasted<HBitwise>(op, left, right);
7905
        break;
7906
      case Token::BIT_OR: {
7907
        HValue* operand, *shift_amount;
7908
        if (left_type->Is(Type::Signed32()) &&
7909
            right_type->Is(Type::Signed32()) &&
7910
            MatchRotateRight(left, right, &operand, &shift_amount)) {
7911
          instr = NewUncasted<HRor>(operand, shift_amount);
7912
        } else {
7913
          instr = NewUncasted<HBitwise>(op, left, right);
7914
        }
7915
        break;
7916
      }
7917
      case Token::SAR:
7918
        instr = NewUncasted<HSar>(left, right);
7919
        break;
7920
      case Token::SHR:
7921
        instr = NewUncasted<HShr>(left, right);
7922
        if (FLAG_opt_safe_uint32_operations && instr->IsShr() &&
7923
            CanBeZero(right)) {
7924
          graph()->RecordUint32Instruction(instr);
7925
        }
7926
        break;
7927
      case Token::SHL:
7928
        instr = NewUncasted<HShl>(left, right);
7929
        break;
7930
      default:
7931
        UNREACHABLE();
7932
    }
7933
  }
7934

    
7935
  if (instr->IsBinaryOperation()) {
7936
    HBinaryOperation* binop = HBinaryOperation::cast(instr);
7937
    binop->set_observed_input_representation(1, left_rep);
7938
    binop->set_observed_input_representation(2, right_rep);
7939
    binop->initialize_output_representation(result_rep);
7940
    if (binop_stub) {
7941
      // Stub should not call into stub.
7942
      instr->SetFlag(HValue::kCannotBeTagged);
7943
      // And should truncate on HForceRepresentation already.
7944
      if (left->IsForceRepresentation()) {
7945
        left->CopyFlag(HValue::kTruncatingToSmi, instr);
7946
        left->CopyFlag(HValue::kTruncatingToInt32, instr);
7947
      }
7948
      if (right->IsForceRepresentation()) {
7949
        right->CopyFlag(HValue::kTruncatingToSmi, instr);
7950
        right->CopyFlag(HValue::kTruncatingToInt32, instr);
7951
      }
7952
    }
7953
  }
7954
  return instr;
7955
}
7956

    
7957

    
7958
// Check for the form (%_ClassOf(foo) === 'BarClass').
7959
static bool IsClassOfTest(CompareOperation* expr) {
7960
  if (expr->op() != Token::EQ_STRICT) return false;
7961
  CallRuntime* call = expr->left()->AsCallRuntime();
7962
  if (call == NULL) return false;
7963
  Literal* literal = expr->right()->AsLiteral();
7964
  if (literal == NULL) return false;
7965
  if (!literal->value()->IsString()) return false;
7966
  if (!call->name()->IsOneByteEqualTo(STATIC_ASCII_VECTOR("_ClassOf"))) {
7967
    return false;
7968
  }
7969
  ASSERT(call->arguments()->length() == 1);
7970
  return true;
7971
}
7972

    
7973

    
7974
void HOptimizedGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
7975
  ASSERT(!HasStackOverflow());
7976
  ASSERT(current_block() != NULL);
7977
  ASSERT(current_block()->HasPredecessor());
7978
  switch (expr->op()) {
7979
    case Token::COMMA:
7980
      return VisitComma(expr);
7981
    case Token::OR:
7982
    case Token::AND:
7983
      return VisitLogicalExpression(expr);
7984
    default:
7985
      return VisitArithmeticExpression(expr);
7986
  }
7987
}
7988

    
7989

    
7990
void HOptimizedGraphBuilder::VisitComma(BinaryOperation* expr) {
7991
  CHECK_ALIVE(VisitForEffect(expr->left()));
7992
  // Visit the right subexpression in the same AST context as the entire
7993
  // expression.
7994
  Visit(expr->right());
7995
}
7996

    
7997

    
7998
void HOptimizedGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
7999
  bool is_logical_and = expr->op() == Token::AND;
8000
  if (ast_context()->IsTest()) {
8001
    TestContext* context = TestContext::cast(ast_context());
8002
    // Translate left subexpression.
8003
    HBasicBlock* eval_right = graph()->CreateBasicBlock();
8004
    if (is_logical_and) {
8005
      CHECK_BAILOUT(VisitForControl(expr->left(),
8006
                                    eval_right,
8007
                                    context->if_false()));
8008
    } else {
8009
      CHECK_BAILOUT(VisitForControl(expr->left(),
8010
                                    context->if_true(),
8011
                                    eval_right));
8012
    }
8013

    
8014
    // Translate right subexpression by visiting it in the same AST
8015
    // context as the entire expression.
8016
    if (eval_right->HasPredecessor()) {
8017
      eval_right->SetJoinId(expr->RightId());
8018
      set_current_block(eval_right);
8019
      Visit(expr->right());
8020
    }
8021

    
8022
  } else if (ast_context()->IsValue()) {
8023
    CHECK_ALIVE(VisitForValue(expr->left()));
8024
    ASSERT(current_block() != NULL);
8025
    HValue* left_value = Top();
8026

    
8027
    if (left_value->IsConstant()) {
8028
      HConstant* left_constant = HConstant::cast(left_value);
8029
      if ((is_logical_and && left_constant->BooleanValue()) ||
8030
          (!is_logical_and && !left_constant->BooleanValue())) {
8031
        Drop(1);  // left_value.
8032
        CHECK_ALIVE(VisitForValue(expr->right()));
8033
      }
8034
      return ast_context()->ReturnValue(Pop());
8035
    }
8036

    
8037
    // We need an extra block to maintain edge-split form.
8038
    HBasicBlock* empty_block = graph()->CreateBasicBlock();
8039
    HBasicBlock* eval_right = graph()->CreateBasicBlock();
8040
    ToBooleanStub::Types expected(expr->left()->to_boolean_types());
8041
    HBranch* test = is_logical_and
8042
        ? New<HBranch>(left_value, expected, eval_right, empty_block)
8043
        : New<HBranch>(left_value, expected, empty_block, eval_right);
8044
    FinishCurrentBlock(test);
8045

    
8046
    set_current_block(eval_right);
8047
    Drop(1);  // Value of the left subexpression.
8048
    CHECK_BAILOUT(VisitForValue(expr->right()));
8049

    
8050
    HBasicBlock* join_block =
8051
      CreateJoin(empty_block, current_block(), expr->id());
8052
    set_current_block(join_block);
8053
    return ast_context()->ReturnValue(Pop());
8054

    
8055
  } else {
8056
    ASSERT(ast_context()->IsEffect());
8057
    // In an effect context, we don't need the value of the left subexpression,
8058
    // only its control flow and side effects.  We need an extra block to
8059
    // maintain edge-split form.
8060
    HBasicBlock* empty_block = graph()->CreateBasicBlock();
8061
    HBasicBlock* right_block = graph()->CreateBasicBlock();
8062
    if (is_logical_and) {
8063
      CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block));
8064
    } else {
8065
      CHECK_BAILOUT(VisitForControl(expr->left(), empty_block, right_block));
8066
    }
8067

    
8068
    // TODO(kmillikin): Find a way to fix this.  It's ugly that there are
8069
    // actually two empty blocks (one here and one inserted by
8070
    // TestContext::BuildBranch, and that they both have an HSimulate though the
8071
    // second one is not a merge node, and that we really have no good AST ID to
8072
    // put on that first HSimulate.
8073

    
8074
    if (empty_block->HasPredecessor()) {
8075
      empty_block->SetJoinId(expr->id());
8076
    } else {
8077
      empty_block = NULL;
8078
    }
8079

    
8080
    if (right_block->HasPredecessor()) {
8081
      right_block->SetJoinId(expr->RightId());
8082
      set_current_block(right_block);
8083
      CHECK_BAILOUT(VisitForEffect(expr->right()));
8084
      right_block = current_block();
8085
    } else {
8086
      right_block = NULL;
8087
    }
8088

    
8089
    HBasicBlock* join_block =
8090
      CreateJoin(empty_block, right_block, expr->id());
8091
    set_current_block(join_block);
8092
    // We did not materialize any value in the predecessor environments,
8093
    // so there is no need to handle it here.
8094
  }
8095
}
8096

    
8097

    
8098
void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) {
8099
  CHECK_ALIVE(VisitForValue(expr->left()));
8100
  CHECK_ALIVE(VisitForValue(expr->right()));
8101
  if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
8102
  HValue* right = Pop();
8103
  HValue* left = Pop();
8104
  HInstruction* instr = BuildBinaryOperation(expr, left, right);
8105
  return ast_context()->ReturnInstruction(instr, expr->id());
8106
}
8107

    
8108

    
8109
void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr,
8110
                                                        Expression* sub_expr,
8111
                                                        Handle<String> check) {
8112
  CHECK_ALIVE(VisitForTypeOf(sub_expr));
8113
  if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
8114
  HValue* value = Pop();
8115
  HTypeofIsAndBranch* instr = New<HTypeofIsAndBranch>(value, check);
8116
  return ast_context()->ReturnControl(instr, expr->id());
8117
}
8118

    
8119

    
8120
static bool IsLiteralCompareBool(Isolate* isolate,
8121
                                 HValue* left,
8122
                                 Token::Value op,
8123
                                 HValue* right) {
8124
  return op == Token::EQ_STRICT &&
8125
      ((left->IsConstant() &&
8126
          HConstant::cast(left)->handle(isolate)->IsBoolean()) ||
8127
       (right->IsConstant() &&
8128
           HConstant::cast(right)->handle(isolate)->IsBoolean()));
8129
}
8130

    
8131

    
8132
void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
8133
  ASSERT(!HasStackOverflow());
8134
  ASSERT(current_block() != NULL);
8135
  ASSERT(current_block()->HasPredecessor());
8136

    
8137
  if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
8138

    
8139
  // Check for a few fast cases. The AST visiting behavior must be in sync
8140
  // with the full codegen: We don't push both left and right values onto
8141
  // the expression stack when one side is a special-case literal.
8142
  Expression* sub_expr = NULL;
8143
  Handle<String> check;
8144
  if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
8145
    return HandleLiteralCompareTypeof(expr, sub_expr, check);
8146
  }
8147
  if (expr->IsLiteralCompareUndefined(&sub_expr, isolate())) {
8148
    return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue);
8149
  }
8150
  if (expr->IsLiteralCompareNull(&sub_expr)) {
8151
    return HandleLiteralCompareNil(expr, sub_expr, kNullValue);
8152
  }
8153

    
8154
  if (IsClassOfTest(expr)) {
8155
    CallRuntime* call = expr->left()->AsCallRuntime();
8156
    ASSERT(call->arguments()->length() == 1);
8157
    CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8158
    HValue* value = Pop();
8159
    Literal* literal = expr->right()->AsLiteral();
8160
    Handle<String> rhs = Handle<String>::cast(literal->value());
8161
    HClassOfTestAndBranch* instr = New<HClassOfTestAndBranch>(value, rhs);
8162
    return ast_context()->ReturnControl(instr, expr->id());
8163
  }
8164

    
8165
  Handle<Type> left_type = expr->left()->bounds().lower;
8166
  Handle<Type> right_type = expr->right()->bounds().lower;
8167
  Handle<Type> combined_type = expr->combined_type();
8168
  Representation combined_rep = Representation::FromType(combined_type);
8169
  Representation left_rep = Representation::FromType(left_type);
8170
  Representation right_rep = Representation::FromType(right_type);
8171

    
8172
  CHECK_ALIVE(VisitForValue(expr->left()));
8173
  CHECK_ALIVE(VisitForValue(expr->right()));
8174

    
8175
  HValue* right = Pop();
8176
  HValue* left = Pop();
8177
  Token::Value op = expr->op();
8178

    
8179
  if (IsLiteralCompareBool(isolate(), left, op, right)) {
8180
    HCompareObjectEqAndBranch* result =
8181
        New<HCompareObjectEqAndBranch>(left, right);
8182
    return ast_context()->ReturnControl(result, expr->id());
8183
  }
8184

    
8185
  if (op == Token::INSTANCEOF) {
8186
    // Check to see if the rhs of the instanceof is a global function not
8187
    // residing in new space. If it is we assume that the function will stay the
8188
    // same.
8189
    Handle<JSFunction> target = Handle<JSFunction>::null();
8190
    VariableProxy* proxy = expr->right()->AsVariableProxy();
8191
    bool global_function = (proxy != NULL) && proxy->var()->IsUnallocated();
8192
    if (global_function &&
8193
        current_info()->has_global_object() &&
8194
        !current_info()->global_object()->IsAccessCheckNeeded()) {
8195
      Handle<String> name = proxy->name();
8196
      Handle<GlobalObject> global(current_info()->global_object());
8197
      LookupResult lookup(isolate());
8198
      global->Lookup(*name, &lookup);
8199
      if (lookup.IsNormal() && lookup.GetValue()->IsJSFunction()) {
8200
        Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue()));
8201
        // If the function is in new space we assume it's more likely to
8202
        // change and thus prefer the general IC code.
8203
        if (!isolate()->heap()->InNewSpace(*candidate)) {
8204
          target = candidate;
8205
        }
8206
      }
8207
    }
8208

    
8209
    // If the target is not null we have found a known global function that is
8210
    // assumed to stay the same for this instanceof.
8211
    if (target.is_null()) {
8212
      HInstanceOf* result = New<HInstanceOf>(left, right);
8213
      return ast_context()->ReturnInstruction(result, expr->id());
8214
    } else {
8215
      Add<HCheckValue>(right, target);
8216
      HInstanceOfKnownGlobal* result =
8217
        New<HInstanceOfKnownGlobal>(left, target);
8218
      return ast_context()->ReturnInstruction(result, expr->id());
8219
    }
8220

    
8221
    // Code below assumes that we don't fall through.
8222
    UNREACHABLE();
8223
  } else if (op == Token::IN) {
8224
    HValue* function = AddLoadJSBuiltin(Builtins::IN);
8225
    Add<HPushArgument>(left);
8226
    Add<HPushArgument>(right);
8227
    // TODO(olivf) InvokeFunction produces a check for the parameter count,
8228
    // even though we are certain to pass the correct number of arguments here.
8229
    HInstruction* result = New<HInvokeFunction>(function, 2);
8230
    return ast_context()->ReturnInstruction(result, expr->id());
8231
  }
8232

    
8233
  // Cases handled below depend on collected type feedback. They should
8234
  // soft deoptimize when there is no type feedback.
8235
  if (combined_type->Is(Type::None())) {
8236
    Add<HDeoptimize>("Insufficient type feedback for combined type "
8237
                     "of binary operation",
8238
                     Deoptimizer::SOFT);
8239
    combined_type = left_type = right_type = handle(Type::Any(), isolate());
8240
  }
8241

    
8242
  if (combined_type->Is(Type::Receiver())) {
8243
    switch (op) {
8244
      case Token::EQ:
8245
      case Token::EQ_STRICT: {
8246
        // Can we get away with map check and not instance type check?
8247
        if (combined_type->IsClass()) {
8248
          Handle<Map> map = combined_type->AsClass();
8249
          AddCheckMap(left, map);
8250
          AddCheckMap(right, map);
8251
          HCompareObjectEqAndBranch* result =
8252
              New<HCompareObjectEqAndBranch>(left, right);
8253
          return ast_context()->ReturnControl(result, expr->id());
8254
        } else {
8255
          BuildCheckHeapObject(left);
8256
          Add<HCheckInstanceType>(left, HCheckInstanceType::IS_SPEC_OBJECT);
8257
          BuildCheckHeapObject(right);
8258
          Add<HCheckInstanceType>(right, HCheckInstanceType::IS_SPEC_OBJECT);
8259
          HCompareObjectEqAndBranch* result =
8260
              New<HCompareObjectEqAndBranch>(left, right);
8261
          return ast_context()->ReturnControl(result, expr->id());
8262
        }
8263
      }
8264
      default:
8265
        return Bailout(kUnsupportedNonPrimitiveCompare);
8266
    }
8267
  } else if (combined_type->Is(Type::InternalizedString()) &&
8268
             Token::IsEqualityOp(op)) {
8269
    BuildCheckHeapObject(left);
8270
    Add<HCheckInstanceType>(left, HCheckInstanceType::IS_INTERNALIZED_STRING);
8271
    BuildCheckHeapObject(right);
8272
    Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING);
8273
    HCompareObjectEqAndBranch* result =
8274
        New<HCompareObjectEqAndBranch>(left, right);
8275
    return ast_context()->ReturnControl(result, expr->id());
8276
  } else if (combined_type->Is(Type::String())) {
8277
    BuildCheckHeapObject(left);
8278
    Add<HCheckInstanceType>(left, HCheckInstanceType::IS_STRING);
8279
    BuildCheckHeapObject(right);
8280
    Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING);
8281
    HStringCompareAndBranch* result =
8282
        New<HStringCompareAndBranch>(left, right, op);
8283
    return ast_context()->ReturnControl(result, expr->id());
8284
  } else {
8285
    if (combined_rep.IsTagged() || combined_rep.IsNone()) {
8286
      HCompareGeneric* result = New<HCompareGeneric>(left, right, op);
8287
      result->set_observed_input_representation(1, left_rep);
8288
      result->set_observed_input_representation(2, right_rep);
8289
      return ast_context()->ReturnInstruction(result, expr->id());
8290
    } else {
8291
      HCompareNumericAndBranch* result =
8292
          New<HCompareNumericAndBranch>(left, right, op);
8293
      result->set_observed_input_representation(left_rep, right_rep);
8294
      return ast_context()->ReturnControl(result, expr->id());
8295
    }
8296
  }
8297
}
8298

    
8299

    
8300
void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
8301
                                                     Expression* sub_expr,
8302
                                                     NilValue nil) {
8303
  ASSERT(!HasStackOverflow());
8304
  ASSERT(current_block() != NULL);
8305
  ASSERT(current_block()->HasPredecessor());
8306
  ASSERT(expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT);
8307
  if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
8308
  CHECK_ALIVE(VisitForValue(sub_expr));
8309
  HValue* value = Pop();
8310
  if (expr->op() == Token::EQ_STRICT) {
8311
    HConstant* nil_constant = nil == kNullValue
8312
        ? graph()->GetConstantNull()
8313
        : graph()->GetConstantUndefined();
8314
    HCompareObjectEqAndBranch* instr =
8315
        New<HCompareObjectEqAndBranch>(value, nil_constant);
8316
    return ast_context()->ReturnControl(instr, expr->id());
8317
  } else {
8318
    ASSERT_EQ(Token::EQ, expr->op());
8319
    Handle<Type> type = expr->combined_type()->Is(Type::None())
8320
        ? handle(Type::Any(), isolate_)
8321
        : expr->combined_type();
8322
    HIfContinuation continuation;
8323
    BuildCompareNil(value, type, &continuation);
8324
    return ast_context()->ReturnContinuation(&continuation, expr->id());
8325
  }
8326
}
8327

    
8328

    
8329
HInstruction* HOptimizedGraphBuilder::BuildThisFunction() {
8330
  // If we share optimized code between different closures, the
8331
  // this-function is not a constant, except inside an inlined body.
8332
  if (function_state()->outer() != NULL) {
8333
      return New<HConstant>(
8334
          function_state()->compilation_info()->closure());
8335
  } else {
8336
      return New<HThisFunction>();
8337
  }
8338
}
8339

    
8340

    
8341
HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
8342
    Handle<JSObject> boilerplate_object,
8343
    AllocationSiteContext* site_context) {
8344
  NoObservableSideEffectsScope no_effects(this);
8345
  InstanceType instance_type = boilerplate_object->map()->instance_type();
8346
  ASSERT(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE);
8347

    
8348
  HType type = instance_type == JS_ARRAY_TYPE
8349
      ? HType::JSArray() : HType::JSObject();
8350
  HValue* object_size_constant = Add<HConstant>(
8351
      boilerplate_object->map()->instance_size());
8352
  HInstruction* object = Add<HAllocate>(object_size_constant, type,
8353
      isolate()->heap()->GetPretenureMode(), instance_type);
8354

    
8355
  BuildEmitObjectHeader(boilerplate_object, object);
8356

    
8357
  Handle<FixedArrayBase> elements(boilerplate_object->elements());
8358
  int elements_size = (elements->length() > 0 &&
8359
      elements->map() != isolate()->heap()->fixed_cow_array_map()) ?
8360
          elements->Size() : 0;
8361

    
8362
  HInstruction* object_elements = NULL;
8363
  if (elements_size > 0) {
8364
    HValue* object_elements_size = Add<HConstant>(elements_size);
8365
    if (boilerplate_object->HasFastDoubleElements()) {
8366
      object_elements = Add<HAllocate>(object_elements_size, HType::JSObject(),
8367
          isolate()->heap()->GetPretenureMode(), FIXED_DOUBLE_ARRAY_TYPE);
8368
    } else {
8369
      object_elements = Add<HAllocate>(object_elements_size, HType::JSObject(),
8370
          isolate()->heap()->GetPretenureMode(), FIXED_ARRAY_TYPE);
8371
    }
8372
  }
8373
  BuildInitElementsInObjectHeader(boilerplate_object, object, object_elements);
8374

    
8375
  // Copy object elements if non-COW.
8376
  if (object_elements != NULL) {
8377
    BuildEmitElements(boilerplate_object, elements, object_elements,
8378
                      site_context);
8379
  }
8380

    
8381
  // Copy in-object properties.
8382
  if (boilerplate_object->map()->NumberOfFields() != 0) {
8383
    BuildEmitInObjectProperties(boilerplate_object, object, site_context);
8384
  }
8385
  return object;
8386
}
8387

    
8388

    
8389
void HOptimizedGraphBuilder::BuildEmitObjectHeader(
8390
    Handle<JSObject> boilerplate_object,
8391
    HInstruction* object) {
8392
  ASSERT(boilerplate_object->properties()->length() == 0);
8393

    
8394
  Handle<Map> boilerplate_object_map(boilerplate_object->map());
8395
  AddStoreMapConstant(object, boilerplate_object_map);
8396

    
8397
  Handle<Object> properties_field =
8398
      Handle<Object>(boilerplate_object->properties(), isolate());
8399
  ASSERT(*properties_field == isolate()->heap()->empty_fixed_array());
8400
  HInstruction* properties = Add<HConstant>(properties_field);
8401
  HObjectAccess access = HObjectAccess::ForPropertiesPointer();
8402
  Add<HStoreNamedField>(object, access, properties);
8403

    
8404
  if (boilerplate_object->IsJSArray()) {
8405
    Handle<JSArray> boilerplate_array =
8406
        Handle<JSArray>::cast(boilerplate_object);
8407
    Handle<Object> length_field =
8408
        Handle<Object>(boilerplate_array->length(), isolate());
8409
    HInstruction* length = Add<HConstant>(length_field);
8410

    
8411
    ASSERT(boilerplate_array->length()->IsSmi());
8412
    Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(
8413
        boilerplate_array->GetElementsKind()), length);
8414
  }
8415
}
8416

    
8417

    
8418
void HOptimizedGraphBuilder::BuildInitElementsInObjectHeader(
8419
    Handle<JSObject> boilerplate_object,
8420
    HInstruction* object,
8421
    HInstruction* object_elements) {
8422
  ASSERT(boilerplate_object->properties()->length() == 0);
8423
  if (object_elements == NULL) {
8424
    Handle<Object> elements_field =
8425
        Handle<Object>(boilerplate_object->elements(), isolate());
8426
    object_elements = Add<HConstant>(elements_field);
8427
  }
8428
  Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
8429
      object_elements);
8430
}
8431

    
8432

    
8433
void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
8434
    Handle<JSObject> boilerplate_object,
8435
    HInstruction* object,
8436
    AllocationSiteContext* site_context) {
8437
  Handle<DescriptorArray> descriptors(
8438
      boilerplate_object->map()->instance_descriptors());
8439
  int limit = boilerplate_object->map()->NumberOfOwnDescriptors();
8440

    
8441
  int copied_fields = 0;
8442
  for (int i = 0; i < limit; i++) {
8443
    PropertyDetails details = descriptors->GetDetails(i);
8444
    if (details.type() != FIELD) continue;
8445
    copied_fields++;
8446
    int index = descriptors->GetFieldIndex(i);
8447
    int property_offset = boilerplate_object->GetInObjectPropertyOffset(index);
8448
    Handle<Name> name(descriptors->GetKey(i));
8449
    Handle<Object> value =
8450
        Handle<Object>(boilerplate_object->InObjectPropertyAt(index),
8451
        isolate());
8452

    
8453
    // The access for the store depends on the type of the boilerplate.
8454
    HObjectAccess access = boilerplate_object->IsJSArray() ?
8455
        HObjectAccess::ForJSArrayOffset(property_offset) :
8456
        HObjectAccess::ForJSObjectOffset(property_offset);
8457

    
8458
    if (value->IsJSObject()) {
8459
      Handle<JSObject> value_object = Handle<JSObject>::cast(value);
8460
      Handle<AllocationSite> current_site = site_context->EnterNewScope();
8461
      HInstruction* result =
8462
          BuildFastLiteral(value_object, site_context);
8463
      site_context->ExitScope(current_site, value_object);
8464
      Add<HStoreNamedField>(object, access, result);
8465
    } else {
8466
      Representation representation = details.representation();
8467
      HInstruction* value_instruction = Add<HConstant>(value);
8468

    
8469
      if (representation.IsDouble()) {
8470
        // Allocate a HeapNumber box and store the value into it.
8471
        HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize);
8472
        // TODO(mvstanton): This heap number alloc does not have a corresponding
8473
        // AllocationSite. That is okay because
8474
        // 1) it's a child object of another object with a valid allocation site
8475
        // 2) we can just use the mode of the parent object for pretenuring
8476
        // The todo is replace GetPretenureMode() with
8477
        // site_context->top()->GetPretenureMode().
8478
        HInstruction* double_box =
8479
            Add<HAllocate>(heap_number_constant, HType::HeapNumber(),
8480
                isolate()->heap()->GetPretenureMode(), HEAP_NUMBER_TYPE);
8481
        AddStoreMapConstant(double_box,
8482
            isolate()->factory()->heap_number_map());
8483
        Add<HStoreNamedField>(double_box, HObjectAccess::ForHeapNumberValue(),
8484
            value_instruction);
8485
        value_instruction = double_box;
8486
      }
8487

    
8488
      Add<HStoreNamedField>(object, access, value_instruction);
8489
    }
8490
  }
8491

    
8492
  int inobject_properties = boilerplate_object->map()->inobject_properties();
8493
  HInstruction* value_instruction =
8494
      Add<HConstant>(isolate()->factory()->one_pointer_filler_map());
8495
  for (int i = copied_fields; i < inobject_properties; i++) {
8496
    ASSERT(boilerplate_object->IsJSObject());
8497
    int property_offset = boilerplate_object->GetInObjectPropertyOffset(i);
8498
    HObjectAccess access = HObjectAccess::ForJSObjectOffset(property_offset);
8499
    Add<HStoreNamedField>(object, access, value_instruction);
8500
  }
8501
}
8502

    
8503

    
8504
void HOptimizedGraphBuilder::BuildEmitElements(
8505
    Handle<JSObject> boilerplate_object,
8506
    Handle<FixedArrayBase> elements,
8507
    HValue* object_elements,
8508
    AllocationSiteContext* site_context) {
8509
  ElementsKind kind = boilerplate_object->map()->elements_kind();
8510
  int elements_length = elements->length();
8511
  HValue* object_elements_length = Add<HConstant>(elements_length);
8512
  BuildInitializeElementsHeader(object_elements, kind, object_elements_length);
8513

    
8514
  // Copy elements backing store content.
8515
  if (elements->IsFixedDoubleArray()) {
8516
    BuildEmitFixedDoubleArray(elements, kind, object_elements);
8517
  } else if (elements->IsFixedArray()) {
8518
    BuildEmitFixedArray(elements, kind, object_elements,
8519
                        site_context);
8520
  } else {
8521
    UNREACHABLE();
8522
  }
8523
}
8524

    
8525

    
8526
void HOptimizedGraphBuilder::BuildEmitFixedDoubleArray(
8527
    Handle<FixedArrayBase> elements,
8528
    ElementsKind kind,
8529
    HValue* object_elements) {
8530
  HInstruction* boilerplate_elements = Add<HConstant>(elements);
8531
  int elements_length = elements->length();
8532
  for (int i = 0; i < elements_length; i++) {
8533
    HValue* key_constant = Add<HConstant>(i);
8534
    HInstruction* value_instruction =
8535
        Add<HLoadKeyed>(boilerplate_elements, key_constant,
8536
                        static_cast<HValue*>(NULL), kind,
8537
                        ALLOW_RETURN_HOLE);
8538
    HInstruction* store = Add<HStoreKeyed>(object_elements, key_constant,
8539
                                           value_instruction, kind);
8540
    store->SetFlag(HValue::kAllowUndefinedAsNaN);
8541
  }
8542
}
8543

    
8544

    
8545
void HOptimizedGraphBuilder::BuildEmitFixedArray(
8546
    Handle<FixedArrayBase> elements,
8547
    ElementsKind kind,
8548
    HValue* object_elements,
8549
    AllocationSiteContext* site_context) {
8550
  HInstruction* boilerplate_elements = Add<HConstant>(elements);
8551
  int elements_length = elements->length();
8552
  Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
8553
  for (int i = 0; i < elements_length; i++) {
8554
    Handle<Object> value(fast_elements->get(i), isolate());
8555
    HValue* key_constant = Add<HConstant>(i);
8556
    if (value->IsJSObject()) {
8557
      Handle<JSObject> value_object = Handle<JSObject>::cast(value);
8558
      Handle<AllocationSite> current_site = site_context->EnterNewScope();
8559
      HInstruction* result =
8560
          BuildFastLiteral(value_object, site_context);
8561
      site_context->ExitScope(current_site, value_object);
8562
      Add<HStoreKeyed>(object_elements, key_constant, result, kind);
8563
    } else {
8564
      HInstruction* value_instruction =
8565
          Add<HLoadKeyed>(boilerplate_elements, key_constant,
8566
                          static_cast<HValue*>(NULL), kind,
8567
                          ALLOW_RETURN_HOLE);
8568
      Add<HStoreKeyed>(object_elements, key_constant, value_instruction, kind);
8569
    }
8570
  }
8571
}
8572

    
8573

    
8574
void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) {
8575
  ASSERT(!HasStackOverflow());
8576
  ASSERT(current_block() != NULL);
8577
  ASSERT(current_block()->HasPredecessor());
8578
  HInstruction* instr = BuildThisFunction();
8579
  return ast_context()->ReturnInstruction(instr, expr->id());
8580
}
8581

    
8582

    
8583
void HOptimizedGraphBuilder::VisitDeclarations(
8584
    ZoneList<Declaration*>* declarations) {
8585
  ASSERT(globals_.is_empty());
8586
  AstVisitor::VisitDeclarations(declarations);
8587
  if (!globals_.is_empty()) {
8588
    Handle<FixedArray> array =
8589
       isolate()->factory()->NewFixedArray(globals_.length(), TENURED);
8590
    for (int i = 0; i < globals_.length(); ++i) array->set(i, *globals_.at(i));
8591
    int flags = DeclareGlobalsEvalFlag::encode(current_info()->is_eval()) |
8592
        DeclareGlobalsNativeFlag::encode(current_info()->is_native()) |
8593
        DeclareGlobalsLanguageMode::encode(current_info()->language_mode());
8594
    Add<HDeclareGlobals>(array, flags);
8595
    globals_.Clear();
8596
  }
8597
}
8598

    
8599

    
8600
void HOptimizedGraphBuilder::VisitVariableDeclaration(
8601
    VariableDeclaration* declaration) {
8602
  VariableProxy* proxy = declaration->proxy();
8603
  VariableMode mode = declaration->mode();
8604
  Variable* variable = proxy->var();
8605
  bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
8606
  switch (variable->location()) {
8607
    case Variable::UNALLOCATED:
8608
      globals_.Add(variable->name(), zone());
8609
      globals_.Add(variable->binding_needs_init()
8610
                       ? isolate()->factory()->the_hole_value()
8611
                       : isolate()->factory()->undefined_value(), zone());
8612
      return;
8613
    case Variable::PARAMETER:
8614
    case Variable::LOCAL:
8615
      if (hole_init) {
8616
        HValue* value = graph()->GetConstantHole();
8617
        environment()->Bind(variable, value);
8618
      }
8619
      break;
8620
    case Variable::CONTEXT:
8621
      if (hole_init) {
8622
        HValue* value = graph()->GetConstantHole();
8623
        HValue* context = environment()->context();
8624
        HStoreContextSlot* store = Add<HStoreContextSlot>(
8625
            context, variable->index(), HStoreContextSlot::kNoCheck, value);
8626
        if (store->HasObservableSideEffects()) {
8627
          Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE);
8628
        }
8629
      }
8630
      break;
8631
    case Variable::LOOKUP:
8632
      return Bailout(kUnsupportedLookupSlotInDeclaration);
8633
  }
8634
}
8635

    
8636

    
8637
void HOptimizedGraphBuilder::VisitFunctionDeclaration(
8638
    FunctionDeclaration* declaration) {
8639
  VariableProxy* proxy = declaration->proxy();
8640
  Variable* variable = proxy->var();
8641
  switch (variable->location()) {
8642
    case Variable::UNALLOCATED: {
8643
      globals_.Add(variable->name(), zone());
8644
      Handle<SharedFunctionInfo> function = Compiler::BuildFunctionInfo(
8645
          declaration->fun(), current_info()->script());
8646
      // Check for stack-overflow exception.
8647
      if (function.is_null()) return SetStackOverflow();
8648
      globals_.Add(function, zone());
8649
      return;
8650
    }
8651
    case Variable::PARAMETER:
8652
    case Variable::LOCAL: {
8653
      CHECK_ALIVE(VisitForValue(declaration->fun()));
8654
      HValue* value = Pop();
8655
      BindIfLive(variable, value);
8656
      break;
8657
    }
8658
    case Variable::CONTEXT: {
8659
      CHECK_ALIVE(VisitForValue(declaration->fun()));
8660
      HValue* value = Pop();
8661
      HValue* context = environment()->context();
8662
      HStoreContextSlot* store = Add<HStoreContextSlot>(
8663
          context, variable->index(), HStoreContextSlot::kNoCheck, value);
8664
      if (store->HasObservableSideEffects()) {
8665
        Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE);
8666
      }
8667
      break;
8668
    }
8669
    case Variable::LOOKUP:
8670
      return Bailout(kUnsupportedLookupSlotInDeclaration);
8671
  }
8672
}
8673

    
8674

    
8675
void HOptimizedGraphBuilder::VisitModuleDeclaration(
8676
    ModuleDeclaration* declaration) {
8677
  UNREACHABLE();
8678
}
8679

    
8680

    
8681
void HOptimizedGraphBuilder::VisitImportDeclaration(
8682
    ImportDeclaration* declaration) {
8683
  UNREACHABLE();
8684
}
8685

    
8686

    
8687
void HOptimizedGraphBuilder::VisitExportDeclaration(
8688
    ExportDeclaration* declaration) {
8689
  UNREACHABLE();
8690
}
8691

    
8692

    
8693
void HOptimizedGraphBuilder::VisitModuleLiteral(ModuleLiteral* module) {
8694
  UNREACHABLE();
8695
}
8696

    
8697

    
8698
void HOptimizedGraphBuilder::VisitModuleVariable(ModuleVariable* module) {
8699
  UNREACHABLE();
8700
}
8701

    
8702

    
8703
void HOptimizedGraphBuilder::VisitModulePath(ModulePath* module) {
8704
  UNREACHABLE();
8705
}
8706

    
8707

    
8708
void HOptimizedGraphBuilder::VisitModuleUrl(ModuleUrl* module) {
8709
  UNREACHABLE();
8710
}
8711

    
8712

    
8713
void HOptimizedGraphBuilder::VisitModuleStatement(ModuleStatement* stmt) {
8714
  UNREACHABLE();
8715
}
8716

    
8717

    
8718
// Generators for inline runtime functions.
8719
// Support for types.
8720
void HOptimizedGraphBuilder::GenerateIsSmi(CallRuntime* call) {
8721
  ASSERT(call->arguments()->length() == 1);
8722
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8723
  HValue* value = Pop();
8724
  HIsSmiAndBranch* result = New<HIsSmiAndBranch>(value);
8725
  return ast_context()->ReturnControl(result, call->id());
8726
}
8727

    
8728

    
8729
void HOptimizedGraphBuilder::GenerateIsSpecObject(CallRuntime* call) {
8730
  ASSERT(call->arguments()->length() == 1);
8731
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8732
  HValue* value = Pop();
8733
  HHasInstanceTypeAndBranch* result =
8734
      New<HHasInstanceTypeAndBranch>(value,
8735
                                     FIRST_SPEC_OBJECT_TYPE,
8736
                                     LAST_SPEC_OBJECT_TYPE);
8737
  return ast_context()->ReturnControl(result, call->id());
8738
}
8739

    
8740

    
8741
void HOptimizedGraphBuilder::GenerateIsFunction(CallRuntime* call) {
8742
  ASSERT(call->arguments()->length() == 1);
8743
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8744
  HValue* value = Pop();
8745
  HHasInstanceTypeAndBranch* result =
8746
      New<HHasInstanceTypeAndBranch>(value, JS_FUNCTION_TYPE);
8747
  return ast_context()->ReturnControl(result, call->id());
8748
}
8749

    
8750

    
8751
void HOptimizedGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) {
8752
  ASSERT(call->arguments()->length() == 1);
8753
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8754
  HValue* value = Pop();
8755
  HHasCachedArrayIndexAndBranch* result =
8756
      New<HHasCachedArrayIndexAndBranch>(value);
8757
  return ast_context()->ReturnControl(result, call->id());
8758
}
8759

    
8760

    
8761
void HOptimizedGraphBuilder::GenerateIsArray(CallRuntime* call) {
8762
  ASSERT(call->arguments()->length() == 1);
8763
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8764
  HValue* value = Pop();
8765
  HHasInstanceTypeAndBranch* result =
8766
      New<HHasInstanceTypeAndBranch>(value, JS_ARRAY_TYPE);
8767
  return ast_context()->ReturnControl(result, call->id());
8768
}
8769

    
8770

    
8771
void HOptimizedGraphBuilder::GenerateIsRegExp(CallRuntime* call) {
8772
  ASSERT(call->arguments()->length() == 1);
8773
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8774
  HValue* value = Pop();
8775
  HHasInstanceTypeAndBranch* result =
8776
      New<HHasInstanceTypeAndBranch>(value, JS_REGEXP_TYPE);
8777
  return ast_context()->ReturnControl(result, call->id());
8778
}
8779

    
8780

    
8781
void HOptimizedGraphBuilder::GenerateIsObject(CallRuntime* call) {
8782
  ASSERT(call->arguments()->length() == 1);
8783
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8784
  HValue* value = Pop();
8785
  HIsObjectAndBranch* result = New<HIsObjectAndBranch>(value);
8786
  return ast_context()->ReturnControl(result, call->id());
8787
}
8788

    
8789

    
8790
void HOptimizedGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) {
8791
  return Bailout(kInlinedRuntimeFunctionIsNonNegativeSmi);
8792
}
8793

    
8794

    
8795
void HOptimizedGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) {
8796
  ASSERT(call->arguments()->length() == 1);
8797
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8798
  HValue* value = Pop();
8799
  HIsUndetectableAndBranch* result = New<HIsUndetectableAndBranch>(value);
8800
  return ast_context()->ReturnControl(result, call->id());
8801
}
8802

    
8803

    
8804
void HOptimizedGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf(
8805
    CallRuntime* call) {
8806
  return Bailout(kInlinedRuntimeFunctionIsStringWrapperSafeForDefaultValueOf);
8807
}
8808

    
8809

    
8810
// Support for construct call checks.
8811
void HOptimizedGraphBuilder::GenerateIsConstructCall(CallRuntime* call) {
8812
  ASSERT(call->arguments()->length() == 0);
8813
  if (function_state()->outer() != NULL) {
8814
    // We are generating graph for inlined function.
8815
    HValue* value = function_state()->inlining_kind() == CONSTRUCT_CALL_RETURN
8816
        ? graph()->GetConstantTrue()
8817
        : graph()->GetConstantFalse();
8818
    return ast_context()->ReturnValue(value);
8819
  } else {
8820
    return ast_context()->ReturnControl(New<HIsConstructCallAndBranch>(),
8821
                                        call->id());
8822
  }
8823
}
8824

    
8825

    
8826
// Support for arguments.length and arguments[?].
8827
void HOptimizedGraphBuilder::GenerateArgumentsLength(CallRuntime* call) {
8828
  // Our implementation of arguments (based on this stack frame or an
8829
  // adapter below it) does not work for inlined functions.  This runtime
8830
  // function is blacklisted by AstNode::IsInlineable.
8831
  ASSERT(function_state()->outer() == NULL);
8832
  ASSERT(call->arguments()->length() == 0);
8833
  HInstruction* elements = Add<HArgumentsElements>(false);
8834
  HArgumentsLength* result = New<HArgumentsLength>(elements);
8835
  return ast_context()->ReturnInstruction(result, call->id());
8836
}
8837

    
8838

    
8839
void HOptimizedGraphBuilder::GenerateArguments(CallRuntime* call) {
8840
  // Our implementation of arguments (based on this stack frame or an
8841
  // adapter below it) does not work for inlined functions.  This runtime
8842
  // function is blacklisted by AstNode::IsInlineable.
8843
  ASSERT(function_state()->outer() == NULL);
8844
  ASSERT(call->arguments()->length() == 1);
8845
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8846
  HValue* index = Pop();
8847
  HInstruction* elements = Add<HArgumentsElements>(false);
8848
  HInstruction* length = Add<HArgumentsLength>(elements);
8849
  HInstruction* checked_index = Add<HBoundsCheck>(index, length);
8850
  HAccessArgumentsAt* result = New<HAccessArgumentsAt>(
8851
      elements, length, checked_index);
8852
  return ast_context()->ReturnInstruction(result, call->id());
8853
}
8854

    
8855

    
8856
// Support for accessing the class and value fields of an object.
8857
void HOptimizedGraphBuilder::GenerateClassOf(CallRuntime* call) {
8858
  // The special form detected by IsClassOfTest is detected before we get here
8859
  // and does not cause a bailout.
8860
  return Bailout(kInlinedRuntimeFunctionClassOf);
8861
}
8862

    
8863

    
8864
void HOptimizedGraphBuilder::GenerateValueOf(CallRuntime* call) {
8865
  ASSERT(call->arguments()->length() == 1);
8866
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8867
  HValue* value = Pop();
8868
  HValueOf* result = New<HValueOf>(value);
8869
  return ast_context()->ReturnInstruction(result, call->id());
8870
}
8871

    
8872

    
8873
void HOptimizedGraphBuilder::GenerateDateField(CallRuntime* call) {
8874
  ASSERT(call->arguments()->length() == 2);
8875
  ASSERT_NE(NULL, call->arguments()->at(1)->AsLiteral());
8876
  Smi* index = Smi::cast(*(call->arguments()->at(1)->AsLiteral()->value()));
8877
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8878
  HValue* date = Pop();
8879
  HDateField* result = New<HDateField>(date, index);
8880
  return ast_context()->ReturnInstruction(result, call->id());
8881
}
8882

    
8883

    
8884
void HOptimizedGraphBuilder::GenerateOneByteSeqStringSetChar(
8885
    CallRuntime* call) {
8886
  ASSERT(call->arguments()->length() == 3);
8887
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8888
  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
8889
  CHECK_ALIVE(VisitForValue(call->arguments()->at(2)));
8890
  HValue* value = Pop();
8891
  HValue* index = Pop();
8892
  HValue* string = Pop();
8893
  HSeqStringSetChar* result = New<HSeqStringSetChar>(
8894
      String::ONE_BYTE_ENCODING, string, index, value);
8895
  return ast_context()->ReturnInstruction(result, call->id());
8896
}
8897

    
8898

    
8899
void HOptimizedGraphBuilder::GenerateTwoByteSeqStringSetChar(
8900
    CallRuntime* call) {
8901
  ASSERT(call->arguments()->length() == 3);
8902
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8903
  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
8904
  CHECK_ALIVE(VisitForValue(call->arguments()->at(2)));
8905
  HValue* value = Pop();
8906
  HValue* index = Pop();
8907
  HValue* string = Pop();
8908
  HSeqStringSetChar* result = New<HSeqStringSetChar>(
8909
      String::TWO_BYTE_ENCODING, string, index, value);
8910
  return ast_context()->ReturnInstruction(result, call->id());
8911
}
8912

    
8913

    
8914
void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) {
8915
  ASSERT(call->arguments()->length() == 2);
8916
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8917
  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
8918
  HValue* value = Pop();
8919
  HValue* object = Pop();
8920
  // Check if object is a not a smi.
8921
  HBasicBlock* if_smi = graph()->CreateBasicBlock();
8922
  HBasicBlock* if_heap_object = graph()->CreateBasicBlock();
8923
  HBasicBlock* join = graph()->CreateBasicBlock();
8924
  FinishCurrentBlock(New<HIsSmiAndBranch>(object, if_smi, if_heap_object));
8925
  Goto(if_smi, join);
8926

    
8927
  // Check if object is a JSValue.
8928
  set_current_block(if_heap_object);
8929
  HHasInstanceTypeAndBranch* typecheck =
8930
      New<HHasInstanceTypeAndBranch>(object, JS_VALUE_TYPE);
8931
  HBasicBlock* if_js_value = graph()->CreateBasicBlock();
8932
  HBasicBlock* not_js_value = graph()->CreateBasicBlock();
8933
  typecheck->SetSuccessorAt(0, if_js_value);
8934
  typecheck->SetSuccessorAt(1, not_js_value);
8935
  FinishCurrentBlock(typecheck);
8936
  Goto(not_js_value, join);
8937

    
8938
  // Create in-object property store to kValueOffset.
8939
  set_current_block(if_js_value);
8940
  Add<HStoreNamedField>(object,
8941
      HObjectAccess::ForJSObjectOffset(JSValue::kValueOffset), value);
8942
  Goto(if_js_value, join);
8943
  join->SetJoinId(call->id());
8944
  set_current_block(join);
8945
  return ast_context()->ReturnValue(value);
8946
}
8947

    
8948

    
8949
// Fast support for charCodeAt(n).
8950
void HOptimizedGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) {
8951
  ASSERT(call->arguments()->length() == 2);
8952
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8953
  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
8954
  HValue* index = Pop();
8955
  HValue* string = Pop();
8956
  HInstruction* result = BuildStringCharCodeAt(string, index);
8957
  return ast_context()->ReturnInstruction(result, call->id());
8958
}
8959

    
8960

    
8961
// Fast support for string.charAt(n) and string[n].
8962
void HOptimizedGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) {
8963
  ASSERT(call->arguments()->length() == 1);
8964
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8965
  HValue* char_code = Pop();
8966
  HInstruction* result = NewUncasted<HStringCharFromCode>(char_code);
8967
  return ast_context()->ReturnInstruction(result, call->id());
8968
}
8969

    
8970

    
8971
// Fast support for string.charAt(n) and string[n].
8972
void HOptimizedGraphBuilder::GenerateStringCharAt(CallRuntime* call) {
8973
  ASSERT(call->arguments()->length() == 2);
8974
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8975
  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
8976
  HValue* index = Pop();
8977
  HValue* string = Pop();
8978
  HInstruction* char_code = BuildStringCharCodeAt(string, index);
8979
  AddInstruction(char_code);
8980
  HInstruction* result = NewUncasted<HStringCharFromCode>(char_code);
8981
  return ast_context()->ReturnInstruction(result, call->id());
8982
}
8983

    
8984

    
8985
// Fast support for object equality testing.
8986
void HOptimizedGraphBuilder::GenerateObjectEquals(CallRuntime* call) {
8987
  ASSERT(call->arguments()->length() == 2);
8988
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
8989
  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
8990
  HValue* right = Pop();
8991
  HValue* left = Pop();
8992
  HCompareObjectEqAndBranch* result =
8993
      New<HCompareObjectEqAndBranch>(left, right);
8994
  return ast_context()->ReturnControl(result, call->id());
8995
}
8996

    
8997

    
8998
void HOptimizedGraphBuilder::GenerateLog(CallRuntime* call) {
8999
  // %_Log is ignored in optimized code.
9000
  return ast_context()->ReturnValue(graph()->GetConstantUndefined());
9001
}
9002

    
9003

    
9004
// Fast support for Math.random().
9005
void HOptimizedGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) {
9006
  HGlobalObject* global_object = Add<HGlobalObject>();
9007
  HRandom* result = New<HRandom>(global_object);
9008
  return ast_context()->ReturnInstruction(result, call->id());
9009
}
9010

    
9011

    
9012
// Fast support for StringAdd.
9013
void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) {
9014
  ASSERT_EQ(2, call->arguments()->length());
9015
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
9016
  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
9017
  HValue* right = Pop();
9018
  HValue* left = Pop();
9019
  HInstruction* result = New<HStringAdd>(left, right, STRING_ADD_CHECK_BOTH);
9020
  return ast_context()->ReturnInstruction(result, call->id());
9021
}
9022

    
9023

    
9024
// Fast support for SubString.
9025
void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) {
9026
  ASSERT_EQ(3, call->arguments()->length());
9027
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
9028
  HCallStub* result = New<HCallStub>(CodeStub::SubString, 3);
9029
  Drop(3);
9030
  return ast_context()->ReturnInstruction(result, call->id());
9031
}
9032

    
9033

    
9034
// Fast support for StringCompare.
9035
void HOptimizedGraphBuilder::GenerateStringCompare(CallRuntime* call) {
9036
  ASSERT_EQ(2, call->arguments()->length());
9037
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
9038
  HCallStub* result = New<HCallStub>(CodeStub::StringCompare, 2);
9039
  Drop(2);
9040
  return ast_context()->ReturnInstruction(result, call->id());
9041
}
9042

    
9043

    
9044
// Support for direct calls from JavaScript to native RegExp code.
9045
void HOptimizedGraphBuilder::GenerateRegExpExec(CallRuntime* call) {
9046
  ASSERT_EQ(4, call->arguments()->length());
9047
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
9048
  HCallStub* result = New<HCallStub>(CodeStub::RegExpExec, 4);
9049
  Drop(4);
9050
  return ast_context()->ReturnInstruction(result, call->id());
9051
}
9052

    
9053

    
9054
// Construct a RegExp exec result with two in-object properties.
9055
void HOptimizedGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) {
9056
  ASSERT_EQ(3, call->arguments()->length());
9057
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
9058
  HCallStub* result = New<HCallStub>(CodeStub::RegExpConstructResult, 3);
9059
  Drop(3);
9060
  return ast_context()->ReturnInstruction(result, call->id());
9061
}
9062

    
9063

    
9064
// Support for fast native caches.
9065
void HOptimizedGraphBuilder::GenerateGetFromCache(CallRuntime* call) {
9066
  return Bailout(kInlinedRuntimeFunctionGetFromCache);
9067
}
9068

    
9069

    
9070
// Fast support for number to string.
9071
void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) {
9072
  ASSERT_EQ(1, call->arguments()->length());
9073
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
9074
  HValue* number = Pop();
9075
  HValue* result = BuildNumberToString(
9076
      number, handle(Type::Number(), isolate()));
9077
  return ast_context()->ReturnValue(result);
9078
}
9079

    
9080

    
9081
// Fast call for custom callbacks.
9082
void HOptimizedGraphBuilder::GenerateCallFunction(CallRuntime* call) {
9083
  // 1 ~ The function to call is not itself an argument to the call.
9084
  int arg_count = call->arguments()->length() - 1;
9085
  ASSERT(arg_count >= 1);  // There's always at least a receiver.
9086

    
9087
  for (int i = 0; i < arg_count; ++i) {
9088
    CHECK_ALIVE(VisitArgument(call->arguments()->at(i)));
9089
  }
9090
  CHECK_ALIVE(VisitForValue(call->arguments()->last()));
9091

    
9092
  HValue* function = Pop();
9093

    
9094
  // Branch for function proxies, or other non-functions.
9095
  HHasInstanceTypeAndBranch* typecheck =
9096
      New<HHasInstanceTypeAndBranch>(function, JS_FUNCTION_TYPE);
9097
  HBasicBlock* if_jsfunction = graph()->CreateBasicBlock();
9098
  HBasicBlock* if_nonfunction = graph()->CreateBasicBlock();
9099
  HBasicBlock* join = graph()->CreateBasicBlock();
9100
  typecheck->SetSuccessorAt(0, if_jsfunction);
9101
  typecheck->SetSuccessorAt(1, if_nonfunction);
9102
  FinishCurrentBlock(typecheck);
9103

    
9104
  set_current_block(if_jsfunction);
9105
  HInstruction* invoke_result = Add<HInvokeFunction>(function, arg_count);
9106
  Drop(arg_count);
9107
  Push(invoke_result);
9108
  Goto(if_jsfunction, join);
9109

    
9110
  set_current_block(if_nonfunction);
9111
  HInstruction* call_result = Add<HCallFunction>(function, arg_count);
9112
  Drop(arg_count);
9113
  Push(call_result);
9114
  Goto(if_nonfunction, join);
9115

    
9116
  set_current_block(join);
9117
  join->SetJoinId(call->id());
9118
  return ast_context()->ReturnValue(Pop());
9119
}
9120

    
9121

    
9122
// Fast call to math functions.
9123
void HOptimizedGraphBuilder::GenerateMathPow(CallRuntime* call) {
9124
  ASSERT_EQ(2, call->arguments()->length());
9125
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
9126
  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
9127
  HValue* right = Pop();
9128
  HValue* left = Pop();
9129
  HInstruction* result = NewUncasted<HPower>(left, right);
9130
  return ast_context()->ReturnInstruction(result, call->id());
9131
}
9132

    
9133

    
9134
void HOptimizedGraphBuilder::GenerateMathSin(CallRuntime* call) {
9135
  ASSERT_EQ(1, call->arguments()->length());
9136
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
9137
  HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1);
9138
  result->set_transcendental_type(TranscendentalCache::SIN);
9139
  Drop(1);
9140
  return ast_context()->ReturnInstruction(result, call->id());
9141
}
9142

    
9143

    
9144
void HOptimizedGraphBuilder::GenerateMathCos(CallRuntime* call) {
9145
  ASSERT_EQ(1, call->arguments()->length());
9146
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
9147
  HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1);
9148
  result->set_transcendental_type(TranscendentalCache::COS);
9149
  Drop(1);
9150
  return ast_context()->ReturnInstruction(result, call->id());
9151
}
9152

    
9153

    
9154
void HOptimizedGraphBuilder::GenerateMathTan(CallRuntime* call) {
9155
  ASSERT_EQ(1, call->arguments()->length());
9156
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
9157
  HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1);
9158
  result->set_transcendental_type(TranscendentalCache::TAN);
9159
  Drop(1);
9160
  return ast_context()->ReturnInstruction(result, call->id());
9161
}
9162

    
9163

    
9164
void HOptimizedGraphBuilder::GenerateMathLog(CallRuntime* call) {
9165
  ASSERT_EQ(1, call->arguments()->length());
9166
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
9167
  HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1);
9168
  result->set_transcendental_type(TranscendentalCache::LOG);
9169
  Drop(1);
9170
  return ast_context()->ReturnInstruction(result, call->id());
9171
}
9172

    
9173

    
9174
void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) {
9175
  ASSERT(call->arguments()->length() == 1);
9176
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
9177
  HValue* value = Pop();
9178
  HInstruction* result = New<HUnaryMathOperation>(value, kMathSqrt);
9179
  return ast_context()->ReturnInstruction(result, call->id());
9180
}
9181

    
9182

    
9183
// Check whether two RegExps are equivalent
9184
void HOptimizedGraphBuilder::GenerateIsRegExpEquivalent(CallRuntime* call) {
9185
  return Bailout(kInlinedRuntimeFunctionIsRegExpEquivalent);
9186
}
9187

    
9188

    
9189
void HOptimizedGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) {
9190
  ASSERT(call->arguments()->length() == 1);
9191
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
9192
  HValue* value = Pop();
9193
  HGetCachedArrayIndex* result = New<HGetCachedArrayIndex>(value);
9194
  return ast_context()->ReturnInstruction(result, call->id());
9195
}
9196

    
9197

    
9198
void HOptimizedGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) {
9199
  return Bailout(kInlinedRuntimeFunctionFastAsciiArrayJoin);
9200
}
9201

    
9202

    
9203
// Support for generators.
9204
void HOptimizedGraphBuilder::GenerateGeneratorNext(CallRuntime* call) {
9205
  return Bailout(kInlinedRuntimeFunctionGeneratorNext);
9206
}
9207

    
9208

    
9209
void HOptimizedGraphBuilder::GenerateGeneratorThrow(CallRuntime* call) {
9210
  return Bailout(kInlinedRuntimeFunctionGeneratorThrow);
9211
}
9212

    
9213

    
9214
void HOptimizedGraphBuilder::GenerateDebugBreakInOptimizedCode(
9215
    CallRuntime* call) {
9216
  Add<HDebugBreak>();
9217
  return ast_context()->ReturnValue(graph()->GetConstant0());
9218
}
9219

    
9220

    
9221
#undef CHECK_BAILOUT
9222
#undef CHECK_ALIVE
9223

    
9224

    
9225
HEnvironment::HEnvironment(HEnvironment* outer,
9226
                           Scope* scope,
9227
                           Handle<JSFunction> closure,
9228
                           Zone* zone)
9229
    : closure_(closure),
9230
      values_(0, zone),
9231
      frame_type_(JS_FUNCTION),
9232
      parameter_count_(0),
9233
      specials_count_(1),
9234
      local_count_(0),
9235
      outer_(outer),
9236
      entry_(NULL),
9237
      pop_count_(0),
9238
      push_count_(0),
9239
      ast_id_(BailoutId::None()),
9240
      zone_(zone) {
9241
  Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0);
9242
}
9243

    
9244

    
9245
HEnvironment::HEnvironment(Zone* zone, int parameter_count)
9246
    : values_(0, zone),
9247
      frame_type_(STUB),
9248
      parameter_count_(parameter_count),
9249
      specials_count_(1),
9250
      local_count_(0),
9251
      outer_(NULL),
9252
      entry_(NULL),
9253
      pop_count_(0),
9254
      push_count_(0),
9255
      ast_id_(BailoutId::None()),
9256
      zone_(zone) {
9257
  Initialize(parameter_count, 0, 0);
9258
}
9259

    
9260

    
9261
HEnvironment::HEnvironment(const HEnvironment* other, Zone* zone)
9262
    : values_(0, zone),
9263
      frame_type_(JS_FUNCTION),
9264
      parameter_count_(0),
9265
      specials_count_(0),
9266
      local_count_(0),
9267
      outer_(NULL),
9268
      entry_(NULL),
9269
      pop_count_(0),
9270
      push_count_(0),
9271
      ast_id_(other->ast_id()),
9272
      zone_(zone) {
9273
  Initialize(other);
9274
}
9275

    
9276

    
9277
HEnvironment::HEnvironment(HEnvironment* outer,
9278
                           Handle<JSFunction> closure,
9279
                           FrameType frame_type,
9280
                           int arguments,
9281
                           Zone* zone)
9282
    : closure_(closure),
9283
      values_(arguments, zone),
9284
      frame_type_(frame_type),
9285
      parameter_count_(arguments),
9286
      specials_count_(0),
9287
      local_count_(0),
9288
      outer_(outer),
9289
      entry_(NULL),
9290
      pop_count_(0),
9291
      push_count_(0),
9292
      ast_id_(BailoutId::None()),
9293
      zone_(zone) {
9294
}
9295

    
9296

    
9297
void HEnvironment::Initialize(int parameter_count,
9298
                              int local_count,
9299
                              int stack_height) {
9300
  parameter_count_ = parameter_count;
9301
  local_count_ = local_count;
9302

    
9303
  // Avoid reallocating the temporaries' backing store on the first Push.
9304
  int total = parameter_count + specials_count_ + local_count + stack_height;
9305
  values_.Initialize(total + 4, zone());
9306
  for (int i = 0; i < total; ++i) values_.Add(NULL, zone());
9307
}
9308

    
9309

    
9310
void HEnvironment::Initialize(const HEnvironment* other) {
9311
  closure_ = other->closure();
9312
  values_.AddAll(other->values_, zone());
9313
  assigned_variables_.Union(other->assigned_variables_, zone());
9314
  frame_type_ = other->frame_type_;
9315
  parameter_count_ = other->parameter_count_;
9316
  local_count_ = other->local_count_;
9317
  if (other->outer_ != NULL) outer_ = other->outer_->Copy();  // Deep copy.
9318
  entry_ = other->entry_;
9319
  pop_count_ = other->pop_count_;
9320
  push_count_ = other->push_count_;
9321
  specials_count_ = other->specials_count_;
9322
  ast_id_ = other->ast_id_;
9323
}
9324

    
9325

    
9326
void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) {
9327
  ASSERT(!block->IsLoopHeader());
9328
  ASSERT(values_.length() == other->values_.length());
9329

    
9330
  int length = values_.length();
9331
  for (int i = 0; i < length; ++i) {
9332
    HValue* value = values_[i];
9333
    if (value != NULL && value->IsPhi() && value->block() == block) {
9334
      // There is already a phi for the i'th value.
9335
      HPhi* phi = HPhi::cast(value);
9336
      // Assert index is correct and that we haven't missed an incoming edge.
9337
      ASSERT(phi->merged_index() == i || !phi->HasMergedIndex());
9338
      ASSERT(phi->OperandCount() == block->predecessors()->length());
9339
      phi->AddInput(other->values_[i]);
9340
    } else if (values_[i] != other->values_[i]) {
9341
      // There is a fresh value on the incoming edge, a phi is needed.
9342
      ASSERT(values_[i] != NULL && other->values_[i] != NULL);
9343
      HPhi* phi = block->AddNewPhi(i);
9344
      HValue* old_value = values_[i];
9345
      for (int j = 0; j < block->predecessors()->length(); j++) {
9346
        phi->AddInput(old_value);
9347
      }
9348
      phi->AddInput(other->values_[i]);
9349
      this->values_[i] = phi;
9350
    }
9351
  }
9352
}
9353

    
9354

    
9355
void HEnvironment::Bind(int index, HValue* value) {
9356
  ASSERT(value != NULL);
9357
  assigned_variables_.Add(index, zone());
9358
  values_[index] = value;
9359
}
9360

    
9361

    
9362
bool HEnvironment::HasExpressionAt(int index) const {
9363
  return index >= parameter_count_ + specials_count_ + local_count_;
9364
}
9365

    
9366

    
9367
bool HEnvironment::ExpressionStackIsEmpty() const {
9368
  ASSERT(length() >= first_expression_index());
9369
  return length() == first_expression_index();
9370
}
9371

    
9372

    
9373
void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) {
9374
  int count = index_from_top + 1;
9375
  int index = values_.length() - count;
9376
  ASSERT(HasExpressionAt(index));
9377
  // The push count must include at least the element in question or else
9378
  // the new value will not be included in this environment's history.
9379
  if (push_count_ < count) {
9380
    // This is the same effect as popping then re-pushing 'count' elements.
9381
    pop_count_ += (count - push_count_);
9382
    push_count_ = count;
9383
  }
9384
  values_[index] = value;
9385
}
9386

    
9387

    
9388
void HEnvironment::Drop(int count) {
9389
  for (int i = 0; i < count; ++i) {
9390
    Pop();
9391
  }
9392
}
9393

    
9394

    
9395
HEnvironment* HEnvironment::Copy() const {
9396
  return new(zone()) HEnvironment(this, zone());
9397
}
9398

    
9399

    
9400
HEnvironment* HEnvironment::CopyWithoutHistory() const {
9401
  HEnvironment* result = Copy();
9402
  result->ClearHistory();
9403
  return result;
9404
}
9405

    
9406

    
9407
HEnvironment* HEnvironment::CopyAsLoopHeader(HBasicBlock* loop_header) const {
9408
  HEnvironment* new_env = Copy();
9409
  for (int i = 0; i < values_.length(); ++i) {
9410
    HPhi* phi = loop_header->AddNewPhi(i);
9411
    phi->AddInput(values_[i]);
9412
    new_env->values_[i] = phi;
9413
  }
9414
  new_env->ClearHistory();
9415
  return new_env;
9416
}
9417

    
9418

    
9419
HEnvironment* HEnvironment::CreateStubEnvironment(HEnvironment* outer,
9420
                                                  Handle<JSFunction> target,
9421
                                                  FrameType frame_type,
9422
                                                  int arguments) const {
9423
  HEnvironment* new_env =
9424
      new(zone()) HEnvironment(outer, target, frame_type,
9425
                               arguments + 1, zone());
9426
  for (int i = 0; i <= arguments; ++i) {  // Include receiver.
9427
    new_env->Push(ExpressionStackAt(arguments - i));
9428
  }
9429
  new_env->ClearHistory();
9430
  return new_env;
9431
}
9432

    
9433

    
9434
HEnvironment* HEnvironment::CopyForInlining(
9435
    Handle<JSFunction> target,
9436
    int arguments,
9437
    FunctionLiteral* function,
9438
    HConstant* undefined,
9439
    InliningKind inlining_kind,
9440
    bool undefined_receiver) const {
9441
  ASSERT(frame_type() == JS_FUNCTION);
9442

    
9443
  // Outer environment is a copy of this one without the arguments.
9444
  int arity = function->scope()->num_parameters();
9445

    
9446
  HEnvironment* outer = Copy();
9447
  outer->Drop(arguments + 1);  // Including receiver.
9448
  outer->ClearHistory();
9449

    
9450
  if (inlining_kind == CONSTRUCT_CALL_RETURN) {
9451
    // Create artificial constructor stub environment.  The receiver should
9452
    // actually be the constructor function, but we pass the newly allocated
9453
    // object instead, DoComputeConstructStubFrame() relies on that.
9454
    outer = CreateStubEnvironment(outer, target, JS_CONSTRUCT, arguments);
9455
  } else if (inlining_kind == GETTER_CALL_RETURN) {
9456
    // We need an additional StackFrame::INTERNAL frame for restoring the
9457
    // correct context.
9458
    outer = CreateStubEnvironment(outer, target, JS_GETTER, arguments);
9459
  } else if (inlining_kind == SETTER_CALL_RETURN) {
9460
    // We need an additional StackFrame::INTERNAL frame for temporarily saving
9461
    // the argument of the setter, see StoreStubCompiler::CompileStoreViaSetter.
9462
    outer = CreateStubEnvironment(outer, target, JS_SETTER, arguments);
9463
  }
9464

    
9465
  if (arity != arguments) {
9466
    // Create artificial arguments adaptation environment.
9467
    outer = CreateStubEnvironment(outer, target, ARGUMENTS_ADAPTOR, arguments);
9468
  }
9469

    
9470
  HEnvironment* inner =
9471
      new(zone()) HEnvironment(outer, function->scope(), target, zone());
9472
  // Get the argument values from the original environment.
9473
  for (int i = 0; i <= arity; ++i) {  // Include receiver.
9474
    HValue* push = (i <= arguments) ?
9475
        ExpressionStackAt(arguments - i) : undefined;
9476
    inner->SetValueAt(i, push);
9477
  }
9478
  // If the function we are inlining is a strict mode function or a
9479
  // builtin function, pass undefined as the receiver for function
9480
  // calls (instead of the global receiver).
9481
  if (undefined_receiver) {
9482
    inner->SetValueAt(0, undefined);
9483
  }
9484
  inner->SetValueAt(arity + 1, context());
9485
  for (int i = arity + 2; i < inner->length(); ++i) {
9486
    inner->SetValueAt(i, undefined);
9487
  }
9488

    
9489
  inner->set_ast_id(BailoutId::FunctionEntry());
9490
  return inner;
9491
}
9492

    
9493

    
9494
void HEnvironment::PrintTo(StringStream* stream) {
9495
  for (int i = 0; i < length(); i++) {
9496
    if (i == 0) stream->Add("parameters\n");
9497
    if (i == parameter_count()) stream->Add("specials\n");
9498
    if (i == parameter_count() + specials_count()) stream->Add("locals\n");
9499
    if (i == parameter_count() + specials_count() + local_count()) {
9500
      stream->Add("expressions\n");
9501
    }
9502
    HValue* val = values_.at(i);
9503
    stream->Add("%d: ", i);
9504
    if (val != NULL) {
9505
      val->PrintNameTo(stream);
9506
    } else {
9507
      stream->Add("NULL");
9508
    }
9509
    stream->Add("\n");
9510
  }
9511
  PrintF("\n");
9512
}
9513

    
9514

    
9515
void HEnvironment::PrintToStd() {
9516
  HeapStringAllocator string_allocator;
9517
  StringStream trace(&string_allocator);
9518
  PrintTo(&trace);
9519
  PrintF("%s", *trace.ToCString());
9520
}
9521

    
9522

    
9523
void HTracer::TraceCompilation(CompilationInfo* info) {
9524
  Tag tag(this, "compilation");
9525
  if (info->IsOptimizing()) {
9526
    Handle<String> name = info->function()->debug_name();
9527
    PrintStringProperty("name", *name->ToCString());
9528
    PrintStringProperty("method", *name->ToCString());
9529
  } else {
9530
    CodeStub::Major major_key = info->code_stub()->MajorKey();
9531
    PrintStringProperty("name", CodeStub::MajorName(major_key, false));
9532
    PrintStringProperty("method", "stub");
9533
  }
9534
  PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis()));
9535
}
9536

    
9537

    
9538
void HTracer::TraceLithium(const char* name, LChunk* chunk) {
9539
  ASSERT(!FLAG_concurrent_recompilation);
9540
  AllowHandleDereference allow_deref;
9541
  AllowDeferredHandleDereference allow_deferred_deref;
9542
  Trace(name, chunk->graph(), chunk);
9543
}
9544

    
9545

    
9546
void HTracer::TraceHydrogen(const char* name, HGraph* graph) {
9547
  ASSERT(!FLAG_concurrent_recompilation);
9548
  AllowHandleDereference allow_deref;
9549
  AllowDeferredHandleDereference allow_deferred_deref;
9550
  Trace(name, graph, NULL);
9551
}
9552

    
9553

    
9554
void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
9555
  Tag tag(this, "cfg");
9556
  PrintStringProperty("name", name);
9557
  const ZoneList<HBasicBlock*>* blocks = graph->blocks();
9558
  for (int i = 0; i < blocks->length(); i++) {
9559
    HBasicBlock* current = blocks->at(i);
9560
    Tag block_tag(this, "block");
9561
    PrintBlockProperty("name", current->block_id());
9562
    PrintIntProperty("from_bci", -1);
9563
    PrintIntProperty("to_bci", -1);
9564

    
9565
    if (!current->predecessors()->is_empty()) {
9566
      PrintIndent();
9567
      trace_.Add("predecessors");
9568
      for (int j = 0; j < current->predecessors()->length(); ++j) {
9569
        trace_.Add(" \"B%d\"", current->predecessors()->at(j)->block_id());
9570
      }
9571
      trace_.Add("\n");
9572
    } else {
9573
      PrintEmptyProperty("predecessors");
9574
    }
9575

    
9576
    if (current->end()->SuccessorCount() == 0) {
9577
      PrintEmptyProperty("successors");
9578
    } else  {
9579
      PrintIndent();
9580
      trace_.Add("successors");
9581
      for (HSuccessorIterator it(current->end()); !it.Done(); it.Advance()) {
9582
        trace_.Add(" \"B%d\"", it.Current()->block_id());
9583
      }
9584
      trace_.Add("\n");
9585
    }
9586

    
9587
    PrintEmptyProperty("xhandlers");
9588
    const char* flags = current->IsLoopSuccessorDominator()
9589
        ? "dom-loop-succ"
9590
        : "";
9591
    PrintStringProperty("flags", flags);
9592

    
9593
    if (current->dominator() != NULL) {
9594
      PrintBlockProperty("dominator", current->dominator()->block_id());
9595
    }
9596

    
9597
    PrintIntProperty("loop_depth", current->LoopNestingDepth());
9598

    
9599
    if (chunk != NULL) {
9600
      int first_index = current->first_instruction_index();
9601
      int last_index = current->last_instruction_index();
9602
      PrintIntProperty(
9603
          "first_lir_id",
9604
          LifetimePosition::FromInstructionIndex(first_index).Value());
9605
      PrintIntProperty(
9606
          "last_lir_id",
9607
          LifetimePosition::FromInstructionIndex(last_index).Value());
9608
    }
9609

    
9610
    {
9611
      Tag states_tag(this, "states");
9612
      Tag locals_tag(this, "locals");
9613
      int total = current->phis()->length();
9614
      PrintIntProperty("size", current->phis()->length());
9615
      PrintStringProperty("method", "None");
9616
      for (int j = 0; j < total; ++j) {
9617
        HPhi* phi = current->phis()->at(j);
9618
        PrintIndent();
9619
        trace_.Add("%d ", phi->merged_index());
9620
        phi->PrintNameTo(&trace_);
9621
        trace_.Add(" ");
9622
        phi->PrintTo(&trace_);
9623
        trace_.Add("\n");
9624
      }
9625
    }
9626

    
9627
    {
9628
      Tag HIR_tag(this, "HIR");
9629
      for (HInstructionIterator it(current); !it.Done(); it.Advance()) {
9630
        HInstruction* instruction = it.Current();
9631
        int bci = 0;
9632
        int uses = instruction->UseCount();
9633
        PrintIndent();
9634
        trace_.Add("%d %d ", bci, uses);
9635
        instruction->PrintNameTo(&trace_);
9636
        trace_.Add(" ");
9637
        instruction->PrintTo(&trace_);
9638
        trace_.Add(" <|@\n");
9639
      }
9640
    }
9641

    
9642

    
9643
    if (chunk != NULL) {
9644
      Tag LIR_tag(this, "LIR");
9645
      int first_index = current->first_instruction_index();
9646
      int last_index = current->last_instruction_index();
9647
      if (first_index != -1 && last_index != -1) {
9648
        const ZoneList<LInstruction*>* instructions = chunk->instructions();
9649
        for (int i = first_index; i <= last_index; ++i) {
9650
          LInstruction* linstr = instructions->at(i);
9651
          if (linstr != NULL) {
9652
            PrintIndent();
9653
            trace_.Add("%d ",
9654
                       LifetimePosition::FromInstructionIndex(i).Value());
9655
            linstr->PrintTo(&trace_);
9656
            trace_.Add(" <|@\n");
9657
          }
9658
        }
9659
      }
9660
    }
9661
  }
9662
}
9663

    
9664

    
9665
void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) {
9666
  Tag tag(this, "intervals");
9667
  PrintStringProperty("name", name);
9668

    
9669
  const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges();
9670
  for (int i = 0; i < fixed_d->length(); ++i) {
9671
    TraceLiveRange(fixed_d->at(i), "fixed", allocator->zone());
9672
  }
9673

    
9674
  const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges();
9675
  for (int i = 0; i < fixed->length(); ++i) {
9676
    TraceLiveRange(fixed->at(i), "fixed", allocator->zone());
9677
  }
9678

    
9679
  const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges();
9680
  for (int i = 0; i < live_ranges->length(); ++i) {
9681
    TraceLiveRange(live_ranges->at(i), "object", allocator->zone());
9682
  }
9683
}
9684

    
9685

    
9686
void HTracer::TraceLiveRange(LiveRange* range, const char* type,
9687
                             Zone* zone) {
9688
  if (range != NULL && !range->IsEmpty()) {
9689
    PrintIndent();
9690
    trace_.Add("%d %s", range->id(), type);
9691
    if (range->HasRegisterAssigned()) {
9692
      LOperand* op = range->CreateAssignedOperand(zone);
9693
      int assigned_reg = op->index();
9694
      if (op->IsDoubleRegister()) {
9695
        trace_.Add(" \"%s\"",
9696
                   DoubleRegister::AllocationIndexToString(assigned_reg));
9697
      } else {
9698
        ASSERT(op->IsRegister());
9699
        trace_.Add(" \"%s\"", Register::AllocationIndexToString(assigned_reg));
9700
      }
9701
    } else if (range->IsSpilled()) {
9702
      LOperand* op = range->TopLevel()->GetSpillOperand();
9703
      if (op->IsDoubleStackSlot()) {
9704
        trace_.Add(" \"double_stack:%d\"", op->index());
9705
      } else {
9706
        ASSERT(op->IsStackSlot());
9707
        trace_.Add(" \"stack:%d\"", op->index());
9708
      }
9709
    }
9710
    int parent_index = -1;
9711
    if (range->IsChild()) {
9712
      parent_index = range->parent()->id();
9713
    } else {
9714
      parent_index = range->id();
9715
    }
9716
    LOperand* op = range->FirstHint();
9717
    int hint_index = -1;
9718
    if (op != NULL && op->IsUnallocated()) {
9719
      hint_index = LUnallocated::cast(op)->virtual_register();
9720
    }
9721
    trace_.Add(" %d %d", parent_index, hint_index);
9722
    UseInterval* cur_interval = range->first_interval();
9723
    while (cur_interval != NULL && range->Covers(cur_interval->start())) {
9724
      trace_.Add(" [%d, %d[",
9725
                 cur_interval->start().Value(),
9726
                 cur_interval->end().Value());
9727
      cur_interval = cur_interval->next();
9728
    }
9729

    
9730
    UsePosition* current_pos = range->first_pos();
9731
    while (current_pos != NULL) {
9732
      if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
9733
        trace_.Add(" %d M", current_pos->pos().Value());
9734
      }
9735
      current_pos = current_pos->next();
9736
    }
9737

    
9738
    trace_.Add(" \"\"\n");
9739
  }
9740
}
9741

    
9742

    
9743
void HTracer::FlushToFile() {
9744
  AppendChars(filename_.start(), *trace_.ToCString(), trace_.length(), false);
9745
  trace_.Reset();
9746
}
9747

    
9748

    
9749
void HStatistics::Initialize(CompilationInfo* info) {
9750
  if (info->shared_info().is_null()) return;
9751
  source_size_ += info->shared_info()->SourceSize();
9752
}
9753

    
9754

    
9755
void HStatistics::Print() {
9756
  PrintF("Timing results:\n");
9757
  TimeDelta sum;
9758
  for (int i = 0; i < times_.length(); ++i) {
9759
    sum += times_[i];
9760
  }
9761

    
9762
  for (int i = 0; i < names_.length(); ++i) {
9763
    PrintF("%32s", names_[i]);
9764
    double ms = times_[i].InMillisecondsF();
9765
    double percent = times_[i].PercentOf(sum);
9766
    PrintF(" %8.3f ms / %4.1f %% ", ms, percent);
9767

    
9768
    unsigned size = sizes_[i];
9769
    double size_percent = static_cast<double>(size) * 100 / total_size_;
9770
    PrintF(" %9u bytes / %4.1f %%\n", size, size_percent);
9771
  }
9772

    
9773
  PrintF("----------------------------------------"
9774
         "---------------------------------------\n");
9775
  TimeDelta total = create_graph_ + optimize_graph_ + generate_code_;
9776
  PrintF("%32s %8.3f ms / %4.1f %% \n",
9777
         "Create graph",
9778
         create_graph_.InMillisecondsF(),
9779
         create_graph_.PercentOf(total));
9780
  PrintF("%32s %8.3f ms / %4.1f %% \n",
9781
         "Optimize graph",
9782
         optimize_graph_.InMillisecondsF(),
9783
         optimize_graph_.PercentOf(total));
9784
  PrintF("%32s %8.3f ms / %4.1f %% \n",
9785
         "Generate and install code",
9786
         generate_code_.InMillisecondsF(),
9787
         generate_code_.PercentOf(total));
9788
  PrintF("----------------------------------------"
9789
         "---------------------------------------\n");
9790
  PrintF("%32s %8.3f ms (%.1f times slower than full code gen)\n",
9791
         "Total",
9792
         total.InMillisecondsF(),
9793
         total.TimesOf(full_code_gen_));
9794

    
9795
  double source_size_in_kb = static_cast<double>(source_size_) / 1024;
9796
  double normalized_time =  source_size_in_kb > 0
9797
      ? total.InMillisecondsF() / source_size_in_kb
9798
      : 0;
9799
  double normalized_size_in_kb = source_size_in_kb > 0
9800
      ? total_size_ / 1024 / source_size_in_kb
9801
      : 0;
9802
  PrintF("%32s %8.3f ms           %7.3f kB allocated\n",
9803
         "Average per kB source",
9804
         normalized_time, normalized_size_in_kb);
9805
}
9806

    
9807

    
9808
void HStatistics::SaveTiming(const char* name, TimeDelta time, unsigned size) {
9809
  total_size_ += size;
9810
  for (int i = 0; i < names_.length(); ++i) {
9811
    if (strcmp(names_[i], name) == 0) {
9812
      times_[i] += time;
9813
      sizes_[i] += size;
9814
      return;
9815
    }
9816
  }
9817
  names_.Add(name);
9818
  times_.Add(time);
9819
  sizes_.Add(size);
9820
}
9821

    
9822

    
9823
HPhase::~HPhase() {
9824
  if (ShouldProduceTraceOutput()) {
9825
    isolate()->GetHTracer()->TraceHydrogen(name(), graph_);
9826
  }
9827

    
9828
#ifdef DEBUG
9829
  graph_->Verify(false);  // No full verify.
9830
#endif
9831
}
9832

    
9833
} }  // namespace v8::internal