~evarlast/ubuntu/utopic/mongodb/upstart-workaround-debian-bug-718702

« back to all changes in this revision

Viewing changes to src/third_party/v8/src/hydrogen.cc

  • Committer: Package Import Robot
  • Author(s): James Page, James Page, Robie Basak
  • Date: 2013-05-29 17:44:42 UTC
  • mfrom: (44.1.7 sid)
  • Revision ID: package-import@ubuntu.com-20130529174442-z0a4qmoww4y0t458
Tags: 1:2.4.3-1ubuntu1
[ James Page ]
* Merge from Debian unstable, remaining changes:
  - Enable SSL support:
    + d/control: Add libssl-dev to BD's.
    + d/rules: Enabled --ssl option.
    + d/mongodb.conf: Add example SSL configuration options.
  - d/mongodb-server.mongodb.upstart: Add upstart configuration.
  - d/rules: Don't strip binaries during scons build for Ubuntu.
  - d/control: Add armhf to target archs.
  - d/p/SConscript.client.patch: fixup install of client libraries.
  - d/p/0010-install-libs-to-usr-lib-not-usr-lib64-Closes-588557.patch:
    Install libraries to lib not lib64.
* Dropped changes:
  - d/p/arm-support.patch: Included in Debian.
  - d/p/double-alignment.patch: Included in Debian.
  - d/rules,control: Debian also builds with avaliable system libraries
    now.
* Fix FTBFS due to gcc and boost upgrades in saucy:
  - d/p/0008-ignore-unused-local-typedefs.patch: Add -Wno-unused-typedefs
    to unbreak building with g++-4.8.
  - d/p/0009-boost-1.53.patch: Fixup signed/unsigned casting issue.

[ Robie Basak ]
* d/p/0011-Use-a-signed-char-to-store-BSONType-enumerations.patch: Fixup
  build failure on ARM due to missing signed'ness of char cast.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2012 the V8 project authors. All rights reserved.
 
2
// Redistribution and use in source and binary forms, with or without
 
3
// modification, are permitted provided that the following conditions are
 
4
// met:
 
5
//
 
6
//     * Redistributions of source code must retain the above copyright
 
7
//       notice, this list of conditions and the following disclaimer.
 
8
//     * Redistributions in binary form must reproduce the above
 
9
//       copyright notice, this list of conditions and the following
 
10
//       disclaimer in the documentation and/or other materials provided
 
11
//       with the distribution.
 
12
//     * Neither the name of Google Inc. nor the names of its
 
13
//       contributors may be used to endorse or promote products derived
 
14
//       from this software without specific prior written permission.
 
15
//
 
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
17
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
18
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
19
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
20
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
23
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
24
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
25
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
26
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
27
 
 
28
#include "v8.h"
 
29
#include "hydrogen.h"
 
30
 
 
31
#include "codegen.h"
 
32
#include "full-codegen.h"
 
33
#include "hashmap.h"
 
34
#include "lithium-allocator.h"
 
35
#include "parser.h"
 
36
#include "scopeinfo.h"
 
37
#include "scopes.h"
 
38
#include "stub-cache.h"
 
39
 
 
40
#if V8_TARGET_ARCH_IA32
 
41
#include "ia32/lithium-codegen-ia32.h"
 
42
#elif V8_TARGET_ARCH_X64
 
43
#include "x64/lithium-codegen-x64.h"
 
44
#elif V8_TARGET_ARCH_ARM
 
45
#include "arm/lithium-codegen-arm.h"
 
46
#elif V8_TARGET_ARCH_MIPS
 
47
#include "mips/lithium-codegen-mips.h"
 
48
#else
 
49
#error Unsupported target architecture.
 
50
#endif
 
51
 
 
52
namespace v8 {
 
53
namespace internal {
 
54
 
 
55
HBasicBlock::HBasicBlock(HGraph* graph)
 
56
    : block_id_(graph->GetNextBlockID()),
 
57
      graph_(graph),
 
58
      phis_(4, graph->zone()),
 
59
      first_(NULL),
 
60
      last_(NULL),
 
61
      end_(NULL),
 
62
      loop_information_(NULL),
 
63
      predecessors_(2, graph->zone()),
 
64
      dominator_(NULL),
 
65
      dominated_blocks_(4, graph->zone()),
 
66
      last_environment_(NULL),
 
67
      argument_count_(-1),
 
68
      first_instruction_index_(-1),
 
69
      last_instruction_index_(-1),
 
70
      deleted_phis_(4, graph->zone()),
 
71
      parent_loop_header_(NULL),
 
72
      is_inline_return_target_(false),
 
73
      is_deoptimizing_(false),
 
74
      dominates_loop_successors_(false) { }
 
75
 
 
76
 
 
77
void HBasicBlock::AttachLoopInformation() {
 
78
  ASSERT(!IsLoopHeader());
 
79
  loop_information_ = new(zone()) HLoopInformation(this, zone());
 
80
}
 
81
 
 
82
 
 
83
void HBasicBlock::DetachLoopInformation() {
 
84
  ASSERT(IsLoopHeader());
 
85
  loop_information_ = NULL;
 
86
}
 
87
 
 
88
 
 
89
void HBasicBlock::AddPhi(HPhi* phi) {
 
90
  ASSERT(!IsStartBlock());
 
91
  phis_.Add(phi, zone());
 
92
  phi->SetBlock(this);
 
93
}
 
94
 
 
95
 
 
96
void HBasicBlock::RemovePhi(HPhi* phi) {
 
97
  ASSERT(phi->block() == this);
 
98
  ASSERT(phis_.Contains(phi));
 
99
  ASSERT(phi->HasNoUses() || !phi->is_live());
 
100
  phi->Kill();
 
101
  phis_.RemoveElement(phi);
 
102
  phi->SetBlock(NULL);
 
103
}
 
104
 
 
105
 
 
106
void HBasicBlock::AddInstruction(HInstruction* instr) {
 
107
  ASSERT(!IsStartBlock() || !IsFinished());
 
108
  ASSERT(!instr->IsLinked());
 
109
  ASSERT(!IsFinished());
 
110
  if (first_ == NULL) {
 
111
    HBlockEntry* entry = new(zone()) HBlockEntry();
 
112
    entry->InitializeAsFirst(this);
 
113
    first_ = last_ = entry;
 
114
  }
 
115
  instr->InsertAfter(last_);
 
116
}
 
117
 
 
118
 
 
119
HDeoptimize* HBasicBlock::CreateDeoptimize(
 
120
    HDeoptimize::UseEnvironment has_uses) {
 
121
  ASSERT(HasEnvironment());
 
122
  if (has_uses == HDeoptimize::kNoUses)
 
123
    return new(zone()) HDeoptimize(0, zone());
 
124
 
 
125
  HEnvironment* environment = last_environment();
 
126
  HDeoptimize* instr = new(zone()) HDeoptimize(environment->length(), zone());
 
127
  for (int i = 0; i < environment->length(); i++) {
 
128
    HValue* val = environment->values()->at(i);
 
129
    instr->AddEnvironmentValue(val, zone());
 
130
  }
 
131
 
 
132
  return instr;
 
133
}
 
134
 
 
135
 
 
136
HSimulate* HBasicBlock::CreateSimulate(int ast_id) {
 
137
  ASSERT(HasEnvironment());
 
138
  HEnvironment* environment = last_environment();
 
139
  ASSERT(ast_id == AstNode::kNoNumber ||
 
140
         environment->closure()->shared()->VerifyBailoutId(ast_id));
 
141
 
 
142
  int push_count = environment->push_count();
 
143
  int pop_count = environment->pop_count();
 
144
 
 
145
  HSimulate* instr = new(zone()) HSimulate(ast_id, pop_count, zone());
 
146
  for (int i = push_count - 1; i >= 0; --i) {
 
147
    instr->AddPushedValue(environment->ExpressionStackAt(i));
 
148
  }
 
149
  for (int i = 0; i < environment->assigned_variables()->length(); ++i) {
 
150
    int index = environment->assigned_variables()->at(i);
 
151
    instr->AddAssignedValue(index, environment->Lookup(index));
 
152
  }
 
153
  environment->ClearHistory();
 
154
  return instr;
 
155
}
 
156
 
 
157
 
 
158
void HBasicBlock::Finish(HControlInstruction* end) {
 
159
  ASSERT(!IsFinished());
 
160
  AddInstruction(end);
 
161
  end_ = end;
 
162
  for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
 
163
    it.Current()->RegisterPredecessor(this);
 
164
  }
 
165
}
 
166
 
 
167
 
 
168
void HBasicBlock::Goto(HBasicBlock* block, FunctionState* state) {
 
169
  bool drop_extra = state != NULL && state->drop_extra();
 
170
  bool arguments_pushed = state != NULL && state->arguments_pushed();
 
171
 
 
172
  if (block->IsInlineReturnTarget()) {
 
173
    AddInstruction(new(zone()) HLeaveInlined(arguments_pushed));
 
174
    last_environment_ = last_environment()->DiscardInlined(drop_extra);
 
175
  }
 
176
 
 
177
  AddSimulate(AstNode::kNoNumber);
 
178
  HGoto* instr = new(zone()) HGoto(block);
 
179
  Finish(instr);
 
180
}
 
181
 
 
182
 
 
183
void HBasicBlock::AddLeaveInlined(HValue* return_value,
 
184
                                  HBasicBlock* target,
 
185
                                  FunctionState* state) {
 
186
  bool drop_extra = state != NULL && state->drop_extra();
 
187
  bool arguments_pushed = state != NULL && state->arguments_pushed();
 
188
 
 
189
  ASSERT(target->IsInlineReturnTarget());
 
190
  ASSERT(return_value != NULL);
 
191
  AddInstruction(new(zone()) HLeaveInlined(arguments_pushed));
 
192
  last_environment_ = last_environment()->DiscardInlined(drop_extra);
 
193
  last_environment()->Push(return_value);
 
194
  AddSimulate(AstNode::kNoNumber);
 
195
  HGoto* instr = new(zone()) HGoto(target);
 
196
  Finish(instr);
 
197
}
 
198
 
 
199
 
 
200
void HBasicBlock::SetInitialEnvironment(HEnvironment* env) {
 
201
  ASSERT(!HasEnvironment());
 
202
  ASSERT(first() == NULL);
 
203
  UpdateEnvironment(env);
 
204
}
 
205
 
 
206
 
 
207
void HBasicBlock::SetJoinId(int ast_id) {
 
208
  int length = predecessors_.length();
 
209
  ASSERT(length > 0);
 
210
  for (int i = 0; i < length; i++) {
 
211
    HBasicBlock* predecessor = predecessors_[i];
 
212
    ASSERT(predecessor->end()->IsGoto());
 
213
    HSimulate* simulate = HSimulate::cast(predecessor->end()->previous());
 
214
    // We only need to verify the ID once.
 
215
    ASSERT(i != 0 ||
 
216
           predecessor->last_environment()->closure()->shared()
 
217
               ->VerifyBailoutId(ast_id));
 
218
    simulate->set_ast_id(ast_id);
 
219
  }
 
220
}
 
221
 
 
222
 
 
223
bool HBasicBlock::Dominates(HBasicBlock* other) const {
 
224
  HBasicBlock* current = other->dominator();
 
225
  while (current != NULL) {
 
226
    if (current == this) return true;
 
227
    current = current->dominator();
 
228
  }
 
229
  return false;
 
230
}
 
231
 
 
232
 
 
233
int HBasicBlock::LoopNestingDepth() const {
 
234
  const HBasicBlock* current = this;
 
235
  int result  = (current->IsLoopHeader()) ? 1 : 0;
 
236
  while (current->parent_loop_header() != NULL) {
 
237
    current = current->parent_loop_header();
 
238
    result++;
 
239
  }
 
240
  return result;
 
241
}
 
242
 
 
243
 
 
244
void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) {
 
245
  ASSERT(IsLoopHeader());
 
246
 
 
247
  SetJoinId(stmt->EntryId());
 
248
  if (predecessors()->length() == 1) {
 
249
    // This is a degenerated loop.
 
250
    DetachLoopInformation();
 
251
    return;
 
252
  }
 
253
 
 
254
  // Only the first entry into the loop is from outside the loop. All other
 
255
  // entries must be back edges.
 
256
  for (int i = 1; i < predecessors()->length(); ++i) {
 
257
    loop_information()->RegisterBackEdge(predecessors()->at(i));
 
258
  }
 
259
}
 
260
 
 
261
 
 
262
void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) {
 
263
  if (HasPredecessor()) {
 
264
    // Only loop header blocks can have a predecessor added after
 
265
    // instructions have been added to the block (they have phis for all
 
266
    // values in the environment, these phis may be eliminated later).
 
267
    ASSERT(IsLoopHeader() || first_ == NULL);
 
268
    HEnvironment* incoming_env = pred->last_environment();
 
269
    if (IsLoopHeader()) {
 
270
      ASSERT(phis()->length() == incoming_env->length());
 
271
      for (int i = 0; i < phis_.length(); ++i) {
 
272
        phis_[i]->AddInput(incoming_env->values()->at(i));
 
273
      }
 
274
    } else {
 
275
      last_environment()->AddIncomingEdge(this, pred->last_environment());
 
276
    }
 
277
  } else if (!HasEnvironment() && !IsFinished()) {
 
278
    ASSERT(!IsLoopHeader());
 
279
    SetInitialEnvironment(pred->last_environment()->Copy());
 
280
  }
 
281
 
 
282
  predecessors_.Add(pred, zone());
 
283
}
 
284
 
 
285
 
 
286
void HBasicBlock::AddDominatedBlock(HBasicBlock* block) {
 
287
  ASSERT(!dominated_blocks_.Contains(block));
 
288
  // Keep the list of dominated blocks sorted such that if there is two
 
289
  // succeeding block in this list, the predecessor is before the successor.
 
290
  int index = 0;
 
291
  while (index < dominated_blocks_.length() &&
 
292
         dominated_blocks_[index]->block_id() < block->block_id()) {
 
293
    ++index;
 
294
  }
 
295
  dominated_blocks_.InsertAt(index, block, zone());
 
296
}
 
297
 
 
298
 
 
299
void HBasicBlock::AssignCommonDominator(HBasicBlock* other) {
 
300
  if (dominator_ == NULL) {
 
301
    dominator_ = other;
 
302
    other->AddDominatedBlock(this);
 
303
  } else if (other->dominator() != NULL) {
 
304
    HBasicBlock* first = dominator_;
 
305
    HBasicBlock* second = other;
 
306
 
 
307
    while (first != second) {
 
308
      if (first->block_id() > second->block_id()) {
 
309
        first = first->dominator();
 
310
      } else {
 
311
        second = second->dominator();
 
312
      }
 
313
      ASSERT(first != NULL && second != NULL);
 
314
    }
 
315
 
 
316
    if (dominator_ != first) {
 
317
      ASSERT(dominator_->dominated_blocks_.Contains(this));
 
318
      dominator_->dominated_blocks_.RemoveElement(this);
 
319
      dominator_ = first;
 
320
      first->AddDominatedBlock(this);
 
321
    }
 
322
  }
 
323
}
 
324
 
 
325
 
 
326
void HBasicBlock::AssignLoopSuccessorDominators() {
 
327
  // Mark blocks that dominate all subsequent reachable blocks inside their
 
328
  // loop. Exploit the fact that blocks are sorted in reverse post order. When
 
329
  // the loop is visited in increasing block id order, if the number of
 
330
  // non-loop-exiting successor edges at the dominator_candidate block doesn't
 
331
  // exceed the number of previously encountered predecessor edges, there is no
 
332
  // path from the loop header to any block with higher id that doesn't go
 
333
  // through the dominator_candidate block. In this case, the
 
334
  // dominator_candidate block is guaranteed to dominate all blocks reachable
 
335
  // from it with higher ids.
 
336
  HBasicBlock* last = loop_information()->GetLastBackEdge();
 
337
  int outstanding_successors = 1;  // one edge from the pre-header
 
338
  // Header always dominates everything.
 
339
  MarkAsLoopSuccessorDominator();
 
340
  for (int j = block_id(); j <= last->block_id(); ++j) {
 
341
    HBasicBlock* dominator_candidate = graph_->blocks()->at(j);
 
342
    for (HPredecessorIterator it(dominator_candidate); !it.Done();
 
343
         it.Advance()) {
 
344
      HBasicBlock* predecessor = it.Current();
 
345
      // Don't count back edges.
 
346
      if (predecessor->block_id() < dominator_candidate->block_id()) {
 
347
        outstanding_successors--;
 
348
      }
 
349
    }
 
350
 
 
351
    // If more successors than predecessors have been seen in the loop up to
 
352
    // now, it's not possible to guarantee that the current block dominates
 
353
    // all of the blocks with higher IDs. In this case, assume conservatively
 
354
    // that those paths through loop that don't go through the current block
 
355
    // contain all of the loop's dependencies. Also be careful to record
 
356
    // dominator information about the current loop that's being processed,
 
357
    // and not nested loops, which will be processed when
 
358
    // AssignLoopSuccessorDominators gets called on their header.
 
359
    ASSERT(outstanding_successors >= 0);
 
360
    HBasicBlock* parent_loop_header = dominator_candidate->parent_loop_header();
 
361
    if (outstanding_successors == 0 &&
 
362
        (parent_loop_header == this && !dominator_candidate->IsLoopHeader())) {
 
363
      dominator_candidate->MarkAsLoopSuccessorDominator();
 
364
    }
 
365
    HControlInstruction* end = dominator_candidate->end();
 
366
    for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
 
367
      HBasicBlock* successor = it.Current();
 
368
      // Only count successors that remain inside the loop and don't loop back
 
369
      // to a loop header.
 
370
      if (successor->block_id() > dominator_candidate->block_id() &&
 
371
          successor->block_id() <= last->block_id()) {
 
372
        // Backwards edges must land on loop headers.
 
373
        ASSERT(successor->block_id() > dominator_candidate->block_id() ||
 
374
               successor->IsLoopHeader());
 
375
        outstanding_successors++;
 
376
      }
 
377
    }
 
378
  }
 
379
}
 
380
 
 
381
 
 
382
int HBasicBlock::PredecessorIndexOf(HBasicBlock* predecessor) const {
 
383
  for (int i = 0; i < predecessors_.length(); ++i) {
 
384
    if (predecessors_[i] == predecessor) return i;
 
385
  }
 
386
  UNREACHABLE();
 
387
  return -1;
 
388
}
 
389
 
 
390
 
 
391
#ifdef DEBUG
 
392
void HBasicBlock::Verify() {
 
393
  // Check that every block is finished.
 
394
  ASSERT(IsFinished());
 
395
  ASSERT(block_id() >= 0);
 
396
 
 
397
  // Check that the incoming edges are in edge split form.
 
398
  if (predecessors_.length() > 1) {
 
399
    for (int i = 0; i < predecessors_.length(); ++i) {
 
400
      ASSERT(predecessors_[i]->end()->SecondSuccessor() == NULL);
 
401
    }
 
402
  }
 
403
}
 
404
#endif
 
405
 
 
406
 
 
407
void HLoopInformation::RegisterBackEdge(HBasicBlock* block) {
 
408
  this->back_edges_.Add(block, block->zone());
 
409
  AddBlock(block);
 
410
}
 
411
 
 
412
 
 
413
HBasicBlock* HLoopInformation::GetLastBackEdge() const {
 
414
  int max_id = -1;
 
415
  HBasicBlock* result = NULL;
 
416
  for (int i = 0; i < back_edges_.length(); ++i) {
 
417
    HBasicBlock* cur = back_edges_[i];
 
418
    if (cur->block_id() > max_id) {
 
419
      max_id = cur->block_id();
 
420
      result = cur;
 
421
    }
 
422
  }
 
423
  return result;
 
424
}
 
425
 
 
426
 
 
427
void HLoopInformation::AddBlock(HBasicBlock* block) {
 
428
  if (block == loop_header()) return;
 
429
  if (block->parent_loop_header() == loop_header()) return;
 
430
  if (block->parent_loop_header() != NULL) {
 
431
    AddBlock(block->parent_loop_header());
 
432
  } else {
 
433
    block->set_parent_loop_header(loop_header());
 
434
    blocks_.Add(block, block->zone());
 
435
    for (int i = 0; i < block->predecessors()->length(); ++i) {
 
436
      AddBlock(block->predecessors()->at(i));
 
437
    }
 
438
  }
 
439
}
 
440
 
 
441
 
 
442
#ifdef DEBUG
 
443
 
 
444
// Checks reachability of the blocks in this graph and stores a bit in
 
445
// the BitVector "reachable()" for every block that can be reached
 
446
// from the start block of the graph. If "dont_visit" is non-null, the given
 
447
// block is treated as if it would not be part of the graph. "visited_count()"
 
448
// returns the number of reachable blocks.
 
449
class ReachabilityAnalyzer BASE_EMBEDDED {
 
450
 public:
 
451
  ReachabilityAnalyzer(HBasicBlock* entry_block,
 
452
                       int block_count,
 
453
                       HBasicBlock* dont_visit)
 
454
      : visited_count_(0),
 
455
        stack_(16, entry_block->zone()),
 
456
        reachable_(block_count, entry_block->zone()),
 
457
        dont_visit_(dont_visit) {
 
458
    PushBlock(entry_block);
 
459
    Analyze();
 
460
  }
 
461
 
 
462
  int visited_count() const { return visited_count_; }
 
463
  const BitVector* reachable() const { return &reachable_; }
 
464
 
 
465
 private:
 
466
  void PushBlock(HBasicBlock* block) {
 
467
    if (block != NULL && block != dont_visit_ &&
 
468
        !reachable_.Contains(block->block_id())) {
 
469
      reachable_.Add(block->block_id());
 
470
      stack_.Add(block, block->zone());
 
471
      visited_count_++;
 
472
    }
 
473
  }
 
474
 
 
475
  void Analyze() {
 
476
    while (!stack_.is_empty()) {
 
477
      HControlInstruction* end = stack_.RemoveLast()->end();
 
478
      for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
 
479
        PushBlock(it.Current());
 
480
      }
 
481
    }
 
482
  }
 
483
 
 
484
  int visited_count_;
 
485
  ZoneList<HBasicBlock*> stack_;
 
486
  BitVector reachable_;
 
487
  HBasicBlock* dont_visit_;
 
488
};
 
489
 
 
490
 
 
491
void HGraph::Verify(bool do_full_verify) const {
 
492
  for (int i = 0; i < blocks_.length(); i++) {
 
493
    HBasicBlock* block = blocks_.at(i);
 
494
 
 
495
    block->Verify();
 
496
 
 
497
    // Check that every block contains at least one node and that only the last
 
498
    // node is a control instruction.
 
499
    HInstruction* current = block->first();
 
500
    ASSERT(current != NULL && current->IsBlockEntry());
 
501
    while (current != NULL) {
 
502
      ASSERT((current->next() == NULL) == current->IsControlInstruction());
 
503
      ASSERT(current->block() == block);
 
504
      current->Verify();
 
505
      current = current->next();
 
506
    }
 
507
 
 
508
    // Check that successors are correctly set.
 
509
    HBasicBlock* first = block->end()->FirstSuccessor();
 
510
    HBasicBlock* second = block->end()->SecondSuccessor();
 
511
    ASSERT(second == NULL || first != NULL);
 
512
 
 
513
    // Check that the predecessor array is correct.
 
514
    if (first != NULL) {
 
515
      ASSERT(first->predecessors()->Contains(block));
 
516
      if (second != NULL) {
 
517
        ASSERT(second->predecessors()->Contains(block));
 
518
      }
 
519
    }
 
520
 
 
521
    // Check that phis have correct arguments.
 
522
    for (int j = 0; j < block->phis()->length(); j++) {
 
523
      HPhi* phi = block->phis()->at(j);
 
524
      phi->Verify();
 
525
    }
 
526
 
 
527
    // Check that all join blocks have predecessors that end with an
 
528
    // unconditional goto and agree on their environment node id.
 
529
    if (block->predecessors()->length() >= 2) {
 
530
      int id = block->predecessors()->first()->last_environment()->ast_id();
 
531
      for (int k = 0; k < block->predecessors()->length(); k++) {
 
532
        HBasicBlock* predecessor = block->predecessors()->at(k);
 
533
        ASSERT(predecessor->end()->IsGoto());
 
534
        ASSERT(predecessor->last_environment()->ast_id() == id);
 
535
      }
 
536
    }
 
537
  }
 
538
 
 
539
  // Check special property of first block to have no predecessors.
 
540
  ASSERT(blocks_.at(0)->predecessors()->is_empty());
 
541
 
 
542
  if (do_full_verify) {
 
543
    // Check that the graph is fully connected.
 
544
    ReachabilityAnalyzer analyzer(entry_block_, blocks_.length(), NULL);
 
545
    ASSERT(analyzer.visited_count() == blocks_.length());
 
546
 
 
547
    // Check that entry block dominator is NULL.
 
548
    ASSERT(entry_block_->dominator() == NULL);
 
549
 
 
550
    // Check dominators.
 
551
    for (int i = 0; i < blocks_.length(); ++i) {
 
552
      HBasicBlock* block = blocks_.at(i);
 
553
      if (block->dominator() == NULL) {
 
554
        // Only start block may have no dominator assigned to.
 
555
        ASSERT(i == 0);
 
556
      } else {
 
557
        // Assert that block is unreachable if dominator must not be visited.
 
558
        ReachabilityAnalyzer dominator_analyzer(entry_block_,
 
559
                                                blocks_.length(),
 
560
                                                block->dominator());
 
561
        ASSERT(!dominator_analyzer.reachable()->Contains(block->block_id()));
 
562
      }
 
563
    }
 
564
  }
 
565
}
 
566
 
 
567
#endif
 
568
 
 
569
 
 
570
HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer,
 
571
                               Handle<Object> value) {
 
572
  if (!pointer->is_set()) {
 
573
    HConstant* constant = new(zone()) HConstant(value,
 
574
                                                Representation::Tagged());
 
575
    constant->InsertAfter(GetConstantUndefined());
 
576
    pointer->set(constant);
 
577
  }
 
578
  return pointer->get();
 
579
}
 
580
 
 
581
 
 
582
HConstant* HGraph::GetConstantInt32(SetOncePointer<HConstant>* pointer,
 
583
                                    int32_t value) {
 
584
  if (!pointer->is_set()) {
 
585
    HConstant* constant =
 
586
        new(zone()) HConstant(value, Representation::Integer32());
 
587
    constant->InsertAfter(GetConstantUndefined());
 
588
    pointer->set(constant);
 
589
  }
 
590
  return pointer->get();
 
591
}
 
592
 
 
593
 
 
594
HConstant* HGraph::GetConstant1() {
 
595
  return GetConstantInt32(&constant_1_, 1);
 
596
}
 
597
 
 
598
 
 
599
HConstant* HGraph::GetConstantMinus1() {
 
600
  return GetConstantInt32(&constant_minus1_, -1);
 
601
}
 
602
 
 
603
 
 
604
HConstant* HGraph::GetConstantTrue() {
 
605
  return GetConstant(&constant_true_, isolate()->factory()->true_value());
 
606
}
 
607
 
 
608
 
 
609
HConstant* HGraph::GetConstantFalse() {
 
610
  return GetConstant(&constant_false_, isolate()->factory()->false_value());
 
611
}
 
612
 
 
613
 
 
614
HConstant* HGraph::GetConstantHole() {
 
615
  return GetConstant(&constant_hole_, isolate()->factory()->the_hole_value());
 
616
}
 
617
 
 
618
 
 
619
HGraphBuilder::HGraphBuilder(CompilationInfo* info,
 
620
                             TypeFeedbackOracle* oracle)
 
621
    : function_state_(NULL),
 
622
      initial_function_state_(this, info, oracle, NORMAL_RETURN),
 
623
      ast_context_(NULL),
 
624
      break_scope_(NULL),
 
625
      graph_(NULL),
 
626
      current_block_(NULL),
 
627
      inlined_count_(0),
 
628
      globals_(10, info->zone()),
 
629
      zone_(info->zone()),
 
630
      inline_bailout_(false) {
 
631
  // This is not initialized in the initializer list because the
 
632
  // constructor for the initial state relies on function_state_ == NULL
 
633
  // to know it's the initial state.
 
634
  function_state_= &initial_function_state_;
 
635
}
 
636
 
 
637
HBasicBlock* HGraphBuilder::CreateJoin(HBasicBlock* first,
 
638
                                       HBasicBlock* second,
 
639
                                       int join_id) {
 
640
  if (first == NULL) {
 
641
    return second;
 
642
  } else if (second == NULL) {
 
643
    return first;
 
644
  } else {
 
645
    HBasicBlock* join_block = graph_->CreateBasicBlock();
 
646
    first->Goto(join_block);
 
647
    second->Goto(join_block);
 
648
    join_block->SetJoinId(join_id);
 
649
    return join_block;
 
650
  }
 
651
}
 
652
 
 
653
 
 
654
HBasicBlock* HGraphBuilder::JoinContinue(IterationStatement* statement,
 
655
                                         HBasicBlock* exit_block,
 
656
                                         HBasicBlock* continue_block) {
 
657
  if (continue_block != NULL) {
 
658
    if (exit_block != NULL) exit_block->Goto(continue_block);
 
659
    continue_block->SetJoinId(statement->ContinueId());
 
660
    return continue_block;
 
661
  }
 
662
  return exit_block;
 
663
}
 
664
 
 
665
 
 
666
HBasicBlock* HGraphBuilder::CreateLoop(IterationStatement* statement,
 
667
                                       HBasicBlock* loop_entry,
 
668
                                       HBasicBlock* body_exit,
 
669
                                       HBasicBlock* loop_successor,
 
670
                                       HBasicBlock* break_block) {
 
671
  if (body_exit != NULL) body_exit->Goto(loop_entry);
 
672
  loop_entry->PostProcessLoopHeader(statement);
 
673
  if (break_block != NULL) {
 
674
    if (loop_successor != NULL) loop_successor->Goto(break_block);
 
675
    break_block->SetJoinId(statement->ExitId());
 
676
    return break_block;
 
677
  }
 
678
  return loop_successor;
 
679
}
 
680
 
 
681
 
 
682
void HBasicBlock::FinishExit(HControlInstruction* instruction) {
 
683
  Finish(instruction);
 
684
  ClearEnvironment();
 
685
}
 
686
 
 
687
 
 
688
HGraph::HGraph(CompilationInfo* info)
 
689
    : isolate_(info->isolate()),
 
690
      next_block_id_(0),
 
691
      entry_block_(NULL),
 
692
      blocks_(8, info->zone()),
 
693
      values_(16, info->zone()),
 
694
      phi_list_(NULL),
 
695
      info_(info),
 
696
      zone_(info->zone()),
 
697
      is_recursive_(false) {
 
698
  start_environment_ =
 
699
      new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_);
 
700
  start_environment_->set_ast_id(AstNode::kFunctionEntryId);
 
701
  entry_block_ = CreateBasicBlock();
 
702
  entry_block_->SetInitialEnvironment(start_environment_);
 
703
}
 
704
 
 
705
 
 
706
HBasicBlock* HGraph::CreateBasicBlock() {
 
707
  HBasicBlock* result = new(zone()) HBasicBlock(this);
 
708
  blocks_.Add(result, zone());
 
709
  return result;
 
710
}
 
711
 
 
712
 
 
713
void HGraph::Canonicalize() {
 
714
  if (!FLAG_use_canonicalizing) return;
 
715
  HPhase phase("H_Canonicalize", this);
 
716
  for (int i = 0; i < blocks()->length(); ++i) {
 
717
    HInstruction* instr = blocks()->at(i)->first();
 
718
    while (instr != NULL) {
 
719
      HValue* value = instr->Canonicalize();
 
720
      if (value != instr) instr->DeleteAndReplaceWith(value);
 
721
      instr = instr->next();
 
722
    }
 
723
  }
 
724
}
 
725
 
 
726
// Block ordering was implemented with two mutually recursive methods,
 
727
// HGraph::Postorder and HGraph::PostorderLoopBlocks.
 
728
// The recursion could lead to stack overflow so the algorithm has been
 
729
// implemented iteratively.
 
730
// At a high level the algorithm looks like this:
 
731
//
 
732
// Postorder(block, loop_header) : {
 
733
//   if (block has already been visited or is of another loop) return;
 
734
//   mark block as visited;
 
735
//   if (block is a loop header) {
 
736
//     VisitLoopMembers(block, loop_header);
 
737
//     VisitSuccessorsOfLoopHeader(block);
 
738
//   } else {
 
739
//     VisitSuccessors(block)
 
740
//   }
 
741
//   put block in result list;
 
742
// }
 
743
//
 
744
// VisitLoopMembers(block, outer_loop_header) {
 
745
//   foreach (block b in block loop members) {
 
746
//     VisitSuccessorsOfLoopMember(b, outer_loop_header);
 
747
//     if (b is loop header) VisitLoopMembers(b);
 
748
//   }
 
749
// }
 
750
//
 
751
// VisitSuccessorsOfLoopMember(block, outer_loop_header) {
 
752
//   foreach (block b in block successors) Postorder(b, outer_loop_header)
 
753
// }
 
754
//
 
755
// VisitSuccessorsOfLoopHeader(block) {
 
756
//   foreach (block b in block successors) Postorder(b, block)
 
757
// }
 
758
//
 
759
// VisitSuccessors(block, loop_header) {
 
760
//   foreach (block b in block successors) Postorder(b, loop_header)
 
761
// }
 
762
//
 
763
// The ordering is started calling Postorder(entry, NULL).
 
764
//
 
765
// Each instance of PostorderProcessor represents the "stack frame" of the
 
766
// recursion, and particularly keeps the state of the loop (iteration) of the
 
767
// "Visit..." function it represents.
 
768
// To recycle memory we keep all the frames in a double linked list but
 
769
// this means that we cannot use constructors to initialize the frames.
 
770
//
 
771
class PostorderProcessor : public ZoneObject {
 
772
 public:
 
773
  // Back link (towards the stack bottom).
 
774
  PostorderProcessor* parent() {return father_; }
 
775
  // Forward link (towards the stack top).
 
776
  PostorderProcessor* child() {return child_; }
 
777
  HBasicBlock* block() { return block_; }
 
778
  HLoopInformation* loop() { return loop_; }
 
779
  HBasicBlock* loop_header() { return loop_header_; }
 
780
 
 
781
  static PostorderProcessor* CreateEntryProcessor(Zone* zone,
 
782
                                                  HBasicBlock* block,
 
783
                                                  BitVector* visited) {
 
784
    PostorderProcessor* result = new(zone) PostorderProcessor(NULL);
 
785
    return result->SetupSuccessors(zone, block, NULL, visited);
 
786
  }
 
787
 
 
788
  PostorderProcessor* PerformStep(Zone* zone,
 
789
                                  BitVector* visited,
 
790
                                  ZoneList<HBasicBlock*>* order) {
 
791
    PostorderProcessor* next =
 
792
        PerformNonBacktrackingStep(zone, visited, order);
 
793
    if (next != NULL) {
 
794
      return next;
 
795
    } else {
 
796
      return Backtrack(zone, visited, order);
 
797
    }
 
798
  }
 
799
 
 
800
 private:
 
801
  explicit PostorderProcessor(PostorderProcessor* father)
 
802
      : father_(father), child_(NULL), successor_iterator(NULL) { }
 
803
 
 
804
  // Each enum value states the cycle whose state is kept by this instance.
 
805
  enum LoopKind {
 
806
    NONE,
 
807
    SUCCESSORS,
 
808
    SUCCESSORS_OF_LOOP_HEADER,
 
809
    LOOP_MEMBERS,
 
810
    SUCCESSORS_OF_LOOP_MEMBER
 
811
  };
 
812
 
 
813
  // Each "Setup..." method is like a constructor for a cycle state.
 
814
  PostorderProcessor* SetupSuccessors(Zone* zone,
 
815
                                      HBasicBlock* block,
 
816
                                      HBasicBlock* loop_header,
 
817
                                      BitVector* visited) {
 
818
    if (block == NULL || visited->Contains(block->block_id()) ||
 
819
        block->parent_loop_header() != loop_header) {
 
820
      kind_ = NONE;
 
821
      block_ = NULL;
 
822
      loop_ = NULL;
 
823
      loop_header_ = NULL;
 
824
      return this;
 
825
    } else {
 
826
      block_ = block;
 
827
      loop_ = NULL;
 
828
      visited->Add(block->block_id());
 
829
 
 
830
      if (block->IsLoopHeader()) {
 
831
        kind_ = SUCCESSORS_OF_LOOP_HEADER;
 
832
        loop_header_ = block;
 
833
        InitializeSuccessors();
 
834
        PostorderProcessor* result = Push(zone);
 
835
        return result->SetupLoopMembers(zone, block, block->loop_information(),
 
836
                                        loop_header);
 
837
      } else {
 
838
        ASSERT(block->IsFinished());
 
839
        kind_ = SUCCESSORS;
 
840
        loop_header_ = loop_header;
 
841
        InitializeSuccessors();
 
842
        return this;
 
843
      }
 
844
    }
 
845
  }
 
846
 
 
847
  PostorderProcessor* SetupLoopMembers(Zone* zone,
 
848
                                       HBasicBlock* block,
 
849
                                       HLoopInformation* loop,
 
850
                                       HBasicBlock* loop_header) {
 
851
    kind_ = LOOP_MEMBERS;
 
852
    block_ = block;
 
853
    loop_ = loop;
 
854
    loop_header_ = loop_header;
 
855
    InitializeLoopMembers();
 
856
    return this;
 
857
  }
 
858
 
 
859
  PostorderProcessor* SetupSuccessorsOfLoopMember(
 
860
      HBasicBlock* block,
 
861
      HLoopInformation* loop,
 
862
      HBasicBlock* loop_header) {
 
863
    kind_ = SUCCESSORS_OF_LOOP_MEMBER;
 
864
    block_ = block;
 
865
    loop_ = loop;
 
866
    loop_header_ = loop_header;
 
867
    InitializeSuccessors();
 
868
    return this;
 
869
  }
 
870
 
 
871
  // This method "allocates" a new stack frame.
 
872
  PostorderProcessor* Push(Zone* zone) {
 
873
    if (child_ == NULL) {
 
874
      child_ = new(zone) PostorderProcessor(this);
 
875
    }
 
876
    return child_;
 
877
  }
 
878
 
 
879
  void ClosePostorder(ZoneList<HBasicBlock*>* order, Zone* zone) {
 
880
    ASSERT(block_->end()->FirstSuccessor() == NULL ||
 
881
           order->Contains(block_->end()->FirstSuccessor()) ||
 
882
           block_->end()->FirstSuccessor()->IsLoopHeader());
 
883
    ASSERT(block_->end()->SecondSuccessor() == NULL ||
 
884
           order->Contains(block_->end()->SecondSuccessor()) ||
 
885
           block_->end()->SecondSuccessor()->IsLoopHeader());
 
886
    order->Add(block_, zone);
 
887
  }
 
888
 
 
889
  // This method is the basic block to walk up the stack.
 
890
  PostorderProcessor* Pop(Zone* zone,
 
891
                          BitVector* visited,
 
892
                          ZoneList<HBasicBlock*>* order) {
 
893
    switch (kind_) {
 
894
      case SUCCESSORS:
 
895
      case SUCCESSORS_OF_LOOP_HEADER:
 
896
        ClosePostorder(order, zone);
 
897
        return father_;
 
898
      case LOOP_MEMBERS:
 
899
        return father_;
 
900
      case SUCCESSORS_OF_LOOP_MEMBER:
 
901
        if (block()->IsLoopHeader() && block() != loop_->loop_header()) {
 
902
          // In this case we need to perform a LOOP_MEMBERS cycle so we
 
903
          // initialize it and return this instead of father.
 
904
          return SetupLoopMembers(zone, block(),
 
905
                                  block()->loop_information(), loop_header_);
 
906
        } else {
 
907
          return father_;
 
908
        }
 
909
      case NONE:
 
910
        return father_;
 
911
    }
 
912
    UNREACHABLE();
 
913
    return NULL;
 
914
  }
 
915
 
 
916
  // Walks up the stack.
 
917
  PostorderProcessor* Backtrack(Zone* zone,
 
918
                                BitVector* visited,
 
919
                                ZoneList<HBasicBlock*>* order) {
 
920
    PostorderProcessor* parent = Pop(zone, visited, order);
 
921
    while (parent != NULL) {
 
922
      PostorderProcessor* next =
 
923
          parent->PerformNonBacktrackingStep(zone, visited, order);
 
924
      if (next != NULL) {
 
925
        return next;
 
926
      } else {
 
927
        parent = parent->Pop(zone, visited, order);
 
928
      }
 
929
    }
 
930
    return NULL;
 
931
  }
 
932
 
 
933
  PostorderProcessor* PerformNonBacktrackingStep(
 
934
      Zone* zone,
 
935
      BitVector* visited,
 
936
      ZoneList<HBasicBlock*>* order) {
 
937
    HBasicBlock* next_block;
 
938
    switch (kind_) {
 
939
      case SUCCESSORS:
 
940
        next_block = AdvanceSuccessors();
 
941
        if (next_block != NULL) {
 
942
          PostorderProcessor* result = Push(zone);
 
943
          return result->SetupSuccessors(zone, next_block,
 
944
                                         loop_header_, visited);
 
945
        }
 
946
        break;
 
947
      case SUCCESSORS_OF_LOOP_HEADER:
 
948
        next_block = AdvanceSuccessors();
 
949
        if (next_block != NULL) {
 
950
          PostorderProcessor* result = Push(zone);
 
951
          return result->SetupSuccessors(zone, next_block,
 
952
                                         block(), visited);
 
953
        }
 
954
        break;
 
955
      case LOOP_MEMBERS:
 
956
        next_block = AdvanceLoopMembers();
 
957
        if (next_block != NULL) {
 
958
          PostorderProcessor* result = Push(zone);
 
959
          return result->SetupSuccessorsOfLoopMember(next_block,
 
960
                                                     loop_, loop_header_);
 
961
        }
 
962
        break;
 
963
      case SUCCESSORS_OF_LOOP_MEMBER:
 
964
        next_block = AdvanceSuccessors();
 
965
        if (next_block != NULL) {
 
966
          PostorderProcessor* result = Push(zone);
 
967
          return result->SetupSuccessors(zone, next_block,
 
968
                                         loop_header_, visited);
 
969
        }
 
970
        break;
 
971
      case NONE:
 
972
        return NULL;
 
973
    }
 
974
    return NULL;
 
975
  }
 
976
 
 
977
  // The following two methods implement a "foreach b in successors" cycle.
 
978
  void InitializeSuccessors() {
 
979
    loop_index = 0;
 
980
    loop_length = 0;
 
981
    successor_iterator = HSuccessorIterator(block_->end());
 
982
  }
 
983
 
 
984
  HBasicBlock* AdvanceSuccessors() {
 
985
    if (!successor_iterator.Done()) {
 
986
      HBasicBlock* result = successor_iterator.Current();
 
987
      successor_iterator.Advance();
 
988
      return result;
 
989
    }
 
990
    return NULL;
 
991
  }
 
992
 
 
993
  // The following two methods implement a "foreach b in loop members" cycle.
 
994
  void InitializeLoopMembers() {
 
995
    loop_index = 0;
 
996
    loop_length = loop_->blocks()->length();
 
997
  }
 
998
 
 
999
  HBasicBlock* AdvanceLoopMembers() {
 
1000
    if (loop_index < loop_length) {
 
1001
      HBasicBlock* result = loop_->blocks()->at(loop_index);
 
1002
      loop_index++;
 
1003
      return result;
 
1004
    } else {
 
1005
      return NULL;
 
1006
    }
 
1007
  }
 
1008
 
 
1009
  LoopKind kind_;
 
1010
  PostorderProcessor* father_;
 
1011
  PostorderProcessor* child_;
 
1012
  HLoopInformation* loop_;
 
1013
  HBasicBlock* block_;
 
1014
  HBasicBlock* loop_header_;
 
1015
  int loop_index;
 
1016
  int loop_length;
 
1017
  HSuccessorIterator successor_iterator;
 
1018
};
 
1019
 
 
1020
 
 
1021
void HGraph::OrderBlocks() {
 
1022
  HPhase phase("H_Block ordering");
 
1023
  BitVector visited(blocks_.length(), zone());
 
1024
 
 
1025
  ZoneList<HBasicBlock*> reverse_result(8, zone());
 
1026
  HBasicBlock* start = blocks_[0];
 
1027
  PostorderProcessor* postorder =
 
1028
      PostorderProcessor::CreateEntryProcessor(zone(), start, &visited);
 
1029
  while (postorder != NULL) {
 
1030
    postorder = postorder->PerformStep(zone(), &visited, &reverse_result);
 
1031
  }
 
1032
  blocks_.Rewind(0);
 
1033
  int index = 0;
 
1034
  for (int i = reverse_result.length() - 1; i >= 0; --i) {
 
1035
    HBasicBlock* b = reverse_result[i];
 
1036
    blocks_.Add(b, zone());
 
1037
    b->set_block_id(index++);
 
1038
  }
 
1039
}
 
1040
 
 
1041
 
 
1042
void HGraph::AssignDominators() {
 
1043
  HPhase phase("H_Assign dominators", this);
 
1044
  for (int i = 0; i < blocks_.length(); ++i) {
 
1045
    HBasicBlock* block = blocks_[i];
 
1046
    if (block->IsLoopHeader()) {
 
1047
      // Only the first predecessor of a loop header is from outside the loop.
 
1048
      // All others are back edges, and thus cannot dominate the loop header.
 
1049
      block->AssignCommonDominator(block->predecessors()->first());
 
1050
      block->AssignLoopSuccessorDominators();
 
1051
    } else {
 
1052
      for (int j = blocks_[i]->predecessors()->length() - 1; j >= 0; --j) {
 
1053
        blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j));
 
1054
      }
 
1055
    }
 
1056
  }
 
1057
}
 
1058
 
 
1059
// Mark all blocks that are dominated by an unconditional soft deoptimize to
 
1060
// prevent code motion across those blocks.
 
1061
void HGraph::PropagateDeoptimizingMark() {
 
1062
  HPhase phase("H_Propagate deoptimizing mark", this);
 
1063
  MarkAsDeoptimizingRecursively(entry_block());
 
1064
}
 
1065
 
 
1066
void HGraph::MarkAsDeoptimizingRecursively(HBasicBlock* block) {
 
1067
  for (int i = 0; i < block->dominated_blocks()->length(); ++i) {
 
1068
    HBasicBlock* dominated = block->dominated_blocks()->at(i);
 
1069
    if (block->IsDeoptimizing()) dominated->MarkAsDeoptimizing();
 
1070
    MarkAsDeoptimizingRecursively(dominated);
 
1071
  }
 
1072
}
 
1073
 
 
1074
void HGraph::EliminateRedundantPhis() {
 
1075
  HPhase phase("H_Redundant phi elimination", this);
 
1076
 
 
1077
  // Worklist of phis that can potentially be eliminated. Initialized with
 
1078
  // all phi nodes. When elimination of a phi node modifies another phi node
 
1079
  // the modified phi node is added to the worklist.
 
1080
  ZoneList<HPhi*> worklist(blocks_.length(), zone());
 
1081
  for (int i = 0; i < blocks_.length(); ++i) {
 
1082
    worklist.AddAll(*blocks_[i]->phis(), zone());
 
1083
  }
 
1084
 
 
1085
  while (!worklist.is_empty()) {
 
1086
    HPhi* phi = worklist.RemoveLast();
 
1087
    HBasicBlock* block = phi->block();
 
1088
 
 
1089
    // Skip phi node if it was already replaced.
 
1090
    if (block == NULL) continue;
 
1091
 
 
1092
    // Get replacement value if phi is redundant.
 
1093
    HValue* replacement = phi->GetRedundantReplacement();
 
1094
 
 
1095
    if (replacement != NULL) {
 
1096
      // Iterate through the uses and replace them all.
 
1097
      for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
 
1098
        HValue* value = it.value();
 
1099
        value->SetOperandAt(it.index(), replacement);
 
1100
        if (value->IsPhi()) worklist.Add(HPhi::cast(value), zone());
 
1101
      }
 
1102
      block->RemovePhi(phi);
 
1103
    }
 
1104
  }
 
1105
}
 
1106
 
 
1107
 
 
1108
void HGraph::EliminateUnreachablePhis() {
 
1109
  HPhase phase("H_Unreachable phi elimination", this);
 
1110
 
 
1111
  // Initialize worklist.
 
1112
  ZoneList<HPhi*> phi_list(blocks_.length(), zone());
 
1113
  ZoneList<HPhi*> worklist(blocks_.length(), zone());
 
1114
  for (int i = 0; i < blocks_.length(); ++i) {
 
1115
    for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
 
1116
      HPhi* phi = blocks_[i]->phis()->at(j);
 
1117
      phi_list.Add(phi, zone());
 
1118
      // We can't eliminate phis in the receiver position in the environment
 
1119
      // because in case of throwing an error we need this value to
 
1120
      // construct a stack trace.
 
1121
      if (phi->HasRealUses() || phi->IsReceiver())  {
 
1122
        phi->set_is_live(true);
 
1123
        worklist.Add(phi, zone());
 
1124
      }
 
1125
    }
 
1126
  }
 
1127
 
 
1128
  // Iteratively mark live phis.
 
1129
  while (!worklist.is_empty()) {
 
1130
    HPhi* phi = worklist.RemoveLast();
 
1131
    for (int i = 0; i < phi->OperandCount(); i++) {
 
1132
      HValue* operand = phi->OperandAt(i);
 
1133
      if (operand->IsPhi() && !HPhi::cast(operand)->is_live()) {
 
1134
        HPhi::cast(operand)->set_is_live(true);
 
1135
        worklist.Add(HPhi::cast(operand), zone());
 
1136
      }
 
1137
    }
 
1138
  }
 
1139
 
 
1140
  // Remove unreachable phis.
 
1141
  for (int i = 0; i < phi_list.length(); i++) {
 
1142
    HPhi* phi = phi_list[i];
 
1143
    if (!phi->is_live()) {
 
1144
      HBasicBlock* block = phi->block();
 
1145
      block->RemovePhi(phi);
 
1146
      block->RecordDeletedPhi(phi->merged_index());
 
1147
    }
 
1148
  }
 
1149
}
 
1150
 
 
1151
 
 
1152
bool HGraph::CheckArgumentsPhiUses() {
 
1153
  int block_count = blocks_.length();
 
1154
  for (int i = 0; i < block_count; ++i) {
 
1155
    for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
 
1156
      HPhi* phi = blocks_[i]->phis()->at(j);
 
1157
      // We don't support phi uses of arguments for now.
 
1158
      if (phi->CheckFlag(HValue::kIsArguments)) return false;
 
1159
    }
 
1160
  }
 
1161
  return true;
 
1162
}
 
1163
 
 
1164
 
 
1165
bool HGraph::CheckConstPhiUses() {
 
1166
  int block_count = blocks_.length();
 
1167
  for (int i = 0; i < block_count; ++i) {
 
1168
    for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
 
1169
      HPhi* phi = blocks_[i]->phis()->at(j);
 
1170
      // Check for the hole value (from an uninitialized const).
 
1171
      for (int k = 0; k < phi->OperandCount(); k++) {
 
1172
        if (phi->OperandAt(k) == GetConstantHole()) return false;
 
1173
      }
 
1174
    }
 
1175
  }
 
1176
  return true;
 
1177
}
 
1178
 
 
1179
 
 
1180
void HGraph::CollectPhis() {
 
1181
  int block_count = blocks_.length();
 
1182
  phi_list_ = new(zone()) ZoneList<HPhi*>(block_count, zone());
 
1183
  for (int i = 0; i < block_count; ++i) {
 
1184
    for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
 
1185
      HPhi* phi = blocks_[i]->phis()->at(j);
 
1186
      phi_list_->Add(phi, zone());
 
1187
    }
 
1188
  }
 
1189
}
 
1190
 
 
1191
 
 
1192
void HGraph::InferTypes(ZoneList<HValue*>* worklist) {
 
1193
  BitVector in_worklist(GetMaximumValueID(), zone());
 
1194
  for (int i = 0; i < worklist->length(); ++i) {
 
1195
    ASSERT(!in_worklist.Contains(worklist->at(i)->id()));
 
1196
    in_worklist.Add(worklist->at(i)->id());
 
1197
  }
 
1198
 
 
1199
  while (!worklist->is_empty()) {
 
1200
    HValue* current = worklist->RemoveLast();
 
1201
    in_worklist.Remove(current->id());
 
1202
    if (current->UpdateInferredType()) {
 
1203
      for (HUseIterator it(current->uses()); !it.Done(); it.Advance()) {
 
1204
        HValue* use = it.value();
 
1205
        if (!in_worklist.Contains(use->id())) {
 
1206
          in_worklist.Add(use->id());
 
1207
          worklist->Add(use, zone());
 
1208
        }
 
1209
      }
 
1210
    }
 
1211
  }
 
1212
}
 
1213
 
 
1214
 
 
1215
class HRangeAnalysis BASE_EMBEDDED {
 
1216
 public:
 
1217
  explicit HRangeAnalysis(HGraph* graph) :
 
1218
      graph_(graph), zone_(graph->zone()), changed_ranges_(16, zone_) { }
 
1219
 
 
1220
  void Analyze();
 
1221
 
 
1222
 private:
 
1223
  void TraceRange(const char* msg, ...);
 
1224
  void Analyze(HBasicBlock* block);
 
1225
  void InferControlFlowRange(HCompareIDAndBranch* test, HBasicBlock* dest);
 
1226
  void UpdateControlFlowRange(Token::Value op, HValue* value, HValue* other);
 
1227
  void InferRange(HValue* value);
 
1228
  void RollBackTo(int index);
 
1229
  void AddRange(HValue* value, Range* range);
 
1230
 
 
1231
  HGraph* graph_;
 
1232
  Zone* zone_;
 
1233
  ZoneList<HValue*> changed_ranges_;
 
1234
};
 
1235
 
 
1236
 
 
1237
void HRangeAnalysis::TraceRange(const char* msg, ...) {
 
1238
  if (FLAG_trace_range) {
 
1239
    va_list arguments;
 
1240
    va_start(arguments, msg);
 
1241
    OS::VPrint(msg, arguments);
 
1242
    va_end(arguments);
 
1243
  }
 
1244
}
 
1245
 
 
1246
 
 
1247
void HRangeAnalysis::Analyze() {
 
1248
  HPhase phase("H_Range analysis", graph_);
 
1249
  Analyze(graph_->entry_block());
 
1250
}
 
1251
 
 
1252
 
 
1253
void HRangeAnalysis::Analyze(HBasicBlock* block) {
 
1254
  TraceRange("Analyzing block B%d\n", block->block_id());
 
1255
 
 
1256
  int last_changed_range = changed_ranges_.length() - 1;
 
1257
 
 
1258
  // Infer range based on control flow.
 
1259
  if (block->predecessors()->length() == 1) {
 
1260
    HBasicBlock* pred = block->predecessors()->first();
 
1261
    if (pred->end()->IsCompareIDAndBranch()) {
 
1262
      InferControlFlowRange(HCompareIDAndBranch::cast(pred->end()), block);
 
1263
    }
 
1264
  }
 
1265
 
 
1266
  // Process phi instructions.
 
1267
  for (int i = 0; i < block->phis()->length(); ++i) {
 
1268
    HPhi* phi = block->phis()->at(i);
 
1269
    InferRange(phi);
 
1270
  }
 
1271
 
 
1272
  // Go through all instructions of the current block.
 
1273
  HInstruction* instr = block->first();
 
1274
  while (instr != block->end()) {
 
1275
    InferRange(instr);
 
1276
    instr = instr->next();
 
1277
  }
 
1278
 
 
1279
  // Continue analysis in all dominated blocks.
 
1280
  for (int i = 0; i < block->dominated_blocks()->length(); ++i) {
 
1281
    Analyze(block->dominated_blocks()->at(i));
 
1282
  }
 
1283
 
 
1284
  RollBackTo(last_changed_range);
 
1285
}
 
1286
 
 
1287
 
 
1288
void HRangeAnalysis::InferControlFlowRange(HCompareIDAndBranch* test,
 
1289
                                           HBasicBlock* dest) {
 
1290
  ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest));
 
1291
  if (test->GetInputRepresentation().IsInteger32()) {
 
1292
    Token::Value op = test->token();
 
1293
    if (test->SecondSuccessor() == dest) {
 
1294
      op = Token::NegateCompareOp(op);
 
1295
    }
 
1296
    Token::Value inverted_op = Token::InvertCompareOp(op);
 
1297
    UpdateControlFlowRange(op, test->left(), test->right());
 
1298
    UpdateControlFlowRange(inverted_op, test->right(), test->left());
 
1299
  }
 
1300
}
 
1301
 
 
1302
 
 
1303
// We know that value [op] other. Use this information to update the range on
 
1304
// value.
 
1305
void HRangeAnalysis::UpdateControlFlowRange(Token::Value op,
 
1306
                                            HValue* value,
 
1307
                                            HValue* other) {
 
1308
  Range temp_range;
 
1309
  Range* range = other->range() != NULL ? other->range() : &temp_range;
 
1310
  Range* new_range = NULL;
 
1311
 
 
1312
  TraceRange("Control flow range infer %d %s %d\n",
 
1313
             value->id(),
 
1314
             Token::Name(op),
 
1315
             other->id());
 
1316
 
 
1317
  if (op == Token::EQ || op == Token::EQ_STRICT) {
 
1318
    // The same range has to apply for value.
 
1319
    new_range = range->Copy(zone_);
 
1320
  } else if (op == Token::LT || op == Token::LTE) {
 
1321
    new_range = range->CopyClearLower(zone_);
 
1322
    if (op == Token::LT) {
 
1323
      new_range->AddConstant(-1);
 
1324
    }
 
1325
  } else if (op == Token::GT || op == Token::GTE) {
 
1326
    new_range = range->CopyClearUpper(zone_);
 
1327
    if (op == Token::GT) {
 
1328
      new_range->AddConstant(1);
 
1329
    }
 
1330
  }
 
1331
 
 
1332
  if (new_range != NULL && !new_range->IsMostGeneric()) {
 
1333
    AddRange(value, new_range);
 
1334
  }
 
1335
}
 
1336
 
 
1337
 
 
1338
void HRangeAnalysis::InferRange(HValue* value) {
 
1339
  ASSERT(!value->HasRange());
 
1340
  if (!value->representation().IsNone()) {
 
1341
    value->ComputeInitialRange(zone_);
 
1342
    Range* range = value->range();
 
1343
    TraceRange("Initial inferred range of %d (%s) set to [%d,%d]\n",
 
1344
               value->id(),
 
1345
               value->Mnemonic(),
 
1346
               range->lower(),
 
1347
               range->upper());
 
1348
  }
 
1349
}
 
1350
 
 
1351
 
 
1352
void HRangeAnalysis::RollBackTo(int index) {
 
1353
  for (int i = index + 1; i < changed_ranges_.length(); ++i) {
 
1354
    changed_ranges_[i]->RemoveLastAddedRange();
 
1355
  }
 
1356
  changed_ranges_.Rewind(index + 1);
 
1357
}
 
1358
 
 
1359
 
 
1360
void HRangeAnalysis::AddRange(HValue* value, Range* range) {
 
1361
  Range* original_range = value->range();
 
1362
  value->AddNewRange(range, zone_);
 
1363
  changed_ranges_.Add(value, zone_);
 
1364
  Range* new_range = value->range();
 
1365
  TraceRange("Updated range of %d set to [%d,%d]\n",
 
1366
             value->id(),
 
1367
             new_range->lower(),
 
1368
             new_range->upper());
 
1369
  if (original_range != NULL) {
 
1370
    TraceRange("Original range was [%d,%d]\n",
 
1371
               original_range->lower(),
 
1372
               original_range->upper());
 
1373
  }
 
1374
  TraceRange("New information was [%d,%d]\n",
 
1375
             range->lower(),
 
1376
             range->upper());
 
1377
}
 
1378
 
 
1379
 
 
1380
void TraceGVN(const char* msg, ...) {
 
1381
  va_list arguments;
 
1382
  va_start(arguments, msg);
 
1383
  OS::VPrint(msg, arguments);
 
1384
  va_end(arguments);
 
1385
}
 
1386
 
 
1387
// Wrap TraceGVN in macros to avoid the expense of evaluating its arguments when
 
1388
// --trace-gvn is off.
 
1389
#define TRACE_GVN_1(msg, a1)                    \
 
1390
  if (FLAG_trace_gvn) {                         \
 
1391
    TraceGVN(msg, a1);                          \
 
1392
  }
 
1393
 
 
1394
#define TRACE_GVN_2(msg, a1, a2)                \
 
1395
  if (FLAG_trace_gvn) {                         \
 
1396
    TraceGVN(msg, a1, a2);                      \
 
1397
  }
 
1398
 
 
1399
#define TRACE_GVN_3(msg, a1, a2, a3)            \
 
1400
  if (FLAG_trace_gvn) {                         \
 
1401
    TraceGVN(msg, a1, a2, a3);                  \
 
1402
  }
 
1403
 
 
1404
#define TRACE_GVN_4(msg, a1, a2, a3, a4)        \
 
1405
  if (FLAG_trace_gvn) {                         \
 
1406
    TraceGVN(msg, a1, a2, a3, a4);              \
 
1407
  }
 
1408
 
 
1409
#define TRACE_GVN_5(msg, a1, a2, a3, a4, a5)    \
 
1410
  if (FLAG_trace_gvn) {                         \
 
1411
    TraceGVN(msg, a1, a2, a3, a4, a5);          \
 
1412
  }
 
1413
 
 
1414
 
 
1415
HValueMap::HValueMap(Zone* zone, const HValueMap* other)
 
1416
    : array_size_(other->array_size_),
 
1417
      lists_size_(other->lists_size_),
 
1418
      count_(other->count_),
 
1419
      present_flags_(other->present_flags_),
 
1420
      array_(zone->NewArray<HValueMapListElement>(other->array_size_)),
 
1421
      lists_(zone->NewArray<HValueMapListElement>(other->lists_size_)),
 
1422
      free_list_head_(other->free_list_head_) {
 
1423
  memcpy(array_, other->array_, array_size_ * sizeof(HValueMapListElement));
 
1424
  memcpy(lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement));
 
1425
}
 
1426
 
 
1427
 
 
1428
void HValueMap::Kill(GVNFlagSet flags) {
 
1429
  GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(flags);
 
1430
  if (!present_flags_.ContainsAnyOf(depends_flags)) return;
 
1431
  present_flags_.RemoveAll();
 
1432
  for (int i = 0; i < array_size_; ++i) {
 
1433
    HValue* value = array_[i].value;
 
1434
    if (value != NULL) {
 
1435
      // Clear list of collisions first, so we know if it becomes empty.
 
1436
      int kept = kNil;  // List of kept elements.
 
1437
      int next;
 
1438
      for (int current = array_[i].next; current != kNil; current = next) {
 
1439
        next = lists_[current].next;
 
1440
        HValue* value = lists_[current].value;
 
1441
        if (value->gvn_flags().ContainsAnyOf(depends_flags)) {
 
1442
          // Drop it.
 
1443
          count_--;
 
1444
          lists_[current].next = free_list_head_;
 
1445
          free_list_head_ = current;
 
1446
        } else {
 
1447
          // Keep it.
 
1448
          lists_[current].next = kept;
 
1449
          kept = current;
 
1450
          present_flags_.Add(value->gvn_flags());
 
1451
        }
 
1452
      }
 
1453
      array_[i].next = kept;
 
1454
 
 
1455
      // Now possibly drop directly indexed element.
 
1456
      value = array_[i].value;
 
1457
      if (value->gvn_flags().ContainsAnyOf(depends_flags)) {  // Drop it.
 
1458
        count_--;
 
1459
        int head = array_[i].next;
 
1460
        if (head == kNil) {
 
1461
          array_[i].value = NULL;
 
1462
        } else {
 
1463
          array_[i].value = lists_[head].value;
 
1464
          array_[i].next = lists_[head].next;
 
1465
          lists_[head].next = free_list_head_;
 
1466
          free_list_head_ = head;
 
1467
        }
 
1468
      } else {
 
1469
        present_flags_.Add(value->gvn_flags());  // Keep it.
 
1470
      }
 
1471
    }
 
1472
  }
 
1473
}
 
1474
 
 
1475
 
 
1476
HValue* HValueMap::Lookup(HValue* value) const {
 
1477
  uint32_t hash = static_cast<uint32_t>(value->Hashcode());
 
1478
  uint32_t pos = Bound(hash);
 
1479
  if (array_[pos].value != NULL) {
 
1480
    if (array_[pos].value->Equals(value)) return array_[pos].value;
 
1481
    int next = array_[pos].next;
 
1482
    while (next != kNil) {
 
1483
      if (lists_[next].value->Equals(value)) return lists_[next].value;
 
1484
      next = lists_[next].next;
 
1485
    }
 
1486
  }
 
1487
  return NULL;
 
1488
}
 
1489
 
 
1490
 
 
1491
void HValueMap::Resize(int new_size, Zone* zone) {
 
1492
  ASSERT(new_size > count_);
 
1493
  // Hashing the values into the new array has no more collisions than in the
 
1494
  // old hash map, so we can use the existing lists_ array, if we are careful.
 
1495
 
 
1496
  // Make sure we have at least one free element.
 
1497
  if (free_list_head_ == kNil) {
 
1498
    ResizeLists(lists_size_ << 1, zone);
 
1499
  }
 
1500
 
 
1501
  HValueMapListElement* new_array =
 
1502
      zone->NewArray<HValueMapListElement>(new_size);
 
1503
  memset(new_array, 0, sizeof(HValueMapListElement) * new_size);
 
1504
 
 
1505
  HValueMapListElement* old_array = array_;
 
1506
  int old_size = array_size_;
 
1507
 
 
1508
  int old_count = count_;
 
1509
  count_ = 0;
 
1510
  // Do not modify present_flags_.  It is currently correct.
 
1511
  array_size_ = new_size;
 
1512
  array_ = new_array;
 
1513
 
 
1514
  if (old_array != NULL) {
 
1515
    // Iterate over all the elements in lists, rehashing them.
 
1516
    for (int i = 0; i < old_size; ++i) {
 
1517
      if (old_array[i].value != NULL) {
 
1518
        int current = old_array[i].next;
 
1519
        while (current != kNil) {
 
1520
          Insert(lists_[current].value, zone);
 
1521
          int next = lists_[current].next;
 
1522
          lists_[current].next = free_list_head_;
 
1523
          free_list_head_ = current;
 
1524
          current = next;
 
1525
        }
 
1526
        // Rehash the directly stored value.
 
1527
        Insert(old_array[i].value, zone);
 
1528
      }
 
1529
    }
 
1530
  }
 
1531
  USE(old_count);
 
1532
  ASSERT(count_ == old_count);
 
1533
}
 
1534
 
 
1535
 
 
1536
void HValueMap::ResizeLists(int new_size, Zone* zone) {
 
1537
  ASSERT(new_size > lists_size_);
 
1538
 
 
1539
  HValueMapListElement* new_lists =
 
1540
      zone->NewArray<HValueMapListElement>(new_size);
 
1541
  memset(new_lists, 0, sizeof(HValueMapListElement) * new_size);
 
1542
 
 
1543
  HValueMapListElement* old_lists = lists_;
 
1544
  int old_size = lists_size_;
 
1545
 
 
1546
  lists_size_ = new_size;
 
1547
  lists_ = new_lists;
 
1548
 
 
1549
  if (old_lists != NULL) {
 
1550
    memcpy(lists_, old_lists, old_size * sizeof(HValueMapListElement));
 
1551
  }
 
1552
  for (int i = old_size; i < lists_size_; ++i) {
 
1553
    lists_[i].next = free_list_head_;
 
1554
    free_list_head_ = i;
 
1555
  }
 
1556
}
 
1557
 
 
1558
 
 
1559
void HValueMap::Insert(HValue* value, Zone* zone) {
 
1560
  ASSERT(value != NULL);
 
1561
  // Resizing when half of the hashtable is filled up.
 
1562
  if (count_ >= array_size_ >> 1) Resize(array_size_ << 1, zone);
 
1563
  ASSERT(count_ < array_size_);
 
1564
  count_++;
 
1565
  uint32_t pos = Bound(static_cast<uint32_t>(value->Hashcode()));
 
1566
  if (array_[pos].value == NULL) {
 
1567
    array_[pos].value = value;
 
1568
    array_[pos].next = kNil;
 
1569
  } else {
 
1570
    if (free_list_head_ == kNil) {
 
1571
      ResizeLists(lists_size_ << 1, zone);
 
1572
    }
 
1573
    int new_element_pos = free_list_head_;
 
1574
    ASSERT(new_element_pos != kNil);
 
1575
    free_list_head_ = lists_[free_list_head_].next;
 
1576
    lists_[new_element_pos].value = value;
 
1577
    lists_[new_element_pos].next = array_[pos].next;
 
1578
    ASSERT(array_[pos].next == kNil || lists_[array_[pos].next].value != NULL);
 
1579
    array_[pos].next = new_element_pos;
 
1580
  }
 
1581
}
 
1582
 
 
1583
 
 
1584
HSideEffectMap::HSideEffectMap() : count_(0) {
 
1585
  memset(data_, 0, kNumberOfTrackedSideEffects * kPointerSize);
 
1586
}
 
1587
 
 
1588
 
 
1589
HSideEffectMap::HSideEffectMap(HSideEffectMap* other) : count_(other->count_) {
 
1590
  *this = *other;  // Calls operator=.
 
1591
}
 
1592
 
 
1593
 
 
1594
HSideEffectMap& HSideEffectMap::operator= (const HSideEffectMap& other) {
 
1595
  if (this != &other) {
 
1596
    memcpy(data_, other.data_, kNumberOfTrackedSideEffects * kPointerSize);
 
1597
  }
 
1598
  return *this;
 
1599
}
 
1600
 
 
1601
void HSideEffectMap::Kill(GVNFlagSet flags) {
 
1602
  for (int i = 0; i < kNumberOfTrackedSideEffects; i++) {
 
1603
    GVNFlag changes_flag = HValue::ChangesFlagFromInt(i);
 
1604
    if (flags.Contains(changes_flag)) {
 
1605
      if (data_[i] != NULL) count_--;
 
1606
      data_[i] = NULL;
 
1607
    }
 
1608
  }
 
1609
}
 
1610
 
 
1611
 
 
1612
void HSideEffectMap::Store(GVNFlagSet flags, HInstruction* instr) {
 
1613
  for (int i = 0; i < kNumberOfTrackedSideEffects; i++) {
 
1614
    GVNFlag changes_flag = HValue::ChangesFlagFromInt(i);
 
1615
    if (flags.Contains(changes_flag)) {
 
1616
      if (data_[i] == NULL) count_++;
 
1617
      data_[i] = instr;
 
1618
    }
 
1619
  }
 
1620
}
 
1621
 
 
1622
 
 
1623
class HStackCheckEliminator BASE_EMBEDDED {
 
1624
 public:
 
1625
  explicit HStackCheckEliminator(HGraph* graph) : graph_(graph) { }
 
1626
 
 
1627
  void Process();
 
1628
 
 
1629
 private:
 
1630
  HGraph* graph_;
 
1631
};
 
1632
 
 
1633
 
 
1634
void HStackCheckEliminator::Process() {
 
1635
  // For each loop block walk the dominator tree from the backwards branch to
 
1636
  // the loop header. If a call instruction is encountered the backwards branch
 
1637
  // is dominated by a call and the stack check in the backwards branch can be
 
1638
  // removed.
 
1639
  for (int i = 0; i < graph_->blocks()->length(); i++) {
 
1640
    HBasicBlock* block = graph_->blocks()->at(i);
 
1641
    if (block->IsLoopHeader()) {
 
1642
      HBasicBlock* back_edge = block->loop_information()->GetLastBackEdge();
 
1643
      HBasicBlock* dominator = back_edge;
 
1644
      while (true) {
 
1645
        HInstruction* instr = dominator->first();
 
1646
        while (instr != NULL) {
 
1647
          if (instr->IsCall()) {
 
1648
            block->loop_information()->stack_check()->Eliminate();
 
1649
            break;
 
1650
          }
 
1651
          instr = instr->next();
 
1652
        }
 
1653
 
 
1654
        // Done when the loop header is processed.
 
1655
        if (dominator == block) break;
 
1656
 
 
1657
        // Move up the dominator tree.
 
1658
        dominator = dominator->dominator();
 
1659
      }
 
1660
    }
 
1661
  }
 
1662
}
 
1663
 
 
1664
 
 
1665
// Simple sparse set with O(1) add, contains, and clear.
 
1666
class SparseSet {
 
1667
 public:
 
1668
  SparseSet(Zone* zone, int capacity)
 
1669
      : capacity_(capacity),
 
1670
        length_(0),
 
1671
        dense_(zone->NewArray<int>(capacity)),
 
1672
        sparse_(zone->NewArray<int>(capacity)) {
 
1673
#ifndef NVALGRIND
 
1674
    // Initialize the sparse array to make valgrind happy.
 
1675
    memset(sparse_, 0, sizeof(sparse_[0]) * capacity);
 
1676
#endif
 
1677
  }
 
1678
 
 
1679
  bool Contains(int n) const {
 
1680
    ASSERT(0 <= n && n < capacity_);
 
1681
    int d = sparse_[n];
 
1682
    return 0 <= d && d < length_ && dense_[d] == n;
 
1683
  }
 
1684
 
 
1685
  bool Add(int n) {
 
1686
    if (Contains(n)) return false;
 
1687
    dense_[length_] = n;
 
1688
    sparse_[n] = length_;
 
1689
    ++length_;
 
1690
    return true;
 
1691
  }
 
1692
 
 
1693
  void Clear() { length_ = 0; }
 
1694
 
 
1695
 private:
 
1696
  int capacity_;
 
1697
  int length_;
 
1698
  int* dense_;
 
1699
  int* sparse_;
 
1700
 
 
1701
  DISALLOW_COPY_AND_ASSIGN(SparseSet);
 
1702
};
 
1703
 
 
1704
 
 
1705
class HGlobalValueNumberer BASE_EMBEDDED {
 
1706
 public:
 
1707
  explicit HGlobalValueNumberer(HGraph* graph, CompilationInfo* info)
 
1708
      : graph_(graph),
 
1709
        info_(info),
 
1710
        removed_side_effects_(false),
 
1711
        block_side_effects_(graph->blocks()->length(), graph->zone()),
 
1712
        loop_side_effects_(graph->blocks()->length(), graph->zone()),
 
1713
        visited_on_paths_(graph->zone(), graph->blocks()->length()) {
 
1714
#ifdef DEBUG
 
1715
    ASSERT(info->isolate()->optimizing_compiler_thread()->IsOptimizerThread() ||
 
1716
           !info->isolate()->heap()->IsAllocationAllowed());
 
1717
#endif
 
1718
    block_side_effects_.AddBlock(GVNFlagSet(), graph_->blocks()->length(),
 
1719
                                 graph_->zone());
 
1720
    loop_side_effects_.AddBlock(GVNFlagSet(), graph_->blocks()->length(),
 
1721
                                graph_->zone());
 
1722
  }
 
1723
 
 
1724
  // Returns true if values with side effects are removed.
 
1725
  bool Analyze();
 
1726
 
 
1727
 private:
 
1728
  GVNFlagSet CollectSideEffectsOnPathsToDominatedBlock(
 
1729
      HBasicBlock* dominator,
 
1730
      HBasicBlock* dominated);
 
1731
  void AnalyzeGraph();
 
1732
  void ComputeBlockSideEffects();
 
1733
  void LoopInvariantCodeMotion();
 
1734
  void ProcessLoopBlock(HBasicBlock* block,
 
1735
                        HBasicBlock* before_loop,
 
1736
                        GVNFlagSet loop_kills,
 
1737
                        GVNFlagSet* accumulated_first_time_depends,
 
1738
                        GVNFlagSet* accumulated_first_time_changes);
 
1739
  bool AllowCodeMotion();
 
1740
  bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header);
 
1741
 
 
1742
  HGraph* graph() { return graph_; }
 
1743
  CompilationInfo* info() { return info_; }
 
1744
  Zone* zone() const { return graph_->zone(); }
 
1745
 
 
1746
  HGraph* graph_;
 
1747
  CompilationInfo* info_;
 
1748
  bool removed_side_effects_;
 
1749
 
 
1750
  // A map of block IDs to their side effects.
 
1751
  ZoneList<GVNFlagSet> block_side_effects_;
 
1752
 
 
1753
  // A map of loop header block IDs to their loop's side effects.
 
1754
  ZoneList<GVNFlagSet> loop_side_effects_;
 
1755
 
 
1756
  // Used when collecting side effects on paths from dominator to
 
1757
  // dominated.
 
1758
  SparseSet visited_on_paths_;
 
1759
};
 
1760
 
 
1761
 
 
1762
bool HGlobalValueNumberer::Analyze() {
 
1763
  removed_side_effects_ = false;
 
1764
  ComputeBlockSideEffects();
 
1765
  if (FLAG_loop_invariant_code_motion) {
 
1766
    LoopInvariantCodeMotion();
 
1767
  }
 
1768
  AnalyzeGraph();
 
1769
  return removed_side_effects_;
 
1770
}
 
1771
 
 
1772
 
 
1773
void HGlobalValueNumberer::ComputeBlockSideEffects() {
 
1774
  // The Analyze phase of GVN can be called multiple times. Clear loop side
 
1775
  // effects before computing them to erase the contents from previous Analyze
 
1776
  // passes.
 
1777
  for (int i = 0; i < loop_side_effects_.length(); ++i) {
 
1778
    loop_side_effects_[i].RemoveAll();
 
1779
  }
 
1780
  for (int i = graph_->blocks()->length() - 1; i >= 0; --i) {
 
1781
    // Compute side effects for the block.
 
1782
    HBasicBlock* block = graph_->blocks()->at(i);
 
1783
    HInstruction* instr = block->first();
 
1784
    int id = block->block_id();
 
1785
    GVNFlagSet side_effects;
 
1786
    while (instr != NULL) {
 
1787
      side_effects.Add(instr->ChangesFlags());
 
1788
      if (instr->IsSoftDeoptimize()) {
 
1789
        block_side_effects_[id].RemoveAll();
 
1790
        side_effects.RemoveAll();
 
1791
        break;
 
1792
      }
 
1793
      instr = instr->next();
 
1794
    }
 
1795
    block_side_effects_[id].Add(side_effects);
 
1796
 
 
1797
    // Loop headers are part of their loop.
 
1798
    if (block->IsLoopHeader()) {
 
1799
      loop_side_effects_[id].Add(side_effects);
 
1800
    }
 
1801
 
 
1802
    // Propagate loop side effects upwards.
 
1803
    if (block->HasParentLoopHeader()) {
 
1804
      int header_id = block->parent_loop_header()->block_id();
 
1805
      loop_side_effects_[header_id].Add(block->IsLoopHeader()
 
1806
                                        ? loop_side_effects_[id]
 
1807
                                        : side_effects);
 
1808
    }
 
1809
  }
 
1810
}
 
1811
 
 
1812
 
 
1813
SmartArrayPointer<char> GetGVNFlagsString(GVNFlagSet flags) {
 
1814
  char underlying_buffer[kLastFlag * 128];
 
1815
  Vector<char> buffer(underlying_buffer, sizeof(underlying_buffer));
 
1816
#if DEBUG
 
1817
  int offset = 0;
 
1818
  const char* separator = "";
 
1819
  const char* comma = ", ";
 
1820
  buffer[0] = 0;
 
1821
  uint32_t set_depends_on = 0;
 
1822
  uint32_t set_changes = 0;
 
1823
  for (int bit = 0; bit < kLastFlag; ++bit) {
 
1824
    if ((flags.ToIntegral() & (1 << bit)) != 0) {
 
1825
      if (bit % 2 == 0) {
 
1826
        set_changes++;
 
1827
      } else {
 
1828
        set_depends_on++;
 
1829
      }
 
1830
    }
 
1831
  }
 
1832
  bool positive_changes = set_changes < (kLastFlag / 2);
 
1833
  bool positive_depends_on = set_depends_on < (kLastFlag / 2);
 
1834
  if (set_changes > 0) {
 
1835
    if (positive_changes) {
 
1836
      offset += OS::SNPrintF(buffer + offset, "changes [");
 
1837
    } else {
 
1838
      offset += OS::SNPrintF(buffer + offset, "changes all except [");
 
1839
    }
 
1840
    for (int bit = 0; bit < kLastFlag; ++bit) {
 
1841
      if (((flags.ToIntegral() & (1 << bit)) != 0) == positive_changes) {
 
1842
        switch (static_cast<GVNFlag>(bit)) {
 
1843
#define DECLARE_FLAG(type)                                       \
 
1844
          case kChanges##type:                                   \
 
1845
            offset += OS::SNPrintF(buffer + offset, separator);  \
 
1846
            offset += OS::SNPrintF(buffer + offset, #type);      \
 
1847
            separator = comma;                                   \
 
1848
            break;
 
1849
GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
 
1850
GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
 
1851
#undef DECLARE_FLAG
 
1852
          default:
 
1853
              break;
 
1854
        }
 
1855
      }
 
1856
    }
 
1857
    offset += OS::SNPrintF(buffer + offset, "]");
 
1858
  }
 
1859
  if (set_depends_on > 0) {
 
1860
    separator = "";
 
1861
    if (set_changes > 0) {
 
1862
      offset += OS::SNPrintF(buffer + offset, ", ");
 
1863
    }
 
1864
    if (positive_depends_on) {
 
1865
      offset += OS::SNPrintF(buffer + offset, "depends on [");
 
1866
    } else {
 
1867
      offset += OS::SNPrintF(buffer + offset, "depends on all except [");
 
1868
    }
 
1869
    for (int bit = 0; bit < kLastFlag; ++bit) {
 
1870
      if (((flags.ToIntegral() & (1 << bit)) != 0) == positive_depends_on) {
 
1871
        switch (static_cast<GVNFlag>(bit)) {
 
1872
#define DECLARE_FLAG(type)                                       \
 
1873
          case kDependsOn##type:                                 \
 
1874
            offset += OS::SNPrintF(buffer + offset, separator);  \
 
1875
            offset += OS::SNPrintF(buffer + offset, #type);      \
 
1876
            separator = comma;                                   \
 
1877
            break;
 
1878
GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
 
1879
GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
 
1880
#undef DECLARE_FLAG
 
1881
          default:
 
1882
            break;
 
1883
        }
 
1884
      }
 
1885
    }
 
1886
    offset += OS::SNPrintF(buffer + offset, "]");
 
1887
  }
 
1888
#else
 
1889
  OS::SNPrintF(buffer, "0x%08X", flags.ToIntegral());
 
1890
#endif
 
1891
  size_t string_len = strlen(underlying_buffer) + 1;
 
1892
  ASSERT(string_len <= sizeof(underlying_buffer));
 
1893
  char* result = new char[strlen(underlying_buffer) + 1];
 
1894
  memcpy(result, underlying_buffer, string_len);
 
1895
  return SmartArrayPointer<char>(result);
 
1896
}
 
1897
 
 
1898
 
 
1899
void HGlobalValueNumberer::LoopInvariantCodeMotion() {
 
1900
  for (int i = graph_->blocks()->length() - 1; i >= 0; --i) {
 
1901
    HBasicBlock* block = graph_->blocks()->at(i);
 
1902
    if (block->IsLoopHeader()) {
 
1903
      GVNFlagSet side_effects = loop_side_effects_[block->block_id()];
 
1904
      TRACE_GVN_2("Try loop invariant motion for block B%d %s\n",
 
1905
                  block->block_id(),
 
1906
                  *GetGVNFlagsString(side_effects));
 
1907
 
 
1908
      GVNFlagSet accumulated_first_time_depends;
 
1909
      GVNFlagSet accumulated_first_time_changes;
 
1910
      HBasicBlock* last = block->loop_information()->GetLastBackEdge();
 
1911
      for (int j = block->block_id(); j <= last->block_id(); ++j) {
 
1912
        ProcessLoopBlock(graph_->blocks()->at(j), block, side_effects,
 
1913
                         &accumulated_first_time_depends,
 
1914
                         &accumulated_first_time_changes);
 
1915
      }
 
1916
    }
 
1917
  }
 
1918
}
 
1919
 
 
1920
 
 
1921
void HGlobalValueNumberer::ProcessLoopBlock(
 
1922
    HBasicBlock* block,
 
1923
    HBasicBlock* loop_header,
 
1924
    GVNFlagSet loop_kills,
 
1925
    GVNFlagSet* first_time_depends,
 
1926
    GVNFlagSet* first_time_changes) {
 
1927
  HBasicBlock* pre_header = loop_header->predecessors()->at(0);
 
1928
  GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills);
 
1929
  TRACE_GVN_2("Loop invariant motion for B%d %s\n",
 
1930
              block->block_id(),
 
1931
              *GetGVNFlagsString(depends_flags));
 
1932
  HInstruction* instr = block->first();
 
1933
  while (instr != NULL) {
 
1934
    HInstruction* next = instr->next();
 
1935
    bool hoisted = false;
 
1936
    if (instr->CheckFlag(HValue::kUseGVN)) {
 
1937
      TRACE_GVN_4("Checking instruction %d (%s) %s. Loop %s\n",
 
1938
                  instr->id(),
 
1939
                  instr->Mnemonic(),
 
1940
                  *GetGVNFlagsString(instr->gvn_flags()),
 
1941
                  *GetGVNFlagsString(loop_kills));
 
1942
      bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags);
 
1943
      if (instr->IsTransitionElementsKind()) {
 
1944
        // It's possible to hoist transitions out of a loop as long as the
 
1945
        // hoisting wouldn't move the transition past an instruction that has a
 
1946
        // DependsOn flag for anything it changes.
 
1947
        GVNFlagSet hoist_depends_blockers =
 
1948
            HValue::ConvertChangesToDependsFlags(instr->ChangesFlags());
 
1949
 
 
1950
        // In addition, the transition must not be hoisted above elements kind
 
1951
        // changes, or if the transition is destructive to the elements buffer,
 
1952
        // changes to array pointer or array contents.
 
1953
        GVNFlagSet hoist_change_blockers;
 
1954
        hoist_change_blockers.Add(kChangesElementsKind);
 
1955
        HTransitionElementsKind* trans = HTransitionElementsKind::cast(instr);
 
1956
        if (trans->original_map()->has_fast_double_elements()) {
 
1957
          hoist_change_blockers.Add(kChangesElementsPointer);
 
1958
          hoist_change_blockers.Add(kChangesDoubleArrayElements);
 
1959
        }
 
1960
        if (trans->transitioned_map()->has_fast_double_elements()) {
 
1961
          hoist_change_blockers.Add(kChangesElementsPointer);
 
1962
          hoist_change_blockers.Add(kChangesArrayElements);
 
1963
        }
 
1964
        if (FLAG_trace_gvn) {
 
1965
          GVNFlagSet hoist_blockers = hoist_depends_blockers;
 
1966
          hoist_blockers.Add(hoist_change_blockers);
 
1967
          GVNFlagSet first_time = *first_time_changes;
 
1968
          first_time.Add(*first_time_depends);
 
1969
          TRACE_GVN_4("Checking dependencies on HTransitionElementsKind "
 
1970
                      "%d (%s) hoist blockers: %s; "
 
1971
                      "first-time accumulated: %s\n",
 
1972
                      instr->id(),
 
1973
                      instr->Mnemonic(),
 
1974
                      *GetGVNFlagsString(hoist_blockers),
 
1975
                      *GetGVNFlagsString(first_time));
 
1976
        }
 
1977
        // It's possible to hoist transition from the current loop loop only if
 
1978
        // they dominate all of the successor blocks in the same loop and there
 
1979
        // are not any instructions that have Changes/DependsOn that intervene
 
1980
        // between it and the beginning of the loop header.
 
1981
        bool in_nested_loop = block != loop_header &&
 
1982
            ((block->parent_loop_header() != loop_header) ||
 
1983
             block->IsLoopHeader());
 
1984
        can_hoist = !in_nested_loop &&
 
1985
            block->IsLoopSuccessorDominator() &&
 
1986
            !first_time_depends->ContainsAnyOf(hoist_depends_blockers) &&
 
1987
            !first_time_changes->ContainsAnyOf(hoist_change_blockers);
 
1988
      }
 
1989
 
 
1990
      if (can_hoist) {
 
1991
        bool inputs_loop_invariant = true;
 
1992
        for (int i = 0; i < instr->OperandCount(); ++i) {
 
1993
          if (instr->OperandAt(i)->IsDefinedAfter(pre_header)) {
 
1994
            inputs_loop_invariant = false;
 
1995
          }
 
1996
        }
 
1997
 
 
1998
        if (inputs_loop_invariant && ShouldMove(instr, loop_header)) {
 
1999
          TRACE_GVN_1("Hoisting loop invariant instruction %d\n", instr->id());
 
2000
          // Move the instruction out of the loop.
 
2001
          instr->Unlink();
 
2002
          instr->InsertBefore(pre_header->end());
 
2003
          if (instr->HasSideEffects()) removed_side_effects_ = true;
 
2004
          hoisted = true;
 
2005
        }
 
2006
      }
 
2007
    }
 
2008
    if (!hoisted) {
 
2009
      // If an instruction is not hoisted, we have to account for its side
 
2010
      // effects when hoisting later HTransitionElementsKind instructions.
 
2011
      GVNFlagSet previous_depends = *first_time_depends;
 
2012
      GVNFlagSet previous_changes = *first_time_changes;
 
2013
      first_time_depends->Add(instr->DependsOnFlags());
 
2014
      first_time_changes->Add(instr->ChangesFlags());
 
2015
      if (!(previous_depends == *first_time_depends)) {
 
2016
        TRACE_GVN_1("Updated first-time accumulated %s\n",
 
2017
                    *GetGVNFlagsString(*first_time_depends));
 
2018
      }
 
2019
      if (!(previous_changes == *first_time_changes)) {
 
2020
        TRACE_GVN_1("Updated first-time accumulated %s\n",
 
2021
                    *GetGVNFlagsString(*first_time_changes));
 
2022
      }
 
2023
    }
 
2024
    instr = next;
 
2025
  }
 
2026
}
 
2027
 
 
2028
 
 
2029
bool HGlobalValueNumberer::AllowCodeMotion() {
 
2030
  return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount;
 
2031
}
 
2032
 
 
2033
 
 
2034
bool HGlobalValueNumberer::ShouldMove(HInstruction* instr,
 
2035
                                      HBasicBlock* loop_header) {
 
2036
  // If we've disabled code motion or we're in a block that unconditionally
 
2037
  // deoptimizes, don't move any instructions.
 
2038
  return AllowCodeMotion() && !instr->block()->IsDeoptimizing();
 
2039
}
 
2040
 
 
2041
 
 
2042
GVNFlagSet HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock(
 
2043
    HBasicBlock* dominator, HBasicBlock* dominated) {
 
2044
  GVNFlagSet side_effects;
 
2045
  for (int i = 0; i < dominated->predecessors()->length(); ++i) {
 
2046
    HBasicBlock* block = dominated->predecessors()->at(i);
 
2047
    if (dominator->block_id() < block->block_id() &&
 
2048
        block->block_id() < dominated->block_id() &&
 
2049
        visited_on_paths_.Add(block->block_id())) {
 
2050
      side_effects.Add(block_side_effects_[block->block_id()]);
 
2051
      if (block->IsLoopHeader()) {
 
2052
        side_effects.Add(loop_side_effects_[block->block_id()]);
 
2053
      }
 
2054
      side_effects.Add(CollectSideEffectsOnPathsToDominatedBlock(
 
2055
          dominator, block));
 
2056
    }
 
2057
  }
 
2058
  return side_effects;
 
2059
}
 
2060
 
 
2061
 
 
2062
// Each instance of this class is like a "stack frame" for the recursive
 
2063
// traversal of the dominator tree done during GVN (the stack is handled
 
2064
// as a double linked list).
 
2065
// We reuse frames when possible so the list length is limited by the depth
 
2066
// of the dominator tree but this forces us to initialize each frame calling
 
2067
// an explicit "Initialize" method instead of a using constructor.
 
2068
class GvnBasicBlockState: public ZoneObject {
 
2069
 public:
 
2070
  static GvnBasicBlockState* CreateEntry(Zone* zone,
 
2071
                                         HBasicBlock* entry_block,
 
2072
                                         HValueMap* entry_map) {
 
2073
    return new(zone)
 
2074
        GvnBasicBlockState(NULL, entry_block, entry_map, NULL, zone);
 
2075
  }
 
2076
 
 
2077
  HBasicBlock* block() { return block_; }
 
2078
  HValueMap* map() { return map_; }
 
2079
  HSideEffectMap* dominators() { return &dominators_; }
 
2080
 
 
2081
  GvnBasicBlockState* next_in_dominator_tree_traversal(
 
2082
      Zone* zone,
 
2083
      HBasicBlock** dominator) {
 
2084
    // This assignment needs to happen before calling next_dominated() because
 
2085
    // that call can reuse "this" if we are at the last dominated block.
 
2086
    *dominator = block();
 
2087
    GvnBasicBlockState* result = next_dominated(zone);
 
2088
    if (result == NULL) {
 
2089
      GvnBasicBlockState* dominator_state = pop();
 
2090
      if (dominator_state != NULL) {
 
2091
        // This branch is guaranteed not to return NULL because pop() never
 
2092
        // returns a state where "is_done() == true".
 
2093
        *dominator = dominator_state->block();
 
2094
        result = dominator_state->next_dominated(zone);
 
2095
      } else {
 
2096
        // Unnecessary (we are returning NULL) but done for cleanness.
 
2097
        *dominator = NULL;
 
2098
      }
 
2099
    }
 
2100
    return result;
 
2101
  }
 
2102
 
 
2103
 private:
 
2104
  void Initialize(HBasicBlock* block,
 
2105
                  HValueMap* map,
 
2106
                  HSideEffectMap* dominators,
 
2107
                  bool copy_map,
 
2108
                  Zone* zone) {
 
2109
    block_ = block;
 
2110
    map_ = copy_map ? map->Copy(zone) : map;
 
2111
    dominated_index_ = -1;
 
2112
    length_ = block->dominated_blocks()->length();
 
2113
    if (dominators != NULL) {
 
2114
      dominators_ = *dominators;
 
2115
    }
 
2116
  }
 
2117
  bool is_done() { return dominated_index_ >= length_; }
 
2118
 
 
2119
  GvnBasicBlockState(GvnBasicBlockState* previous,
 
2120
                     HBasicBlock* block,
 
2121
                     HValueMap* map,
 
2122
                     HSideEffectMap* dominators,
 
2123
                     Zone* zone)
 
2124
      : previous_(previous), next_(NULL) {
 
2125
    Initialize(block, map, dominators, true, zone);
 
2126
  }
 
2127
 
 
2128
  GvnBasicBlockState* next_dominated(Zone* zone) {
 
2129
    dominated_index_++;
 
2130
    if (dominated_index_ == length_ - 1) {
 
2131
      // No need to copy the map for the last child in the dominator tree.
 
2132
      Initialize(block_->dominated_blocks()->at(dominated_index_),
 
2133
                 map(),
 
2134
                 dominators(),
 
2135
                 false,
 
2136
                 zone);
 
2137
      return this;
 
2138
    } else if (dominated_index_ < length_) {
 
2139
      return push(zone,
 
2140
                  block_->dominated_blocks()->at(dominated_index_),
 
2141
                  dominators());
 
2142
    } else {
 
2143
      return NULL;
 
2144
    }
 
2145
  }
 
2146
 
 
2147
  GvnBasicBlockState* push(Zone* zone,
 
2148
                           HBasicBlock* block,
 
2149
                           HSideEffectMap* dominators) {
 
2150
    if (next_ == NULL) {
 
2151
      next_ =
 
2152
          new(zone) GvnBasicBlockState(this, block, map(), dominators, zone);
 
2153
    } else {
 
2154
      next_->Initialize(block, map(), dominators, true, zone);
 
2155
    }
 
2156
    return next_;
 
2157
  }
 
2158
  GvnBasicBlockState* pop() {
 
2159
    GvnBasicBlockState* result = previous_;
 
2160
    while (result != NULL && result->is_done()) {
 
2161
      TRACE_GVN_2("Backtracking from block B%d to block b%d\n",
 
2162
                  block()->block_id(),
 
2163
                  previous_->block()->block_id())
 
2164
      result = result->previous_;
 
2165
    }
 
2166
    return result;
 
2167
  }
 
2168
 
 
2169
  GvnBasicBlockState* previous_;
 
2170
  GvnBasicBlockState* next_;
 
2171
  HBasicBlock* block_;
 
2172
  HValueMap* map_;
 
2173
  HSideEffectMap dominators_;
 
2174
  int dominated_index_;
 
2175
  int length_;
 
2176
};
 
2177
 
 
2178
// This is a recursive traversal of the dominator tree but it has been turned
 
2179
// into a loop to avoid stack overflows.
 
2180
// The logical "stack frames" of the recursion are kept in a list of
 
2181
// GvnBasicBlockState instances.
 
2182
void HGlobalValueNumberer::AnalyzeGraph() {
 
2183
  HBasicBlock* entry_block = graph_->entry_block();
 
2184
  HValueMap* entry_map = new(zone()) HValueMap(zone());
 
2185
  GvnBasicBlockState* current =
 
2186
      GvnBasicBlockState::CreateEntry(zone(), entry_block, entry_map);
 
2187
 
 
2188
  while (current != NULL) {
 
2189
    HBasicBlock* block = current->block();
 
2190
    HValueMap* map = current->map();
 
2191
    HSideEffectMap* dominators = current->dominators();
 
2192
 
 
2193
    TRACE_GVN_2("Analyzing block B%d%s\n",
 
2194
                block->block_id(),
 
2195
                block->IsLoopHeader() ? " (loop header)" : "");
 
2196
 
 
2197
    // If this is a loop header kill everything killed by the loop.
 
2198
    if (block->IsLoopHeader()) {
 
2199
      map->Kill(loop_side_effects_[block->block_id()]);
 
2200
    }
 
2201
 
 
2202
    // Go through all instructions of the current block.
 
2203
    HInstruction* instr = block->first();
 
2204
    while (instr != NULL) {
 
2205
      HInstruction* next = instr->next();
 
2206
      GVNFlagSet flags = instr->ChangesFlags();
 
2207
      if (!flags.IsEmpty()) {
 
2208
        // Clear all instructions in the map that are affected by side effects.
 
2209
        // Store instruction as the dominating one for tracked side effects.
 
2210
        map->Kill(flags);
 
2211
        dominators->Store(flags, instr);
 
2212
        TRACE_GVN_2("Instruction %d %s\n", instr->id(),
 
2213
                    *GetGVNFlagsString(flags));
 
2214
      }
 
2215
      if (instr->CheckFlag(HValue::kUseGVN)) {
 
2216
        ASSERT(!instr->HasObservableSideEffects());
 
2217
        HValue* other = map->Lookup(instr);
 
2218
        if (other != NULL) {
 
2219
          ASSERT(instr->Equals(other) && other->Equals(instr));
 
2220
          TRACE_GVN_4("Replacing value %d (%s) with value %d (%s)\n",
 
2221
                      instr->id(),
 
2222
                      instr->Mnemonic(),
 
2223
                      other->id(),
 
2224
                      other->Mnemonic());
 
2225
          if (instr->HasSideEffects()) removed_side_effects_ = true;
 
2226
          instr->DeleteAndReplaceWith(other);
 
2227
        } else {
 
2228
          map->Add(instr, zone());
 
2229
        }
 
2230
      }
 
2231
      if (instr->CheckFlag(HValue::kTrackSideEffectDominators)) {
 
2232
        for (int i = 0; i < kNumberOfTrackedSideEffects; i++) {
 
2233
          HValue* other = dominators->at(i);
 
2234
          GVNFlag changes_flag = HValue::ChangesFlagFromInt(i);
 
2235
          GVNFlag depends_on_flag = HValue::DependsOnFlagFromInt(i);
 
2236
          if (instr->DependsOnFlags().Contains(depends_on_flag) &&
 
2237
              (other != NULL)) {
 
2238
            TRACE_GVN_5("Side-effect #%d in %d (%s) is dominated by %d (%s)\n",
 
2239
                        i,
 
2240
                        instr->id(),
 
2241
                        instr->Mnemonic(),
 
2242
                        other->id(),
 
2243
                        other->Mnemonic());
 
2244
            instr->SetSideEffectDominator(changes_flag, other);
 
2245
          }
 
2246
        }
 
2247
      }
 
2248
      instr = next;
 
2249
    }
 
2250
 
 
2251
    HBasicBlock* dominator_block;
 
2252
    GvnBasicBlockState* next =
 
2253
        current->next_in_dominator_tree_traversal(zone(), &dominator_block);
 
2254
 
 
2255
    if (next != NULL) {
 
2256
      HBasicBlock* dominated = next->block();
 
2257
      HValueMap* successor_map = next->map();
 
2258
      HSideEffectMap* successor_dominators = next->dominators();
 
2259
 
 
2260
      // Kill everything killed on any path between this block and the
 
2261
      // dominated block.  We don't have to traverse these paths if the
 
2262
      // value map and the dominators list is already empty.  If the range
 
2263
      // of block ids (block_id, dominated_id) is empty there are no such
 
2264
      // paths.
 
2265
      if ((!successor_map->IsEmpty() || !successor_dominators->IsEmpty()) &&
 
2266
          dominator_block->block_id() + 1 < dominated->block_id()) {
 
2267
        visited_on_paths_.Clear();
 
2268
        GVNFlagSet side_effects_on_all_paths =
 
2269
            CollectSideEffectsOnPathsToDominatedBlock(dominator_block,
 
2270
                                                      dominated);
 
2271
        successor_map->Kill(side_effects_on_all_paths);
 
2272
        successor_dominators->Kill(side_effects_on_all_paths);
 
2273
      }
 
2274
    }
 
2275
    current = next;
 
2276
  }
 
2277
}
 
2278
 
 
2279
 
 
2280
class HInferRepresentation BASE_EMBEDDED {
 
2281
 public:
 
2282
  explicit HInferRepresentation(HGraph* graph)
 
2283
      : graph_(graph),
 
2284
        worklist_(8, graph->zone()),
 
2285
        in_worklist_(graph->GetMaximumValueID(), graph->zone()) { }
 
2286
 
 
2287
  void Analyze();
 
2288
 
 
2289
 private:
 
2290
  Representation TryChange(HValue* current);
 
2291
  void AddToWorklist(HValue* current);
 
2292
  void InferBasedOnInputs(HValue* current);
 
2293
  void AddDependantsToWorklist(HValue* current);
 
2294
  void InferBasedOnUses(HValue* current);
 
2295
 
 
2296
  Zone* zone() const { return graph_->zone(); }
 
2297
 
 
2298
  HGraph* graph_;
 
2299
  ZoneList<HValue*> worklist_;
 
2300
  BitVector in_worklist_;
 
2301
};
 
2302
 
 
2303
 
 
2304
void HInferRepresentation::AddToWorklist(HValue* current) {
 
2305
  if (current->representation().IsSpecialization()) return;
 
2306
  if (!current->CheckFlag(HValue::kFlexibleRepresentation)) return;
 
2307
  if (in_worklist_.Contains(current->id())) return;
 
2308
  worklist_.Add(current, zone());
 
2309
  in_worklist_.Add(current->id());
 
2310
}
 
2311
 
 
2312
 
 
2313
// This method tries to specialize the representation type of the value
 
2314
// given as a parameter. The value is asked to infer its representation type
 
2315
// based on its inputs. If the inferred type is more specialized, then this
 
2316
// becomes the new representation type of the node.
 
2317
void HInferRepresentation::InferBasedOnInputs(HValue* current) {
 
2318
  Representation r = current->representation();
 
2319
  if (r.IsSpecialization()) return;
 
2320
  ASSERT(current->CheckFlag(HValue::kFlexibleRepresentation));
 
2321
  Representation inferred = current->InferredRepresentation();
 
2322
  if (inferred.IsSpecialization()) {
 
2323
    if (FLAG_trace_representation) {
 
2324
      PrintF("Changing #%d representation %s -> %s based on inputs\n",
 
2325
             current->id(),
 
2326
             r.Mnemonic(),
 
2327
             inferred.Mnemonic());
 
2328
    }
 
2329
    current->ChangeRepresentation(inferred);
 
2330
    AddDependantsToWorklist(current);
 
2331
  }
 
2332
}
 
2333
 
 
2334
 
 
2335
void HInferRepresentation::AddDependantsToWorklist(HValue* value) {
 
2336
  for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
 
2337
    AddToWorklist(it.value());
 
2338
  }
 
2339
  for (int i = 0; i < value->OperandCount(); ++i) {
 
2340
    AddToWorklist(value->OperandAt(i));
 
2341
  }
 
2342
}
 
2343
 
 
2344
 
 
2345
// This method calculates whether specializing the representation of the value
 
2346
// given as the parameter has a benefit in terms of less necessary type
 
2347
// conversions. If there is a benefit, then the representation of the value is
 
2348
// specialized.
 
2349
void HInferRepresentation::InferBasedOnUses(HValue* value) {
 
2350
  Representation r = value->representation();
 
2351
  if (r.IsSpecialization() || value->HasNoUses()) return;
 
2352
  ASSERT(value->CheckFlag(HValue::kFlexibleRepresentation));
 
2353
  Representation new_rep = TryChange(value);
 
2354
  if (!new_rep.IsNone()) {
 
2355
    if (!value->representation().Equals(new_rep)) {
 
2356
      if (FLAG_trace_representation) {
 
2357
        PrintF("Changing #%d representation %s -> %s based on uses\n",
 
2358
               value->id(),
 
2359
               r.Mnemonic(),
 
2360
               new_rep.Mnemonic());
 
2361
      }
 
2362
      value->ChangeRepresentation(new_rep);
 
2363
      AddDependantsToWorklist(value);
 
2364
    }
 
2365
  }
 
2366
}
 
2367
 
 
2368
 
 
2369
Representation HInferRepresentation::TryChange(HValue* value) {
 
2370
  // Array of use counts for each representation.
 
2371
  int use_count[Representation::kNumRepresentations] = { 0 };
 
2372
 
 
2373
  for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
 
2374
    HValue* use = it.value();
 
2375
    Representation rep = use->ObservedInputRepresentation(it.index());
 
2376
    if (rep.IsNone()) continue;
 
2377
    if (FLAG_trace_representation) {
 
2378
      PrintF("%d %s is used by %d %s as %s\n",
 
2379
             value->id(),
 
2380
             value->Mnemonic(),
 
2381
             use->id(),
 
2382
             use->Mnemonic(),
 
2383
             rep.Mnemonic());
 
2384
    }
 
2385
    if (use->IsPhi()) HPhi::cast(use)->AddIndirectUsesTo(&use_count[0]);
 
2386
    use_count[rep.kind()] += use->LoopWeight();
 
2387
  }
 
2388
  int tagged_count = use_count[Representation::kTagged];
 
2389
  int double_count = use_count[Representation::kDouble];
 
2390
  int int32_count = use_count[Representation::kInteger32];
 
2391
  int non_tagged_count = double_count + int32_count;
 
2392
 
 
2393
  // If a non-loop phi has tagged uses, don't convert it to untagged.
 
2394
  if (value->IsPhi() && !value->block()->IsLoopHeader() && tagged_count > 0) {
 
2395
    return Representation::None();
 
2396
  }
 
2397
 
 
2398
  // Prefer unboxing over boxing, the latter is more expensive.
 
2399
  if (tagged_count > non_tagged_count) return Representation::None();
 
2400
 
 
2401
  // Prefer Integer32 over Double, if possible.
 
2402
  if (int32_count > 0 && value->IsConvertibleToInteger()) {
 
2403
    return Representation::Integer32();
 
2404
  }
 
2405
 
 
2406
  if (double_count > 0) return Representation::Double();
 
2407
 
 
2408
  return Representation::None();
 
2409
}
 
2410
 
 
2411
 
 
2412
void HInferRepresentation::Analyze() {
 
2413
  HPhase phase("H_Infer representations", graph_);
 
2414
 
 
2415
  // (1) Initialize bit vectors and count real uses. Each phi gets a
 
2416
  // bit-vector of length <number of phis>.
 
2417
  const ZoneList<HPhi*>* phi_list = graph_->phi_list();
 
2418
  int phi_count = phi_list->length();
 
2419
  ZoneList<BitVector*> connected_phis(phi_count, graph_->zone());
 
2420
  for (int i = 0; i < phi_count; ++i) {
 
2421
    phi_list->at(i)->InitRealUses(i);
 
2422
    BitVector* connected_set = new(zone()) BitVector(phi_count, graph_->zone());
 
2423
    connected_set->Add(i);
 
2424
    connected_phis.Add(connected_set, zone());
 
2425
  }
 
2426
 
 
2427
  // (2) Do a fixed point iteration to find the set of connected phis.  A
 
2428
  // phi is connected to another phi if its value is used either directly or
 
2429
  // indirectly through a transitive closure of the def-use relation.
 
2430
  bool change = true;
 
2431
  while (change) {
 
2432
    change = false;
 
2433
    // We normally have far more "forward edges" than "backward edges",
 
2434
    // so we terminate faster when we walk backwards.
 
2435
    for (int i = phi_count - 1; i >= 0; --i) {
 
2436
      HPhi* phi = phi_list->at(i);
 
2437
      for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
 
2438
        HValue* use = it.value();
 
2439
        if (use->IsPhi()) {
 
2440
          int id = HPhi::cast(use)->phi_id();
 
2441
          if (connected_phis[i]->UnionIsChanged(*connected_phis[id]))
 
2442
            change = true;
 
2443
        }
 
2444
      }
 
2445
    }
 
2446
  }
 
2447
 
 
2448
  // (3a) Use the phi reachability information from step 2 to
 
2449
  // push information about values which can't be converted to integer
 
2450
  // without deoptimization through the phi use-def chains, avoiding
 
2451
  // unnecessary deoptimizations later.
 
2452
  for (int i = 0; i < phi_count; ++i) {
 
2453
    HPhi* phi = phi_list->at(i);
 
2454
    bool cti = phi->AllOperandsConvertibleToInteger();
 
2455
    if (cti) continue;
 
2456
 
 
2457
    for (BitVector::Iterator it(connected_phis.at(i));
 
2458
         !it.Done();
 
2459
         it.Advance()) {
 
2460
      HPhi* phi = phi_list->at(it.Current());
 
2461
      phi->set_is_convertible_to_integer(false);
 
2462
      phi->ResetInteger32Uses();
 
2463
    }
 
2464
  }
 
2465
 
 
2466
  // (3b) Use the phi reachability information from step 2 to
 
2467
  // sum up the non-phi use counts of all connected phis.
 
2468
  for (int i = 0; i < phi_count; ++i) {
 
2469
    HPhi* phi = phi_list->at(i);
 
2470
    for (BitVector::Iterator it(connected_phis.at(i));
 
2471
         !it.Done();
 
2472
         it.Advance()) {
 
2473
      int index = it.Current();
 
2474
      HPhi* it_use = phi_list->at(index);
 
2475
      if (index != i) phi->AddNonPhiUsesFrom(it_use);  // Don't count twice.
 
2476
    }
 
2477
  }
 
2478
 
 
2479
  // Initialize work list
 
2480
  for (int i = 0; i < graph_->blocks()->length(); ++i) {
 
2481
    HBasicBlock* block = graph_->blocks()->at(i);
 
2482
    const ZoneList<HPhi*>* phis = block->phis();
 
2483
    for (int j = 0; j < phis->length(); ++j) {
 
2484
      AddToWorklist(phis->at(j));
 
2485
    }
 
2486
 
 
2487
    HInstruction* current = block->first();
 
2488
    while (current != NULL) {
 
2489
      AddToWorklist(current);
 
2490
      current = current->next();
 
2491
    }
 
2492
  }
 
2493
 
 
2494
  // Do a fixed point iteration, trying to improve representations
 
2495
  while (!worklist_.is_empty()) {
 
2496
    HValue* current = worklist_.RemoveLast();
 
2497
    in_worklist_.Remove(current->id());
 
2498
    InferBasedOnInputs(current);
 
2499
    InferBasedOnUses(current);
 
2500
  }
 
2501
}
 
2502
 
 
2503
 
 
2504
void HGraph::InitializeInferredTypes() {
 
2505
  HPhase phase("H_Inferring types", this);
 
2506
  InitializeInferredTypes(0, this->blocks_.length() - 1);
 
2507
}
 
2508
 
 
2509
 
 
2510
void HGraph::InitializeInferredTypes(int from_inclusive, int to_inclusive) {
 
2511
  for (int i = from_inclusive; i <= to_inclusive; ++i) {
 
2512
    HBasicBlock* block = blocks_[i];
 
2513
 
 
2514
    const ZoneList<HPhi*>* phis = block->phis();
 
2515
    for (int j = 0; j < phis->length(); j++) {
 
2516
      phis->at(j)->UpdateInferredType();
 
2517
    }
 
2518
 
 
2519
    HInstruction* current = block->first();
 
2520
    while (current != NULL) {
 
2521
      current->UpdateInferredType();
 
2522
      current = current->next();
 
2523
    }
 
2524
 
 
2525
    if (block->IsLoopHeader()) {
 
2526
      HBasicBlock* last_back_edge =
 
2527
          block->loop_information()->GetLastBackEdge();
 
2528
      InitializeInferredTypes(i + 1, last_back_edge->block_id());
 
2529
      // Skip all blocks already processed by the recursive call.
 
2530
      i = last_back_edge->block_id();
 
2531
      // Update phis of the loop header now after the whole loop body is
 
2532
      // guaranteed to be processed.
 
2533
      ZoneList<HValue*> worklist(block->phis()->length(), zone());
 
2534
      for (int j = 0; j < block->phis()->length(); ++j) {
 
2535
        worklist.Add(block->phis()->at(j), zone());
 
2536
      }
 
2537
      InferTypes(&worklist);
 
2538
    }
 
2539
  }
 
2540
}
 
2541
 
 
2542
 
 
2543
void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) {
 
2544
  HValue* current = value;
 
2545
  while (current != NULL) {
 
2546
    if (visited->Contains(current->id())) return;
 
2547
 
 
2548
    // For phis, we must propagate the check to all of its inputs.
 
2549
    if (current->IsPhi()) {
 
2550
      visited->Add(current->id());
 
2551
      HPhi* phi = HPhi::cast(current);
 
2552
      for (int i = 0; i < phi->OperandCount(); ++i) {
 
2553
        PropagateMinusZeroChecks(phi->OperandAt(i), visited);
 
2554
      }
 
2555
      break;
 
2556
    }
 
2557
 
 
2558
    // For multiplication and division, we must propagate to the left and
 
2559
    // the right side.
 
2560
    if (current->IsMul()) {
 
2561
      HMul* mul = HMul::cast(current);
 
2562
      mul->EnsureAndPropagateNotMinusZero(visited);
 
2563
      PropagateMinusZeroChecks(mul->left(), visited);
 
2564
      PropagateMinusZeroChecks(mul->right(), visited);
 
2565
    } else if (current->IsDiv()) {
 
2566
      HDiv* div = HDiv::cast(current);
 
2567
      div->EnsureAndPropagateNotMinusZero(visited);
 
2568
      PropagateMinusZeroChecks(div->left(), visited);
 
2569
      PropagateMinusZeroChecks(div->right(), visited);
 
2570
    }
 
2571
 
 
2572
    current = current->EnsureAndPropagateNotMinusZero(visited);
 
2573
  }
 
2574
}
 
2575
 
 
2576
 
 
2577
void HGraph::InsertRepresentationChangeForUse(HValue* value,
 
2578
                                              HValue* use_value,
 
2579
                                              int use_index,
 
2580
                                              Representation to) {
 
2581
  // Insert the representation change right before its use. For phi-uses we
 
2582
  // insert at the end of the corresponding predecessor.
 
2583
  HInstruction* next = NULL;
 
2584
  if (use_value->IsPhi()) {
 
2585
    next = use_value->block()->predecessors()->at(use_index)->end();
 
2586
  } else {
 
2587
    next = HInstruction::cast(use_value);
 
2588
  }
 
2589
 
 
2590
  // For constants we try to make the representation change at compile
 
2591
  // time. When a representation change is not possible without loss of
 
2592
  // information we treat constants like normal instructions and insert the
 
2593
  // change instructions for them.
 
2594
  HInstruction* new_value = NULL;
 
2595
  bool is_truncating = use_value->CheckFlag(HValue::kTruncatingToInt32);
 
2596
  bool deoptimize_on_undefined =
 
2597
      use_value->CheckFlag(HValue::kDeoptimizeOnUndefined);
 
2598
  if (value->IsConstant()) {
 
2599
    HConstant* constant = HConstant::cast(value);
 
2600
    // Try to create a new copy of the constant with the new representation.
 
2601
    new_value = is_truncating
 
2602
        ? constant->CopyToTruncatedInt32(zone())
 
2603
        : constant->CopyToRepresentation(to, zone());
 
2604
  }
 
2605
 
 
2606
  if (new_value == NULL) {
 
2607
    new_value = new(zone()) HChange(value, to,
 
2608
                                    is_truncating, deoptimize_on_undefined);
 
2609
  }
 
2610
 
 
2611
  new_value->InsertBefore(next);
 
2612
  use_value->SetOperandAt(use_index, new_value);
 
2613
}
 
2614
 
 
2615
 
 
2616
void HGraph::InsertRepresentationChangesForValue(HValue* value) {
 
2617
  Representation r = value->representation();
 
2618
  if (r.IsNone()) return;
 
2619
  if (value->HasNoUses()) return;
 
2620
 
 
2621
  for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
 
2622
    HValue* use_value = it.value();
 
2623
    int use_index = it.index();
 
2624
    Representation req = use_value->RequiredInputRepresentation(use_index);
 
2625
    if (req.IsNone() || req.Equals(r)) continue;
 
2626
    InsertRepresentationChangeForUse(value, use_value, use_index, req);
 
2627
  }
 
2628
  if (value->HasNoUses()) {
 
2629
    ASSERT(value->IsConstant());
 
2630
    value->DeleteAndReplaceWith(NULL);
 
2631
  }
 
2632
 
 
2633
  // The only purpose of a HForceRepresentation is to represent the value
 
2634
  // after the (possible) HChange instruction.  We make it disappear.
 
2635
  if (value->IsForceRepresentation()) {
 
2636
    value->DeleteAndReplaceWith(HForceRepresentation::cast(value)->value());
 
2637
  }
 
2638
}
 
2639
 
 
2640
 
 
2641
void HGraph::InsertRepresentationChanges() {
 
2642
  HPhase phase("H_Representation changes", this);
 
2643
 
 
2644
  // Compute truncation flag for phis: Initially assume that all
 
2645
  // int32-phis allow truncation and iteratively remove the ones that
 
2646
  // are used in an operation that does not allow a truncating
 
2647
  // conversion.
 
2648
  // TODO(fschneider): Replace this with a worklist-based iteration.
 
2649
  for (int i = 0; i < phi_list()->length(); i++) {
 
2650
    HPhi* phi = phi_list()->at(i);
 
2651
    if (phi->representation().IsInteger32()) {
 
2652
      phi->SetFlag(HValue::kTruncatingToInt32);
 
2653
    }
 
2654
  }
 
2655
  bool change = true;
 
2656
  while (change) {
 
2657
    change = false;
 
2658
    for (int i = 0; i < phi_list()->length(); i++) {
 
2659
      HPhi* phi = phi_list()->at(i);
 
2660
      if (!phi->CheckFlag(HValue::kTruncatingToInt32)) continue;
 
2661
      if (!phi->CheckUsesForFlag(HValue::kTruncatingToInt32)) {
 
2662
        phi->ClearFlag(HValue::kTruncatingToInt32);
 
2663
        change = true;
 
2664
      }
 
2665
    }
 
2666
  }
 
2667
 
 
2668
  for (int i = 0; i < blocks_.length(); ++i) {
 
2669
    // Process phi instructions first.
 
2670
    const ZoneList<HPhi*>* phis = blocks_[i]->phis();
 
2671
    for (int j = 0; j < phis->length(); j++) {
 
2672
      InsertRepresentationChangesForValue(phis->at(j));
 
2673
    }
 
2674
 
 
2675
    // Process normal instructions.
 
2676
    HInstruction* current = blocks_[i]->first();
 
2677
    while (current != NULL) {
 
2678
      InsertRepresentationChangesForValue(current);
 
2679
      current = current->next();
 
2680
    }
 
2681
  }
 
2682
}
 
2683
 
 
2684
 
 
2685
void HGraph::RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi) {
 
2686
  if (phi->CheckFlag(HValue::kDeoptimizeOnUndefined)) return;
 
2687
  phi->SetFlag(HValue::kDeoptimizeOnUndefined);
 
2688
  for (int i = 0; i < phi->OperandCount(); ++i) {
 
2689
    HValue* input = phi->OperandAt(i);
 
2690
    if (input->IsPhi()) {
 
2691
      RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi::cast(input));
 
2692
    }
 
2693
  }
 
2694
}
 
2695
 
 
2696
 
 
2697
void HGraph::MarkDeoptimizeOnUndefined() {
 
2698
  HPhase phase("H_MarkDeoptimizeOnUndefined", this);
 
2699
  // Compute DeoptimizeOnUndefined flag for phis.
 
2700
  // Any phi that can reach a use with DeoptimizeOnUndefined set must
 
2701
  // have DeoptimizeOnUndefined set.  Currently only HCompareIDAndBranch, with
 
2702
  // double input representation, has this flag set.
 
2703
  // The flag is used by HChange tagged->double, which must deoptimize
 
2704
  // if one of its uses has this flag set.
 
2705
  for (int i = 0; i < phi_list()->length(); i++) {
 
2706
    HPhi* phi = phi_list()->at(i);
 
2707
    if (phi->representation().IsDouble()) {
 
2708
      for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
 
2709
        if (it.value()->CheckFlag(HValue::kDeoptimizeOnUndefined)) {
 
2710
          RecursivelyMarkPhiDeoptimizeOnUndefined(phi);
 
2711
          break;
 
2712
        }
 
2713
      }
 
2714
    }
 
2715
  }
 
2716
}
 
2717
 
 
2718
 
 
2719
void HGraph::ComputeMinusZeroChecks() {
 
2720
  BitVector visited(GetMaximumValueID(), zone());
 
2721
  for (int i = 0; i < blocks_.length(); ++i) {
 
2722
    for (HInstruction* current = blocks_[i]->first();
 
2723
         current != NULL;
 
2724
         current = current->next()) {
 
2725
      if (current->IsChange()) {
 
2726
        HChange* change = HChange::cast(current);
 
2727
        // Propagate flags for negative zero checks upwards from conversions
 
2728
        // int32-to-tagged and int32-to-double.
 
2729
        Representation from = change->value()->representation();
 
2730
        ASSERT(from.Equals(change->from()));
 
2731
        if (from.IsInteger32()) {
 
2732
          ASSERT(change->to().IsTagged() || change->to().IsDouble());
 
2733
          ASSERT(visited.IsEmpty());
 
2734
          PropagateMinusZeroChecks(change->value(), &visited);
 
2735
          visited.Clear();
 
2736
        }
 
2737
      }
 
2738
    }
 
2739
  }
 
2740
}
 
2741
 
 
2742
 
 
2743
// Implementation of utility class to encapsulate the translation state for
 
2744
// a (possibly inlined) function.
 
2745
FunctionState::FunctionState(HGraphBuilder* owner,
 
2746
                             CompilationInfo* info,
 
2747
                             TypeFeedbackOracle* oracle,
 
2748
                             ReturnHandlingFlag return_handling)
 
2749
    : owner_(owner),
 
2750
      compilation_info_(info),
 
2751
      oracle_(oracle),
 
2752
      call_context_(NULL),
 
2753
      return_handling_(return_handling),
 
2754
      function_return_(NULL),
 
2755
      test_context_(NULL),
 
2756
      entry_(NULL),
 
2757
      arguments_elements_(NULL),
 
2758
      outer_(owner->function_state()) {
 
2759
  if (outer_ != NULL) {
 
2760
    // State for an inline function.
 
2761
    if (owner->ast_context()->IsTest()) {
 
2762
      HBasicBlock* if_true = owner->graph()->CreateBasicBlock();
 
2763
      HBasicBlock* if_false = owner->graph()->CreateBasicBlock();
 
2764
      if_true->MarkAsInlineReturnTarget();
 
2765
      if_false->MarkAsInlineReturnTarget();
 
2766
      Expression* cond = TestContext::cast(owner->ast_context())->condition();
 
2767
      // The AstContext constructor pushed on the context stack.  This newed
 
2768
      // instance is the reason that AstContext can't be BASE_EMBEDDED.
 
2769
      test_context_ = new TestContext(owner, cond, if_true, if_false);
 
2770
    } else {
 
2771
      function_return_ = owner->graph()->CreateBasicBlock();
 
2772
      function_return()->MarkAsInlineReturnTarget();
 
2773
    }
 
2774
    // Set this after possibly allocating a new TestContext above.
 
2775
    call_context_ = owner->ast_context();
 
2776
  }
 
2777
 
 
2778
  // Push on the state stack.
 
2779
  owner->set_function_state(this);
 
2780
}
 
2781
 
 
2782
 
 
2783
FunctionState::~FunctionState() {
 
2784
  delete test_context_;
 
2785
  owner_->set_function_state(outer_);
 
2786
}
 
2787
 
 
2788
 
 
2789
// Implementation of utility classes to represent an expression's context in
 
2790
// the AST.
 
2791
AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind)
 
2792
    : owner_(owner),
 
2793
      kind_(kind),
 
2794
      outer_(owner->ast_context()),
 
2795
      for_typeof_(false) {
 
2796
  owner->set_ast_context(this);  // Push.
 
2797
#ifdef DEBUG
 
2798
  ASSERT(owner->environment()->frame_type() == JS_FUNCTION);
 
2799
  original_length_ = owner->environment()->length();
 
2800
#endif
 
2801
}
 
2802
 
 
2803
 
 
2804
AstContext::~AstContext() {
 
2805
  owner_->set_ast_context(outer_);  // Pop.
 
2806
}
 
2807
 
 
2808
 
 
2809
EffectContext::~EffectContext() {
 
2810
  ASSERT(owner()->HasStackOverflow() ||
 
2811
         owner()->current_block() == NULL ||
 
2812
         (owner()->environment()->length() == original_length_ &&
 
2813
          owner()->environment()->frame_type() == JS_FUNCTION));
 
2814
}
 
2815
 
 
2816
 
 
2817
ValueContext::~ValueContext() {
 
2818
  ASSERT(owner()->HasStackOverflow() ||
 
2819
         owner()->current_block() == NULL ||
 
2820
         (owner()->environment()->length() == original_length_ + 1 &&
 
2821
          owner()->environment()->frame_type() == JS_FUNCTION));
 
2822
}
 
2823
 
 
2824
 
 
2825
void EffectContext::ReturnValue(HValue* value) {
 
2826
  // The value is simply ignored.
 
2827
}
 
2828
 
 
2829
 
 
2830
void ValueContext::ReturnValue(HValue* value) {
 
2831
  // The value is tracked in the bailout environment, and communicated
 
2832
  // through the environment as the result of the expression.
 
2833
  if (!arguments_allowed() && value->CheckFlag(HValue::kIsArguments)) {
 
2834
    owner()->Bailout("bad value context for arguments value");
 
2835
  }
 
2836
  owner()->Push(value);
 
2837
}
 
2838
 
 
2839
 
 
2840
void TestContext::ReturnValue(HValue* value) {
 
2841
  BuildBranch(value);
 
2842
}
 
2843
 
 
2844
 
 
2845
void EffectContext::ReturnInstruction(HInstruction* instr, int ast_id) {
 
2846
  ASSERT(!instr->IsControlInstruction());
 
2847
  owner()->AddInstruction(instr);
 
2848
  if (instr->HasObservableSideEffects()) owner()->AddSimulate(ast_id);
 
2849
}
 
2850
 
 
2851
 
 
2852
void EffectContext::ReturnControl(HControlInstruction* instr, int ast_id) {
 
2853
  ASSERT(!instr->HasObservableSideEffects());
 
2854
  HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
 
2855
  HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
 
2856
  instr->SetSuccessorAt(0, empty_true);
 
2857
  instr->SetSuccessorAt(1, empty_false);
 
2858
  owner()->current_block()->Finish(instr);
 
2859
  HBasicBlock* join = owner()->CreateJoin(empty_true, empty_false, ast_id);
 
2860
  owner()->set_current_block(join);
 
2861
}
 
2862
 
 
2863
 
 
2864
void ValueContext::ReturnInstruction(HInstruction* instr, int ast_id) {
 
2865
  ASSERT(!instr->IsControlInstruction());
 
2866
  if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
 
2867
    return owner()->Bailout("bad value context for arguments object value");
 
2868
  }
 
2869
  owner()->AddInstruction(instr);
 
2870
  owner()->Push(instr);
 
2871
  if (instr->HasObservableSideEffects()) owner()->AddSimulate(ast_id);
 
2872
}
 
2873
 
 
2874
 
 
2875
void ValueContext::ReturnControl(HControlInstruction* instr, int ast_id) {
 
2876
  ASSERT(!instr->HasObservableSideEffects());
 
2877
  if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
 
2878
    return owner()->Bailout("bad value context for arguments object value");
 
2879
  }
 
2880
  HBasicBlock* materialize_false = owner()->graph()->CreateBasicBlock();
 
2881
  HBasicBlock* materialize_true = owner()->graph()->CreateBasicBlock();
 
2882
  instr->SetSuccessorAt(0, materialize_true);
 
2883
  instr->SetSuccessorAt(1, materialize_false);
 
2884
  owner()->current_block()->Finish(instr);
 
2885
  owner()->set_current_block(materialize_true);
 
2886
  owner()->Push(owner()->graph()->GetConstantTrue());
 
2887
  owner()->set_current_block(materialize_false);
 
2888
  owner()->Push(owner()->graph()->GetConstantFalse());
 
2889
  HBasicBlock* join =
 
2890
    owner()->CreateJoin(materialize_true, materialize_false, ast_id);
 
2891
  owner()->set_current_block(join);
 
2892
}
 
2893
 
 
2894
 
 
2895
void TestContext::ReturnInstruction(HInstruction* instr, int ast_id) {
 
2896
  ASSERT(!instr->IsControlInstruction());
 
2897
  HGraphBuilder* builder = owner();
 
2898
  builder->AddInstruction(instr);
 
2899
  // We expect a simulate after every expression with side effects, though
 
2900
  // this one isn't actually needed (and wouldn't work if it were targeted).
 
2901
  if (instr->HasObservableSideEffects()) {
 
2902
    builder->Push(instr);
 
2903
    builder->AddSimulate(ast_id);
 
2904
    builder->Pop();
 
2905
  }
 
2906
  BuildBranch(instr);
 
2907
}
 
2908
 
 
2909
 
 
2910
void TestContext::ReturnControl(HControlInstruction* instr, int ast_id) {
 
2911
  ASSERT(!instr->HasObservableSideEffects());
 
2912
  HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
 
2913
  HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
 
2914
  instr->SetSuccessorAt(0, empty_true);
 
2915
  instr->SetSuccessorAt(1, empty_false);
 
2916
  owner()->current_block()->Finish(instr);
 
2917
  empty_true->Goto(if_true(), owner()->function_state());
 
2918
  empty_false->Goto(if_false(), owner()->function_state());
 
2919
  owner()->set_current_block(NULL);
 
2920
}
 
2921
 
 
2922
 
 
2923
void TestContext::BuildBranch(HValue* value) {
 
2924
  // We expect the graph to be in edge-split form: there is no edge that
 
2925
  // connects a branch node to a join node.  We conservatively ensure that
 
2926
  // property by always adding an empty block on the outgoing edges of this
 
2927
  // branch.
 
2928
  HGraphBuilder* builder = owner();
 
2929
  if (value != NULL && value->CheckFlag(HValue::kIsArguments)) {
 
2930
    builder->Bailout("arguments object value in a test context");
 
2931
  }
 
2932
  HBasicBlock* empty_true = builder->graph()->CreateBasicBlock();
 
2933
  HBasicBlock* empty_false = builder->graph()->CreateBasicBlock();
 
2934
  unsigned test_id = condition()->test_id();
 
2935
  ToBooleanStub::Types expected(builder->oracle()->ToBooleanTypes(test_id));
 
2936
  HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected);
 
2937
  builder->current_block()->Finish(test);
 
2938
 
 
2939
  empty_true->Goto(if_true(), owner()->function_state());
 
2940
  empty_false->Goto(if_false(), owner()->function_state());
 
2941
  builder->set_current_block(NULL);
 
2942
}
 
2943
 
 
2944
 
 
2945
// HGraphBuilder infrastructure for bailing out and checking bailouts.
 
2946
#define CHECK_BAILOUT(call)                     \
 
2947
  do {                                          \
 
2948
    call;                                       \
 
2949
    if (HasStackOverflow()) return;             \
 
2950
  } while (false)
 
2951
 
 
2952
 
 
2953
#define CHECK_ALIVE(call)                                       \
 
2954
  do {                                                          \
 
2955
    call;                                                       \
 
2956
    if (HasStackOverflow() || current_block() == NULL) return;  \
 
2957
  } while (false)
 
2958
 
 
2959
 
 
2960
void HGraphBuilder::Bailout(const char* reason) {
 
2961
  if (FLAG_trace_bailout) {
 
2962
    SmartArrayPointer<char> name(
 
2963
        info()->shared_info()->DebugName()->ToCString());
 
2964
    PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *name, reason);
 
2965
  }
 
2966
  SetStackOverflow();
 
2967
}
 
2968
 
 
2969
 
 
2970
void HGraphBuilder::VisitForEffect(Expression* expr) {
 
2971
  EffectContext for_effect(this);
 
2972
  Visit(expr);
 
2973
}
 
2974
 
 
2975
 
 
2976
void HGraphBuilder::VisitForValue(Expression* expr, ArgumentsAllowedFlag flag) {
 
2977
  ValueContext for_value(this, flag);
 
2978
  Visit(expr);
 
2979
}
 
2980
 
 
2981
 
 
2982
void HGraphBuilder::VisitForTypeOf(Expression* expr) {
 
2983
  ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
 
2984
  for_value.set_for_typeof(true);
 
2985
  Visit(expr);
 
2986
}
 
2987
 
 
2988
 
 
2989
 
 
2990
void HGraphBuilder::VisitForControl(Expression* expr,
 
2991
                                    HBasicBlock* true_block,
 
2992
                                    HBasicBlock* false_block) {
 
2993
  TestContext for_test(this, expr, true_block, false_block);
 
2994
  Visit(expr);
 
2995
}
 
2996
 
 
2997
 
 
2998
void HGraphBuilder::VisitArgument(Expression* expr) {
 
2999
  CHECK_ALIVE(VisitForValue(expr));
 
3000
  Push(AddInstruction(new(zone()) HPushArgument(Pop())));
 
3001
}
 
3002
 
 
3003
 
 
3004
void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) {
 
3005
  for (int i = 0; i < arguments->length(); i++) {
 
3006
    CHECK_ALIVE(VisitArgument(arguments->at(i)));
 
3007
  }
 
3008
}
 
3009
 
 
3010
 
 
3011
void HGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs) {
 
3012
  for (int i = 0; i < exprs->length(); ++i) {
 
3013
    CHECK_ALIVE(VisitForValue(exprs->at(i)));
 
3014
  }
 
3015
}
 
3016
 
 
3017
 
 
3018
HGraph* HGraphBuilder::CreateGraph() {
 
3019
  graph_ = new(zone()) HGraph(info());
 
3020
  if (FLAG_hydrogen_stats) HStatistics::Instance()->Initialize(info());
 
3021
 
 
3022
  {
 
3023
    HPhase phase("H_Block building");
 
3024
    current_block_ = graph()->entry_block();
 
3025
 
 
3026
    Scope* scope = info()->scope();
 
3027
    if (scope->HasIllegalRedeclaration()) {
 
3028
      Bailout("function with illegal redeclaration");
 
3029
      return NULL;
 
3030
    }
 
3031
    if (scope->calls_eval()) {
 
3032
      Bailout("function calls eval");
 
3033
      return NULL;
 
3034
    }
 
3035
    SetUpScope(scope);
 
3036
 
 
3037
    // Add an edge to the body entry.  This is warty: the graph's start
 
3038
    // environment will be used by the Lithium translation as the initial
 
3039
    // environment on graph entry, but it has now been mutated by the
 
3040
    // Hydrogen translation of the instructions in the start block.  This
 
3041
    // environment uses values which have not been defined yet.  These
 
3042
    // Hydrogen instructions will then be replayed by the Lithium
 
3043
    // translation, so they cannot have an environment effect.  The edge to
 
3044
    // the body's entry block (along with some special logic for the start
 
3045
    // block in HInstruction::InsertAfter) seals the start block from
 
3046
    // getting unwanted instructions inserted.
 
3047
    //
 
3048
    // TODO(kmillikin): Fix this.  Stop mutating the initial environment.
 
3049
    // Make the Hydrogen instructions in the initial block into Hydrogen
 
3050
    // values (but not instructions), present in the initial environment and
 
3051
    // not replayed by the Lithium translation.
 
3052
    HEnvironment* initial_env = environment()->CopyWithoutHistory();
 
3053
    HBasicBlock* body_entry = CreateBasicBlock(initial_env);
 
3054
    current_block()->Goto(body_entry);
 
3055
    body_entry->SetJoinId(AstNode::kFunctionEntryId);
 
3056
    set_current_block(body_entry);
 
3057
 
 
3058
    // Handle implicit declaration of the function name in named function
 
3059
    // expressions before other declarations.
 
3060
    if (scope->is_function_scope() && scope->function() != NULL) {
 
3061
      VisitVariableDeclaration(scope->function());
 
3062
    }
 
3063
    VisitDeclarations(scope->declarations());
 
3064
    AddSimulate(AstNode::kDeclarationsId);
 
3065
 
 
3066
    HValue* context = environment()->LookupContext();
 
3067
    AddInstruction(
 
3068
        new(zone()) HStackCheck(context, HStackCheck::kFunctionEntry));
 
3069
 
 
3070
    VisitStatements(info()->function()->body());
 
3071
    if (HasStackOverflow()) return NULL;
 
3072
 
 
3073
    if (current_block() != NULL) {
 
3074
      HReturn* instr = new(zone()) HReturn(graph()->GetConstantUndefined());
 
3075
      current_block()->FinishExit(instr);
 
3076
      set_current_block(NULL);
 
3077
    }
 
3078
  }
 
3079
 
 
3080
  return graph();
 
3081
}
 
3082
 
 
3083
bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) {
 
3084
  *bailout_reason = SmartArrayPointer<char>();
 
3085
  OrderBlocks();
 
3086
  AssignDominators();
 
3087
 
 
3088
#ifdef DEBUG
 
3089
  // Do a full verify after building the graph and computing dominators.
 
3090
  Verify(true);
 
3091
#endif
 
3092
 
 
3093
  PropagateDeoptimizingMark();
 
3094
  if (!CheckConstPhiUses()) {
 
3095
    *bailout_reason = SmartArrayPointer<char>(StrDup(
 
3096
        "Unsupported phi use of const variable"));
 
3097
    return false;
 
3098
  }
 
3099
  EliminateRedundantPhis();
 
3100
  if (!CheckArgumentsPhiUses()) {
 
3101
    *bailout_reason = SmartArrayPointer<char>(StrDup(
 
3102
        "Unsupported phi use of arguments"));
 
3103
    return false;
 
3104
  }
 
3105
  if (FLAG_eliminate_dead_phis) EliminateUnreachablePhis();
 
3106
  CollectPhis();
 
3107
 
 
3108
  if (has_osr_loop_entry()) {
 
3109
    const ZoneList<HPhi*>* phis = osr_loop_entry()->phis();
 
3110
    for (int j = 0; j < phis->length(); j++) {
 
3111
      HPhi* phi = phis->at(j);
 
3112
      osr_values()->at(phi->merged_index())->set_incoming_value(phi);
 
3113
    }
 
3114
  }
 
3115
 
 
3116
  HInferRepresentation rep(this);
 
3117
  rep.Analyze();
 
3118
 
 
3119
  MarkDeoptimizeOnUndefined();
 
3120
  InsertRepresentationChanges();
 
3121
 
 
3122
  InitializeInferredTypes();
 
3123
  Canonicalize();
 
3124
 
 
3125
  // Perform common subexpression elimination and loop-invariant code motion.
 
3126
  if (FLAG_use_gvn) {
 
3127
    HPhase phase("H_Global value numbering", this);
 
3128
    HGlobalValueNumberer gvn(this, info());
 
3129
    bool removed_side_effects = gvn.Analyze();
 
3130
    // Trigger a second analysis pass to further eliminate duplicate values that
 
3131
    // could only be discovered by removing side-effect-generating instructions
 
3132
    // during the first pass.
 
3133
    if (FLAG_smi_only_arrays && removed_side_effects) {
 
3134
      removed_side_effects = gvn.Analyze();
 
3135
      ASSERT(!removed_side_effects);
 
3136
    }
 
3137
  }
 
3138
 
 
3139
  if (FLAG_use_range) {
 
3140
    HRangeAnalysis rangeAnalysis(this);
 
3141
    rangeAnalysis.Analyze();
 
3142
  }
 
3143
  ComputeMinusZeroChecks();
 
3144
 
 
3145
  // Eliminate redundant stack checks on backwards branches.
 
3146
  HStackCheckEliminator sce(this);
 
3147
  sce.Process();
 
3148
 
 
3149
  EliminateRedundantBoundsChecks();
 
3150
  DehoistSimpleArrayIndexComputations();
 
3151
 
 
3152
  return true;
 
3153
}
 
3154
 
 
3155
 
 
3156
// We try to "factor up" HBoundsCheck instructions towards the root of the
 
3157
// dominator tree.
 
3158
// For now we handle checks where the index is like "exp + int32value".
 
3159
// If in the dominator tree we check "exp + v1" and later (dominated)
 
3160
// "exp + v2", if v2 <= v1 we can safely remove the second check, and if
 
3161
// v2 > v1 we can use v2 in the 1st check and again remove the second.
 
3162
// To do so we keep a dictionary of all checks where the key if the pair
 
3163
// "exp, length".
 
3164
// The class BoundsCheckKey represents this key.
 
3165
class BoundsCheckKey : public ZoneObject {
 
3166
 public:
 
3167
  HValue* IndexBase() const { return index_base_; }
 
3168
  HValue* Length() const { return length_; }
 
3169
 
 
3170
  uint32_t Hash() {
 
3171
    return static_cast<uint32_t>(index_base_->Hashcode() ^ length_->Hashcode());
 
3172
  }
 
3173
 
 
3174
  static BoundsCheckKey* Create(Zone* zone,
 
3175
                                HBoundsCheck* check,
 
3176
                                int32_t* offset) {
 
3177
    HValue* index_base = NULL;
 
3178
    HConstant* constant = NULL;
 
3179
    bool is_sub = false;
 
3180
 
 
3181
    if (check->index()->IsAdd()) {
 
3182
      HAdd* index = HAdd::cast(check->index());
 
3183
      if (index->left()->IsConstant()) {
 
3184
        constant = HConstant::cast(index->left());
 
3185
        index_base = index->right();
 
3186
      } else if (index->right()->IsConstant()) {
 
3187
        constant = HConstant::cast(index->right());
 
3188
        index_base = index->left();
 
3189
      }
 
3190
    } else if (check->index()->IsSub()) {
 
3191
      HSub* index = HSub::cast(check->index());
 
3192
      is_sub = true;
 
3193
      if (index->left()->IsConstant()) {
 
3194
        constant = HConstant::cast(index->left());
 
3195
        index_base = index->right();
 
3196
      } else if (index->right()->IsConstant()) {
 
3197
        constant = HConstant::cast(index->right());
 
3198
        index_base = index->left();
 
3199
      }
 
3200
    }
 
3201
 
 
3202
    if (constant != NULL && constant->HasInteger32Value()) {
 
3203
      *offset = is_sub ? - constant->Integer32Value()
 
3204
                       : constant->Integer32Value();
 
3205
    } else {
 
3206
      *offset = 0;
 
3207
      index_base = check->index();
 
3208
    }
 
3209
 
 
3210
    return new(zone) BoundsCheckKey(index_base, check->length());
 
3211
  }
 
3212
 
 
3213
 private:
 
3214
  BoundsCheckKey(HValue* index_base, HValue* length)
 
3215
    : index_base_(index_base),
 
3216
      length_(length) { }
 
3217
 
 
3218
  HValue* index_base_;
 
3219
  HValue* length_;
 
3220
};
 
3221
 
 
3222
 
 
3223
// Data about each HBoundsCheck that can be eliminated or moved.
 
3224
// It is the "value" in the dictionary indexed by "base-index, length"
 
3225
// (the key is BoundsCheckKey).
 
3226
// We scan the code with a dominator tree traversal.
 
3227
// Traversing the dominator tree we keep a stack (implemented as a singly
 
3228
// linked list) of "data" for each basic block that contains a relevant check
 
3229
// with the same key (the dictionary holds the head of the list).
 
3230
// We also keep all the "data" created for a given basic block in a list, and
 
3231
// use it to "clean up" the dictionary when backtracking in the dominator tree
 
3232
// traversal.
 
3233
// Doing this each dictionary entry always directly points to the check that
 
3234
// is dominating the code being examined now.
 
3235
// We also track the current "offset" of the index expression and use it to
 
3236
// decide if any check is already "covered" (so it can be removed) or not.
 
3237
class BoundsCheckBbData: public ZoneObject {
 
3238
 public:
 
3239
  BoundsCheckKey* Key() const { return key_; }
 
3240
  int32_t LowerOffset() const { return lower_offset_; }
 
3241
  int32_t UpperOffset() const { return upper_offset_; }
 
3242
  HBasicBlock* BasicBlock() const { return basic_block_; }
 
3243
  HBoundsCheck* LowerCheck() const { return lower_check_; }
 
3244
  HBoundsCheck* UpperCheck() const { return upper_check_; }
 
3245
  BoundsCheckBbData* NextInBasicBlock() const { return next_in_bb_; }
 
3246
  BoundsCheckBbData* FatherInDominatorTree() const { return father_in_dt_; }
 
3247
 
 
3248
  bool OffsetIsCovered(int32_t offset) const {
 
3249
    return offset >= LowerOffset() && offset <= UpperOffset();
 
3250
  }
 
3251
 
 
3252
  bool HasSingleCheck() { return lower_check_ == upper_check_; }
 
3253
 
 
3254
  // The goal of this method is to modify either upper_offset_ or
 
3255
  // lower_offset_ so that also new_offset is covered (the covered
 
3256
  // range grows).
 
3257
  //
 
3258
  // The precondition is that new_check follows UpperCheck() and
 
3259
  // LowerCheck() in the same basic block, and that new_offset is not
 
3260
  // covered (otherwise we could simply remove new_check).
 
3261
  //
 
3262
  // If HasSingleCheck() is true then new_check is added as "second check"
 
3263
  // (either upper or lower; note that HasSingleCheck() becomes false).
 
3264
  // Otherwise one of the current checks is modified so that it also covers
 
3265
  // new_offset, and new_check is removed.
 
3266
  void CoverCheck(HBoundsCheck* new_check,
 
3267
                  int32_t new_offset) {
 
3268
    ASSERT(new_check->index()->representation().IsInteger32());
 
3269
    bool keep_new_check = false;
 
3270
 
 
3271
    if (new_offset > upper_offset_) {
 
3272
      upper_offset_ = new_offset;
 
3273
      if (HasSingleCheck()) {
 
3274
        keep_new_check = true;
 
3275
        upper_check_ = new_check;
 
3276
      } else {
 
3277
        BuildOffsetAdd(upper_check_,
 
3278
                       &added_upper_index_,
 
3279
                       &added_upper_offset_,
 
3280
                       Key()->IndexBase(),
 
3281
                       new_check->index()->representation(),
 
3282
                       new_offset);
 
3283
        upper_check_->SetOperandAt(0, added_upper_index_);
 
3284
      }
 
3285
    } else if (new_offset < lower_offset_) {
 
3286
      lower_offset_ = new_offset;
 
3287
      if (HasSingleCheck()) {
 
3288
        keep_new_check = true;
 
3289
        lower_check_ = new_check;
 
3290
      } else {
 
3291
        BuildOffsetAdd(lower_check_,
 
3292
                       &added_lower_index_,
 
3293
                       &added_lower_offset_,
 
3294
                       Key()->IndexBase(),
 
3295
                       new_check->index()->representation(),
 
3296
                       new_offset);
 
3297
        lower_check_->SetOperandAt(0, added_lower_index_);
 
3298
      }
 
3299
    } else {
 
3300
      ASSERT(false);
 
3301
    }
 
3302
 
 
3303
    if (!keep_new_check) {
 
3304
      new_check->DeleteAndReplaceWith(NULL);
 
3305
    }
 
3306
  }
 
3307
 
 
3308
  void RemoveZeroOperations() {
 
3309
    RemoveZeroAdd(&added_lower_index_, &added_lower_offset_);
 
3310
    RemoveZeroAdd(&added_upper_index_, &added_upper_offset_);
 
3311
  }
 
3312
 
 
3313
  BoundsCheckBbData(BoundsCheckKey* key,
 
3314
                    int32_t lower_offset,
 
3315
                    int32_t upper_offset,
 
3316
                    HBasicBlock* bb,
 
3317
                    HBoundsCheck* lower_check,
 
3318
                    HBoundsCheck* upper_check,
 
3319
                    BoundsCheckBbData* next_in_bb,
 
3320
                    BoundsCheckBbData* father_in_dt)
 
3321
  : key_(key),
 
3322
    lower_offset_(lower_offset),
 
3323
    upper_offset_(upper_offset),
 
3324
    basic_block_(bb),
 
3325
    lower_check_(lower_check),
 
3326
    upper_check_(upper_check),
 
3327
    added_lower_index_(NULL),
 
3328
    added_lower_offset_(NULL),
 
3329
    added_upper_index_(NULL),
 
3330
    added_upper_offset_(NULL),
 
3331
    next_in_bb_(next_in_bb),
 
3332
    father_in_dt_(father_in_dt) { }
 
3333
 
 
3334
 private:
 
3335
  BoundsCheckKey* key_;
 
3336
  int32_t lower_offset_;
 
3337
  int32_t upper_offset_;
 
3338
  HBasicBlock* basic_block_;
 
3339
  HBoundsCheck* lower_check_;
 
3340
  HBoundsCheck* upper_check_;
 
3341
  HAdd* added_lower_index_;
 
3342
  HConstant* added_lower_offset_;
 
3343
  HAdd* added_upper_index_;
 
3344
  HConstant* added_upper_offset_;
 
3345
  BoundsCheckBbData* next_in_bb_;
 
3346
  BoundsCheckBbData* father_in_dt_;
 
3347
 
 
3348
  void BuildOffsetAdd(HBoundsCheck* check,
 
3349
                      HAdd** add,
 
3350
                      HConstant** constant,
 
3351
                      HValue* original_value,
 
3352
                      Representation representation,
 
3353
                      int32_t new_offset) {
 
3354
    HConstant* new_constant = new(BasicBlock()->zone())
 
3355
       HConstant(new_offset, Representation::Integer32());
 
3356
    if (*add == NULL) {
 
3357
      new_constant->InsertBefore(check);
 
3358
      *add = new(BasicBlock()->zone()) HAdd(NULL,
 
3359
                                            original_value,
 
3360
                                            new_constant);
 
3361
      (*add)->AssumeRepresentation(representation);
 
3362
      (*add)->InsertBefore(check);
 
3363
    } else {
 
3364
      new_constant->InsertBefore(*add);
 
3365
      (*constant)->DeleteAndReplaceWith(new_constant);
 
3366
    }
 
3367
    *constant = new_constant;
 
3368
  }
 
3369
 
 
3370
  void RemoveZeroAdd(HAdd** add, HConstant** constant) {
 
3371
    if (*add != NULL && (*constant)->Integer32Value() == 0) {
 
3372
      (*add)->DeleteAndReplaceWith((*add)->left());
 
3373
      (*constant)->DeleteAndReplaceWith(NULL);
 
3374
    }
 
3375
  }
 
3376
};
 
3377
 
 
3378
 
 
3379
static bool BoundsCheckKeyMatch(void* key1, void* key2) {
 
3380
  BoundsCheckKey* k1 = static_cast<BoundsCheckKey*>(key1);
 
3381
  BoundsCheckKey* k2 = static_cast<BoundsCheckKey*>(key2);
 
3382
  return k1->IndexBase() == k2->IndexBase() && k1->Length() == k2->Length();
 
3383
}
 
3384
 
 
3385
 
 
3386
class BoundsCheckTable : private ZoneHashMap {
 
3387
 public:
 
3388
  BoundsCheckBbData** LookupOrInsert(BoundsCheckKey* key, Zone* zone) {
 
3389
    return reinterpret_cast<BoundsCheckBbData**>(
 
3390
        &(Lookup(key, key->Hash(), true, ZoneAllocationPolicy(zone))->value));
 
3391
  }
 
3392
 
 
3393
  void Insert(BoundsCheckKey* key, BoundsCheckBbData* data, Zone* zone) {
 
3394
    Lookup(key, key->Hash(), true, ZoneAllocationPolicy(zone))->value = data;
 
3395
  }
 
3396
 
 
3397
  void Delete(BoundsCheckKey* key) {
 
3398
    Remove(key, key->Hash());
 
3399
  }
 
3400
 
 
3401
  explicit BoundsCheckTable(Zone* zone)
 
3402
      : ZoneHashMap(BoundsCheckKeyMatch, ZoneHashMap::kDefaultHashMapCapacity,
 
3403
                    ZoneAllocationPolicy(zone)) { }
 
3404
};
 
3405
 
 
3406
 
 
3407
// Eliminates checks in bb and recursively in the dominated blocks.
 
3408
// Also replace the results of check instructions with the original value, if
 
3409
// the result is used. This is safe now, since we don't do code motion after
 
3410
// this point. It enables better register allocation since the value produced
 
3411
// by check instructions is really a copy of the original value.
 
3412
void HGraph::EliminateRedundantBoundsChecks(HBasicBlock* bb,
 
3413
                                            BoundsCheckTable* table) {
 
3414
  BoundsCheckBbData* bb_data_list = NULL;
 
3415
 
 
3416
  for (HInstruction* i = bb->first(); i != NULL; i = i->next()) {
 
3417
    if (!i->IsBoundsCheck()) continue;
 
3418
 
 
3419
    HBoundsCheck* check = HBoundsCheck::cast(i);
 
3420
    check->ReplaceAllUsesWith(check->index());
 
3421
 
 
3422
    if (!FLAG_array_bounds_checks_elimination) continue;
 
3423
 
 
3424
    int32_t offset;
 
3425
    BoundsCheckKey* key =
 
3426
        BoundsCheckKey::Create(zone(), check, &offset);
 
3427
    BoundsCheckBbData** data_p = table->LookupOrInsert(key, zone());
 
3428
    BoundsCheckBbData* data = *data_p;
 
3429
    if (data == NULL) {
 
3430
      bb_data_list = new(zone()) BoundsCheckBbData(key,
 
3431
                                                   offset,
 
3432
                                                   offset,
 
3433
                                                   bb,
 
3434
                                                   check,
 
3435
                                                   check,
 
3436
                                                   bb_data_list,
 
3437
                                                   NULL);
 
3438
      *data_p = bb_data_list;
 
3439
    } else if (data->OffsetIsCovered(offset)) {
 
3440
      check->DeleteAndReplaceWith(NULL);
 
3441
    } else if (data->BasicBlock() == bb) {
 
3442
      data->CoverCheck(check, offset);
 
3443
    } else {
 
3444
      int32_t new_lower_offset = offset < data->LowerOffset()
 
3445
          ? offset
 
3446
          : data->LowerOffset();
 
3447
      int32_t new_upper_offset = offset > data->UpperOffset()
 
3448
          ? offset
 
3449
          : data->UpperOffset();
 
3450
      bb_data_list = new(zone()) BoundsCheckBbData(key,
 
3451
                                                   new_lower_offset,
 
3452
                                                   new_upper_offset,
 
3453
                                                   bb,
 
3454
                                                   data->LowerCheck(),
 
3455
                                                   data->UpperCheck(),
 
3456
                                                   bb_data_list,
 
3457
                                                   data);
 
3458
      table->Insert(key, bb_data_list, zone());
 
3459
    }
 
3460
  }
 
3461
 
 
3462
  for (int i = 0; i < bb->dominated_blocks()->length(); ++i) {
 
3463
    EliminateRedundantBoundsChecks(bb->dominated_blocks()->at(i), table);
 
3464
  }
 
3465
 
 
3466
  for (BoundsCheckBbData* data = bb_data_list;
 
3467
       data != NULL;
 
3468
       data = data->NextInBasicBlock()) {
 
3469
    data->RemoveZeroOperations();
 
3470
    if (data->FatherInDominatorTree()) {
 
3471
      table->Insert(data->Key(), data->FatherInDominatorTree(), zone());
 
3472
    } else {
 
3473
      table->Delete(data->Key());
 
3474
    }
 
3475
  }
 
3476
}
 
3477
 
 
3478
 
 
3479
void HGraph::EliminateRedundantBoundsChecks() {
 
3480
  HPhase phase("H_Eliminate bounds checks", this);
 
3481
  BoundsCheckTable checks_table(zone());
 
3482
  EliminateRedundantBoundsChecks(entry_block(), &checks_table);
 
3483
}
 
3484
 
 
3485
 
 
3486
static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) {
 
3487
  HValue* index = array_operation->GetKey();
 
3488
 
 
3489
  HConstant* constant;
 
3490
  HValue* subexpression;
 
3491
  int32_t sign;
 
3492
  if (index->IsAdd()) {
 
3493
    sign = 1;
 
3494
    HAdd* add = HAdd::cast(index);
 
3495
    if (add->left()->IsConstant()) {
 
3496
      subexpression = add->right();
 
3497
      constant = HConstant::cast(add->left());
 
3498
    } else if (add->right()->IsConstant()) {
 
3499
      subexpression = add->left();
 
3500
      constant = HConstant::cast(add->right());
 
3501
    } else {
 
3502
      return;
 
3503
    }
 
3504
  } else if (index->IsSub()) {
 
3505
    sign = -1;
 
3506
    HSub* sub = HSub::cast(index);
 
3507
    if (sub->left()->IsConstant()) {
 
3508
      subexpression = sub->right();
 
3509
      constant = HConstant::cast(sub->left());
 
3510
    } else if (sub->right()->IsConstant()) {
 
3511
      subexpression = sub->left();
 
3512
      constant = HConstant::cast(sub->right());
 
3513
    } return;
 
3514
  } else {
 
3515
    return;
 
3516
  }
 
3517
 
 
3518
  if (!constant->HasInteger32Value()) return;
 
3519
  int32_t value = constant->Integer32Value() * sign;
 
3520
  // We limit offset values to 30 bits because we want to avoid the risk of
 
3521
  // overflows when the offset is added to the object header size.
 
3522
  if (value >= 1 << 30 || value < 0) return;
 
3523
  array_operation->SetKey(subexpression);
 
3524
  if (index->HasNoUses()) {
 
3525
    index->DeleteAndReplaceWith(NULL);
 
3526
  }
 
3527
  ASSERT(value >= 0);
 
3528
  array_operation->SetIndexOffset(static_cast<uint32_t>(value));
 
3529
  array_operation->SetDehoisted(true);
 
3530
}
 
3531
 
 
3532
 
 
3533
void HGraph::DehoistSimpleArrayIndexComputations() {
 
3534
  if (!FLAG_array_index_dehoisting) return;
 
3535
 
 
3536
  HPhase phase("H_Dehoist index computations", this);
 
3537
  for (int i = 0; i < blocks()->length(); ++i) {
 
3538
    for (HInstruction* instr = blocks()->at(i)->first();
 
3539
        instr != NULL;
 
3540
        instr = instr->next()) {
 
3541
      ArrayInstructionInterface* array_instruction = NULL;
 
3542
      if (instr->IsLoadKeyedFastElement()) {
 
3543
        HLoadKeyedFastElement* op = HLoadKeyedFastElement::cast(instr);
 
3544
        array_instruction = static_cast<ArrayInstructionInterface*>(op);
 
3545
      } else if (instr->IsLoadKeyedFastDoubleElement()) {
 
3546
        HLoadKeyedFastDoubleElement* op =
 
3547
            HLoadKeyedFastDoubleElement::cast(instr);
 
3548
        array_instruction = static_cast<ArrayInstructionInterface*>(op);
 
3549
      } else if (instr->IsLoadKeyedSpecializedArrayElement()) {
 
3550
        HLoadKeyedSpecializedArrayElement* op =
 
3551
            HLoadKeyedSpecializedArrayElement::cast(instr);
 
3552
        array_instruction = static_cast<ArrayInstructionInterface*>(op);
 
3553
      } else if (instr->IsStoreKeyedFastElement()) {
 
3554
        HStoreKeyedFastElement* op = HStoreKeyedFastElement::cast(instr);
 
3555
        array_instruction = static_cast<ArrayInstructionInterface*>(op);
 
3556
      } else if (instr->IsStoreKeyedFastDoubleElement()) {
 
3557
        HStoreKeyedFastDoubleElement* op =
 
3558
            HStoreKeyedFastDoubleElement::cast(instr);
 
3559
        array_instruction = static_cast<ArrayInstructionInterface*>(op);
 
3560
      } else if (instr->IsStoreKeyedSpecializedArrayElement()) {
 
3561
        HStoreKeyedSpecializedArrayElement* op =
 
3562
            HStoreKeyedSpecializedArrayElement::cast(instr);
 
3563
        array_instruction = static_cast<ArrayInstructionInterface*>(op);
 
3564
      } else {
 
3565
        continue;
 
3566
      }
 
3567
      DehoistArrayIndex(array_instruction);
 
3568
    }
 
3569
  }
 
3570
}
 
3571
 
 
3572
 
 
3573
HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
 
3574
  ASSERT(current_block() != NULL);
 
3575
  current_block()->AddInstruction(instr);
 
3576
  return instr;
 
3577
}
 
3578
 
 
3579
 
 
3580
void HGraphBuilder::AddSimulate(int ast_id) {
 
3581
  ASSERT(current_block() != NULL);
 
3582
  current_block()->AddSimulate(ast_id);
 
3583
}
 
3584
 
 
3585
 
 
3586
void HGraphBuilder::AddPhi(HPhi* instr) {
 
3587
  ASSERT(current_block() != NULL);
 
3588
  current_block()->AddPhi(instr);
 
3589
}
 
3590
 
 
3591
 
 
3592
void HGraphBuilder::PushAndAdd(HInstruction* instr) {
 
3593
  Push(instr);
 
3594
  AddInstruction(instr);
 
3595
}
 
3596
 
 
3597
 
 
3598
template <class Instruction>
 
3599
HInstruction* HGraphBuilder::PreProcessCall(Instruction* call) {
 
3600
  int count = call->argument_count();
 
3601
  ZoneList<HValue*> arguments(count, zone());
 
3602
  for (int i = 0; i < count; ++i) {
 
3603
    arguments.Add(Pop(), zone());
 
3604
  }
 
3605
 
 
3606
  while (!arguments.is_empty()) {
 
3607
    AddInstruction(new(zone()) HPushArgument(arguments.RemoveLast()));
 
3608
  }
 
3609
  return call;
 
3610
}
 
3611
 
 
3612
 
 
3613
void HGraphBuilder::SetUpScope(Scope* scope) {
 
3614
  HConstant* undefined_constant = new(zone()) HConstant(
 
3615
      isolate()->factory()->undefined_value(), Representation::Tagged());
 
3616
  AddInstruction(undefined_constant);
 
3617
  graph_->set_undefined_constant(undefined_constant);
 
3618
 
 
3619
  HArgumentsObject* object = new(zone()) HArgumentsObject;
 
3620
  AddInstruction(object);
 
3621
  graph()->SetArgumentsObject(object);
 
3622
 
 
3623
  // Set the initial values of parameters including "this".  "This" has
 
3624
  // parameter index 0.
 
3625
  ASSERT_EQ(scope->num_parameters() + 1, environment()->parameter_count());
 
3626
 
 
3627
  for (int i = 0; i < environment()->parameter_count(); ++i) {
 
3628
    HInstruction* parameter = AddInstruction(new(zone()) HParameter(i));
 
3629
    environment()->Bind(i, parameter);
 
3630
  }
 
3631
 
 
3632
  // First special is HContext.
 
3633
  HInstruction* context = AddInstruction(new(zone()) HContext);
 
3634
  environment()->BindContext(context);
 
3635
 
 
3636
  // Initialize specials and locals to undefined.
 
3637
  for (int i = environment()->parameter_count() + 1;
 
3638
       i < environment()->length();
 
3639
       ++i) {
 
3640
    environment()->Bind(i, undefined_constant);
 
3641
  }
 
3642
 
 
3643
  // Handle the arguments and arguments shadow variables specially (they do
 
3644
  // not have declarations).
 
3645
  if (scope->arguments() != NULL) {
 
3646
    if (!scope->arguments()->IsStackAllocated()) {
 
3647
      return Bailout("context-allocated arguments");
 
3648
    }
 
3649
 
 
3650
    environment()->Bind(scope->arguments(),
 
3651
                        graph()->GetArgumentsObject());
 
3652
  }
 
3653
}
 
3654
 
 
3655
 
 
3656
void HGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) {
 
3657
  for (int i = 0; i < statements->length(); i++) {
 
3658
    CHECK_ALIVE(Visit(statements->at(i)));
 
3659
  }
 
3660
}
 
3661
 
 
3662
 
 
3663
HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) {
 
3664
  HBasicBlock* b = graph()->CreateBasicBlock();
 
3665
  b->SetInitialEnvironment(env);
 
3666
  return b;
 
3667
}
 
3668
 
 
3669
 
 
3670
HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
 
3671
  HBasicBlock* header = graph()->CreateBasicBlock();
 
3672
  HEnvironment* entry_env = environment()->CopyAsLoopHeader(header);
 
3673
  header->SetInitialEnvironment(entry_env);
 
3674
  header->AttachLoopInformation();
 
3675
  return header;
 
3676
}
 
3677
 
 
3678
 
 
3679
void HGraphBuilder::VisitBlock(Block* stmt) {
 
3680
  ASSERT(!HasStackOverflow());
 
3681
  ASSERT(current_block() != NULL);
 
3682
  ASSERT(current_block()->HasPredecessor());
 
3683
  if (stmt->scope() != NULL) {
 
3684
    return Bailout("ScopedBlock");
 
3685
  }
 
3686
  BreakAndContinueInfo break_info(stmt);
 
3687
  { BreakAndContinueScope push(&break_info, this);
 
3688
    CHECK_BAILOUT(VisitStatements(stmt->statements()));
 
3689
  }
 
3690
  HBasicBlock* break_block = break_info.break_block();
 
3691
  if (break_block != NULL) {
 
3692
    if (current_block() != NULL) current_block()->Goto(break_block);
 
3693
    break_block->SetJoinId(stmt->ExitId());
 
3694
    set_current_block(break_block);
 
3695
  }
 
3696
}
 
3697
 
 
3698
 
 
3699
void HGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
 
3700
  ASSERT(!HasStackOverflow());
 
3701
  ASSERT(current_block() != NULL);
 
3702
  ASSERT(current_block()->HasPredecessor());
 
3703
  VisitForEffect(stmt->expression());
 
3704
}
 
3705
 
 
3706
 
 
3707
void HGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
 
3708
  ASSERT(!HasStackOverflow());
 
3709
  ASSERT(current_block() != NULL);
 
3710
  ASSERT(current_block()->HasPredecessor());
 
3711
}
 
3712
 
 
3713
 
 
3714
void HGraphBuilder::VisitIfStatement(IfStatement* stmt) {
 
3715
  ASSERT(!HasStackOverflow());
 
3716
  ASSERT(current_block() != NULL);
 
3717
  ASSERT(current_block()->HasPredecessor());
 
3718
  if (stmt->condition()->ToBooleanIsTrue()) {
 
3719
    AddSimulate(stmt->ThenId());
 
3720
    Visit(stmt->then_statement());
 
3721
  } else if (stmt->condition()->ToBooleanIsFalse()) {
 
3722
    AddSimulate(stmt->ElseId());
 
3723
    Visit(stmt->else_statement());
 
3724
  } else {
 
3725
    HBasicBlock* cond_true = graph()->CreateBasicBlock();
 
3726
    HBasicBlock* cond_false = graph()->CreateBasicBlock();
 
3727
    CHECK_BAILOUT(VisitForControl(stmt->condition(), cond_true, cond_false));
 
3728
 
 
3729
    if (cond_true->HasPredecessor()) {
 
3730
      cond_true->SetJoinId(stmt->ThenId());
 
3731
      set_current_block(cond_true);
 
3732
      CHECK_BAILOUT(Visit(stmt->then_statement()));
 
3733
      cond_true = current_block();
 
3734
    } else {
 
3735
      cond_true = NULL;
 
3736
    }
 
3737
 
 
3738
    if (cond_false->HasPredecessor()) {
 
3739
      cond_false->SetJoinId(stmt->ElseId());
 
3740
      set_current_block(cond_false);
 
3741
      CHECK_BAILOUT(Visit(stmt->else_statement()));
 
3742
      cond_false = current_block();
 
3743
    } else {
 
3744
      cond_false = NULL;
 
3745
    }
 
3746
 
 
3747
    HBasicBlock* join = CreateJoin(cond_true, cond_false, stmt->IfId());
 
3748
    set_current_block(join);
 
3749
  }
 
3750
}
 
3751
 
 
3752
 
 
3753
HBasicBlock* HGraphBuilder::BreakAndContinueScope::Get(
 
3754
    BreakableStatement* stmt,
 
3755
    BreakType type,
 
3756
    int* drop_extra) {
 
3757
  *drop_extra = 0;
 
3758
  BreakAndContinueScope* current = this;
 
3759
  while (current != NULL && current->info()->target() != stmt) {
 
3760
    *drop_extra += current->info()->drop_extra();
 
3761
    current = current->next();
 
3762
  }
 
3763
  ASSERT(current != NULL);  // Always found (unless stack is malformed).
 
3764
 
 
3765
  if (type == BREAK) {
 
3766
    *drop_extra += current->info()->drop_extra();
 
3767
  }
 
3768
 
 
3769
  HBasicBlock* block = NULL;
 
3770
  switch (type) {
 
3771
    case BREAK:
 
3772
      block = current->info()->break_block();
 
3773
      if (block == NULL) {
 
3774
        block = current->owner()->graph()->CreateBasicBlock();
 
3775
        current->info()->set_break_block(block);
 
3776
      }
 
3777
      break;
 
3778
 
 
3779
    case CONTINUE:
 
3780
      block = current->info()->continue_block();
 
3781
      if (block == NULL) {
 
3782
        block = current->owner()->graph()->CreateBasicBlock();
 
3783
        current->info()->set_continue_block(block);
 
3784
      }
 
3785
      break;
 
3786
  }
 
3787
 
 
3788
  return block;
 
3789
}
 
3790
 
 
3791
 
 
3792
void HGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
 
3793
  ASSERT(!HasStackOverflow());
 
3794
  ASSERT(current_block() != NULL);
 
3795
  ASSERT(current_block()->HasPredecessor());
 
3796
  int drop_extra = 0;
 
3797
  HBasicBlock* continue_block = break_scope()->Get(stmt->target(),
 
3798
                                                   CONTINUE,
 
3799
                                                   &drop_extra);
 
3800
  Drop(drop_extra);
 
3801
  current_block()->Goto(continue_block);
 
3802
  set_current_block(NULL);
 
3803
}
 
3804
 
 
3805
 
 
3806
void HGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
 
3807
  ASSERT(!HasStackOverflow());
 
3808
  ASSERT(current_block() != NULL);
 
3809
  ASSERT(current_block()->HasPredecessor());
 
3810
  int drop_extra = 0;
 
3811
  HBasicBlock* break_block = break_scope()->Get(stmt->target(),
 
3812
                                                BREAK,
 
3813
                                                &drop_extra);
 
3814
  Drop(drop_extra);
 
3815
  current_block()->Goto(break_block);
 
3816
  set_current_block(NULL);
 
3817
}
 
3818
 
 
3819
 
 
3820
void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
 
3821
  ASSERT(!HasStackOverflow());
 
3822
  ASSERT(current_block() != NULL);
 
3823
  ASSERT(current_block()->HasPredecessor());
 
3824
  AstContext* context = call_context();
 
3825
  if (context == NULL) {
 
3826
    // Not an inlined return, so an actual one.
 
3827
    CHECK_ALIVE(VisitForValue(stmt->expression()));
 
3828
    HValue* result = environment()->Pop();
 
3829
    current_block()->FinishExit(new(zone()) HReturn(result));
 
3830
  } else if (function_state()->is_construct()) {
 
3831
    // Return from an inlined construct call.  In a test context the return
 
3832
    // value will always evaluate to true, in a value context the return value
 
3833
    // needs to be a JSObject.
 
3834
    if (context->IsTest()) {
 
3835
      TestContext* test = TestContext::cast(context);
 
3836
      CHECK_ALIVE(VisitForEffect(stmt->expression()));
 
3837
      current_block()->Goto(test->if_true(), function_state());
 
3838
    } else if (context->IsEffect()) {
 
3839
      CHECK_ALIVE(VisitForEffect(stmt->expression()));
 
3840
      current_block()->Goto(function_return(), function_state());
 
3841
    } else {
 
3842
      ASSERT(context->IsValue());
 
3843
      CHECK_ALIVE(VisitForValue(stmt->expression()));
 
3844
      HValue* return_value = Pop();
 
3845
      HValue* receiver = environment()->Lookup(0);
 
3846
      HHasInstanceTypeAndBranch* typecheck =
 
3847
          new(zone()) HHasInstanceTypeAndBranch(return_value,
 
3848
                                                FIRST_SPEC_OBJECT_TYPE,
 
3849
                                                LAST_SPEC_OBJECT_TYPE);
 
3850
      HBasicBlock* if_spec_object = graph()->CreateBasicBlock();
 
3851
      HBasicBlock* not_spec_object = graph()->CreateBasicBlock();
 
3852
      typecheck->SetSuccessorAt(0, if_spec_object);
 
3853
      typecheck->SetSuccessorAt(1, not_spec_object);
 
3854
      current_block()->Finish(typecheck);
 
3855
      if_spec_object->AddLeaveInlined(return_value,
 
3856
                                      function_return(),
 
3857
                                      function_state());
 
3858
      not_spec_object->AddLeaveInlined(receiver,
 
3859
                                       function_return(),
 
3860
                                       function_state());
 
3861
    }
 
3862
  } else {
 
3863
    // Return from an inlined function, visit the subexpression in the
 
3864
    // expression context of the call.
 
3865
    if (context->IsTest()) {
 
3866
      TestContext* test = TestContext::cast(context);
 
3867
      VisitForControl(stmt->expression(),
 
3868
                      test->if_true(),
 
3869
                      test->if_false());
 
3870
    } else if (context->IsEffect()) {
 
3871
      CHECK_ALIVE(VisitForEffect(stmt->expression()));
 
3872
      current_block()->Goto(function_return(), function_state());
 
3873
    } else {
 
3874
      ASSERT(context->IsValue());
 
3875
      CHECK_ALIVE(VisitForValue(stmt->expression()));
 
3876
      HValue* return_value = Pop();
 
3877
      current_block()->AddLeaveInlined(return_value,
 
3878
                                       function_return(),
 
3879
                                       function_state());
 
3880
    }
 
3881
  }
 
3882
  set_current_block(NULL);
 
3883
}
 
3884
 
 
3885
 
 
3886
void HGraphBuilder::VisitWithStatement(WithStatement* stmt) {
 
3887
  ASSERT(!HasStackOverflow());
 
3888
  ASSERT(current_block() != NULL);
 
3889
  ASSERT(current_block()->HasPredecessor());
 
3890
  return Bailout("WithStatement");
 
3891
}
 
3892
 
 
3893
 
 
3894
void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
 
3895
  ASSERT(!HasStackOverflow());
 
3896
  ASSERT(current_block() != NULL);
 
3897
  ASSERT(current_block()->HasPredecessor());
 
3898
  // We only optimize switch statements with smi-literal smi comparisons,
 
3899
  // with a bounded number of clauses.
 
3900
  const int kCaseClauseLimit = 128;
 
3901
  ZoneList<CaseClause*>* clauses = stmt->cases();
 
3902
  int clause_count = clauses->length();
 
3903
  if (clause_count > kCaseClauseLimit) {
 
3904
    return Bailout("SwitchStatement: too many clauses");
 
3905
  }
 
3906
 
 
3907
  HValue* context = environment()->LookupContext();
 
3908
 
 
3909
  CHECK_ALIVE(VisitForValue(stmt->tag()));
 
3910
  AddSimulate(stmt->EntryId());
 
3911
  HValue* tag_value = Pop();
 
3912
  HBasicBlock* first_test_block = current_block();
 
3913
 
 
3914
  SwitchType switch_type = UNKNOWN_SWITCH;
 
3915
 
 
3916
  // 1. Extract clause type
 
3917
  for (int i = 0; i < clause_count; ++i) {
 
3918
    CaseClause* clause = clauses->at(i);
 
3919
    if (clause->is_default()) continue;
 
3920
 
 
3921
    if (switch_type == UNKNOWN_SWITCH) {
 
3922
      if (clause->label()->IsSmiLiteral()) {
 
3923
        switch_type = SMI_SWITCH;
 
3924
      } else if (clause->label()->IsStringLiteral()) {
 
3925
        switch_type = STRING_SWITCH;
 
3926
      } else {
 
3927
        return Bailout("SwitchStatement: non-literal switch label");
 
3928
      }
 
3929
    } else if ((switch_type == STRING_SWITCH &&
 
3930
                !clause->label()->IsStringLiteral()) ||
 
3931
               (switch_type == SMI_SWITCH &&
 
3932
                !clause->label()->IsSmiLiteral())) {
 
3933
      return Bailout("SwitchStatemnt: mixed label types are not supported");
 
3934
    }
 
3935
  }
 
3936
 
 
3937
  HUnaryControlInstruction* string_check = NULL;
 
3938
  HBasicBlock* not_string_block = NULL;
 
3939
 
 
3940
  // Test switch's tag value if all clauses are string literals
 
3941
  if (switch_type == STRING_SWITCH) {
 
3942
    string_check = new(zone()) HIsStringAndBranch(tag_value);
 
3943
    first_test_block = graph()->CreateBasicBlock();
 
3944
    not_string_block = graph()->CreateBasicBlock();
 
3945
 
 
3946
    string_check->SetSuccessorAt(0, first_test_block);
 
3947
    string_check->SetSuccessorAt(1, not_string_block);
 
3948
    current_block()->Finish(string_check);
 
3949
 
 
3950
    set_current_block(first_test_block);
 
3951
  }
 
3952
 
 
3953
  // 2. Build all the tests, with dangling true branches
 
3954
  int default_id = AstNode::kNoNumber;
 
3955
  for (int i = 0; i < clause_count; ++i) {
 
3956
    CaseClause* clause = clauses->at(i);
 
3957
    if (clause->is_default()) {
 
3958
      default_id = clause->EntryId();
 
3959
      continue;
 
3960
    }
 
3961
    if (switch_type == SMI_SWITCH) {
 
3962
      clause->RecordTypeFeedback(oracle());
 
3963
    }
 
3964
 
 
3965
    // Generate a compare and branch.
 
3966
    CHECK_ALIVE(VisitForValue(clause->label()));
 
3967
    HValue* label_value = Pop();
 
3968
 
 
3969
    HBasicBlock* next_test_block = graph()->CreateBasicBlock();
 
3970
    HBasicBlock* body_block = graph()->CreateBasicBlock();
 
3971
 
 
3972
    HControlInstruction* compare;
 
3973
 
 
3974
    if (switch_type == SMI_SWITCH) {
 
3975
      if (!clause->IsSmiCompare()) {
 
3976
        // Finish with deoptimize and add uses of enviroment values to
 
3977
        // account for invisible uses.
 
3978
        current_block()->FinishExitWithDeoptimization(HDeoptimize::kUseAll);
 
3979
        set_current_block(NULL);
 
3980
        break;
 
3981
      }
 
3982
 
 
3983
      HCompareIDAndBranch* compare_ =
 
3984
          new(zone()) HCompareIDAndBranch(tag_value,
 
3985
                                          label_value,
 
3986
                                          Token::EQ_STRICT);
 
3987
      compare_->SetInputRepresentation(Representation::Integer32());
 
3988
      compare = compare_;
 
3989
    } else {
 
3990
      compare = new(zone()) HStringCompareAndBranch(context, tag_value,
 
3991
                                                     label_value,
 
3992
                                                     Token::EQ_STRICT);
 
3993
    }
 
3994
 
 
3995
    compare->SetSuccessorAt(0, body_block);
 
3996
    compare->SetSuccessorAt(1, next_test_block);
 
3997
    current_block()->Finish(compare);
 
3998
 
 
3999
    set_current_block(next_test_block);
 
4000
  }
 
4001
 
 
4002
  // Save the current block to use for the default or to join with the
 
4003
  // exit.  This block is NULL if we deoptimized.
 
4004
  HBasicBlock* last_block = current_block();
 
4005
 
 
4006
  if (not_string_block != NULL) {
 
4007
    int join_id = (default_id != AstNode::kNoNumber)
 
4008
        ? default_id
 
4009
        : stmt->ExitId();
 
4010
    last_block = CreateJoin(last_block, not_string_block, join_id);
 
4011
  }
 
4012
 
 
4013
  // 3. Loop over the clauses and the linked list of tests in lockstep,
 
4014
  // translating the clause bodies.
 
4015
  HBasicBlock* curr_test_block = first_test_block;
 
4016
  HBasicBlock* fall_through_block = NULL;
 
4017
 
 
4018
  BreakAndContinueInfo break_info(stmt);
 
4019
  { BreakAndContinueScope push(&break_info, this);
 
4020
    for (int i = 0; i < clause_count; ++i) {
 
4021
      CaseClause* clause = clauses->at(i);
 
4022
 
 
4023
      // Identify the block where normal (non-fall-through) control flow
 
4024
      // goes to.
 
4025
      HBasicBlock* normal_block = NULL;
 
4026
      if (clause->is_default()) {
 
4027
        if (last_block != NULL) {
 
4028
          normal_block = last_block;
 
4029
          last_block = NULL;  // Cleared to indicate we've handled it.
 
4030
        }
 
4031
      } else if (!curr_test_block->end()->IsDeoptimize()) {
 
4032
        normal_block = curr_test_block->end()->FirstSuccessor();
 
4033
        curr_test_block = curr_test_block->end()->SecondSuccessor();
 
4034
      }
 
4035
 
 
4036
      // Identify a block to emit the body into.
 
4037
      if (normal_block == NULL) {
 
4038
        if (fall_through_block == NULL) {
 
4039
          // (a) Unreachable.
 
4040
          if (clause->is_default()) {
 
4041
            continue;  // Might still be reachable clause bodies.
 
4042
          } else {
 
4043
            break;
 
4044
          }
 
4045
        } else {
 
4046
          // (b) Reachable only as fall through.
 
4047
          set_current_block(fall_through_block);
 
4048
        }
 
4049
      } else if (fall_through_block == NULL) {
 
4050
        // (c) Reachable only normally.
 
4051
        set_current_block(normal_block);
 
4052
      } else {
 
4053
        // (d) Reachable both ways.
 
4054
        HBasicBlock* join = CreateJoin(fall_through_block,
 
4055
                                       normal_block,
 
4056
                                       clause->EntryId());
 
4057
        set_current_block(join);
 
4058
      }
 
4059
 
 
4060
      CHECK_BAILOUT(VisitStatements(clause->statements()));
 
4061
      fall_through_block = current_block();
 
4062
    }
 
4063
  }
 
4064
 
 
4065
  // Create an up-to-3-way join.  Use the break block if it exists since
 
4066
  // it's already a join block.
 
4067
  HBasicBlock* break_block = break_info.break_block();
 
4068
  if (break_block == NULL) {
 
4069
    set_current_block(CreateJoin(fall_through_block,
 
4070
                                 last_block,
 
4071
                                 stmt->ExitId()));
 
4072
  } else {
 
4073
    if (fall_through_block != NULL) fall_through_block->Goto(break_block);
 
4074
    if (last_block != NULL) last_block->Goto(break_block);
 
4075
    break_block->SetJoinId(stmt->ExitId());
 
4076
    set_current_block(break_block);
 
4077
  }
 
4078
}
 
4079
 
 
4080
 
 
4081
bool HGraphBuilder::HasOsrEntryAt(IterationStatement* statement) {
 
4082
  return statement->OsrEntryId() == info()->osr_ast_id();
 
4083
}
 
4084
 
 
4085
 
 
4086
bool HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) {
 
4087
  if (!HasOsrEntryAt(statement)) return false;
 
4088
 
 
4089
  HBasicBlock* non_osr_entry = graph()->CreateBasicBlock();
 
4090
  HBasicBlock* osr_entry = graph()->CreateBasicBlock();
 
4091
  HValue* true_value = graph()->GetConstantTrue();
 
4092
  HBranch* test = new(zone()) HBranch(true_value, non_osr_entry, osr_entry);
 
4093
  current_block()->Finish(test);
 
4094
 
 
4095
  HBasicBlock* loop_predecessor = graph()->CreateBasicBlock();
 
4096
  non_osr_entry->Goto(loop_predecessor);
 
4097
 
 
4098
  set_current_block(osr_entry);
 
4099
  int osr_entry_id = statement->OsrEntryId();
 
4100
  int first_expression_index = environment()->first_expression_index();
 
4101
  int length = environment()->length();
 
4102
  ZoneList<HUnknownOSRValue*>* osr_values =
 
4103
      new(zone()) ZoneList<HUnknownOSRValue*>(length, zone());
 
4104
 
 
4105
  for (int i = 0; i < first_expression_index; ++i) {
 
4106
    HUnknownOSRValue* osr_value = new(zone()) HUnknownOSRValue;
 
4107
    AddInstruction(osr_value);
 
4108
    environment()->Bind(i, osr_value);
 
4109
    osr_values->Add(osr_value, zone());
 
4110
  }
 
4111
 
 
4112
  if (first_expression_index != length) {
 
4113
    environment()->Drop(length - first_expression_index);
 
4114
    for (int i = first_expression_index; i < length; ++i) {
 
4115
      HUnknownOSRValue* osr_value = new(zone()) HUnknownOSRValue;
 
4116
      AddInstruction(osr_value);
 
4117
      environment()->Push(osr_value);
 
4118
      osr_values->Add(osr_value, zone());
 
4119
    }
 
4120
  }
 
4121
 
 
4122
  graph()->set_osr_values(osr_values);
 
4123
 
 
4124
  AddSimulate(osr_entry_id);
 
4125
  AddInstruction(new(zone()) HOsrEntry(osr_entry_id));
 
4126
  HContext* context = new(zone()) HContext;
 
4127
  AddInstruction(context);
 
4128
  environment()->BindContext(context);
 
4129
  current_block()->Goto(loop_predecessor);
 
4130
  loop_predecessor->SetJoinId(statement->EntryId());
 
4131
  set_current_block(loop_predecessor);
 
4132
  return true;
 
4133
}
 
4134
 
 
4135
 
 
4136
void HGraphBuilder::VisitLoopBody(IterationStatement* stmt,
 
4137
                                  HBasicBlock* loop_entry,
 
4138
                                  BreakAndContinueInfo* break_info) {
 
4139
  BreakAndContinueScope push(break_info, this);
 
4140
  AddSimulate(stmt->StackCheckId());
 
4141
  HValue* context = environment()->LookupContext();
 
4142
  HStackCheck* stack_check =
 
4143
    new(zone()) HStackCheck(context, HStackCheck::kBackwardsBranch);
 
4144
  AddInstruction(stack_check);
 
4145
  ASSERT(loop_entry->IsLoopHeader());
 
4146
  loop_entry->loop_information()->set_stack_check(stack_check);
 
4147
  CHECK_BAILOUT(Visit(stmt->body()));
 
4148
}
 
4149
 
 
4150
 
 
4151
void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
 
4152
  ASSERT(!HasStackOverflow());
 
4153
  ASSERT(current_block() != NULL);
 
4154
  ASSERT(current_block()->HasPredecessor());
 
4155
  ASSERT(current_block() != NULL);
 
4156
  bool osr_entry = PreProcessOsrEntry(stmt);
 
4157
  HBasicBlock* loop_entry = CreateLoopHeaderBlock();
 
4158
  current_block()->Goto(loop_entry);
 
4159
  set_current_block(loop_entry);
 
4160
  if (osr_entry) graph()->set_osr_loop_entry(loop_entry);
 
4161
 
 
4162
  BreakAndContinueInfo break_info(stmt);
 
4163
  CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
 
4164
  HBasicBlock* body_exit =
 
4165
      JoinContinue(stmt, current_block(), break_info.continue_block());
 
4166
  HBasicBlock* loop_successor = NULL;
 
4167
  if (body_exit != NULL && !stmt->cond()->ToBooleanIsTrue()) {
 
4168
    set_current_block(body_exit);
 
4169
    // The block for a true condition, the actual predecessor block of the
 
4170
    // back edge.
 
4171
    body_exit = graph()->CreateBasicBlock();
 
4172
    loop_successor = graph()->CreateBasicBlock();
 
4173
    CHECK_BAILOUT(VisitForControl(stmt->cond(), body_exit, loop_successor));
 
4174
    if (body_exit->HasPredecessor()) {
 
4175
      body_exit->SetJoinId(stmt->BackEdgeId());
 
4176
    } else {
 
4177
      body_exit = NULL;
 
4178
    }
 
4179
    if (loop_successor->HasPredecessor()) {
 
4180
      loop_successor->SetJoinId(stmt->ExitId());
 
4181
    } else {
 
4182
      loop_successor = NULL;
 
4183
    }
 
4184
  }
 
4185
  HBasicBlock* loop_exit = CreateLoop(stmt,
 
4186
                                      loop_entry,
 
4187
                                      body_exit,
 
4188
                                      loop_successor,
 
4189
                                      break_info.break_block());
 
4190
  set_current_block(loop_exit);
 
4191
}
 
4192
 
 
4193
 
 
4194
void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
 
4195
  ASSERT(!HasStackOverflow());
 
4196
  ASSERT(current_block() != NULL);
 
4197
  ASSERT(current_block()->HasPredecessor());
 
4198
  ASSERT(current_block() != NULL);
 
4199
  bool osr_entry = PreProcessOsrEntry(stmt);
 
4200
  HBasicBlock* loop_entry = CreateLoopHeaderBlock();
 
4201
  current_block()->Goto(loop_entry);
 
4202
  set_current_block(loop_entry);
 
4203
  if (osr_entry) graph()->set_osr_loop_entry(loop_entry);
 
4204
 
 
4205
 
 
4206
  // If the condition is constant true, do not generate a branch.
 
4207
  HBasicBlock* loop_successor = NULL;
 
4208
  if (!stmt->cond()->ToBooleanIsTrue()) {
 
4209
    HBasicBlock* body_entry = graph()->CreateBasicBlock();
 
4210
    loop_successor = graph()->CreateBasicBlock();
 
4211
    CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor));
 
4212
    if (body_entry->HasPredecessor()) {
 
4213
      body_entry->SetJoinId(stmt->BodyId());
 
4214
      set_current_block(body_entry);
 
4215
    }
 
4216
    if (loop_successor->HasPredecessor()) {
 
4217
      loop_successor->SetJoinId(stmt->ExitId());
 
4218
    } else {
 
4219
      loop_successor = NULL;
 
4220
    }
 
4221
  }
 
4222
 
 
4223
  BreakAndContinueInfo break_info(stmt);
 
4224
  if (current_block() != NULL) {
 
4225
    CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
 
4226
  }
 
4227
  HBasicBlock* body_exit =
 
4228
      JoinContinue(stmt, current_block(), break_info.continue_block());
 
4229
  HBasicBlock* loop_exit = CreateLoop(stmt,
 
4230
                                      loop_entry,
 
4231
                                      body_exit,
 
4232
                                      loop_successor,
 
4233
                                      break_info.break_block());
 
4234
  set_current_block(loop_exit);
 
4235
}
 
4236
 
 
4237
 
 
4238
void HGraphBuilder::VisitForStatement(ForStatement* stmt) {
 
4239
  ASSERT(!HasStackOverflow());
 
4240
  ASSERT(current_block() != NULL);
 
4241
  ASSERT(current_block()->HasPredecessor());
 
4242
  if (stmt->init() != NULL) {
 
4243
    CHECK_ALIVE(Visit(stmt->init()));
 
4244
  }
 
4245
  ASSERT(current_block() != NULL);
 
4246
  bool osr_entry = PreProcessOsrEntry(stmt);
 
4247
  HBasicBlock* loop_entry = CreateLoopHeaderBlock();
 
4248
  current_block()->Goto(loop_entry);
 
4249
  set_current_block(loop_entry);
 
4250
  if (osr_entry) graph()->set_osr_loop_entry(loop_entry);
 
4251
 
 
4252
  HBasicBlock* loop_successor = NULL;
 
4253
  if (stmt->cond() != NULL) {
 
4254
    HBasicBlock* body_entry = graph()->CreateBasicBlock();
 
4255
    loop_successor = graph()->CreateBasicBlock();
 
4256
    CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor));
 
4257
    if (body_entry->HasPredecessor()) {
 
4258
      body_entry->SetJoinId(stmt->BodyId());
 
4259
      set_current_block(body_entry);
 
4260
    }
 
4261
    if (loop_successor->HasPredecessor()) {
 
4262
      loop_successor->SetJoinId(stmt->ExitId());
 
4263
    } else {
 
4264
      loop_successor = NULL;
 
4265
    }
 
4266
  }
 
4267
 
 
4268
  BreakAndContinueInfo break_info(stmt);
 
4269
  if (current_block() != NULL) {
 
4270
    CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
 
4271
  }
 
4272
  HBasicBlock* body_exit =
 
4273
      JoinContinue(stmt, current_block(), break_info.continue_block());
 
4274
 
 
4275
  if (stmt->next() != NULL && body_exit != NULL) {
 
4276
    set_current_block(body_exit);
 
4277
    CHECK_BAILOUT(Visit(stmt->next()));
 
4278
    body_exit = current_block();
 
4279
  }
 
4280
 
 
4281
  HBasicBlock* loop_exit = CreateLoop(stmt,
 
4282
                                      loop_entry,
 
4283
                                      body_exit,
 
4284
                                      loop_successor,
 
4285
                                      break_info.break_block());
 
4286
  set_current_block(loop_exit);
 
4287
}
 
4288
 
 
4289
 
 
4290
void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
 
4291
  ASSERT(!HasStackOverflow());
 
4292
  ASSERT(current_block() != NULL);
 
4293
  ASSERT(current_block()->HasPredecessor());
 
4294
 
 
4295
  if (!FLAG_optimize_for_in) {
 
4296
    return Bailout("ForInStatement optimization is disabled");
 
4297
  }
 
4298
 
 
4299
  if (!oracle()->IsForInFastCase(stmt)) {
 
4300
    return Bailout("ForInStatement is not fast case");
 
4301
  }
 
4302
 
 
4303
  if (!stmt->each()->IsVariableProxy() ||
 
4304
      !stmt->each()->AsVariableProxy()->var()->IsStackLocal()) {
 
4305
    return Bailout("ForInStatement with non-local each variable");
 
4306
  }
 
4307
 
 
4308
  Variable* each_var = stmt->each()->AsVariableProxy()->var();
 
4309
 
 
4310
  CHECK_ALIVE(VisitForValue(stmt->enumerable()));
 
4311
  HValue* enumerable = Top();  // Leave enumerable at the top.
 
4312
 
 
4313
  HInstruction* map = AddInstruction(new(zone()) HForInPrepareMap(
 
4314
      environment()->LookupContext(), enumerable));
 
4315
  AddSimulate(stmt->PrepareId());
 
4316
 
 
4317
  HInstruction* array = AddInstruction(
 
4318
      new(zone()) HForInCacheArray(
 
4319
          enumerable,
 
4320
          map,
 
4321
          DescriptorArray::kEnumCacheBridgeCacheIndex));
 
4322
 
 
4323
  HInstruction* array_length = AddInstruction(
 
4324
      new(zone()) HFixedArrayBaseLength(array));
 
4325
 
 
4326
  HInstruction* start_index = AddInstruction(new(zone()) HConstant(
 
4327
      Handle<Object>(Smi::FromInt(0)), Representation::Integer32()));
 
4328
 
 
4329
  Push(map);
 
4330
  Push(array);
 
4331
  Push(array_length);
 
4332
  Push(start_index);
 
4333
 
 
4334
  HInstruction* index_cache = AddInstruction(
 
4335
      new(zone()) HForInCacheArray(
 
4336
          enumerable,
 
4337
          map,
 
4338
          DescriptorArray::kEnumCacheBridgeIndicesCacheIndex));
 
4339
  HForInCacheArray::cast(array)->set_index_cache(
 
4340
      HForInCacheArray::cast(index_cache));
 
4341
 
 
4342
  bool osr_entry = PreProcessOsrEntry(stmt);
 
4343
  HBasicBlock* loop_entry = CreateLoopHeaderBlock();
 
4344
  current_block()->Goto(loop_entry);
 
4345
  set_current_block(loop_entry);
 
4346
  if (osr_entry) graph()->set_osr_loop_entry(loop_entry);
 
4347
 
 
4348
  HValue* index = environment()->ExpressionStackAt(0);
 
4349
  HValue* limit = environment()->ExpressionStackAt(1);
 
4350
 
 
4351
  // Check that we still have more keys.
 
4352
  HCompareIDAndBranch* compare_index =
 
4353
      new(zone()) HCompareIDAndBranch(index, limit, Token::LT);
 
4354
  compare_index->SetInputRepresentation(Representation::Integer32());
 
4355
 
 
4356
  HBasicBlock* loop_body = graph()->CreateBasicBlock();
 
4357
  HBasicBlock* loop_successor = graph()->CreateBasicBlock();
 
4358
 
 
4359
  compare_index->SetSuccessorAt(0, loop_body);
 
4360
  compare_index->SetSuccessorAt(1, loop_successor);
 
4361
  current_block()->Finish(compare_index);
 
4362
 
 
4363
  set_current_block(loop_successor);
 
4364
  Drop(5);
 
4365
 
 
4366
  set_current_block(loop_body);
 
4367
 
 
4368
  HValue* key = AddInstruction(
 
4369
      new(zone()) HLoadKeyedFastElement(
 
4370
          environment()->ExpressionStackAt(2),  // Enum cache.
 
4371
          environment()->ExpressionStackAt(0),  // Iteration index.
 
4372
          environment()->ExpressionStackAt(0)));
 
4373
 
 
4374
  // Check if the expected map still matches that of the enumerable.
 
4375
  // If not just deoptimize.
 
4376
  AddInstruction(new(zone()) HCheckMapValue(
 
4377
      environment()->ExpressionStackAt(4),
 
4378
      environment()->ExpressionStackAt(3)));
 
4379
 
 
4380
  Bind(each_var, key);
 
4381
 
 
4382
  BreakAndContinueInfo break_info(stmt, 5);
 
4383
  CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
 
4384
 
 
4385
  HBasicBlock* body_exit =
 
4386
      JoinContinue(stmt, current_block(), break_info.continue_block());
 
4387
 
 
4388
  if (body_exit != NULL) {
 
4389
    set_current_block(body_exit);
 
4390
 
 
4391
    HValue* current_index = Pop();
 
4392
    HInstruction* new_index = new(zone()) HAdd(environment()->LookupContext(),
 
4393
                                               current_index,
 
4394
                                               graph()->GetConstant1());
 
4395
    new_index->AssumeRepresentation(Representation::Integer32());
 
4396
    PushAndAdd(new_index);
 
4397
    body_exit = current_block();
 
4398
  }
 
4399
 
 
4400
  HBasicBlock* loop_exit = CreateLoop(stmt,
 
4401
                                      loop_entry,
 
4402
                                      body_exit,
 
4403
                                      loop_successor,
 
4404
                                      break_info.break_block());
 
4405
 
 
4406
  set_current_block(loop_exit);
 
4407
}
 
4408
 
 
4409
 
 
4410
void HGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
 
4411
  ASSERT(!HasStackOverflow());
 
4412
  ASSERT(current_block() != NULL);
 
4413
  ASSERT(current_block()->HasPredecessor());
 
4414
  return Bailout("TryCatchStatement");
 
4415
}
 
4416
 
 
4417
 
 
4418
void HGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
 
4419
  ASSERT(!HasStackOverflow());
 
4420
  ASSERT(current_block() != NULL);
 
4421
  ASSERT(current_block()->HasPredecessor());
 
4422
  return Bailout("TryFinallyStatement");
 
4423
}
 
4424
 
 
4425
 
 
4426
void HGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
 
4427
  ASSERT(!HasStackOverflow());
 
4428
  ASSERT(current_block() != NULL);
 
4429
  ASSERT(current_block()->HasPredecessor());
 
4430
  return Bailout("DebuggerStatement");
 
4431
}
 
4432
 
 
4433
 
 
4434
static Handle<SharedFunctionInfo> SearchSharedFunctionInfo(
 
4435
    Code* unoptimized_code, FunctionLiteral* expr) {
 
4436
  int start_position = expr->start_position();
 
4437
  RelocIterator it(unoptimized_code);
 
4438
  for (;!it.done(); it.next()) {
 
4439
    RelocInfo* rinfo = it.rinfo();
 
4440
    if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue;
 
4441
    Object* obj = rinfo->target_object();
 
4442
    if (obj->IsSharedFunctionInfo()) {
 
4443
      SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
 
4444
      if (shared->start_position() == start_position) {
 
4445
        return Handle<SharedFunctionInfo>(shared);
 
4446
      }
 
4447
    }
 
4448
  }
 
4449
 
 
4450
  return Handle<SharedFunctionInfo>();
 
4451
}
 
4452
 
 
4453
 
 
4454
void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
 
4455
  ASSERT(!HasStackOverflow());
 
4456
  ASSERT(current_block() != NULL);
 
4457
  ASSERT(current_block()->HasPredecessor());
 
4458
  Handle<SharedFunctionInfo> shared_info =
 
4459
      SearchSharedFunctionInfo(info()->shared_info()->code(),
 
4460
                               expr);
 
4461
  if (shared_info.is_null()) {
 
4462
    shared_info = Compiler::BuildFunctionInfo(expr, info()->script());
 
4463
  }
 
4464
  // We also have a stack overflow if the recursive compilation did.
 
4465
  if (HasStackOverflow()) return;
 
4466
  HValue* context = environment()->LookupContext();
 
4467
  HFunctionLiteral* instr =
 
4468
      new(zone()) HFunctionLiteral(context, shared_info, expr->pretenure());
 
4469
  return ast_context()->ReturnInstruction(instr, expr->id());
 
4470
}
 
4471
 
 
4472
 
 
4473
void HGraphBuilder::VisitSharedFunctionInfoLiteral(
 
4474
    SharedFunctionInfoLiteral* expr) {
 
4475
  ASSERT(!HasStackOverflow());
 
4476
  ASSERT(current_block() != NULL);
 
4477
  ASSERT(current_block()->HasPredecessor());
 
4478
  return Bailout("SharedFunctionInfoLiteral");
 
4479
}
 
4480
 
 
4481
 
 
4482
void HGraphBuilder::VisitConditional(Conditional* expr) {
 
4483
  ASSERT(!HasStackOverflow());
 
4484
  ASSERT(current_block() != NULL);
 
4485
  ASSERT(current_block()->HasPredecessor());
 
4486
  HBasicBlock* cond_true = graph()->CreateBasicBlock();
 
4487
  HBasicBlock* cond_false = graph()->CreateBasicBlock();
 
4488
  CHECK_BAILOUT(VisitForControl(expr->condition(), cond_true, cond_false));
 
4489
 
 
4490
  // Visit the true and false subexpressions in the same AST context as the
 
4491
  // whole expression.
 
4492
  if (cond_true->HasPredecessor()) {
 
4493
    cond_true->SetJoinId(expr->ThenId());
 
4494
    set_current_block(cond_true);
 
4495
    CHECK_BAILOUT(Visit(expr->then_expression()));
 
4496
    cond_true = current_block();
 
4497
  } else {
 
4498
    cond_true = NULL;
 
4499
  }
 
4500
 
 
4501
  if (cond_false->HasPredecessor()) {
 
4502
    cond_false->SetJoinId(expr->ElseId());
 
4503
    set_current_block(cond_false);
 
4504
    CHECK_BAILOUT(Visit(expr->else_expression()));
 
4505
    cond_false = current_block();
 
4506
  } else {
 
4507
    cond_false = NULL;
 
4508
  }
 
4509
 
 
4510
  if (!ast_context()->IsTest()) {
 
4511
    HBasicBlock* join = CreateJoin(cond_true, cond_false, expr->id());
 
4512
    set_current_block(join);
 
4513
    if (join != NULL && !ast_context()->IsEffect()) {
 
4514
      return ast_context()->ReturnValue(Pop());
 
4515
    }
 
4516
  }
 
4517
}
 
4518
 
 
4519
 
 
4520
HGraphBuilder::GlobalPropertyAccess HGraphBuilder::LookupGlobalProperty(
 
4521
    Variable* var, LookupResult* lookup, bool is_store) {
 
4522
  if (var->is_this() || !info()->has_global_object()) {
 
4523
    return kUseGeneric;
 
4524
  }
 
4525
  Handle<GlobalObject> global(info()->global_object());
 
4526
  global->Lookup(*var->name(), lookup);
 
4527
  if (!lookup->IsNormal() ||
 
4528
      (is_store && lookup->IsReadOnly()) ||
 
4529
      lookup->holder() != *global) {
 
4530
    return kUseGeneric;
 
4531
  }
 
4532
 
 
4533
  return kUseCell;
 
4534
}
 
4535
 
 
4536
 
 
4537
HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) {
 
4538
  ASSERT(var->IsContextSlot());
 
4539
  HValue* context = environment()->LookupContext();
 
4540
  int length = info()->scope()->ContextChainLength(var->scope());
 
4541
  while (length-- > 0) {
 
4542
    HInstruction* context_instruction = new(zone()) HOuterContext(context);
 
4543
    AddInstruction(context_instruction);
 
4544
    context = context_instruction;
 
4545
  }
 
4546
  return context;
 
4547
}
 
4548
 
 
4549
 
 
4550
void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
 
4551
  ASSERT(!HasStackOverflow());
 
4552
  ASSERT(current_block() != NULL);
 
4553
  ASSERT(current_block()->HasPredecessor());
 
4554
  Variable* variable = expr->var();
 
4555
  switch (variable->location()) {
 
4556
    case Variable::UNALLOCATED: {
 
4557
      if (variable->mode() == LET || variable->mode() == CONST_HARMONY) {
 
4558
        return Bailout("reference to global harmony declared variable");
 
4559
      }
 
4560
      // Handle known global constants like 'undefined' specially to avoid a
 
4561
      // load from a global cell for them.
 
4562
      Handle<Object> constant_value =
 
4563
          isolate()->factory()->GlobalConstantFor(variable->name());
 
4564
      if (!constant_value.is_null()) {
 
4565
        HConstant* instr =
 
4566
            new(zone()) HConstant(constant_value, Representation::Tagged());
 
4567
        return ast_context()->ReturnInstruction(instr, expr->id());
 
4568
      }
 
4569
 
 
4570
      LookupResult lookup(isolate());
 
4571
      GlobalPropertyAccess type =
 
4572
          LookupGlobalProperty(variable, &lookup, false);
 
4573
 
 
4574
      if (type == kUseCell &&
 
4575
          info()->global_object()->IsAccessCheckNeeded()) {
 
4576
        type = kUseGeneric;
 
4577
      }
 
4578
 
 
4579
      if (type == kUseCell) {
 
4580
        Handle<GlobalObject> global(info()->global_object());
 
4581
        Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
 
4582
        HLoadGlobalCell* instr =
 
4583
            new(zone()) HLoadGlobalCell(cell, lookup.GetPropertyDetails());
 
4584
        return ast_context()->ReturnInstruction(instr, expr->id());
 
4585
      } else {
 
4586
        HValue* context = environment()->LookupContext();
 
4587
        HGlobalObject* global_object = new(zone()) HGlobalObject(context);
 
4588
        AddInstruction(global_object);
 
4589
        HLoadGlobalGeneric* instr =
 
4590
            new(zone()) HLoadGlobalGeneric(context,
 
4591
                                           global_object,
 
4592
                                           variable->name(),
 
4593
                                           ast_context()->is_for_typeof());
 
4594
        instr->set_position(expr->position());
 
4595
        return ast_context()->ReturnInstruction(instr, expr->id());
 
4596
      }
 
4597
    }
 
4598
 
 
4599
    case Variable::PARAMETER:
 
4600
    case Variable::LOCAL: {
 
4601
      HValue* value = environment()->Lookup(variable);
 
4602
      if (value == graph()->GetConstantHole()) {
 
4603
        ASSERT(variable->mode() == CONST ||
 
4604
               variable->mode() == CONST_HARMONY ||
 
4605
               variable->mode() == LET);
 
4606
        return Bailout("reference to uninitialized variable");
 
4607
      }
 
4608
      return ast_context()->ReturnValue(value);
 
4609
    }
 
4610
 
 
4611
    case Variable::CONTEXT: {
 
4612
      HValue* context = BuildContextChainWalk(variable);
 
4613
      HLoadContextSlot* instr = new(zone()) HLoadContextSlot(context, variable);
 
4614
      return ast_context()->ReturnInstruction(instr, expr->id());
 
4615
    }
 
4616
 
 
4617
    case Variable::LOOKUP:
 
4618
      return Bailout("reference to a variable which requires dynamic lookup");
 
4619
  }
 
4620
}
 
4621
 
 
4622
 
 
4623
void HGraphBuilder::VisitLiteral(Literal* expr) {
 
4624
  ASSERT(!HasStackOverflow());
 
4625
  ASSERT(current_block() != NULL);
 
4626
  ASSERT(current_block()->HasPredecessor());
 
4627
  HConstant* instr =
 
4628
      new(zone()) HConstant(expr->handle(), Representation::Tagged());
 
4629
  return ast_context()->ReturnInstruction(instr, expr->id());
 
4630
}
 
4631
 
 
4632
 
 
4633
void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
 
4634
  ASSERT(!HasStackOverflow());
 
4635
  ASSERT(current_block() != NULL);
 
4636
  ASSERT(current_block()->HasPredecessor());
 
4637
  Handle<JSFunction> closure = function_state()->compilation_info()->closure();
 
4638
  Handle<FixedArray> literals(closure->literals());
 
4639
  HValue* context = environment()->LookupContext();
 
4640
 
 
4641
  HRegExpLiteral* instr = new(zone()) HRegExpLiteral(context,
 
4642
                                                     literals,
 
4643
                                                     expr->pattern(),
 
4644
                                                     expr->flags(),
 
4645
                                                     expr->literal_index());
 
4646
  return ast_context()->ReturnInstruction(instr, expr->id());
 
4647
}
 
4648
 
 
4649
 
 
4650
// Determines whether the given array or object literal boilerplate satisfies
 
4651
// all limits to be considered for fast deep-copying and computes the total
 
4652
// size of all objects that are part of the graph.
 
4653
static bool IsFastLiteral(Handle<JSObject> boilerplate,
 
4654
                          int max_depth,
 
4655
                          int* max_properties,
 
4656
                          int* total_size) {
 
4657
  ASSERT(max_depth >= 0 && *max_properties >= 0);
 
4658
  if (max_depth == 0) return false;
 
4659
 
 
4660
  Handle<FixedArrayBase> elements(boilerplate->elements());
 
4661
  if (elements->length() > 0 &&
 
4662
      elements->map() != boilerplate->GetHeap()->fixed_cow_array_map()) {
 
4663
    if (boilerplate->HasFastDoubleElements()) {
 
4664
      *total_size += FixedDoubleArray::SizeFor(elements->length());
 
4665
    } else if (boilerplate->HasFastObjectElements()) {
 
4666
      Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
 
4667
      int length = elements->length();
 
4668
      for (int i = 0; i < length; i++) {
 
4669
        if ((*max_properties)-- == 0) return false;
 
4670
        Handle<Object> value(fast_elements->get(i));
 
4671
        if (value->IsJSObject()) {
 
4672
          Handle<JSObject> value_object = Handle<JSObject>::cast(value);
 
4673
          if (!IsFastLiteral(value_object,
 
4674
                             max_depth - 1,
 
4675
                             max_properties,
 
4676
                             total_size)) {
 
4677
            return false;
 
4678
          }
 
4679
        }
 
4680
      }
 
4681
      *total_size += FixedArray::SizeFor(length);
 
4682
    } else {
 
4683
      return false;
 
4684
    }
 
4685
  }
 
4686
 
 
4687
  Handle<FixedArray> properties(boilerplate->properties());
 
4688
  if (properties->length() > 0) {
 
4689
    return false;
 
4690
  } else {
 
4691
    int nof = boilerplate->map()->inobject_properties();
 
4692
    for (int i = 0; i < nof; i++) {
 
4693
      if ((*max_properties)-- == 0) return false;
 
4694
      Handle<Object> value(boilerplate->InObjectPropertyAt(i));
 
4695
      if (value->IsJSObject()) {
 
4696
        Handle<JSObject> value_object = Handle<JSObject>::cast(value);
 
4697
        if (!IsFastLiteral(value_object,
 
4698
                           max_depth - 1,
 
4699
                           max_properties,
 
4700
                           total_size)) {
 
4701
          return false;
 
4702
        }
 
4703
      }
 
4704
    }
 
4705
  }
 
4706
 
 
4707
  *total_size += boilerplate->map()->instance_size();
 
4708
  return true;
 
4709
}
 
4710
 
 
4711
 
 
4712
void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
 
4713
  ASSERT(!HasStackOverflow());
 
4714
  ASSERT(current_block() != NULL);
 
4715
  ASSERT(current_block()->HasPredecessor());
 
4716
  Handle<JSFunction> closure = function_state()->compilation_info()->closure();
 
4717
  HValue* context = environment()->LookupContext();
 
4718
  HInstruction* literal;
 
4719
 
 
4720
  // Check whether to use fast or slow deep-copying for boilerplate.
 
4721
  int total_size = 0;
 
4722
  int max_properties = HFastLiteral::kMaxLiteralProperties;
 
4723
  Handle<Object> boilerplate(closure->literals()->get(expr->literal_index()));
 
4724
  if (boilerplate->IsJSObject() &&
 
4725
      IsFastLiteral(Handle<JSObject>::cast(boilerplate),
 
4726
                    HFastLiteral::kMaxLiteralDepth,
 
4727
                    &max_properties,
 
4728
                    &total_size)) {
 
4729
    Handle<JSObject> boilerplate_object = Handle<JSObject>::cast(boilerplate);
 
4730
    literal = new(zone()) HFastLiteral(context,
 
4731
                                       boilerplate_object,
 
4732
                                       total_size,
 
4733
                                       expr->literal_index(),
 
4734
                                       expr->depth());
 
4735
  } else {
 
4736
    literal = new(zone()) HObjectLiteral(context,
 
4737
                                         expr->constant_properties(),
 
4738
                                         expr->fast_elements(),
 
4739
                                         expr->literal_index(),
 
4740
                                         expr->depth(),
 
4741
                                         expr->has_function());
 
4742
  }
 
4743
 
 
4744
  // The object is expected in the bailout environment during computation
 
4745
  // of the property values and is the value of the entire expression.
 
4746
  PushAndAdd(literal);
 
4747
 
 
4748
  expr->CalculateEmitStore(zone());
 
4749
 
 
4750
  for (int i = 0; i < expr->properties()->length(); i++) {
 
4751
    ObjectLiteral::Property* property = expr->properties()->at(i);
 
4752
    if (property->IsCompileTimeValue()) continue;
 
4753
 
 
4754
    Literal* key = property->key();
 
4755
    Expression* value = property->value();
 
4756
 
 
4757
    switch (property->kind()) {
 
4758
      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
 
4759
        ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
 
4760
        // Fall through.
 
4761
      case ObjectLiteral::Property::COMPUTED:
 
4762
        if (key->handle()->IsSymbol()) {
 
4763
          if (property->emit_store()) {
 
4764
            property->RecordTypeFeedback(oracle());
 
4765
            CHECK_ALIVE(VisitForValue(value));
 
4766
            HValue* value = Pop();
 
4767
            Handle<Map> map = property->GetReceiverType();
 
4768
            Handle<String> name = property->key()->AsPropertyName();
 
4769
            HInstruction* store;
 
4770
            if (map.is_null()) {
 
4771
              // If we don't know the monomorphic type, do a generic store.
 
4772
              CHECK_ALIVE(store = BuildStoreNamedGeneric(literal, name, value));
 
4773
            } else {
 
4774
#if DEBUG
 
4775
              Handle<AccessorPair> accessors;
 
4776
              Handle<JSObject> holder;
 
4777
              ASSERT(!LookupAccessorPair(map, name, &accessors, &holder));
 
4778
#endif
 
4779
              CHECK_ALIVE(store = BuildStoreNamedMonomorphic(literal,
 
4780
                                                             name,
 
4781
                                                             value,
 
4782
                                                             map));
 
4783
            }
 
4784
            AddInstruction(store);
 
4785
            if (store->HasObservableSideEffects()) AddSimulate(key->id());
 
4786
          } else {
 
4787
            CHECK_ALIVE(VisitForEffect(value));
 
4788
          }
 
4789
          break;
 
4790
        }
 
4791
        // Fall through.
 
4792
      case ObjectLiteral::Property::PROTOTYPE:
 
4793
      case ObjectLiteral::Property::SETTER:
 
4794
      case ObjectLiteral::Property::GETTER:
 
4795
        return Bailout("Object literal with complex property");
 
4796
      default: UNREACHABLE();
 
4797
    }
 
4798
  }
 
4799
 
 
4800
  if (expr->has_function()) {
 
4801
    // Return the result of the transformation to fast properties
 
4802
    // instead of the original since this operation changes the map
 
4803
    // of the object. This makes sure that the original object won't
 
4804
    // be used by other optimized code before it is transformed
 
4805
    // (e.g. because of code motion).
 
4806
    HToFastProperties* result = new(zone()) HToFastProperties(Pop());
 
4807
    AddInstruction(result);
 
4808
    return ast_context()->ReturnValue(result);
 
4809
  } else {
 
4810
    return ast_context()->ReturnValue(Pop());
 
4811
  }
 
4812
}
 
4813
 
 
4814
 
 
4815
void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
 
4816
  ASSERT(!HasStackOverflow());
 
4817
  ASSERT(current_block() != NULL);
 
4818
  ASSERT(current_block()->HasPredecessor());
 
4819
  ZoneList<Expression*>* subexprs = expr->values();
 
4820
  int length = subexprs->length();
 
4821
  HValue* context = environment()->LookupContext();
 
4822
  HInstruction* literal;
 
4823
 
 
4824
  Handle<FixedArray> literals(environment()->closure()->literals());
 
4825
  Handle<Object> raw_boilerplate(literals->get(expr->literal_index()));
 
4826
 
 
4827
  if (raw_boilerplate->IsUndefined()) {
 
4828
    raw_boilerplate = Runtime::CreateArrayLiteralBoilerplate(
 
4829
        isolate(), literals, expr->constant_elements());
 
4830
    if (raw_boilerplate.is_null()) {
 
4831
      return Bailout("array boilerplate creation failed");
 
4832
    }
 
4833
    literals->set(expr->literal_index(), *raw_boilerplate);
 
4834
    if (JSObject::cast(*raw_boilerplate)->elements()->map() ==
 
4835
        isolate()->heap()->fixed_cow_array_map()) {
 
4836
      isolate()->counters()->cow_arrays_created_runtime()->Increment();
 
4837
    }
 
4838
  }
 
4839
 
 
4840
  Handle<JSObject> boilerplate = Handle<JSObject>::cast(raw_boilerplate);
 
4841
  ElementsKind boilerplate_elements_kind =
 
4842
        Handle<JSObject>::cast(boilerplate)->GetElementsKind();
 
4843
 
 
4844
  // Check whether to use fast or slow deep-copying for boilerplate.
 
4845
  int total_size = 0;
 
4846
  int max_properties = HFastLiteral::kMaxLiteralProperties;
 
4847
  if (IsFastLiteral(boilerplate,
 
4848
                    HFastLiteral::kMaxLiteralDepth,
 
4849
                    &max_properties,
 
4850
                    &total_size)) {
 
4851
    literal = new(zone()) HFastLiteral(context,
 
4852
                                       boilerplate,
 
4853
                                       total_size,
 
4854
                                       expr->literal_index(),
 
4855
                                       expr->depth());
 
4856
  } else {
 
4857
    literal = new(zone()) HArrayLiteral(context,
 
4858
                                        boilerplate,
 
4859
                                        length,
 
4860
                                        expr->literal_index(),
 
4861
                                        expr->depth());
 
4862
  }
 
4863
 
 
4864
  // The array is expected in the bailout environment during computation
 
4865
  // of the property values and is the value of the entire expression.
 
4866
  PushAndAdd(literal);
 
4867
 
 
4868
  HLoadElements* elements = NULL;
 
4869
 
 
4870
  for (int i = 0; i < length; i++) {
 
4871
    Expression* subexpr = subexprs->at(i);
 
4872
    // If the subexpression is a literal or a simple materialized literal it
 
4873
    // is already set in the cloned array.
 
4874
    if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
 
4875
 
 
4876
    CHECK_ALIVE(VisitForValue(subexpr));
 
4877
    HValue* value = Pop();
 
4878
    if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal");
 
4879
 
 
4880
    elements = new(zone()) HLoadElements(literal);
 
4881
    AddInstruction(elements);
 
4882
 
 
4883
    HValue* key = AddInstruction(
 
4884
        new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)),
 
4885
                              Representation::Integer32()));
 
4886
 
 
4887
    switch (boilerplate_elements_kind) {
 
4888
      case FAST_SMI_ELEMENTS:
 
4889
      case FAST_HOLEY_SMI_ELEMENTS:
 
4890
        // Smi-only arrays need a smi check.
 
4891
        AddInstruction(new(zone()) HCheckSmi(value));
 
4892
        // Fall through.
 
4893
      case FAST_ELEMENTS:
 
4894
      case FAST_HOLEY_ELEMENTS:
 
4895
        AddInstruction(new(zone()) HStoreKeyedFastElement(
 
4896
            elements,
 
4897
            key,
 
4898
            value,
 
4899
            boilerplate_elements_kind));
 
4900
        break;
 
4901
      case FAST_DOUBLE_ELEMENTS:
 
4902
      case FAST_HOLEY_DOUBLE_ELEMENTS:
 
4903
        AddInstruction(new(zone()) HStoreKeyedFastDoubleElement(elements,
 
4904
                                                                key,
 
4905
                                                                value));
 
4906
        break;
 
4907
      default:
 
4908
        UNREACHABLE();
 
4909
        break;
 
4910
    }
 
4911
 
 
4912
    AddSimulate(expr->GetIdForElement(i));
 
4913
  }
 
4914
  return ast_context()->ReturnValue(Pop());
 
4915
}
 
4916
 
 
4917
 
 
4918
// Sets the lookup result and returns true if the load/store can be inlined.
 
4919
static bool ComputeLoadStoreField(Handle<Map> type,
 
4920
                                  Handle<String> name,
 
4921
                                  LookupResult* lookup,
 
4922
                                  bool is_store) {
 
4923
  // If we directly find a field, the access can be inlined.
 
4924
  type->LookupDescriptor(NULL, *name, lookup);
 
4925
  if (lookup->IsField()) return true;
 
4926
 
 
4927
  // For a load, we are out of luck if there is no such field.
 
4928
  if (!is_store) return false;
 
4929
 
 
4930
  // 2nd chance: A store into a non-existent field can still be inlined if we
 
4931
  // have a matching transition and some room left in the object.
 
4932
  type->LookupTransition(NULL, *name, lookup);
 
4933
  return lookup->IsTransitionToField(*type) &&
 
4934
      (type->unused_property_fields() > 0);
 
4935
}
 
4936
 
 
4937
 
 
4938
static int ComputeLoadStoreFieldIndex(Handle<Map> type,
 
4939
                                      Handle<String> name,
 
4940
                                      LookupResult* lookup) {
 
4941
  ASSERT(lookup->IsField() || lookup->IsTransitionToField(*type));
 
4942
  if (lookup->IsField()) {
 
4943
    return lookup->GetLocalFieldIndexFromMap(*type);
 
4944
  } else {
 
4945
    Map* transition = lookup->GetTransitionMapFromMap(*type);
 
4946
    return transition->PropertyIndexFor(*name) - type->inobject_properties();
 
4947
  }
 
4948
}
 
4949
 
 
4950
 
 
4951
HInstruction* HGraphBuilder::BuildStoreNamedField(HValue* object,
 
4952
                                                  Handle<String> name,
 
4953
                                                  HValue* value,
 
4954
                                                  Handle<Map> map,
 
4955
                                                  LookupResult* lookup,
 
4956
                                                  bool smi_and_map_check) {
 
4957
  ASSERT(lookup->IsFound());
 
4958
  if (smi_and_map_check) {
 
4959
    AddInstruction(new(zone()) HCheckNonSmi(object));
 
4960
    AddInstruction(HCheckMaps::NewWithTransitions(object, map, zone()));
 
4961
  }
 
4962
 
 
4963
  // If the property does not exist yet, we have to check that it wasn't made
 
4964
  // readonly or turned into a setter by some meanwhile modifications on the
 
4965
  // prototype chain.
 
4966
  if (!lookup->IsProperty() && map->prototype()->IsJSReceiver()) {
 
4967
    Object* proto = map->prototype();
 
4968
    // First check that the prototype chain isn't affected already.
 
4969
    LookupResult proto_result(isolate());
 
4970
    proto->Lookup(*name, &proto_result);
 
4971
    if (proto_result.IsProperty()) {
 
4972
      // If the inherited property could induce readonly-ness, bail out.
 
4973
      if (proto_result.IsReadOnly() || !proto_result.IsCacheable()) {
 
4974
        Bailout("improper object on prototype chain for store");
 
4975
        return NULL;
 
4976
      }
 
4977
      // We only need to check up to the preexisting property.
 
4978
      proto = proto_result.holder();
 
4979
    } else {
 
4980
      // Otherwise, find the top prototype.
 
4981
      while (proto->GetPrototype()->IsJSObject()) proto = proto->GetPrototype();
 
4982
      ASSERT(proto->GetPrototype()->IsNull());
 
4983
    }
 
4984
    ASSERT(proto->IsJSObject());
 
4985
    AddInstruction(new(zone()) HCheckPrototypeMaps(
 
4986
        Handle<JSObject>(JSObject::cast(map->prototype())),
 
4987
        Handle<JSObject>(JSObject::cast(proto))));
 
4988
  }
 
4989
 
 
4990
  int index = ComputeLoadStoreFieldIndex(map, name, lookup);
 
4991
  bool is_in_object = index < 0;
 
4992
  int offset = index * kPointerSize;
 
4993
  if (index < 0) {
 
4994
    // Negative property indices are in-object properties, indexed
 
4995
    // from the end of the fixed part of the object.
 
4996
    offset += map->instance_size();
 
4997
  } else {
 
4998
    offset += FixedArray::kHeaderSize;
 
4999
  }
 
5000
  HStoreNamedField* instr =
 
5001
      new(zone()) HStoreNamedField(object, name, value, is_in_object, offset);
 
5002
  if (lookup->IsTransitionToField(*map)) {
 
5003
    Handle<Map> transition(lookup->GetTransitionMapFromMap(*map));
 
5004
    instr->set_transition(transition);
 
5005
    // TODO(fschneider): Record the new map type of the object in the IR to
 
5006
    // enable elimination of redundant checks after the transition store.
 
5007
    instr->SetGVNFlag(kChangesMaps);
 
5008
  }
 
5009
  return instr;
 
5010
}
 
5011
 
 
5012
 
 
5013
HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object,
 
5014
                                                    Handle<String> name,
 
5015
                                                    HValue* value) {
 
5016
  HValue* context = environment()->LookupContext();
 
5017
  return new(zone()) HStoreNamedGeneric(
 
5018
                         context,
 
5019
                         object,
 
5020
                         name,
 
5021
                         value,
 
5022
                         function_strict_mode_flag());
 
5023
}
 
5024
 
 
5025
 
 
5026
static void LookupInPrototypes(Handle<Map> map,
 
5027
                               Handle<String> name,
 
5028
                               LookupResult* lookup) {
 
5029
  while (map->prototype()->IsJSObject()) {
 
5030
    Handle<JSObject> holder(JSObject::cast(map->prototype()));
 
5031
    if (!holder->HasFastProperties()) break;
 
5032
    map = Handle<Map>(holder->map());
 
5033
    map->LookupDescriptor(*holder, *name, lookup);
 
5034
    if (lookup->IsFound()) return;
 
5035
  }
 
5036
  lookup->NotFound();
 
5037
}
 
5038
 
 
5039
 
 
5040
HInstruction* HGraphBuilder::BuildCallSetter(HValue* object,
 
5041
                                             HValue* value,
 
5042
                                             Handle<Map> map,
 
5043
                                             Handle<AccessorPair> accessors,
 
5044
                                             Handle<JSObject> holder) {
 
5045
  Handle<JSFunction> setter(JSFunction::cast(accessors->setter()));
 
5046
  AddCheckConstantFunction(holder, object, map, true);
 
5047
  AddInstruction(new(zone()) HPushArgument(object));
 
5048
  AddInstruction(new(zone()) HPushArgument(value));
 
5049
  return new(zone()) HCallConstantFunction(setter, 2);
 
5050
}
 
5051
 
 
5052
 
 
5053
HInstruction* HGraphBuilder::BuildStoreNamedMonomorphic(HValue* object,
 
5054
                                                        Handle<String> name,
 
5055
                                                        HValue* value,
 
5056
                                                        Handle<Map> map) {
 
5057
  // Handle a store to a known field.
 
5058
  LookupResult lookup(isolate());
 
5059
  if (ComputeLoadStoreField(map, name, &lookup, true)) {
 
5060
    // true = needs smi and map check.
 
5061
    return BuildStoreNamedField(object, name, value, map, &lookup, true);
 
5062
  }
 
5063
 
 
5064
  // No luck, do a generic store.
 
5065
  return BuildStoreNamedGeneric(object, name, value);
 
5066
}
 
5067
 
 
5068
 
 
5069
void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr,
 
5070
                                                    HValue* object,
 
5071
                                                    SmallMapList* types,
 
5072
                                                    Handle<String> name) {
 
5073
  int count = 0;
 
5074
  int previous_field_offset = 0;
 
5075
  bool previous_field_is_in_object = false;
 
5076
  bool is_monomorphic_field = true;
 
5077
  Handle<Map> map;
 
5078
  LookupResult lookup(isolate());
 
5079
  for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
 
5080
    map = types->at(i);
 
5081
    if (ComputeLoadStoreField(map, name, &lookup, false)) {
 
5082
      int index = ComputeLoadStoreFieldIndex(map, name, &lookup);
 
5083
      bool is_in_object = index < 0;
 
5084
      int offset = index * kPointerSize;
 
5085
      if (index < 0) {
 
5086
        // Negative property indices are in-object properties, indexed
 
5087
        // from the end of the fixed part of the object.
 
5088
        offset += map->instance_size();
 
5089
      } else {
 
5090
        offset += FixedArray::kHeaderSize;
 
5091
      }
 
5092
      if (count == 0) {
 
5093
        previous_field_offset = offset;
 
5094
        previous_field_is_in_object = is_in_object;
 
5095
      } else if (is_monomorphic_field) {
 
5096
        is_monomorphic_field = (offset == previous_field_offset) &&
 
5097
                               (is_in_object == previous_field_is_in_object);
 
5098
      }
 
5099
      ++count;
 
5100
    }
 
5101
  }
 
5102
 
 
5103
  // Use monomorphic load if property lookup results in the same field index
 
5104
  // for all maps.  Requires special map check on the set of all handled maps.
 
5105
  AddInstruction(new(zone()) HCheckNonSmi(object));
 
5106
  HInstruction* instr;
 
5107
  if (count == types->length() && is_monomorphic_field) {
 
5108
    AddInstruction(new(zone()) HCheckMaps(object, types, zone()));
 
5109
    instr = BuildLoadNamedField(object, map, &lookup, false);
 
5110
  } else {
 
5111
    HValue* context = environment()->LookupContext();
 
5112
    instr = new(zone()) HLoadNamedFieldPolymorphic(context,
 
5113
                                                   object,
 
5114
                                                   types,
 
5115
                                                   name,
 
5116
                                                   zone());
 
5117
  }
 
5118
 
 
5119
  instr->set_position(expr->position());
 
5120
  return ast_context()->ReturnInstruction(instr, expr->id());
 
5121
}
 
5122
 
 
5123
 
 
5124
void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr,
 
5125
                                                     HValue* object,
 
5126
                                                     HValue* value,
 
5127
                                                     SmallMapList* types,
 
5128
                                                     Handle<String> name) {
 
5129
  // TODO(ager): We should recognize when the prototype chains for different
 
5130
  // maps are identical. In that case we can avoid repeatedly generating the
 
5131
  // same prototype map checks.
 
5132
  int count = 0;
 
5133
  HBasicBlock* join = NULL;
 
5134
  for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) {
 
5135
    Handle<Map> map = types->at(i);
 
5136
    LookupResult lookup(isolate());
 
5137
    if (ComputeLoadStoreField(map, name, &lookup, true)) {
 
5138
      if (count == 0) {
 
5139
        AddInstruction(new(zone()) HCheckNonSmi(object));  // Only needed once.
 
5140
        join = graph()->CreateBasicBlock();
 
5141
      }
 
5142
      ++count;
 
5143
      HBasicBlock* if_true = graph()->CreateBasicBlock();
 
5144
      HBasicBlock* if_false = graph()->CreateBasicBlock();
 
5145
      HCompareMap* compare =
 
5146
          new(zone()) HCompareMap(object, map, if_true, if_false);
 
5147
      current_block()->Finish(compare);
 
5148
 
 
5149
      set_current_block(if_true);
 
5150
      HInstruction* instr;
 
5151
      CHECK_ALIVE(instr =
 
5152
          BuildStoreNamedField(object, name, value, map, &lookup, false));
 
5153
      instr->set_position(expr->position());
 
5154
      // Goto will add the HSimulate for the store.
 
5155
      AddInstruction(instr);
 
5156
      if (!ast_context()->IsEffect()) Push(value);
 
5157
      current_block()->Goto(join);
 
5158
 
 
5159
      set_current_block(if_false);
 
5160
    }
 
5161
  }
 
5162
 
 
5163
  // Finish up.  Unconditionally deoptimize if we've handled all the maps we
 
5164
  // know about and do not want to handle ones we've never seen.  Otherwise
 
5165
  // use a generic IC.
 
5166
  if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
 
5167
    current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
 
5168
  } else {
 
5169
    HInstruction* instr = BuildStoreNamedGeneric(object, name, value);
 
5170
    instr->set_position(expr->position());
 
5171
    AddInstruction(instr);
 
5172
 
 
5173
    if (join != NULL) {
 
5174
      if (!ast_context()->IsEffect()) Push(value);
 
5175
      current_block()->Goto(join);
 
5176
    } else {
 
5177
      // The HSimulate for the store should not see the stored value in
 
5178
      // effect contexts (it is not materialized at expr->id() in the
 
5179
      // unoptimized code).
 
5180
      if (instr->HasObservableSideEffects()) {
 
5181
        if (ast_context()->IsEffect()) {
 
5182
          AddSimulate(expr->id());
 
5183
        } else {
 
5184
          Push(value);
 
5185
          AddSimulate(expr->id());
 
5186
          Drop(1);
 
5187
        }
 
5188
      }
 
5189
      return ast_context()->ReturnValue(value);
 
5190
    }
 
5191
  }
 
5192
 
 
5193
  ASSERT(join != NULL);
 
5194
  join->SetJoinId(expr->id());
 
5195
  set_current_block(join);
 
5196
  if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop());
 
5197
}
 
5198
 
 
5199
 
 
5200
void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
 
5201
  Property* prop = expr->target()->AsProperty();
 
5202
  ASSERT(prop != NULL);
 
5203
  expr->RecordTypeFeedback(oracle(), zone());
 
5204
  CHECK_ALIVE(VisitForValue(prop->obj()));
 
5205
 
 
5206
  if (prop->key()->IsPropertyName()) {
 
5207
    // Named store.
 
5208
    CHECK_ALIVE(VisitForValue(expr->value()));
 
5209
    HValue* value = environment()->ExpressionStackAt(0);
 
5210
    HValue* object = environment()->ExpressionStackAt(1);
 
5211
 
 
5212
    Literal* key = prop->key()->AsLiteral();
 
5213
    Handle<String> name = Handle<String>::cast(key->handle());
 
5214
    ASSERT(!name.is_null());
 
5215
 
 
5216
    HInstruction* instr = NULL;
 
5217
    SmallMapList* types = expr->GetReceiverTypes();
 
5218
    bool monomorphic = expr->IsMonomorphic();
 
5219
    Handle<Map> map;
 
5220
    if (monomorphic) {
 
5221
      map = types->first();
 
5222
      if (map->is_dictionary_map()) monomorphic = false;
 
5223
    }
 
5224
    if (monomorphic) {
 
5225
      Handle<AccessorPair> accessors;
 
5226
      Handle<JSObject> holder;
 
5227
      if (LookupAccessorPair(map, name, &accessors, &holder)) {
 
5228
        Drop(2);
 
5229
        instr = BuildCallSetter(object, value, map, accessors, holder);
 
5230
      } else {
 
5231
        Drop(2);
 
5232
        CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object,
 
5233
                                                       name,
 
5234
                                                       value,
 
5235
                                                       map));
 
5236
      }
 
5237
 
 
5238
    } else if (types != NULL && types->length() > 1) {
 
5239
      Drop(2);
 
5240
      return HandlePolymorphicStoreNamedField(expr, object, value, types, name);
 
5241
    } else {
 
5242
      Drop(2);
 
5243
      instr = BuildStoreNamedGeneric(object, name, value);
 
5244
    }
 
5245
 
 
5246
    Push(value);
 
5247
    instr->set_position(expr->position());
 
5248
    AddInstruction(instr);
 
5249
    if (instr->HasObservableSideEffects()) AddSimulate(expr->AssignmentId());
 
5250
    return ast_context()->ReturnValue(Pop());
 
5251
 
 
5252
  } else {
 
5253
    // Keyed store.
 
5254
    CHECK_ALIVE(VisitForValue(prop->key()));
 
5255
    CHECK_ALIVE(VisitForValue(expr->value()));
 
5256
    HValue* value = Pop();
 
5257
    HValue* key = Pop();
 
5258
    HValue* object = Pop();
 
5259
    bool has_side_effects = false;
 
5260
    HandleKeyedElementAccess(object, key, value, expr, expr->AssignmentId(),
 
5261
                             expr->position(),
 
5262
                             true,  // is_store
 
5263
                             &has_side_effects);
 
5264
    Push(value);
 
5265
    ASSERT(has_side_effects);  // Stores always have side effects.
 
5266
    AddSimulate(expr->AssignmentId());
 
5267
    return ast_context()->ReturnValue(Pop());
 
5268
  }
 
5269
}
 
5270
 
 
5271
 
 
5272
// Because not every expression has a position and there is not common
 
5273
// superclass of Assignment and CountOperation, we cannot just pass the
 
5274
// owning expression instead of position and ast_id separately.
 
5275
void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var,
 
5276
                                                   HValue* value,
 
5277
                                                   int position,
 
5278
                                                   int ast_id) {
 
5279
  LookupResult lookup(isolate());
 
5280
  GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true);
 
5281
  if (type == kUseCell) {
 
5282
    Handle<GlobalObject> global(info()->global_object());
 
5283
    Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
 
5284
    HInstruction* instr =
 
5285
        new(zone()) HStoreGlobalCell(value, cell, lookup.GetPropertyDetails());
 
5286
    instr->set_position(position);
 
5287
    AddInstruction(instr);
 
5288
    if (instr->HasObservableSideEffects()) AddSimulate(ast_id);
 
5289
  } else {
 
5290
    HValue* context =  environment()->LookupContext();
 
5291
    HGlobalObject* global_object = new(zone()) HGlobalObject(context);
 
5292
    AddInstruction(global_object);
 
5293
    HStoreGlobalGeneric* instr =
 
5294
        new(zone()) HStoreGlobalGeneric(context,
 
5295
                                        global_object,
 
5296
                                        var->name(),
 
5297
                                        value,
 
5298
                                        function_strict_mode_flag());
 
5299
    instr->set_position(position);
 
5300
    AddInstruction(instr);
 
5301
    ASSERT(instr->HasObservableSideEffects());
 
5302
    if (instr->HasObservableSideEffects()) AddSimulate(ast_id);
 
5303
  }
 
5304
}
 
5305
 
 
5306
 
 
5307
void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
 
5308
  Expression* target = expr->target();
 
5309
  VariableProxy* proxy = target->AsVariableProxy();
 
5310
  Property* prop = target->AsProperty();
 
5311
  ASSERT(proxy == NULL || prop == NULL);
 
5312
 
 
5313
  // We have a second position recorded in the FullCodeGenerator to have
 
5314
  // type feedback for the binary operation.
 
5315
  BinaryOperation* operation = expr->binary_operation();
 
5316
 
 
5317
  if (proxy != NULL) {
 
5318
    Variable* var = proxy->var();
 
5319
    if (var->mode() == LET)  {
 
5320
      return Bailout("unsupported let compound assignment");
 
5321
    }
 
5322
 
 
5323
    CHECK_ALIVE(VisitForValue(operation));
 
5324
 
 
5325
    switch (var->location()) {
 
5326
      case Variable::UNALLOCATED:
 
5327
        HandleGlobalVariableAssignment(var,
 
5328
                                       Top(),
 
5329
                                       expr->position(),
 
5330
                                       expr->AssignmentId());
 
5331
        break;
 
5332
 
 
5333
      case Variable::PARAMETER:
 
5334
      case Variable::LOCAL:
 
5335
        if (var->mode() == CONST)  {
 
5336
          return Bailout("unsupported const compound assignment");
 
5337
        }
 
5338
        Bind(var, Top());
 
5339
        break;
 
5340
 
 
5341
      case Variable::CONTEXT: {
 
5342
        // Bail out if we try to mutate a parameter value in a function
 
5343
        // using the arguments object.  We do not (yet) correctly handle the
 
5344
        // arguments property of the function.
 
5345
        if (info()->scope()->arguments() != NULL) {
 
5346
          // Parameters will be allocated to context slots.  We have no
 
5347
          // direct way to detect that the variable is a parameter so we do
 
5348
          // a linear search of the parameter variables.
 
5349
          int count = info()->scope()->num_parameters();
 
5350
          for (int i = 0; i < count; ++i) {
 
5351
            if (var == info()->scope()->parameter(i)) {
 
5352
              Bailout(
 
5353
                  "assignment to parameter, function uses arguments object");
 
5354
            }
 
5355
          }
 
5356
        }
 
5357
 
 
5358
        HStoreContextSlot::Mode mode;
 
5359
 
 
5360
        switch (var->mode()) {
 
5361
          case LET:
 
5362
            mode = HStoreContextSlot::kCheckDeoptimize;
 
5363
            break;
 
5364
          case CONST:
 
5365
            return ast_context()->ReturnValue(Pop());
 
5366
          case CONST_HARMONY:
 
5367
            // This case is checked statically so no need to
 
5368
            // perform checks here
 
5369
            UNREACHABLE();
 
5370
          default:
 
5371
            mode = HStoreContextSlot::kNoCheck;
 
5372
        }
 
5373
 
 
5374
        HValue* context = BuildContextChainWalk(var);
 
5375
        HStoreContextSlot* instr =
 
5376
            new(zone()) HStoreContextSlot(context, var->index(), mode, Top());
 
5377
        AddInstruction(instr);
 
5378
        if (instr->HasObservableSideEffects()) {
 
5379
          AddSimulate(expr->AssignmentId());
 
5380
        }
 
5381
        break;
 
5382
      }
 
5383
 
 
5384
      case Variable::LOOKUP:
 
5385
        return Bailout("compound assignment to lookup slot");
 
5386
    }
 
5387
    return ast_context()->ReturnValue(Pop());
 
5388
 
 
5389
  } else if (prop != NULL) {
 
5390
    prop->RecordTypeFeedback(oracle(), zone());
 
5391
 
 
5392
    if (prop->key()->IsPropertyName()) {
 
5393
      // Named property.
 
5394
      CHECK_ALIVE(VisitForValue(prop->obj()));
 
5395
      HValue* object = Top();
 
5396
 
 
5397
      Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
 
5398
      Handle<Map> map;
 
5399
      HInstruction* load;
 
5400
      bool monomorphic = prop->IsMonomorphic();
 
5401
      if (monomorphic) {
 
5402
        map = prop->GetReceiverTypes()->first();
 
5403
        // We can't generate code for a monomorphic dict mode load so
 
5404
        // just pretend it is not monomorphic.
 
5405
        if (map->is_dictionary_map()) monomorphic = false;
 
5406
      }
 
5407
      if (monomorphic) {
 
5408
        Handle<AccessorPair> accessors;
 
5409
        Handle<JSObject> holder;
 
5410
        if (LookupAccessorPair(map, name, &accessors, &holder)) {
 
5411
          load = BuildCallGetter(object, map, accessors, holder);
 
5412
        } else {
 
5413
          load = BuildLoadNamedMonomorphic(object, name, prop, map);
 
5414
        }
 
5415
      } else {
 
5416
        load = BuildLoadNamedGeneric(object, name, prop);
 
5417
      }
 
5418
      PushAndAdd(load);
 
5419
      if (load->HasObservableSideEffects()) AddSimulate(expr->CompoundLoadId());
 
5420
 
 
5421
      CHECK_ALIVE(VisitForValue(expr->value()));
 
5422
      HValue* right = Pop();
 
5423
      HValue* left = Pop();
 
5424
 
 
5425
      HInstruction* instr = BuildBinaryOperation(operation, left, right);
 
5426
      PushAndAdd(instr);
 
5427
      if (instr->HasObservableSideEffects()) AddSimulate(operation->id());
 
5428
 
 
5429
      HInstruction* store;
 
5430
      if (!monomorphic) {
 
5431
        // If we don't know the monomorphic type, do a generic store.
 
5432
        CHECK_ALIVE(store = BuildStoreNamedGeneric(object, name, instr));
 
5433
      } else {
 
5434
        Handle<AccessorPair> accessors;
 
5435
        Handle<JSObject> holder;
 
5436
        // Because we re-use the load type feedback, there might be no setter.
 
5437
        if (LookupAccessorPair(map, name, &accessors, &holder) &&
 
5438
            accessors->setter()->IsJSFunction()) {
 
5439
          store = BuildCallSetter(object, instr, map, accessors, holder);
 
5440
        } else {
 
5441
          CHECK_ALIVE(store = BuildStoreNamedMonomorphic(object,
 
5442
                                                         name,
 
5443
                                                         instr,
 
5444
                                                         map));
 
5445
        }
 
5446
      }
 
5447
      AddInstruction(store);
 
5448
      // Drop the simulated receiver and value.  Return the value.
 
5449
      Drop(2);
 
5450
      Push(instr);
 
5451
      if (store->HasObservableSideEffects()) AddSimulate(expr->AssignmentId());
 
5452
      return ast_context()->ReturnValue(Pop());
 
5453
 
 
5454
    } else {
 
5455
      // Keyed property.
 
5456
      CHECK_ALIVE(VisitForValue(prop->obj()));
 
5457
      CHECK_ALIVE(VisitForValue(prop->key()));
 
5458
      HValue* obj = environment()->ExpressionStackAt(1);
 
5459
      HValue* key = environment()->ExpressionStackAt(0);
 
5460
 
 
5461
      bool has_side_effects = false;
 
5462
      HValue* load = HandleKeyedElementAccess(
 
5463
          obj, key, NULL, prop, expr->CompoundLoadId(), RelocInfo::kNoPosition,
 
5464
          false,  // is_store
 
5465
          &has_side_effects);
 
5466
      Push(load);
 
5467
      if (has_side_effects) AddSimulate(expr->CompoundLoadId());
 
5468
 
 
5469
 
 
5470
      CHECK_ALIVE(VisitForValue(expr->value()));
 
5471
      HValue* right = Pop();
 
5472
      HValue* left = Pop();
 
5473
 
 
5474
      HInstruction* instr = BuildBinaryOperation(operation, left, right);
 
5475
      PushAndAdd(instr);
 
5476
      if (instr->HasObservableSideEffects()) AddSimulate(operation->id());
 
5477
 
 
5478
      expr->RecordTypeFeedback(oracle(), zone());
 
5479
      HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(),
 
5480
                               RelocInfo::kNoPosition,
 
5481
                               true,  // is_store
 
5482
                               &has_side_effects);
 
5483
 
 
5484
      // Drop the simulated receiver, key, and value.  Return the value.
 
5485
      Drop(3);
 
5486
      Push(instr);
 
5487
      ASSERT(has_side_effects);  // Stores always have side effects.
 
5488
      AddSimulate(expr->AssignmentId());
 
5489
      return ast_context()->ReturnValue(Pop());
 
5490
    }
 
5491
 
 
5492
  } else {
 
5493
    return Bailout("invalid lhs in compound assignment");
 
5494
  }
 
5495
}
 
5496
 
 
5497
 
 
5498
void HGraphBuilder::VisitAssignment(Assignment* expr) {
 
5499
  ASSERT(!HasStackOverflow());
 
5500
  ASSERT(current_block() != NULL);
 
5501
  ASSERT(current_block()->HasPredecessor());
 
5502
  VariableProxy* proxy = expr->target()->AsVariableProxy();
 
5503
  Property* prop = expr->target()->AsProperty();
 
5504
  ASSERT(proxy == NULL || prop == NULL);
 
5505
 
 
5506
  if (expr->is_compound()) {
 
5507
    HandleCompoundAssignment(expr);
 
5508
    return;
 
5509
  }
 
5510
 
 
5511
  if (prop != NULL) {
 
5512
    HandlePropertyAssignment(expr);
 
5513
  } else if (proxy != NULL) {
 
5514
    Variable* var = proxy->var();
 
5515
 
 
5516
    if (var->mode() == CONST) {
 
5517
      if (expr->op() != Token::INIT_CONST) {
 
5518
        CHECK_ALIVE(VisitForValue(expr->value()));
 
5519
        return ast_context()->ReturnValue(Pop());
 
5520
      }
 
5521
 
 
5522
      if (var->IsStackAllocated()) {
 
5523
        // We insert a use of the old value to detect unsupported uses of const
 
5524
        // variables (e.g. initialization inside a loop).
 
5525
        HValue* old_value = environment()->Lookup(var);
 
5526
        AddInstruction(new(zone()) HUseConst(old_value));
 
5527
      }
 
5528
    } else if (var->mode() == CONST_HARMONY) {
 
5529
      if (expr->op() != Token::INIT_CONST_HARMONY) {
 
5530
        return Bailout("non-initializer assignment to const");
 
5531
      }
 
5532
    }
 
5533
 
 
5534
    if (proxy->IsArguments()) return Bailout("assignment to arguments");
 
5535
 
 
5536
    // Handle the assignment.
 
5537
    switch (var->location()) {
 
5538
      case Variable::UNALLOCATED:
 
5539
        CHECK_ALIVE(VisitForValue(expr->value()));
 
5540
        HandleGlobalVariableAssignment(var,
 
5541
                                       Top(),
 
5542
                                       expr->position(),
 
5543
                                       expr->AssignmentId());
 
5544
        return ast_context()->ReturnValue(Pop());
 
5545
 
 
5546
      case Variable::PARAMETER:
 
5547
      case Variable::LOCAL: {
 
5548
        // Perform an initialization check for let declared variables
 
5549
        // or parameters.
 
5550
        if (var->mode() == LET && expr->op() == Token::ASSIGN) {
 
5551
          HValue* env_value = environment()->Lookup(var);
 
5552
          if (env_value == graph()->GetConstantHole()) {
 
5553
            return Bailout("assignment to let variable before initialization");
 
5554
          }
 
5555
        }
 
5556
        // We do not allow the arguments object to occur in a context where it
 
5557
        // may escape, but assignments to stack-allocated locals are
 
5558
        // permitted.
 
5559
        CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED));
 
5560
        HValue* value = Pop();
 
5561
        Bind(var, value);
 
5562
        return ast_context()->ReturnValue(value);
 
5563
      }
 
5564
 
 
5565
      case Variable::CONTEXT: {
 
5566
        // Bail out if we try to mutate a parameter value in a function using
 
5567
        // the arguments object.  We do not (yet) correctly handle the
 
5568
        // arguments property of the function.
 
5569
        if (info()->scope()->arguments() != NULL) {
 
5570
          // Parameters will rewrite to context slots.  We have no direct way
 
5571
          // to detect that the variable is a parameter.
 
5572
          int count = info()->scope()->num_parameters();
 
5573
          for (int i = 0; i < count; ++i) {
 
5574
            if (var == info()->scope()->parameter(i)) {
 
5575
              return Bailout("assignment to parameter in arguments object");
 
5576
            }
 
5577
          }
 
5578
        }
 
5579
 
 
5580
        CHECK_ALIVE(VisitForValue(expr->value()));
 
5581
        HStoreContextSlot::Mode mode;
 
5582
        if (expr->op() == Token::ASSIGN) {
 
5583
          switch (var->mode()) {
 
5584
            case LET:
 
5585
              mode = HStoreContextSlot::kCheckDeoptimize;
 
5586
              break;
 
5587
            case CONST:
 
5588
              return ast_context()->ReturnValue(Pop());
 
5589
            case CONST_HARMONY:
 
5590
              // This case is checked statically so no need to
 
5591
              // perform checks here
 
5592
              UNREACHABLE();
 
5593
            default:
 
5594
              mode = HStoreContextSlot::kNoCheck;
 
5595
          }
 
5596
        } else if (expr->op() == Token::INIT_VAR ||
 
5597
                   expr->op() == Token::INIT_LET ||
 
5598
                   expr->op() == Token::INIT_CONST_HARMONY) {
 
5599
          mode = HStoreContextSlot::kNoCheck;
 
5600
        } else {
 
5601
          ASSERT(expr->op() == Token::INIT_CONST);
 
5602
 
 
5603
          mode = HStoreContextSlot::kCheckIgnoreAssignment;
 
5604
        }
 
5605
 
 
5606
        HValue* context = BuildContextChainWalk(var);
 
5607
        HStoreContextSlot* instr = new(zone()) HStoreContextSlot(
 
5608
            context, var->index(), mode, Top());
 
5609
        AddInstruction(instr);
 
5610
        if (instr->HasObservableSideEffects()) {
 
5611
          AddSimulate(expr->AssignmentId());
 
5612
        }
 
5613
        return ast_context()->ReturnValue(Pop());
 
5614
      }
 
5615
 
 
5616
      case Variable::LOOKUP:
 
5617
        return Bailout("assignment to LOOKUP variable");
 
5618
    }
 
5619
  } else {
 
5620
    return Bailout("invalid left-hand side in assignment");
 
5621
  }
 
5622
}
 
5623
 
 
5624
 
 
5625
void HGraphBuilder::VisitThrow(Throw* expr) {
 
5626
  ASSERT(!HasStackOverflow());
 
5627
  ASSERT(current_block() != NULL);
 
5628
  ASSERT(current_block()->HasPredecessor());
 
5629
  // We don't optimize functions with invalid left-hand sides in
 
5630
  // assignments, count operations, or for-in.  Consequently throw can
 
5631
  // currently only occur in an effect context.
 
5632
  ASSERT(ast_context()->IsEffect());
 
5633
  CHECK_ALIVE(VisitForValue(expr->exception()));
 
5634
 
 
5635
  HValue* context = environment()->LookupContext();
 
5636
  HValue* value = environment()->Pop();
 
5637
  HThrow* instr = new(zone()) HThrow(context, value);
 
5638
  instr->set_position(expr->position());
 
5639
  AddInstruction(instr);
 
5640
  AddSimulate(expr->id());
 
5641
  current_block()->FinishExit(new(zone()) HAbnormalExit);
 
5642
  set_current_block(NULL);
 
5643
}
 
5644
 
 
5645
 
 
5646
HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object,
 
5647
                                                    Handle<Map> map,
 
5648
                                                    LookupResult* lookup,
 
5649
                                                    bool smi_and_map_check) {
 
5650
  if (smi_and_map_check) {
 
5651
    AddInstruction(new(zone()) HCheckNonSmi(object));
 
5652
    AddInstruction(HCheckMaps::NewWithTransitions(object, map, zone()));
 
5653
  }
 
5654
 
 
5655
  int index = lookup->GetLocalFieldIndexFromMap(*map);
 
5656
  if (index < 0) {
 
5657
    // Negative property indices are in-object properties, indexed
 
5658
    // from the end of the fixed part of the object.
 
5659
    int offset = (index * kPointerSize) + map->instance_size();
 
5660
    return new(zone()) HLoadNamedField(object, true, offset);
 
5661
  } else {
 
5662
    // Non-negative property indices are in the properties array.
 
5663
    int offset = (index * kPointerSize) + FixedArray::kHeaderSize;
 
5664
    return new(zone()) HLoadNamedField(object, false, offset);
 
5665
  }
 
5666
}
 
5667
 
 
5668
 
 
5669
HInstruction* HGraphBuilder::BuildLoadNamedGeneric(HValue* object,
 
5670
                                                   Handle<String> name,
 
5671
                                                   Property* expr) {
 
5672
  if (expr->IsUninitialized() && !FLAG_always_opt) {
 
5673
    AddInstruction(new(zone()) HSoftDeoptimize);
 
5674
    current_block()->MarkAsDeoptimizing();
 
5675
  }
 
5676
  HValue* context = environment()->LookupContext();
 
5677
  return new(zone()) HLoadNamedGeneric(context, object, name);
 
5678
}
 
5679
 
 
5680
 
 
5681
HInstruction* HGraphBuilder::BuildCallGetter(HValue* object,
 
5682
                                             Handle<Map> map,
 
5683
                                             Handle<AccessorPair> accessors,
 
5684
                                             Handle<JSObject> holder) {
 
5685
  Handle<JSFunction> getter(JSFunction::cast(accessors->getter()));
 
5686
  AddCheckConstantFunction(holder, object, map, true);
 
5687
  AddInstruction(new(zone()) HPushArgument(object));
 
5688
  return new(zone()) HCallConstantFunction(getter, 1);
 
5689
}
 
5690
 
 
5691
 
 
5692
bool HGraphBuilder::LookupAccessorPair(Handle<Map> map,
 
5693
                                       Handle<String> name,
 
5694
                                       Handle<AccessorPair>* accessors,
 
5695
                                       Handle<JSObject>* holder) {
 
5696
  LookupResult lookup(isolate());
 
5697
 
 
5698
  // Check for a JavaScript accessor directly in the map.
 
5699
  map->LookupDescriptor(NULL, *name, &lookup);
 
5700
  if (lookup.IsPropertyCallbacks()) {
 
5701
    Handle<Object> callback(lookup.GetValueFromMap(*map));
 
5702
    if (!callback->IsAccessorPair()) return false;
 
5703
    *accessors = Handle<AccessorPair>::cast(callback);
 
5704
    *holder = Handle<JSObject>();
 
5705
    return true;
 
5706
  }
 
5707
 
 
5708
  // Everything else, e.g. a field, can't be an accessor call.
 
5709
  if (lookup.IsFound()) return false;
 
5710
 
 
5711
  // Check for a JavaScript accessor somewhere in the proto chain.
 
5712
  LookupInPrototypes(map, name, &lookup);
 
5713
  if (lookup.IsPropertyCallbacks()) {
 
5714
    Handle<Object> callback(lookup.GetValue());
 
5715
    if (!callback->IsAccessorPair()) return false;
 
5716
    *accessors = Handle<AccessorPair>::cast(callback);
 
5717
    *holder = Handle<JSObject>(lookup.holder());
 
5718
    return true;
 
5719
  }
 
5720
 
 
5721
  // We haven't found a JavaScript accessor anywhere.
 
5722
  return false;
 
5723
}
 
5724
 
 
5725
 
 
5726
HInstruction* HGraphBuilder::BuildLoadNamedMonomorphic(HValue* object,
 
5727
                                                       Handle<String> name,
 
5728
                                                       Property* expr,
 
5729
                                                       Handle<Map> map) {
 
5730
  // Handle a load from a known field.
 
5731
  ASSERT(!map->is_dictionary_map());
 
5732
  LookupResult lookup(isolate());
 
5733
  map->LookupDescriptor(NULL, *name, &lookup);
 
5734
  if (lookup.IsField()) {
 
5735
    return BuildLoadNamedField(object, map, &lookup, true);
 
5736
  }
 
5737
 
 
5738
  // Handle a load of a constant known function.
 
5739
  if (lookup.IsConstantFunction()) {
 
5740
    AddInstruction(new(zone()) HCheckNonSmi(object));
 
5741
    AddInstruction(HCheckMaps::NewWithTransitions(object, map, zone()));
 
5742
    Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map));
 
5743
    return new(zone()) HConstant(function, Representation::Tagged());
 
5744
  }
 
5745
 
 
5746
  // No luck, do a generic load.
 
5747
  return BuildLoadNamedGeneric(object, name, expr);
 
5748
}
 
5749
 
 
5750
 
 
5751
HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
 
5752
                                                   HValue* key) {
 
5753
  HValue* context = environment()->LookupContext();
 
5754
  return new(zone()) HLoadKeyedGeneric(context, object, key);
 
5755
}
 
5756
 
 
5757
 
 
5758
HInstruction* HGraphBuilder::BuildExternalArrayElementAccess(
 
5759
    HValue* external_elements,
 
5760
    HValue* checked_key,
 
5761
    HValue* val,
 
5762
    HValue* dependency,
 
5763
    ElementsKind elements_kind,
 
5764
    bool is_store) {
 
5765
  if (is_store) {
 
5766
    ASSERT(val != NULL);
 
5767
    switch (elements_kind) {
 
5768
      case EXTERNAL_PIXEL_ELEMENTS: {
 
5769
        val = AddInstruction(new(zone()) HClampToUint8(val));
 
5770
        break;
 
5771
      }
 
5772
      case EXTERNAL_BYTE_ELEMENTS:
 
5773
      case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
 
5774
      case EXTERNAL_SHORT_ELEMENTS:
 
5775
      case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
 
5776
      case EXTERNAL_INT_ELEMENTS:
 
5777
      case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
 
5778
        if (!val->representation().IsInteger32()) {
 
5779
          val = AddInstruction(new(zone()) HChange(
 
5780
              val,
 
5781
              Representation::Integer32(),
 
5782
              true,  // Truncate to int32.
 
5783
              false));  // Don't deoptimize undefined (irrelevant here).
 
5784
        }
 
5785
        break;
 
5786
      }
 
5787
      case EXTERNAL_FLOAT_ELEMENTS:
 
5788
      case EXTERNAL_DOUBLE_ELEMENTS:
 
5789
        break;
 
5790
      case FAST_SMI_ELEMENTS:
 
5791
      case FAST_ELEMENTS:
 
5792
      case FAST_DOUBLE_ELEMENTS:
 
5793
      case FAST_HOLEY_SMI_ELEMENTS:
 
5794
      case FAST_HOLEY_ELEMENTS:
 
5795
      case FAST_HOLEY_DOUBLE_ELEMENTS:
 
5796
      case DICTIONARY_ELEMENTS:
 
5797
      case NON_STRICT_ARGUMENTS_ELEMENTS:
 
5798
        UNREACHABLE();
 
5799
        break;
 
5800
    }
 
5801
    return new(zone()) HStoreKeyedSpecializedArrayElement(
 
5802
        external_elements, checked_key, val, elements_kind);
 
5803
  } else {
 
5804
    ASSERT(val == NULL);
 
5805
    return new(zone()) HLoadKeyedSpecializedArrayElement(
 
5806
        external_elements, checked_key, dependency, elements_kind);
 
5807
  }
 
5808
}
 
5809
 
 
5810
 
 
5811
HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements,
 
5812
                                                    HValue* checked_key,
 
5813
                                                    HValue* val,
 
5814
                                                    HValue* load_dependency,
 
5815
                                                    ElementsKind elements_kind,
 
5816
                                                    bool is_store) {
 
5817
  if (is_store) {
 
5818
    ASSERT(val != NULL);
 
5819
    switch (elements_kind) {
 
5820
      case FAST_DOUBLE_ELEMENTS:
 
5821
      case FAST_HOLEY_DOUBLE_ELEMENTS:
 
5822
        return new(zone()) HStoreKeyedFastDoubleElement(
 
5823
            elements, checked_key, val);
 
5824
      case FAST_SMI_ELEMENTS:
 
5825
      case FAST_HOLEY_SMI_ELEMENTS:
 
5826
        // Smi-only arrays need a smi check.
 
5827
        AddInstruction(new(zone()) HCheckSmi(val));
 
5828
        // Fall through.
 
5829
      case FAST_ELEMENTS:
 
5830
      case FAST_HOLEY_ELEMENTS:
 
5831
        return new(zone()) HStoreKeyedFastElement(
 
5832
            elements, checked_key, val, elements_kind);
 
5833
      default:
 
5834
        UNREACHABLE();
 
5835
        return NULL;
 
5836
    }
 
5837
  }
 
5838
  // It's an element load (!is_store).
 
5839
  HoleCheckMode mode = IsFastPackedElementsKind(elements_kind) ?
 
5840
      OMIT_HOLE_CHECK :
 
5841
      PERFORM_HOLE_CHECK;
 
5842
  if (IsFastDoubleElementsKind(elements_kind)) {
 
5843
    return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key,
 
5844
                                                   load_dependency, mode);
 
5845
  } else {  // Smi or Object elements.
 
5846
    return new(zone()) HLoadKeyedFastElement(elements, checked_key,
 
5847
                                             load_dependency, elements_kind);
 
5848
  }
 
5849
}
 
5850
 
 
5851
 
 
5852
HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
 
5853
                                                           HValue* key,
 
5854
                                                           HValue* val,
 
5855
                                                           HValue* dependency,
 
5856
                                                           Handle<Map> map,
 
5857
                                                           bool is_store) {
 
5858
  HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map,
 
5859
                                                zone(), dependency);
 
5860
  AddInstruction(mapcheck);
 
5861
  if (dependency) {
 
5862
    mapcheck->ClearGVNFlag(kDependsOnElementsKind);
 
5863
  }
 
5864
  return BuildUncheckedMonomorphicElementAccess(object, key, val,
 
5865
                                                mapcheck, map, is_store);
 
5866
}
 
5867
 
 
5868
 
 
5869
HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
 
5870
    HValue* object,
 
5871
    HValue* key,
 
5872
    HValue* val,
 
5873
    HCheckMaps* mapcheck,
 
5874
    Handle<Map> map,
 
5875
    bool is_store) {
 
5876
  // No GVNFlag is necessary for ElementsKind if there is an explicit dependency
 
5877
  // on a HElementsTransition instruction. The flag can also be removed if the
 
5878
  // map to check has FAST_HOLEY_ELEMENTS, since there can be no further
 
5879
  // ElementsKind transitions. Finally, the dependency can be removed for stores
 
5880
  // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the
 
5881
  // generated store code.
 
5882
  if ((map->elements_kind() == FAST_HOLEY_ELEMENTS) ||
 
5883
      (map->elements_kind() == FAST_ELEMENTS && is_store)) {
 
5884
    mapcheck->ClearGVNFlag(kDependsOnElementsKind);
 
5885
  }
 
5886
  bool fast_smi_only_elements = map->has_fast_smi_elements();
 
5887
  bool fast_elements = map->has_fast_object_elements();
 
5888
  HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object));
 
5889
  if (is_store && (fast_elements || fast_smi_only_elements)) {
 
5890
    HCheckMaps* check_cow_map = new(zone()) HCheckMaps(
 
5891
        elements, isolate()->factory()->fixed_array_map(), zone());
 
5892
    check_cow_map->ClearGVNFlag(kDependsOnElementsKind);
 
5893
    AddInstruction(check_cow_map);
 
5894
  }
 
5895
  HInstruction* length = NULL;
 
5896
  HInstruction* checked_key = NULL;
 
5897
  if (map->has_external_array_elements()) {
 
5898
    length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
 
5899
    checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
 
5900
                                                          ALLOW_SMI_KEY));
 
5901
    HLoadExternalArrayPointer* external_elements =
 
5902
        new(zone()) HLoadExternalArrayPointer(elements);
 
5903
    AddInstruction(external_elements);
 
5904
    return BuildExternalArrayElementAccess(
 
5905
        external_elements, checked_key, val, mapcheck,
 
5906
        map->elements_kind(), is_store);
 
5907
  }
 
5908
  ASSERT(fast_smi_only_elements ||
 
5909
         fast_elements ||
 
5910
         map->has_fast_double_elements());
 
5911
  if (map->instance_type() == JS_ARRAY_TYPE) {
 
5912
    length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck,
 
5913
                                                       HType::Smi()));
 
5914
  } else {
 
5915
    length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
 
5916
  }
 
5917
  checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
 
5918
                                                        ALLOW_SMI_KEY));
 
5919
  return BuildFastElementAccess(elements, checked_key, val, mapcheck,
 
5920
                                map->elements_kind(), is_store);
 
5921
}
 
5922
 
 
5923
 
 
5924
HInstruction* HGraphBuilder::TryBuildConsolidatedElementLoad(
 
5925
    HValue* object,
 
5926
    HValue* key,
 
5927
    HValue* val,
 
5928
    SmallMapList* maps) {
 
5929
  // For polymorphic loads of similar elements kinds (i.e. all tagged or all
 
5930
  // double), always use the "worst case" code without a transition.  This is
 
5931
  // much faster than transitioning the elements to the worst case, trading a
 
5932
  // HTransitionElements for a HCheckMaps, and avoiding mutation of the array.
 
5933
  bool has_double_maps = false;
 
5934
  bool has_smi_or_object_maps = false;
 
5935
  bool has_js_array_access = false;
 
5936
  bool has_non_js_array_access = false;
 
5937
  Handle<Map> most_general_consolidated_map;
 
5938
  for (int i = 0; i < maps->length(); ++i) {
 
5939
    Handle<Map> map = maps->at(i);
 
5940
    // Don't allow mixing of JSArrays with JSObjects.
 
5941
    if (map->instance_type() == JS_ARRAY_TYPE) {
 
5942
      if (has_non_js_array_access) return NULL;
 
5943
      has_js_array_access = true;
 
5944
    } else if (has_js_array_access) {
 
5945
      return NULL;
 
5946
    } else {
 
5947
      has_non_js_array_access = true;
 
5948
    }
 
5949
    // Don't allow mixed, incompatible elements kinds.
 
5950
    if (map->has_fast_double_elements()) {
 
5951
      if (has_smi_or_object_maps) return NULL;
 
5952
      has_double_maps = true;
 
5953
    } else if (map->has_fast_smi_or_object_elements()) {
 
5954
      if (has_double_maps) return NULL;
 
5955
      has_smi_or_object_maps = true;
 
5956
    } else {
 
5957
      return NULL;
 
5958
    }
 
5959
    // Remember the most general elements kind, the code for its load will
 
5960
    // properly handle all of the more specific cases.
 
5961
    if ((i == 0) || IsMoreGeneralElementsKindTransition(
 
5962
            most_general_consolidated_map->elements_kind(),
 
5963
            map->elements_kind())) {
 
5964
      most_general_consolidated_map = map;
 
5965
    }
 
5966
  }
 
5967
  if (!has_double_maps && !has_smi_or_object_maps) return NULL;
 
5968
 
 
5969
  HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone());
 
5970
  AddInstruction(check_maps);
 
5971
  HInstruction* instr = BuildUncheckedMonomorphicElementAccess(
 
5972
      object, key, val, check_maps, most_general_consolidated_map, false);
 
5973
  return instr;
 
5974
}
 
5975
 
 
5976
 
 
5977
HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
 
5978
                                                      HValue* key,
 
5979
                                                      HValue* val,
 
5980
                                                      Expression* prop,
 
5981
                                                      int ast_id,
 
5982
                                                      int position,
 
5983
                                                      bool is_store,
 
5984
                                                      bool* has_side_effects) {
 
5985
  *has_side_effects = false;
 
5986
  AddInstruction(new(zone()) HCheckNonSmi(object));
 
5987
  SmallMapList* maps = prop->GetReceiverTypes();
 
5988
  bool todo_external_array = false;
 
5989
 
 
5990
  if (!is_store) {
 
5991
    HInstruction* consolidated_load =
 
5992
        TryBuildConsolidatedElementLoad(object, key, val, maps);
 
5993
    if (consolidated_load != NULL) {
 
5994
      AddInstruction(consolidated_load);
 
5995
      *has_side_effects |= consolidated_load->HasObservableSideEffects();
 
5996
      if (position != RelocInfo::kNoPosition) {
 
5997
        consolidated_load->set_position(position);
 
5998
      }
 
5999
      return consolidated_load;
 
6000
    }
 
6001
  }
 
6002
 
 
6003
  static const int kNumElementTypes = kElementsKindCount;
 
6004
  bool type_todo[kNumElementTypes];
 
6005
  for (int i = 0; i < kNumElementTypes; ++i) {
 
6006
    type_todo[i] = false;
 
6007
  }
 
6008
 
 
6009
  // Elements_kind transition support.
 
6010
  MapHandleList transition_target(maps->length());
 
6011
  // Collect possible transition targets.
 
6012
  MapHandleList possible_transitioned_maps(maps->length());
 
6013
  for (int i = 0; i < maps->length(); ++i) {
 
6014
    Handle<Map> map = maps->at(i);
 
6015
    ElementsKind elements_kind = map->elements_kind();
 
6016
    if (IsFastElementsKind(elements_kind) &&
 
6017
        elements_kind != GetInitialFastElementsKind()) {
 
6018
      possible_transitioned_maps.Add(map);
 
6019
    }
 
6020
  }
 
6021
  // Get transition target for each map (NULL == no transition).
 
6022
  for (int i = 0; i < maps->length(); ++i) {
 
6023
    Handle<Map> map = maps->at(i);
 
6024
    Handle<Map> transitioned_map =
 
6025
        map->FindTransitionedMap(&possible_transitioned_maps);
 
6026
    transition_target.Add(transitioned_map);
 
6027
  }
 
6028
 
 
6029
  int num_untransitionable_maps = 0;
 
6030
  Handle<Map> untransitionable_map;
 
6031
  HTransitionElementsKind* transition = NULL;
 
6032
  for (int i = 0; i < maps->length(); ++i) {
 
6033
    Handle<Map> map = maps->at(i);
 
6034
    ASSERT(map->IsMap());
 
6035
    if (!transition_target.at(i).is_null()) {
 
6036
      ASSERT(Map::IsValidElementsTransition(
 
6037
          map->elements_kind(),
 
6038
          transition_target.at(i)->elements_kind()));
 
6039
      transition = new(zone()) HTransitionElementsKind(
 
6040
          object, map, transition_target.at(i));
 
6041
      AddInstruction(transition);
 
6042
    } else {
 
6043
      type_todo[map->elements_kind()] = true;
 
6044
      if (IsExternalArrayElementsKind(map->elements_kind())) {
 
6045
        todo_external_array = true;
 
6046
      }
 
6047
      num_untransitionable_maps++;
 
6048
      untransitionable_map = map;
 
6049
    }
 
6050
  }
 
6051
 
 
6052
  // If only one map is left after transitioning, handle this case
 
6053
  // monomorphically.
 
6054
  if (num_untransitionable_maps == 1) {
 
6055
    HInstruction* instr = NULL;
 
6056
    if (untransitionable_map->has_slow_elements_kind()) {
 
6057
      instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val)
 
6058
                                      : BuildLoadKeyedGeneric(object, key));
 
6059
    } else {
 
6060
      instr = AddInstruction(BuildMonomorphicElementAccess(
 
6061
          object, key, val, transition, untransitionable_map, is_store));
 
6062
    }
 
6063
    *has_side_effects |= instr->HasObservableSideEffects();
 
6064
    if (position != RelocInfo::kNoPosition) instr->set_position(position);
 
6065
    return is_store ? NULL : instr;
 
6066
  }
 
6067
 
 
6068
  AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone()));
 
6069
  HBasicBlock* join = graph()->CreateBasicBlock();
 
6070
 
 
6071
  HInstruction* elements_kind_instr =
 
6072
      AddInstruction(new(zone()) HElementsKind(object));
 
6073
  HCompareConstantEqAndBranch* elements_kind_branch = NULL;
 
6074
  HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object));
 
6075
  HLoadExternalArrayPointer* external_elements = NULL;
 
6076
  HInstruction* checked_key = NULL;
 
6077
 
 
6078
  // Generated code assumes that FAST_* and DICTIONARY_ELEMENTS ElementsKinds
 
6079
  // are handled before external arrays.
 
6080
  STATIC_ASSERT(FAST_SMI_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
 
6081
  STATIC_ASSERT(FAST_HOLEY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
 
6082
  STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
 
6083
  STATIC_ASSERT(DICTIONARY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
 
6084
 
 
6085
  for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND;
 
6086
       elements_kind <= LAST_ELEMENTS_KIND;
 
6087
       elements_kind = ElementsKind(elements_kind + 1)) {
 
6088
    // After having handled FAST_* and DICTIONARY_ELEMENTS, we need to add some
 
6089
    // code that's executed for all external array cases.
 
6090
    STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND ==
 
6091
                  LAST_ELEMENTS_KIND);
 
6092
    if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND
 
6093
        && todo_external_array) {
 
6094
      HInstruction* length =
 
6095
          AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
 
6096
      checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
 
6097
      external_elements = new(zone()) HLoadExternalArrayPointer(elements);
 
6098
      AddInstruction(external_elements);
 
6099
    }
 
6100
    if (type_todo[elements_kind]) {
 
6101
      HBasicBlock* if_true = graph()->CreateBasicBlock();
 
6102
      HBasicBlock* if_false = graph()->CreateBasicBlock();
 
6103
      elements_kind_branch = new(zone()) HCompareConstantEqAndBranch(
 
6104
          elements_kind_instr, elements_kind, Token::EQ_STRICT);
 
6105
      elements_kind_branch->SetSuccessorAt(0, if_true);
 
6106
      elements_kind_branch->SetSuccessorAt(1, if_false);
 
6107
      current_block()->Finish(elements_kind_branch);
 
6108
 
 
6109
      set_current_block(if_true);
 
6110
      HInstruction* access;
 
6111
      if (IsFastElementsKind(elements_kind)) {
 
6112
        if (is_store && !IsFastDoubleElementsKind(elements_kind)) {
 
6113
          AddInstruction(new(zone()) HCheckMaps(
 
6114
              elements, isolate()->factory()->fixed_array_map(),
 
6115
              zone(), elements_kind_branch));
 
6116
        }
 
6117
        // TODO(jkummerow): The need for these two blocks could be avoided
 
6118
        // in one of two ways:
 
6119
        // (1) Introduce ElementsKinds for JSArrays that are distinct from
 
6120
        //     those for fast objects.
 
6121
        // (2) Put the common instructions into a third "join" block. This
 
6122
        //     requires additional AST IDs that we can deopt to from inside
 
6123
        //     that join block. They must be added to the Property class (when
 
6124
        //     it's a keyed property) and registered in the full codegen.
 
6125
        HBasicBlock* if_jsarray = graph()->CreateBasicBlock();
 
6126
        HBasicBlock* if_fastobject = graph()->CreateBasicBlock();
 
6127
        HHasInstanceTypeAndBranch* typecheck =
 
6128
            new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE);
 
6129
        typecheck->SetSuccessorAt(0, if_jsarray);
 
6130
        typecheck->SetSuccessorAt(1, if_fastobject);
 
6131
        current_block()->Finish(typecheck);
 
6132
 
 
6133
        set_current_block(if_jsarray);
 
6134
        HInstruction* length;
 
6135
        length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck,
 
6136
                                                           HType::Smi()));
 
6137
        checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
 
6138
                                                              ALLOW_SMI_KEY));
 
6139
        access = AddInstruction(BuildFastElementAccess(
 
6140
            elements, checked_key, val, elements_kind_branch,
 
6141
            elements_kind, is_store));
 
6142
        if (!is_store) {
 
6143
          Push(access);
 
6144
        }
 
6145
 
 
6146
        *has_side_effects |= access->HasObservableSideEffects();
 
6147
        if (position != -1) {
 
6148
          access->set_position(position);
 
6149
        }
 
6150
        if_jsarray->Goto(join);
 
6151
 
 
6152
        set_current_block(if_fastobject);
 
6153
        length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
 
6154
        checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
 
6155
                                                              ALLOW_SMI_KEY));
 
6156
        access = AddInstruction(BuildFastElementAccess(
 
6157
            elements, checked_key, val, elements_kind_branch,
 
6158
            elements_kind, is_store));
 
6159
      } else if (elements_kind == DICTIONARY_ELEMENTS) {
 
6160
        if (is_store) {
 
6161
          access = AddInstruction(BuildStoreKeyedGeneric(object, key, val));
 
6162
        } else {
 
6163
          access = AddInstruction(BuildLoadKeyedGeneric(object, key));
 
6164
        }
 
6165
      } else {  // External array elements.
 
6166
        access = AddInstruction(BuildExternalArrayElementAccess(
 
6167
            external_elements, checked_key, val, elements_kind_branch,
 
6168
            elements_kind, is_store));
 
6169
      }
 
6170
      *has_side_effects |= access->HasObservableSideEffects();
 
6171
      if (position != RelocInfo::kNoPosition) access->set_position(position);
 
6172
      if (!is_store) {
 
6173
        Push(access);
 
6174
      }
 
6175
      current_block()->Goto(join);
 
6176
      set_current_block(if_false);
 
6177
    }
 
6178
  }
 
6179
 
 
6180
  // Deopt if none of the cases matched.
 
6181
  current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
 
6182
  join->SetJoinId(ast_id);
 
6183
  set_current_block(join);
 
6184
  return is_store ? NULL : Pop();
 
6185
}
 
6186
 
 
6187
 
 
6188
HValue* HGraphBuilder::HandleKeyedElementAccess(HValue* obj,
 
6189
                                                HValue* key,
 
6190
                                                HValue* val,
 
6191
                                                Expression* expr,
 
6192
                                                int ast_id,
 
6193
                                                int position,
 
6194
                                                bool is_store,
 
6195
                                                bool* has_side_effects) {
 
6196
  ASSERT(!expr->IsPropertyName());
 
6197
  HInstruction* instr = NULL;
 
6198
  if (expr->IsMonomorphic()) {
 
6199
    Handle<Map> map = expr->GetMonomorphicReceiverType();
 
6200
    if (map->has_slow_elements_kind()) {
 
6201
      instr = is_store ? BuildStoreKeyedGeneric(obj, key, val)
 
6202
                       : BuildLoadKeyedGeneric(obj, key);
 
6203
    } else {
 
6204
      AddInstruction(new(zone()) HCheckNonSmi(obj));
 
6205
      instr = BuildMonomorphicElementAccess(obj, key, val, NULL, map, is_store);
 
6206
    }
 
6207
  } else if (expr->GetReceiverTypes() != NULL &&
 
6208
             !expr->GetReceiverTypes()->is_empty()) {
 
6209
    return HandlePolymorphicElementAccess(
 
6210
        obj, key, val, expr, ast_id, position, is_store, has_side_effects);
 
6211
  } else {
 
6212
    if (is_store) {
 
6213
      instr = BuildStoreKeyedGeneric(obj, key, val);
 
6214
    } else {
 
6215
      instr = BuildLoadKeyedGeneric(obj, key);
 
6216
    }
 
6217
  }
 
6218
  if (position != RelocInfo::kNoPosition) instr->set_position(position);
 
6219
  AddInstruction(instr);
 
6220
  *has_side_effects = instr->HasObservableSideEffects();
 
6221
  return instr;
 
6222
}
 
6223
 
 
6224
 
 
6225
HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object,
 
6226
                                                    HValue* key,
 
6227
                                                    HValue* value) {
 
6228
  HValue* context = environment()->LookupContext();
 
6229
  return new(zone()) HStoreKeyedGeneric(
 
6230
                         context,
 
6231
                         object,
 
6232
                         key,
 
6233
                         value,
 
6234
                         function_strict_mode_flag());
 
6235
}
 
6236
 
 
6237
 
 
6238
void HGraphBuilder::EnsureArgumentsArePushedForAccess() {
 
6239
  // Outermost function already has arguments on the stack.
 
6240
  if (function_state()->outer() == NULL) return;
 
6241
 
 
6242
  if (function_state()->arguments_pushed()) return;
 
6243
 
 
6244
  // Push arguments when entering inlined function.
 
6245
  HEnterInlined* entry = function_state()->entry();
 
6246
 
 
6247
  ZoneList<HValue*>* arguments_values = entry->arguments_values();
 
6248
 
 
6249
  HInstruction* insert_after = entry;
 
6250
  for (int i = 0; i < arguments_values->length(); i++) {
 
6251
    HValue* argument = arguments_values->at(i);
 
6252
    HInstruction* push_argument = new(zone()) HPushArgument(argument);
 
6253
    push_argument->InsertAfter(insert_after);
 
6254
    insert_after = push_argument;
 
6255
  }
 
6256
 
 
6257
  HArgumentsElements* arguments_elements =
 
6258
      new(zone()) HArgumentsElements(true);
 
6259
  arguments_elements->ClearFlag(HValue::kUseGVN);
 
6260
  arguments_elements->InsertAfter(insert_after);
 
6261
  function_state()->set_arguments_elements(arguments_elements);
 
6262
}
 
6263
 
 
6264
 
 
6265
bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
 
6266
  VariableProxy* proxy = expr->obj()->AsVariableProxy();
 
6267
  if (proxy == NULL) return false;
 
6268
  if (!proxy->var()->IsStackAllocated()) return false;
 
6269
  if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) {
 
6270
    return false;
 
6271
  }
 
6272
 
 
6273
  HInstruction* result = NULL;
 
6274
  if (expr->key()->IsPropertyName()) {
 
6275
    Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
 
6276
    if (!name->IsEqualTo(CStrVector("length"))) return false;
 
6277
 
 
6278
    if (function_state()->outer() == NULL) {
 
6279
      HInstruction* elements = AddInstruction(
 
6280
          new(zone()) HArgumentsElements(false));
 
6281
      result = new(zone()) HArgumentsLength(elements);
 
6282
    } else {
 
6283
      // Number of arguments without receiver.
 
6284
      int argument_count = environment()->
 
6285
          arguments_environment()->parameter_count() - 1;
 
6286
      result = new(zone()) HConstant(
 
6287
        Handle<Object>(Smi::FromInt(argument_count)),
 
6288
        Representation::Integer32());
 
6289
    }
 
6290
  } else {
 
6291
    Push(graph()->GetArgumentsObject());
 
6292
    VisitForValue(expr->key());
 
6293
    if (HasStackOverflow() || current_block() == NULL) return true;
 
6294
    HValue* key = Pop();
 
6295
    Drop(1);  // Arguments object.
 
6296
    if (function_state()->outer() == NULL) {
 
6297
      HInstruction* elements = AddInstruction(
 
6298
          new(zone()) HArgumentsElements(false));
 
6299
      HInstruction* length = AddInstruction(
 
6300
          new(zone()) HArgumentsLength(elements));
 
6301
      HInstruction* checked_key =
 
6302
          AddInstruction(new(zone()) HBoundsCheck(key, length));
 
6303
      result = new(zone()) HAccessArgumentsAt(elements, length, checked_key);
 
6304
    } else {
 
6305
      EnsureArgumentsArePushedForAccess();
 
6306
 
 
6307
      // Number of arguments without receiver.
 
6308
      HInstruction* elements = function_state()->arguments_elements();
 
6309
      int argument_count = environment()->
 
6310
          arguments_environment()->parameter_count() - 1;
 
6311
      HInstruction* length = AddInstruction(new(zone()) HConstant(
 
6312
        Handle<Object>(Smi::FromInt(argument_count)),
 
6313
        Representation::Integer32()));
 
6314
      HInstruction* checked_key =
 
6315
          AddInstruction(new(zone()) HBoundsCheck(key, length));
 
6316
      result = new(zone()) HAccessArgumentsAt(elements, length, checked_key);
 
6317
    }
 
6318
  }
 
6319
  ast_context()->ReturnInstruction(result, expr->id());
 
6320
  return true;
 
6321
}
 
6322
 
 
6323
 
 
6324
void HGraphBuilder::VisitProperty(Property* expr) {
 
6325
  ASSERT(!HasStackOverflow());
 
6326
  ASSERT(current_block() != NULL);
 
6327
  ASSERT(current_block()->HasPredecessor());
 
6328
  expr->RecordTypeFeedback(oracle(), zone());
 
6329
 
 
6330
  if (TryArgumentsAccess(expr)) return;
 
6331
 
 
6332
  CHECK_ALIVE(VisitForValue(expr->obj()));
 
6333
 
 
6334
  HInstruction* instr = NULL;
 
6335
  if (expr->AsProperty()->IsArrayLength()) {
 
6336
    HValue* array = Pop();
 
6337
    AddInstruction(new(zone()) HCheckNonSmi(array));
 
6338
    HInstruction* mapcheck =
 
6339
        AddInstruction(HCheckInstanceType::NewIsJSArray(array, zone()));
 
6340
    instr = new(zone()) HJSArrayLength(array, mapcheck);
 
6341
  } else if (expr->IsStringLength()) {
 
6342
    HValue* string = Pop();
 
6343
    AddInstruction(new(zone()) HCheckNonSmi(string));
 
6344
    AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
 
6345
    instr = new(zone()) HStringLength(string);
 
6346
  } else if (expr->IsStringAccess()) {
 
6347
    CHECK_ALIVE(VisitForValue(expr->key()));
 
6348
    HValue* index = Pop();
 
6349
    HValue* string = Pop();
 
6350
    HValue* context = environment()->LookupContext();
 
6351
    HStringCharCodeAt* char_code =
 
6352
      BuildStringCharCodeAt(context, string, index);
 
6353
    AddInstruction(char_code);
 
6354
    instr = new(zone()) HStringCharFromCode(context, char_code);
 
6355
 
 
6356
  } else if (expr->IsFunctionPrototype()) {
 
6357
    HValue* function = Pop();
 
6358
    AddInstruction(new(zone()) HCheckNonSmi(function));
 
6359
    instr = new(zone()) HLoadFunctionPrototype(function);
 
6360
 
 
6361
  } else if (expr->key()->IsPropertyName()) {
 
6362
    Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
 
6363
    SmallMapList* types = expr->GetReceiverTypes();
 
6364
 
 
6365
    bool monomorphic = expr->IsMonomorphic();
 
6366
    Handle<Map> map;
 
6367
    if (expr->IsMonomorphic()) {
 
6368
      map = types->first();
 
6369
      if (map->is_dictionary_map()) monomorphic = false;
 
6370
    }
 
6371
    if (monomorphic) {
 
6372
      Handle<AccessorPair> accessors;
 
6373
      Handle<JSObject> holder;
 
6374
      if (LookupAccessorPair(map, name, &accessors, &holder)) {
 
6375
        AddCheckConstantFunction(holder, Top(), map, true);
 
6376
        Handle<JSFunction> getter(JSFunction::cast(accessors->getter()));
 
6377
        if (FLAG_inline_accessors && TryInlineGetter(getter, expr)) return;
 
6378
        AddInstruction(new(zone()) HPushArgument(Pop()));
 
6379
        instr = new(zone()) HCallConstantFunction(getter, 1);
 
6380
      } else {
 
6381
        instr = BuildLoadNamedMonomorphic(Pop(), name, expr, map);
 
6382
      }
 
6383
    } else if (types != NULL && types->length() > 1) {
 
6384
      return HandlePolymorphicLoadNamedField(expr, Pop(), types, name);
 
6385
    } else {
 
6386
      instr = BuildLoadNamedGeneric(Pop(), name, expr);
 
6387
    }
 
6388
 
 
6389
  } else {
 
6390
    CHECK_ALIVE(VisitForValue(expr->key()));
 
6391
 
 
6392
    HValue* key = Pop();
 
6393
    HValue* obj = Pop();
 
6394
 
 
6395
    bool has_side_effects = false;
 
6396
    HValue* load = HandleKeyedElementAccess(
 
6397
        obj, key, NULL, expr, expr->id(), expr->position(),
 
6398
        false,  // is_store
 
6399
        &has_side_effects);
 
6400
    if (has_side_effects) {
 
6401
      if (ast_context()->IsEffect()) {
 
6402
        AddSimulate(expr->id());
 
6403
      } else {
 
6404
        Push(load);
 
6405
        AddSimulate(expr->id());
 
6406
        Drop(1);
 
6407
      }
 
6408
    }
 
6409
    return ast_context()->ReturnValue(load);
 
6410
  }
 
6411
  instr->set_position(expr->position());
 
6412
  return ast_context()->ReturnInstruction(instr, expr->id());
 
6413
}
 
6414
 
 
6415
 
 
6416
void HGraphBuilder::AddCheckConstantFunction(Handle<JSObject> holder,
 
6417
                                             HValue* receiver,
 
6418
                                             Handle<Map> receiver_map,
 
6419
                                             bool smi_and_map_check) {
 
6420
  // Constant functions have the nice property that the map will change if they
 
6421
  // are overwritten.  Therefore it is enough to check the map of the holder and
 
6422
  // its prototypes.
 
6423
  if (smi_and_map_check) {
 
6424
    AddInstruction(new(zone()) HCheckNonSmi(receiver));
 
6425
    AddInstruction(HCheckMaps::NewWithTransitions(receiver, receiver_map,
 
6426
                                                  zone()));
 
6427
  }
 
6428
  if (!holder.is_null()) {
 
6429
    AddInstruction(new(zone()) HCheckPrototypeMaps(
 
6430
        Handle<JSObject>(JSObject::cast(receiver_map->prototype())), holder));
 
6431
  }
 
6432
}
 
6433
 
 
6434
 
 
6435
class FunctionSorter {
 
6436
 public:
 
6437
  FunctionSorter() : index_(0), ticks_(0), ast_length_(0), src_length_(0) { }
 
6438
  FunctionSorter(int index, int ticks, int ast_length, int src_length)
 
6439
      : index_(index),
 
6440
        ticks_(ticks),
 
6441
        ast_length_(ast_length),
 
6442
        src_length_(src_length) { }
 
6443
 
 
6444
  int index() const { return index_; }
 
6445
  int ticks() const { return ticks_; }
 
6446
  int ast_length() const { return ast_length_; }
 
6447
  int src_length() const { return src_length_; }
 
6448
 
 
6449
 private:
 
6450
  int index_;
 
6451
  int ticks_;
 
6452
  int ast_length_;
 
6453
  int src_length_;
 
6454
};
 
6455
 
 
6456
 
 
6457
static int CompareHotness(void const* a, void const* b) {
 
6458
  FunctionSorter const* function1 = reinterpret_cast<FunctionSorter const*>(a);
 
6459
  FunctionSorter const* function2 = reinterpret_cast<FunctionSorter const*>(b);
 
6460
  int diff = function1->ticks() - function2->ticks();
 
6461
  if (diff != 0) return -diff;
 
6462
  diff = function1->ast_length() - function2->ast_length();
 
6463
  if (diff != 0) return diff;
 
6464
  return function1->src_length() - function2->src_length();
 
6465
}
 
6466
 
 
6467
 
 
6468
void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
 
6469
                                               HValue* receiver,
 
6470
                                               SmallMapList* types,
 
6471
                                               Handle<String> name) {
 
6472
  // TODO(ager): We should recognize when the prototype chains for different
 
6473
  // maps are identical. In that case we can avoid repeatedly generating the
 
6474
  // same prototype map checks.
 
6475
  int argument_count = expr->arguments()->length() + 1;  // Includes receiver.
 
6476
  HBasicBlock* join = NULL;
 
6477
  FunctionSorter order[kMaxCallPolymorphism];
 
6478
  int ordered_functions = 0;
 
6479
  for (int i = 0;
 
6480
       i < types->length() && ordered_functions < kMaxCallPolymorphism;
 
6481
       ++i) {
 
6482
    Handle<Map> map = types->at(i);
 
6483
    if (expr->ComputeTarget(map, name)) {
 
6484
      order[ordered_functions++] =
 
6485
          FunctionSorter(i,
 
6486
                         expr->target()->shared()->profiler_ticks(),
 
6487
                         InliningAstSize(expr->target()),
 
6488
                         expr->target()->shared()->SourceSize());
 
6489
    }
 
6490
  }
 
6491
 
 
6492
  qsort(reinterpret_cast<void*>(&order[0]),
 
6493
        ordered_functions,
 
6494
        sizeof(order[0]),
 
6495
        &CompareHotness);
 
6496
 
 
6497
  for (int fn = 0; fn < ordered_functions; ++fn) {
 
6498
    int i = order[fn].index();
 
6499
    Handle<Map> map = types->at(i);
 
6500
    if (fn == 0) {
 
6501
      // Only needed once.
 
6502
      AddInstruction(new(zone()) HCheckNonSmi(receiver));
 
6503
      join = graph()->CreateBasicBlock();
 
6504
    }
 
6505
    HBasicBlock* if_true = graph()->CreateBasicBlock();
 
6506
    HBasicBlock* if_false = graph()->CreateBasicBlock();
 
6507
    HCompareMap* compare =
 
6508
        new(zone()) HCompareMap(receiver, map, if_true, if_false);
 
6509
    current_block()->Finish(compare);
 
6510
 
 
6511
    set_current_block(if_true);
 
6512
    expr->ComputeTarget(map, name);
 
6513
    AddCheckConstantFunction(expr->holder(), receiver, map, false);
 
6514
    if (FLAG_trace_inlining && FLAG_polymorphic_inlining) {
 
6515
      Handle<JSFunction> caller = info()->closure();
 
6516
      SmartArrayPointer<char> caller_name =
 
6517
          caller->shared()->DebugName()->ToCString();
 
6518
      PrintF("Trying to inline the polymorphic call to %s from %s\n",
 
6519
             *name->ToCString(),
 
6520
             *caller_name);
 
6521
    }
 
6522
    if (FLAG_polymorphic_inlining && TryInlineCall(expr)) {
 
6523
      // Trying to inline will signal that we should bailout from the
 
6524
      // entire compilation by setting stack overflow on the visitor.
 
6525
      if (HasStackOverflow()) return;
 
6526
    } else {
 
6527
      HCallConstantFunction* call =
 
6528
          new(zone()) HCallConstantFunction(expr->target(), argument_count);
 
6529
      call->set_position(expr->position());
 
6530
      PreProcessCall(call);
 
6531
      AddInstruction(call);
 
6532
      if (!ast_context()->IsEffect()) Push(call);
 
6533
    }
 
6534
 
 
6535
    if (current_block() != NULL) current_block()->Goto(join);
 
6536
    set_current_block(if_false);
 
6537
  }
 
6538
 
 
6539
  // Finish up.  Unconditionally deoptimize if we've handled all the maps we
 
6540
  // know about and do not want to handle ones we've never seen.  Otherwise
 
6541
  // use a generic IC.
 
6542
  if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) {
 
6543
    current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
 
6544
  } else {
 
6545
    HValue* context = environment()->LookupContext();
 
6546
    HCallNamed* call = new(zone()) HCallNamed(context, name, argument_count);
 
6547
    call->set_position(expr->position());
 
6548
    PreProcessCall(call);
 
6549
 
 
6550
    if (join != NULL) {
 
6551
      AddInstruction(call);
 
6552
      if (!ast_context()->IsEffect()) Push(call);
 
6553
      current_block()->Goto(join);
 
6554
    } else {
 
6555
      return ast_context()->ReturnInstruction(call, expr->id());
 
6556
    }
 
6557
  }
 
6558
 
 
6559
  // We assume that control flow is always live after an expression.  So
 
6560
  // even without predecessors to the join block, we set it as the exit
 
6561
  // block and continue by adding instructions there.
 
6562
  ASSERT(join != NULL);
 
6563
  if (join->HasPredecessor()) {
 
6564
    set_current_block(join);
 
6565
    join->SetJoinId(expr->id());
 
6566
    if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop());
 
6567
  } else {
 
6568
    set_current_block(NULL);
 
6569
  }
 
6570
}
 
6571
 
 
6572
 
 
6573
void HGraphBuilder::TraceInline(Handle<JSFunction> target,
 
6574
                                Handle<JSFunction> caller,
 
6575
                                const char* reason) {
 
6576
  if (FLAG_trace_inlining) {
 
6577
    SmartArrayPointer<char> target_name =
 
6578
        target->shared()->DebugName()->ToCString();
 
6579
    SmartArrayPointer<char> caller_name =
 
6580
        caller->shared()->DebugName()->ToCString();
 
6581
    if (reason == NULL) {
 
6582
      PrintF("Inlined %s called from %s.\n", *target_name, *caller_name);
 
6583
    } else {
 
6584
      PrintF("Did not inline %s called from %s (%s).\n",
 
6585
             *target_name, *caller_name, reason);
 
6586
    }
 
6587
  }
 
6588
}
 
6589
 
 
6590
 
 
6591
static const int kNotInlinable = 1000000000;
 
6592
 
 
6593
 
 
6594
int HGraphBuilder::InliningAstSize(Handle<JSFunction> target) {
 
6595
  if (!FLAG_use_inlining) return kNotInlinable;
 
6596
 
 
6597
  // Precondition: call is monomorphic and we have found a target with the
 
6598
  // appropriate arity.
 
6599
  Handle<JSFunction> caller = info()->closure();
 
6600
  Handle<SharedFunctionInfo> target_shared(target->shared());
 
6601
 
 
6602
  // Do a quick check on source code length to avoid parsing large
 
6603
  // inlining candidates.
 
6604
  if (target_shared->SourceSize() >
 
6605
      Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) {
 
6606
    TraceInline(target, caller, "target text too big");
 
6607
    return kNotInlinable;
 
6608
  }
 
6609
 
 
6610
  // Target must be inlineable.
 
6611
  if (!target->IsInlineable()) {
 
6612
    TraceInline(target, caller, "target not inlineable");
 
6613
    return kNotInlinable;
 
6614
  }
 
6615
  if (target_shared->dont_inline() || target_shared->dont_optimize()) {
 
6616
    TraceInline(target, caller, "target contains unsupported syntax [early]");
 
6617
    return kNotInlinable;
 
6618
  }
 
6619
 
 
6620
  int nodes_added = target_shared->ast_node_count();
 
6621
  return nodes_added;
 
6622
}
 
6623
 
 
6624
 
 
6625
bool HGraphBuilder::TryInline(CallKind call_kind,
 
6626
                              Handle<JSFunction> target,
 
6627
                              int arguments_count,
 
6628
                              HValue* receiver,
 
6629
                              int ast_id,
 
6630
                              int return_id,
 
6631
                              ReturnHandlingFlag return_handling) {
 
6632
  int nodes_added = InliningAstSize(target);
 
6633
  if (nodes_added == kNotInlinable) return false;
 
6634
 
 
6635
  Handle<JSFunction> caller = info()->closure();
 
6636
 
 
6637
  if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
 
6638
    TraceInline(target, caller, "target AST is too large [early]");
 
6639
    return false;
 
6640
  }
 
6641
 
 
6642
  Handle<SharedFunctionInfo> target_shared(target->shared());
 
6643
 
 
6644
#if !defined(V8_TARGET_ARCH_IA32)
 
6645
  // Target must be able to use caller's context.
 
6646
  CompilationInfo* outer_info = info();
 
6647
  if (target->context() != outer_info->closure()->context() ||
 
6648
      outer_info->scope()->contains_with() ||
 
6649
      outer_info->scope()->num_heap_slots() > 0) {
 
6650
    TraceInline(target, caller, "target requires context change");
 
6651
    return false;
 
6652
  }
 
6653
#endif
 
6654
 
 
6655
 
 
6656
  // Don't inline deeper than kMaxInliningLevels calls.
 
6657
  HEnvironment* env = environment();
 
6658
  int current_level = 1;
 
6659
  while (env->outer() != NULL) {
 
6660
    if (current_level == Compiler::kMaxInliningLevels) {
 
6661
      TraceInline(target, caller, "inline depth limit reached");
 
6662
      return false;
 
6663
    }
 
6664
    if (env->outer()->frame_type() == JS_FUNCTION) {
 
6665
      current_level++;
 
6666
    }
 
6667
    env = env->outer();
 
6668
  }
 
6669
 
 
6670
  // Don't inline recursive functions.
 
6671
  for (FunctionState* state = function_state();
 
6672
       state != NULL;
 
6673
       state = state->outer()) {
 
6674
    if (state->compilation_info()->closure()->shared() == *target_shared) {
 
6675
      TraceInline(target, caller, "target is recursive");
 
6676
      return false;
 
6677
    }
 
6678
  }
 
6679
 
 
6680
  // We don't want to add more than a certain number of nodes from inlining.
 
6681
  if (inlined_count_ > Min(FLAG_max_inlined_nodes_cumulative,
 
6682
                           kUnlimitedMaxInlinedNodesCumulative)) {
 
6683
    TraceInline(target, caller, "cumulative AST node limit reached");
 
6684
    return false;
 
6685
  }
 
6686
 
 
6687
  // Parse and allocate variables.
 
6688
  CompilationInfo target_info(target, zone());
 
6689
  if (!ParserApi::Parse(&target_info, kNoParsingFlags) ||
 
6690
      !Scope::Analyze(&target_info)) {
 
6691
    if (target_info.isolate()->has_pending_exception()) {
 
6692
      // Parse or scope error, never optimize this function.
 
6693
      SetStackOverflow();
 
6694
      target_shared->DisableOptimization();
 
6695
    }
 
6696
    TraceInline(target, caller, "parse failure");
 
6697
    return false;
 
6698
  }
 
6699
 
 
6700
  if (target_info.scope()->num_heap_slots() > 0) {
 
6701
    TraceInline(target, caller, "target has context-allocated variables");
 
6702
    return false;
 
6703
  }
 
6704
  FunctionLiteral* function = target_info.function();
 
6705
 
 
6706
  // The following conditions must be checked again after re-parsing, because
 
6707
  // earlier the information might not have been complete due to lazy parsing.
 
6708
  nodes_added = function->ast_node_count();
 
6709
  if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
 
6710
    TraceInline(target, caller, "target AST is too large [late]");
 
6711
    return false;
 
6712
  }
 
6713
  AstProperties::Flags* flags(function->flags());
 
6714
  if (flags->Contains(kDontInline) || flags->Contains(kDontOptimize)) {
 
6715
    TraceInline(target, caller, "target contains unsupported syntax [late]");
 
6716
    return false;
 
6717
  }
 
6718
 
 
6719
  // If the function uses the arguments object check that inlining of functions
 
6720
  // with arguments object is enabled and the arguments-variable is
 
6721
  // stack allocated.
 
6722
  if (function->scope()->arguments() != NULL) {
 
6723
    if (!FLAG_inline_arguments) {
 
6724
      TraceInline(target, caller, "target uses arguments object");
 
6725
      return false;
 
6726
    }
 
6727
 
 
6728
    if (!function->scope()->arguments()->IsStackAllocated()) {
 
6729
      TraceInline(target,
 
6730
                  caller,
 
6731
                  "target uses non-stackallocated arguments object");
 
6732
      return false;
 
6733
    }
 
6734
  }
 
6735
 
 
6736
  // All declarations must be inlineable.
 
6737
  ZoneList<Declaration*>* decls = target_info.scope()->declarations();
 
6738
  int decl_count = decls->length();
 
6739
  for (int i = 0; i < decl_count; ++i) {
 
6740
    if (!decls->at(i)->IsInlineable()) {
 
6741
      TraceInline(target, caller, "target has non-trivial declaration");
 
6742
      return false;
 
6743
    }
 
6744
  }
 
6745
 
 
6746
  // Generate the deoptimization data for the unoptimized version of
 
6747
  // the target function if we don't already have it.
 
6748
  if (!target_shared->has_deoptimization_support()) {
 
6749
    // Note that we compile here using the same AST that we will use for
 
6750
    // generating the optimized inline code.
 
6751
    target_info.EnableDeoptimizationSupport();
 
6752
    if (!FullCodeGenerator::MakeCode(&target_info)) {
 
6753
      TraceInline(target, caller, "could not generate deoptimization info");
 
6754
      return false;
 
6755
    }
 
6756
    if (target_shared->scope_info() == ScopeInfo::Empty()) {
 
6757
      // The scope info might not have been set if a lazily compiled
 
6758
      // function is inlined before being called for the first time.
 
6759
      Handle<ScopeInfo> target_scope_info =
 
6760
          ScopeInfo::Create(target_info.scope(), zone());
 
6761
      target_shared->set_scope_info(*target_scope_info);
 
6762
    }
 
6763
    target_shared->EnableDeoptimizationSupport(*target_info.code());
 
6764
    Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG,
 
6765
                                        &target_info,
 
6766
                                        target_shared);
 
6767
  }
 
6768
 
 
6769
  // ----------------------------------------------------------------
 
6770
  // After this point, we've made a decision to inline this function (so
 
6771
  // TryInline should always return true).
 
6772
 
 
6773
  // Save the pending call context and type feedback oracle. Set up new ones
 
6774
  // for the inlined function.
 
6775
  ASSERT(target_shared->has_deoptimization_support());
 
6776
  TypeFeedbackOracle target_oracle(
 
6777
      Handle<Code>(target_shared->code()),
 
6778
      Handle<Context>(target->context()->global_context()),
 
6779
      isolate(),
 
6780
      zone());
 
6781
  // The function state is new-allocated because we need to delete it
 
6782
  // in two different places.
 
6783
  FunctionState* target_state = new FunctionState(
 
6784
      this, &target_info, &target_oracle, return_handling);
 
6785
 
 
6786
  HConstant* undefined = graph()->GetConstantUndefined();
 
6787
  HEnvironment* inner_env =
 
6788
      environment()->CopyForInlining(target,
 
6789
                                     arguments_count,
 
6790
                                     function,
 
6791
                                     undefined,
 
6792
                                     call_kind,
 
6793
                                     function_state()->is_construct());
 
6794
#ifdef V8_TARGET_ARCH_IA32
 
6795
  // IA32 only, overwrite the caller's context in the deoptimization
 
6796
  // environment with the correct one.
 
6797
  //
 
6798
  // TODO(kmillikin): implement the same inlining on other platforms so we
 
6799
  // can remove the unsightly ifdefs in this function.
 
6800
  HConstant* context =
 
6801
      new(zone()) HConstant(Handle<Context>(target->context()),
 
6802
                            Representation::Tagged());
 
6803
  AddInstruction(context);
 
6804
  inner_env->BindContext(context);
 
6805
#endif
 
6806
 
 
6807
  AddSimulate(return_id);
 
6808
  current_block()->UpdateEnvironment(inner_env);
 
6809
 
 
6810
  ZoneList<HValue*>* arguments_values = NULL;
 
6811
 
 
6812
  // If the function uses arguments copy current arguments values
 
6813
  // to use them for materialization.
 
6814
  if (function->scope()->arguments() != NULL) {
 
6815
    HEnvironment* arguments_env = inner_env->arguments_environment();
 
6816
    int arguments_count = arguments_env->parameter_count();
 
6817
    arguments_values = new(zone()) ZoneList<HValue*>(arguments_count, zone());
 
6818
    for (int i = 0; i < arguments_count; i++) {
 
6819
      arguments_values->Add(arguments_env->Lookup(i), zone());
 
6820
    }
 
6821
  }
 
6822
 
 
6823
  HEnterInlined* enter_inlined =
 
6824
      new(zone()) HEnterInlined(target,
 
6825
                                arguments_count,
 
6826
                                function,
 
6827
                                call_kind,
 
6828
                                function_state()->is_construct(),
 
6829
                                function->scope()->arguments(),
 
6830
                                arguments_values);
 
6831
  function_state()->set_entry(enter_inlined);
 
6832
  AddInstruction(enter_inlined);
 
6833
 
 
6834
  // If the function uses arguments object create and bind one.
 
6835
  if (function->scope()->arguments() != NULL) {
 
6836
    ASSERT(function->scope()->arguments()->IsStackAllocated());
 
6837
    inner_env->Bind(function->scope()->arguments(),
 
6838
                    graph()->GetArgumentsObject());
 
6839
  }
 
6840
 
 
6841
 
 
6842
  VisitDeclarations(target_info.scope()->declarations());
 
6843
  VisitStatements(function->body());
 
6844
  if (HasStackOverflow()) {
 
6845
    // Bail out if the inline function did, as we cannot residualize a call
 
6846
    // instead.
 
6847
    TraceInline(target, caller, "inline graph construction failed");
 
6848
    target_shared->DisableOptimization();
 
6849
    inline_bailout_ = true;
 
6850
    delete target_state;
 
6851
    return true;
 
6852
  }
 
6853
 
 
6854
  // Update inlined nodes count.
 
6855
  inlined_count_ += nodes_added;
 
6856
 
 
6857
  TraceInline(target, caller, NULL);
 
6858
 
 
6859
  if (current_block() != NULL) {
 
6860
    // Add default return value (i.e. undefined for normals calls or the newly
 
6861
    // allocated receiver for construct calls) if control can fall off the
 
6862
    // body.  In a test context, undefined is false and any JSObject is true.
 
6863
    if (call_context()->IsValue()) {
 
6864
      ASSERT(function_return() != NULL);
 
6865
      HValue* return_value = function_state()->is_construct()
 
6866
          ? receiver
 
6867
          : undefined;
 
6868
      current_block()->AddLeaveInlined(return_value,
 
6869
                                       function_return(),
 
6870
                                       function_state());
 
6871
    } else if (call_context()->IsEffect()) {
 
6872
      ASSERT(function_return() != NULL);
 
6873
      current_block()->Goto(function_return(), function_state());
 
6874
    } else {
 
6875
      ASSERT(call_context()->IsTest());
 
6876
      ASSERT(inlined_test_context() != NULL);
 
6877
      HBasicBlock* target = function_state()->is_construct()
 
6878
          ? inlined_test_context()->if_true()
 
6879
          : inlined_test_context()->if_false();
 
6880
      current_block()->Goto(target, function_state());
 
6881
    }
 
6882
  }
 
6883
 
 
6884
  // Fix up the function exits.
 
6885
  if (inlined_test_context() != NULL) {
 
6886
    HBasicBlock* if_true = inlined_test_context()->if_true();
 
6887
    HBasicBlock* if_false = inlined_test_context()->if_false();
 
6888
 
 
6889
    // Pop the return test context from the expression context stack.
 
6890
    ASSERT(ast_context() == inlined_test_context());
 
6891
    ClearInlinedTestContext();
 
6892
    delete target_state;
 
6893
 
 
6894
    // Forward to the real test context.
 
6895
    if (if_true->HasPredecessor()) {
 
6896
      if_true->SetJoinId(ast_id);
 
6897
      HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
 
6898
      if_true->Goto(true_target, function_state());
 
6899
    }
 
6900
    if (if_false->HasPredecessor()) {
 
6901
      if_false->SetJoinId(ast_id);
 
6902
      HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
 
6903
      if_false->Goto(false_target, function_state());
 
6904
    }
 
6905
    set_current_block(NULL);
 
6906
    return true;
 
6907
 
 
6908
  } else if (function_return()->HasPredecessor()) {
 
6909
    function_return()->SetJoinId(ast_id);
 
6910
    set_current_block(function_return());
 
6911
  } else {
 
6912
    set_current_block(NULL);
 
6913
  }
 
6914
  delete target_state;
 
6915
  return true;
 
6916
}
 
6917
 
 
6918
 
 
6919
bool HGraphBuilder::TryInlineCall(Call* expr, bool drop_extra) {
 
6920
  // The function call we are inlining is a method call if the call
 
6921
  // is a property call.
 
6922
  CallKind call_kind = (expr->expression()->AsProperty() == NULL)
 
6923
      ? CALL_AS_FUNCTION
 
6924
      : CALL_AS_METHOD;
 
6925
 
 
6926
  return TryInline(call_kind,
 
6927
                   expr->target(),
 
6928
                   expr->arguments()->length(),
 
6929
                   NULL,
 
6930
                   expr->id(),
 
6931
                   expr->ReturnId(),
 
6932
                   drop_extra ? DROP_EXTRA_ON_RETURN : NORMAL_RETURN);
 
6933
}
 
6934
 
 
6935
 
 
6936
bool HGraphBuilder::TryInlineConstruct(CallNew* expr, HValue* receiver) {
 
6937
  return TryInline(CALL_AS_FUNCTION,
 
6938
                   expr->target(),
 
6939
                   expr->arguments()->length(),
 
6940
                   receiver,
 
6941
                   expr->id(),
 
6942
                   expr->ReturnId(),
 
6943
                   CONSTRUCT_CALL_RETURN);
 
6944
}
 
6945
 
 
6946
 
 
6947
bool HGraphBuilder::TryInlineGetter(Handle<JSFunction> getter,
 
6948
                                    Property* prop) {
 
6949
  return TryInline(CALL_AS_METHOD,
 
6950
                   getter,
 
6951
                   0,
 
6952
                   NULL,
 
6953
                   prop->id(),
 
6954
                   prop->ReturnId(),
 
6955
                   NORMAL_RETURN);
 
6956
}
 
6957
 
 
6958
 
 
6959
bool HGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, bool drop_extra) {
 
6960
  if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
 
6961
  BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
 
6962
  switch (id) {
 
6963
    case kMathRound:
 
6964
    case kMathAbs:
 
6965
    case kMathSqrt:
 
6966
    case kMathLog:
 
6967
    case kMathSin:
 
6968
    case kMathCos:
 
6969
    case kMathTan:
 
6970
      if (expr->arguments()->length() == 1) {
 
6971
        HValue* argument = Pop();
 
6972
        HValue* context = environment()->LookupContext();
 
6973
        Drop(1);  // Receiver.
 
6974
        HUnaryMathOperation* op =
 
6975
            new(zone()) HUnaryMathOperation(context, argument, id);
 
6976
        op->set_position(expr->position());
 
6977
        if (drop_extra) Drop(1);  // Optionally drop the function.
 
6978
        ast_context()->ReturnInstruction(op, expr->id());
 
6979
        return true;
 
6980
      }
 
6981
      break;
 
6982
    default:
 
6983
      // Not supported for inlining yet.
 
6984
      break;
 
6985
  }
 
6986
  return false;
 
6987
}
 
6988
 
 
6989
 
 
6990
bool HGraphBuilder::TryInlineBuiltinMethodCall(Call* expr,
 
6991
                                               HValue* receiver,
 
6992
                                               Handle<Map> receiver_map,
 
6993
                                               CheckType check_type) {
 
6994
  ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null());
 
6995
  // Try to inline calls like Math.* as operations in the calling function.
 
6996
  if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
 
6997
  BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
 
6998
  int argument_count = expr->arguments()->length() + 1;  // Plus receiver.
 
6999
  switch (id) {
 
7000
    case kStringCharCodeAt:
 
7001
    case kStringCharAt:
 
7002
      if (argument_count == 2 && check_type == STRING_CHECK) {
 
7003
        HValue* index = Pop();
 
7004
        HValue* string = Pop();
 
7005
        HValue* context = environment()->LookupContext();
 
7006
        ASSERT(!expr->holder().is_null());
 
7007
        AddInstruction(new(zone()) HCheckPrototypeMaps(
 
7008
            oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK),
 
7009
            expr->holder()));
 
7010
        HStringCharCodeAt* char_code =
 
7011
            BuildStringCharCodeAt(context, string, index);
 
7012
        if (id == kStringCharCodeAt) {
 
7013
          ast_context()->ReturnInstruction(char_code, expr->id());
 
7014
          return true;
 
7015
        }
 
7016
        AddInstruction(char_code);
 
7017
        HStringCharFromCode* result =
 
7018
            new(zone()) HStringCharFromCode(context, char_code);
 
7019
        ast_context()->ReturnInstruction(result, expr->id());
 
7020
        return true;
 
7021
      }
 
7022
      break;
 
7023
    case kMathRound:
 
7024
    case kMathFloor:
 
7025
    case kMathAbs:
 
7026
    case kMathSqrt:
 
7027
    case kMathLog:
 
7028
    case kMathSin:
 
7029
    case kMathCos:
 
7030
    case kMathTan:
 
7031
      if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
 
7032
        AddCheckConstantFunction(expr->holder(), receiver, receiver_map, true);
 
7033
        HValue* argument = Pop();
 
7034
        HValue* context = environment()->LookupContext();
 
7035
        Drop(1);  // Receiver.
 
7036
        HUnaryMathOperation* op =
 
7037
            new(zone()) HUnaryMathOperation(context, argument, id);
 
7038
        op->set_position(expr->position());
 
7039
        ast_context()->ReturnInstruction(op, expr->id());
 
7040
        return true;
 
7041
      }
 
7042
      break;
 
7043
    case kMathPow:
 
7044
      if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
 
7045
        AddCheckConstantFunction(expr->holder(), receiver, receiver_map, true);
 
7046
        HValue* right = Pop();
 
7047
        HValue* left = Pop();
 
7048
        Pop();  // Pop receiver.
 
7049
        HValue* context = environment()->LookupContext();
 
7050
        HInstruction* result = NULL;
 
7051
        // Use sqrt() if exponent is 0.5 or -0.5.
 
7052
        if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) {
 
7053
          double exponent = HConstant::cast(right)->DoubleValue();
 
7054
          if (exponent == 0.5) {
 
7055
            result =
 
7056
                new(zone()) HUnaryMathOperation(context, left, kMathPowHalf);
 
7057
          } else if (exponent == -0.5) {
 
7058
            HConstant* double_one =
 
7059
                new(zone()) HConstant(Handle<Object>(Smi::FromInt(1)),
 
7060
                                      Representation::Double());
 
7061
            AddInstruction(double_one);
 
7062
            HUnaryMathOperation* square_root =
 
7063
                new(zone()) HUnaryMathOperation(context, left, kMathPowHalf);
 
7064
            AddInstruction(square_root);
 
7065
            // MathPowHalf doesn't have side effects so there's no need for
 
7066
            // an environment simulation here.
 
7067
            ASSERT(!square_root->HasObservableSideEffects());
 
7068
            result = new(zone()) HDiv(context, double_one, square_root);
 
7069
          } else if (exponent == 2.0) {
 
7070
            result = new(zone()) HMul(context, left, left);
 
7071
          }
 
7072
        } else if (right->IsConstant() &&
 
7073
                   HConstant::cast(right)->HasInteger32Value() &&
 
7074
                   HConstant::cast(right)->Integer32Value() == 2) {
 
7075
          result = new(zone()) HMul(context, left, left);
 
7076
        }
 
7077
 
 
7078
        if (result == NULL) {
 
7079
          result = new(zone()) HPower(left, right);
 
7080
        }
 
7081
        ast_context()->ReturnInstruction(result, expr->id());
 
7082
        return true;
 
7083
      }
 
7084
      break;
 
7085
    case kMathRandom:
 
7086
      if (argument_count == 1 && check_type == RECEIVER_MAP_CHECK) {
 
7087
        AddCheckConstantFunction(expr->holder(), receiver, receiver_map, true);
 
7088
        Drop(1);  // Receiver.
 
7089
        HValue* context = environment()->LookupContext();
 
7090
        HGlobalObject* global_object = new(zone()) HGlobalObject(context);
 
7091
        AddInstruction(global_object);
 
7092
        HRandom* result = new(zone()) HRandom(global_object);
 
7093
        ast_context()->ReturnInstruction(result, expr->id());
 
7094
        return true;
 
7095
      }
 
7096
      break;
 
7097
    case kMathMax:
 
7098
    case kMathMin:
 
7099
      if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
 
7100
        AddCheckConstantFunction(expr->holder(), receiver, receiver_map, true);
 
7101
        HValue* right = Pop();
 
7102
        HValue* left = Pop();
 
7103
        Pop();  // Pop receiver.
 
7104
 
 
7105
        HValue* left_operand = left;
 
7106
        HValue* right_operand = right;
 
7107
 
 
7108
        // If we do not have two integers, we convert to double for comparison.
 
7109
        if (!left->representation().IsInteger32() ||
 
7110
            !right->representation().IsInteger32()) {
 
7111
          if (!left->representation().IsDouble()) {
 
7112
            HChange* left_convert = new(zone()) HChange(
 
7113
                left,
 
7114
                Representation::Double(),
 
7115
                false,  // Do not truncate when converting to double.
 
7116
                true);  // Deoptimize for undefined.
 
7117
            left_convert->SetFlag(HValue::kBailoutOnMinusZero);
 
7118
            left_operand = AddInstruction(left_convert);
 
7119
          }
 
7120
          if (!right->representation().IsDouble()) {
 
7121
            HChange* right_convert = new(zone()) HChange(
 
7122
                right,
 
7123
                Representation::Double(),
 
7124
                false,  // Do not truncate when converting to double.
 
7125
                true);  // Deoptimize for undefined.
 
7126
            right_convert->SetFlag(HValue::kBailoutOnMinusZero);
 
7127
            right_operand = AddInstruction(right_convert);
 
7128
          }
 
7129
        }
 
7130
 
 
7131
        ASSERT(left_operand->representation().Equals(
 
7132
               right_operand->representation()));
 
7133
        ASSERT(!left_operand->representation().IsTagged());
 
7134
 
 
7135
        Token::Value op = (id == kMathMin) ? Token::LT : Token::GT;
 
7136
 
 
7137
        HCompareIDAndBranch* compare =
 
7138
            new(zone()) HCompareIDAndBranch(left_operand, right_operand, op);
 
7139
        compare->SetInputRepresentation(left_operand->representation());
 
7140
 
 
7141
        HBasicBlock* return_left = graph()->CreateBasicBlock();
 
7142
        HBasicBlock* return_right = graph()->CreateBasicBlock();
 
7143
 
 
7144
        compare->SetSuccessorAt(0, return_left);
 
7145
        compare->SetSuccessorAt(1, return_right);
 
7146
        current_block()->Finish(compare);
 
7147
 
 
7148
        set_current_block(return_left);
 
7149
        Push(left);
 
7150
        set_current_block(return_right);
 
7151
        // The branch above always returns the right operand if either of
 
7152
        // them is NaN, but the spec requires that max/min(NaN, X) = NaN.
 
7153
        // We add another branch that checks if the left operand is NaN or not.
 
7154
        if (left_operand->representation().IsDouble()) {
 
7155
          // If left_operand != left_operand then it is NaN.
 
7156
          HCompareIDAndBranch* compare_nan = new(zone()) HCompareIDAndBranch(
 
7157
              left_operand, left_operand, Token::EQ);
 
7158
          compare_nan->SetInputRepresentation(left_operand->representation());
 
7159
          HBasicBlock* left_is_number = graph()->CreateBasicBlock();
 
7160
          HBasicBlock* left_is_nan = graph()->CreateBasicBlock();
 
7161
          compare_nan->SetSuccessorAt(0, left_is_number);
 
7162
          compare_nan->SetSuccessorAt(1, left_is_nan);
 
7163
          current_block()->Finish(compare_nan);
 
7164
          set_current_block(left_is_nan);
 
7165
          Push(left);
 
7166
          set_current_block(left_is_number);
 
7167
          Push(right);
 
7168
          return_right = CreateJoin(left_is_number, left_is_nan, expr->id());
 
7169
        } else {
 
7170
          Push(right);
 
7171
        }
 
7172
 
 
7173
        HBasicBlock* join = CreateJoin(return_left, return_right, expr->id());
 
7174
        set_current_block(join);
 
7175
        ast_context()->ReturnValue(Pop());
 
7176
        return true;
 
7177
      }
 
7178
      break;
 
7179
    default:
 
7180
      // Not yet supported for inlining.
 
7181
      break;
 
7182
  }
 
7183
  return false;
 
7184
}
 
7185
 
 
7186
 
 
7187
bool HGraphBuilder::TryCallApply(Call* expr) {
 
7188
  Expression* callee = expr->expression();
 
7189
  Property* prop = callee->AsProperty();
 
7190
  ASSERT(prop != NULL);
 
7191
 
 
7192
  if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) {
 
7193
    return false;
 
7194
  }
 
7195
  Handle<Map> function_map = expr->GetReceiverTypes()->first();
 
7196
  if (function_map->instance_type() != JS_FUNCTION_TYPE ||
 
7197
      !expr->target()->shared()->HasBuiltinFunctionId() ||
 
7198
      expr->target()->shared()->builtin_function_id() != kFunctionApply) {
 
7199
    return false;
 
7200
  }
 
7201
 
 
7202
  if (info()->scope()->arguments() == NULL) return false;
 
7203
 
 
7204
  ZoneList<Expression*>* args = expr->arguments();
 
7205
  if (args->length() != 2) return false;
 
7206
 
 
7207
  VariableProxy* arg_two = args->at(1)->AsVariableProxy();
 
7208
  if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
 
7209
  HValue* arg_two_value = environment()->Lookup(arg_two->var());
 
7210
  if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
 
7211
 
 
7212
  // Found pattern f.apply(receiver, arguments).
 
7213
  VisitForValue(prop->obj());
 
7214
  if (HasStackOverflow() || current_block() == NULL) return true;
 
7215
  HValue* function = Top();
 
7216
  AddCheckConstantFunction(expr->holder(), function, function_map, true);
 
7217
  Drop(1);
 
7218
 
 
7219
  VisitForValue(args->at(0));
 
7220
  if (HasStackOverflow() || current_block() == NULL) return true;
 
7221
  HValue* receiver = Pop();
 
7222
 
 
7223
  if (function_state()->outer() == NULL) {
 
7224
    HInstruction* elements = AddInstruction(
 
7225
        new(zone()) HArgumentsElements(false));
 
7226
    HInstruction* length =
 
7227
        AddInstruction(new(zone()) HArgumentsLength(elements));
 
7228
    HValue* wrapped_receiver =
 
7229
        AddInstruction(new(zone()) HWrapReceiver(receiver, function));
 
7230
    HInstruction* result =
 
7231
        new(zone()) HApplyArguments(function,
 
7232
                                    wrapped_receiver,
 
7233
                                    length,
 
7234
                                    elements);
 
7235
    result->set_position(expr->position());
 
7236
    ast_context()->ReturnInstruction(result, expr->id());
 
7237
    return true;
 
7238
  } else {
 
7239
    // We are inside inlined function and we know exactly what is inside
 
7240
    // arguments object.
 
7241
    HValue* context = environment()->LookupContext();
 
7242
 
 
7243
    HValue* wrapped_receiver =
 
7244
        AddInstruction(new(zone()) HWrapReceiver(receiver, function));
 
7245
    PushAndAdd(new(zone()) HPushArgument(wrapped_receiver));
 
7246
 
 
7247
    HEnvironment* arguments_env = environment()->arguments_environment();
 
7248
 
 
7249
    int parameter_count = arguments_env->parameter_count();
 
7250
    for (int i = 1; i < arguments_env->parameter_count(); i++) {
 
7251
      PushAndAdd(new(zone()) HPushArgument(arguments_env->Lookup(i)));
 
7252
    }
 
7253
 
 
7254
    HInvokeFunction* call = new(zone()) HInvokeFunction(
 
7255
        context,
 
7256
        function,
 
7257
        parameter_count);
 
7258
    Drop(parameter_count);
 
7259
    call->set_position(expr->position());
 
7260
    ast_context()->ReturnInstruction(call, expr->id());
 
7261
    return true;
 
7262
  }
 
7263
}
 
7264
 
 
7265
 
 
7266
void HGraphBuilder::VisitCall(Call* expr) {
 
7267
  ASSERT(!HasStackOverflow());
 
7268
  ASSERT(current_block() != NULL);
 
7269
  ASSERT(current_block()->HasPredecessor());
 
7270
  Expression* callee = expr->expression();
 
7271
  int argument_count = expr->arguments()->length() + 1;  // Plus receiver.
 
7272
  HInstruction* call = NULL;
 
7273
 
 
7274
  Property* prop = callee->AsProperty();
 
7275
  if (prop != NULL) {
 
7276
    if (!prop->key()->IsPropertyName()) {
 
7277
      // Keyed function call.
 
7278
      CHECK_ALIVE(VisitArgument(prop->obj()));
 
7279
 
 
7280
      CHECK_ALIVE(VisitForValue(prop->key()));
 
7281
      // Push receiver and key like the non-optimized code generator expects it.
 
7282
      HValue* key = Pop();
 
7283
      HValue* receiver = Pop();
 
7284
      Push(key);
 
7285
      Push(receiver);
 
7286
 
 
7287
      CHECK_ALIVE(VisitArgumentList(expr->arguments()));
 
7288
 
 
7289
      HValue* context = environment()->LookupContext();
 
7290
      call = new(zone()) HCallKeyed(context, key, argument_count);
 
7291
      call->set_position(expr->position());
 
7292
      Drop(argument_count + 1);  // 1 is the key.
 
7293
      return ast_context()->ReturnInstruction(call, expr->id());
 
7294
    }
 
7295
 
 
7296
    // Named function call.
 
7297
    expr->RecordTypeFeedback(oracle(), CALL_AS_METHOD);
 
7298
 
 
7299
    if (TryCallApply(expr)) return;
 
7300
 
 
7301
    CHECK_ALIVE(VisitForValue(prop->obj()));
 
7302
    CHECK_ALIVE(VisitExpressions(expr->arguments()));
 
7303
 
 
7304
    Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
 
7305
 
 
7306
    SmallMapList* types = expr->GetReceiverTypes();
 
7307
 
 
7308
    HValue* receiver =
 
7309
        environment()->ExpressionStackAt(expr->arguments()->length());
 
7310
    if (expr->IsMonomorphic()) {
 
7311
      Handle<Map> receiver_map = (types == NULL || types->is_empty())
 
7312
          ? Handle<Map>::null()
 
7313
          : types->first();
 
7314
      if (TryInlineBuiltinMethodCall(expr,
 
7315
                                     receiver,
 
7316
                                     receiver_map,
 
7317
                                     expr->check_type())) {
 
7318
        if (FLAG_trace_inlining) {
 
7319
          PrintF("Inlining builtin ");
 
7320
          expr->target()->ShortPrint();
 
7321
          PrintF("\n");
 
7322
        }
 
7323
        return;
 
7324
      }
 
7325
 
 
7326
      if (CallStubCompiler::HasCustomCallGenerator(expr->target()) ||
 
7327
          expr->check_type() != RECEIVER_MAP_CHECK) {
 
7328
        // When the target has a custom call IC generator, use the IC,
 
7329
        // because it is likely to generate better code.  Also use the IC
 
7330
        // when a primitive receiver check is required.
 
7331
        HValue* context = environment()->LookupContext();
 
7332
        call = PreProcessCall(
 
7333
            new(zone()) HCallNamed(context, name, argument_count));
 
7334
      } else {
 
7335
        AddCheckConstantFunction(expr->holder(), receiver, receiver_map, true);
 
7336
 
 
7337
        if (TryInlineCall(expr)) return;
 
7338
        call = PreProcessCall(
 
7339
            new(zone()) HCallConstantFunction(expr->target(),
 
7340
                                              argument_count));
 
7341
      }
 
7342
    } else if (types != NULL && types->length() > 1) {
 
7343
      ASSERT(expr->check_type() == RECEIVER_MAP_CHECK);
 
7344
      HandlePolymorphicCallNamed(expr, receiver, types, name);
 
7345
      return;
 
7346
 
 
7347
    } else {
 
7348
      HValue* context = environment()->LookupContext();
 
7349
      call = PreProcessCall(
 
7350
          new(zone()) HCallNamed(context, name, argument_count));
 
7351
    }
 
7352
 
 
7353
  } else {
 
7354
    expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION);
 
7355
    VariableProxy* proxy = expr->expression()->AsVariableProxy();
 
7356
    bool global_call = proxy != NULL && proxy->var()->IsUnallocated();
 
7357
 
 
7358
    if (proxy != NULL && proxy->var()->is_possibly_eval()) {
 
7359
      return Bailout("possible direct call to eval");
 
7360
    }
 
7361
 
 
7362
    if (global_call) {
 
7363
      Variable* var = proxy->var();
 
7364
      bool known_global_function = false;
 
7365
      // If there is a global property cell for the name at compile time and
 
7366
      // access check is not enabled we assume that the function will not change
 
7367
      // and generate optimized code for calling the function.
 
7368
      LookupResult lookup(isolate());
 
7369
      GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false);
 
7370
      if (type == kUseCell &&
 
7371
          !info()->global_object()->IsAccessCheckNeeded()) {
 
7372
        Handle<GlobalObject> global(info()->global_object());
 
7373
        known_global_function = expr->ComputeGlobalTarget(global, &lookup);
 
7374
      }
 
7375
      if (known_global_function) {
 
7376
        // Push the global object instead of the global receiver because
 
7377
        // code generated by the full code generator expects it.
 
7378
        HValue* context = environment()->LookupContext();
 
7379
        HGlobalObject* global_object = new(zone()) HGlobalObject(context);
 
7380
        PushAndAdd(global_object);
 
7381
        CHECK_ALIVE(VisitExpressions(expr->arguments()));
 
7382
 
 
7383
        CHECK_ALIVE(VisitForValue(expr->expression()));
 
7384
        HValue* function = Pop();
 
7385
        AddInstruction(new(zone()) HCheckFunction(function, expr->target()));
 
7386
 
 
7387
        // Replace the global object with the global receiver.
 
7388
        HGlobalReceiver* global_receiver =
 
7389
            new(zone()) HGlobalReceiver(global_object);
 
7390
        // Index of the receiver from the top of the expression stack.
 
7391
        const int receiver_index = argument_count - 1;
 
7392
        AddInstruction(global_receiver);
 
7393
        ASSERT(environment()->ExpressionStackAt(receiver_index)->
 
7394
               IsGlobalObject());
 
7395
        environment()->SetExpressionStackAt(receiver_index, global_receiver);
 
7396
 
 
7397
        if (TryInlineBuiltinFunctionCall(expr, false)) {  // Nothing to drop.
 
7398
          if (FLAG_trace_inlining) {
 
7399
            PrintF("Inlining builtin ");
 
7400
            expr->target()->ShortPrint();
 
7401
            PrintF("\n");
 
7402
          }
 
7403
          return;
 
7404
        }
 
7405
        if (TryInlineCall(expr)) return;
 
7406
 
 
7407
        if (expr->target().is_identical_to(info()->closure())) {
 
7408
          graph()->MarkRecursive();
 
7409
        }
 
7410
 
 
7411
        call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(),
 
7412
                                                           argument_count));
 
7413
      } else {
 
7414
        HValue* context = environment()->LookupContext();
 
7415
        HGlobalObject* receiver = new(zone()) HGlobalObject(context);
 
7416
        AddInstruction(receiver);
 
7417
        PushAndAdd(new(zone()) HPushArgument(receiver));
 
7418
        CHECK_ALIVE(VisitArgumentList(expr->arguments()));
 
7419
 
 
7420
        call = new(zone()) HCallGlobal(context, var->name(), argument_count);
 
7421
        Drop(argument_count);
 
7422
      }
 
7423
 
 
7424
    } else if (expr->IsMonomorphic()) {
 
7425
      // The function is on the stack in the unoptimized code during
 
7426
      // evaluation of the arguments.
 
7427
      CHECK_ALIVE(VisitForValue(expr->expression()));
 
7428
      HValue* function = Top();
 
7429
      HValue* context = environment()->LookupContext();
 
7430
      HGlobalObject* global = new(zone()) HGlobalObject(context);
 
7431
      AddInstruction(global);
 
7432
      HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global);
 
7433
      PushAndAdd(receiver);
 
7434
      CHECK_ALIVE(VisitExpressions(expr->arguments()));
 
7435
      AddInstruction(new(zone()) HCheckFunction(function, expr->target()));
 
7436
 
 
7437
      if (TryInlineBuiltinFunctionCall(expr, true)) {  // Drop the function.
 
7438
        if (FLAG_trace_inlining) {
 
7439
          PrintF("Inlining builtin ");
 
7440
          expr->target()->ShortPrint();
 
7441
          PrintF("\n");
 
7442
        }
 
7443
        return;
 
7444
      }
 
7445
 
 
7446
      if (TryInlineCall(expr, true)) {   // Drop function from environment.
 
7447
        return;
 
7448
      } else {
 
7449
        call = PreProcessCall(
 
7450
            new(zone()) HInvokeFunction(context,
 
7451
                                        function,
 
7452
                                        expr->target(),
 
7453
                                        argument_count));
 
7454
        Drop(1);  // The function.
 
7455
      }
 
7456
 
 
7457
    } else {
 
7458
      CHECK_ALIVE(VisitForValue(expr->expression()));
 
7459
      HValue* function = Top();
 
7460
      HValue* context = environment()->LookupContext();
 
7461
      HGlobalObject* global_object = new(zone()) HGlobalObject(context);
 
7462
      AddInstruction(global_object);
 
7463
      HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global_object);
 
7464
      AddInstruction(receiver);
 
7465
      PushAndAdd(new(zone()) HPushArgument(receiver));
 
7466
      CHECK_ALIVE(VisitArgumentList(expr->arguments()));
 
7467
 
 
7468
      call = new(zone()) HCallFunction(context, function, argument_count);
 
7469
      Drop(argument_count + 1);
 
7470
    }
 
7471
  }
 
7472
 
 
7473
  call->set_position(expr->position());
 
7474
  return ast_context()->ReturnInstruction(call, expr->id());
 
7475
}
 
7476
 
 
7477
 
 
7478
// Checks whether allocation using the given constructor can be inlined.
 
7479
static bool IsAllocationInlineable(Handle<JSFunction> constructor) {
 
7480
  return constructor->has_initial_map() &&
 
7481
      constructor->initial_map()->instance_type() == JS_OBJECT_TYPE &&
 
7482
      constructor->initial_map()->instance_size() < HAllocateObject::kMaxSize;
 
7483
}
 
7484
 
 
7485
 
 
7486
void HGraphBuilder::VisitCallNew(CallNew* expr) {
 
7487
  ASSERT(!HasStackOverflow());
 
7488
  ASSERT(current_block() != NULL);
 
7489
  ASSERT(current_block()->HasPredecessor());
 
7490
  expr->RecordTypeFeedback(oracle());
 
7491
  int argument_count = expr->arguments()->length() + 1;  // Plus constructor.
 
7492
  HValue* context = environment()->LookupContext();
 
7493
 
 
7494
  if (FLAG_inline_construct &&
 
7495
      expr->IsMonomorphic() &&
 
7496
      IsAllocationInlineable(expr->target())) {
 
7497
    // The constructor function is on the stack in the unoptimized code
 
7498
    // during evaluation of the arguments.
 
7499
    CHECK_ALIVE(VisitForValue(expr->expression()));
 
7500
    HValue* function = Top();
 
7501
    CHECK_ALIVE(VisitExpressions(expr->arguments()));
 
7502
    Handle<JSFunction> constructor = expr->target();
 
7503
    HValue* check = AddInstruction(
 
7504
        new(zone()) HCheckFunction(function, constructor));
 
7505
 
 
7506
    // Force completion of inobject slack tracking before generating
 
7507
    // allocation code to finalize instance size.
 
7508
    if (constructor->shared()->IsInobjectSlackTrackingInProgress()) {
 
7509
      constructor->shared()->CompleteInobjectSlackTracking();
 
7510
    }
 
7511
 
 
7512
    // Replace the constructor function with a newly allocated receiver.
 
7513
    HInstruction* receiver = new(zone()) HAllocateObject(context, constructor);
 
7514
    // Index of the receiver from the top of the expression stack.
 
7515
    const int receiver_index = argument_count - 1;
 
7516
    AddInstruction(receiver);
 
7517
    ASSERT(environment()->ExpressionStackAt(receiver_index) == function);
 
7518
    environment()->SetExpressionStackAt(receiver_index, receiver);
 
7519
 
 
7520
    if (TryInlineConstruct(expr, receiver)) return;
 
7521
 
 
7522
    // TODO(mstarzinger): For now we remove the previous HAllocateObject and
 
7523
    // add HPushArgument for the arguments in case inlining failed.  What we
 
7524
    // actually should do is emit HInvokeFunction on the constructor instead
 
7525
    // of using HCallNew as a fallback.
 
7526
    receiver->DeleteAndReplaceWith(NULL);
 
7527
    check->DeleteAndReplaceWith(NULL);
 
7528
    environment()->SetExpressionStackAt(receiver_index, function);
 
7529
    HInstruction* call = PreProcessCall(
 
7530
        new(zone()) HCallNew(context, function, argument_count));
 
7531
    call->set_position(expr->position());
 
7532
    return ast_context()->ReturnInstruction(call, expr->id());
 
7533
  } else {
 
7534
    // The constructor function is both an operand to the instruction and an
 
7535
    // argument to the construct call.
 
7536
    CHECK_ALIVE(VisitArgument(expr->expression()));
 
7537
    HValue* constructor = HPushArgument::cast(Top())->argument();
 
7538
    CHECK_ALIVE(VisitArgumentList(expr->arguments()));
 
7539
    HInstruction* call =
 
7540
        new(zone()) HCallNew(context, constructor, argument_count);
 
7541
    Drop(argument_count);
 
7542
    call->set_position(expr->position());
 
7543
    return ast_context()->ReturnInstruction(call, expr->id());
 
7544
  }
 
7545
}
 
7546
 
 
7547
 
 
7548
// Support for generating inlined runtime functions.
 
7549
 
 
7550
// Lookup table for generators for runtime calls that are  generated inline.
 
7551
// Elements of the table are member pointers to functions of HGraphBuilder.
 
7552
#define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize)  \
 
7553
    &HGraphBuilder::Generate##Name,
 
7554
 
 
7555
const HGraphBuilder::InlineFunctionGenerator
 
7556
    HGraphBuilder::kInlineFunctionGenerators[] = {
 
7557
        INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
 
7558
        INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
 
7559
};
 
7560
#undef INLINE_FUNCTION_GENERATOR_ADDRESS
 
7561
 
 
7562
 
 
7563
void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
 
7564
  ASSERT(!HasStackOverflow());
 
7565
  ASSERT(current_block() != NULL);
 
7566
  ASSERT(current_block()->HasPredecessor());
 
7567
  if (expr->is_jsruntime()) {
 
7568
    return Bailout("call to a JavaScript runtime function");
 
7569
  }
 
7570
 
 
7571
  const Runtime::Function* function = expr->function();
 
7572
  ASSERT(function != NULL);
 
7573
  if (function->intrinsic_type == Runtime::INLINE) {
 
7574
    ASSERT(expr->name()->length() > 0);
 
7575
    ASSERT(expr->name()->Get(0) == '_');
 
7576
    // Call to an inline function.
 
7577
    int lookup_index = static_cast<int>(function->function_id) -
 
7578
        static_cast<int>(Runtime::kFirstInlineFunction);
 
7579
    ASSERT(lookup_index >= 0);
 
7580
    ASSERT(static_cast<size_t>(lookup_index) <
 
7581
           ARRAY_SIZE(kInlineFunctionGenerators));
 
7582
    InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index];
 
7583
 
 
7584
    // Call the inline code generator using the pointer-to-member.
 
7585
    (this->*generator)(expr);
 
7586
  } else {
 
7587
    ASSERT(function->intrinsic_type == Runtime::RUNTIME);
 
7588
    CHECK_ALIVE(VisitArgumentList(expr->arguments()));
 
7589
 
 
7590
    HValue* context = environment()->LookupContext();
 
7591
    Handle<String> name = expr->name();
 
7592
    int argument_count = expr->arguments()->length();
 
7593
    HCallRuntime* call =
 
7594
        new(zone()) HCallRuntime(context, name, function, argument_count);
 
7595
    Drop(argument_count);
 
7596
    return ast_context()->ReturnInstruction(call, expr->id());
 
7597
  }
 
7598
}
 
7599
 
 
7600
 
 
7601
void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
 
7602
  ASSERT(!HasStackOverflow());
 
7603
  ASSERT(current_block() != NULL);
 
7604
  ASSERT(current_block()->HasPredecessor());
 
7605
  switch (expr->op()) {
 
7606
    case Token::DELETE: return VisitDelete(expr);
 
7607
    case Token::VOID: return VisitVoid(expr);
 
7608
    case Token::TYPEOF: return VisitTypeof(expr);
 
7609
    case Token::ADD: return VisitAdd(expr);
 
7610
    case Token::SUB: return VisitSub(expr);
 
7611
    case Token::BIT_NOT: return VisitBitNot(expr);
 
7612
    case Token::NOT: return VisitNot(expr);
 
7613
    default: UNREACHABLE();
 
7614
  }
 
7615
}
 
7616
 
 
7617
void HGraphBuilder::VisitDelete(UnaryOperation* expr) {
 
7618
  Property* prop = expr->expression()->AsProperty();
 
7619
  VariableProxy* proxy = expr->expression()->AsVariableProxy();
 
7620
  if (prop != NULL) {
 
7621
    CHECK_ALIVE(VisitForValue(prop->obj()));
 
7622
    CHECK_ALIVE(VisitForValue(prop->key()));
 
7623
    HValue* key = Pop();
 
7624
    HValue* obj = Pop();
 
7625
    HValue* context = environment()->LookupContext();
 
7626
    HDeleteProperty* instr = new(zone()) HDeleteProperty(context, obj, key);
 
7627
    return ast_context()->ReturnInstruction(instr, expr->id());
 
7628
  } else if (proxy != NULL) {
 
7629
    Variable* var = proxy->var();
 
7630
    if (var->IsUnallocated()) {
 
7631
      Bailout("delete with global variable");
 
7632
    } else if (var->IsStackAllocated() || var->IsContextSlot()) {
 
7633
      // Result of deleting non-global variables is false.  'this' is not
 
7634
      // really a variable, though we implement it as one.  The
 
7635
      // subexpression does not have side effects.
 
7636
      HValue* value = var->is_this()
 
7637
          ? graph()->GetConstantTrue()
 
7638
          : graph()->GetConstantFalse();
 
7639
      return ast_context()->ReturnValue(value);
 
7640
    } else {
 
7641
      Bailout("delete with non-global variable");
 
7642
    }
 
7643
  } else {
 
7644
    // Result of deleting non-property, non-variable reference is true.
 
7645
    // Evaluate the subexpression for side effects.
 
7646
    CHECK_ALIVE(VisitForEffect(expr->expression()));
 
7647
    return ast_context()->ReturnValue(graph()->GetConstantTrue());
 
7648
  }
 
7649
}
 
7650
 
 
7651
 
 
7652
void HGraphBuilder::VisitVoid(UnaryOperation* expr) {
 
7653
  CHECK_ALIVE(VisitForEffect(expr->expression()));
 
7654
  return ast_context()->ReturnValue(graph()->GetConstantUndefined());
 
7655
}
 
7656
 
 
7657
 
 
7658
void HGraphBuilder::VisitTypeof(UnaryOperation* expr) {
 
7659
  CHECK_ALIVE(VisitForTypeOf(expr->expression()));
 
7660
  HValue* value = Pop();
 
7661
  HValue* context = environment()->LookupContext();
 
7662
  HInstruction* instr = new(zone()) HTypeof(context, value);
 
7663
  return ast_context()->ReturnInstruction(instr, expr->id());
 
7664
}
 
7665
 
 
7666
 
 
7667
void HGraphBuilder::VisitAdd(UnaryOperation* expr) {
 
7668
  CHECK_ALIVE(VisitForValue(expr->expression()));
 
7669
  HValue* value = Pop();
 
7670
  HValue* context = environment()->LookupContext();
 
7671
  HInstruction* instr =
 
7672
      new(zone()) HMul(context, value, graph_->GetConstant1());
 
7673
  return ast_context()->ReturnInstruction(instr, expr->id());
 
7674
}
 
7675
 
 
7676
 
 
7677
void HGraphBuilder::VisitSub(UnaryOperation* expr) {
 
7678
  CHECK_ALIVE(VisitForValue(expr->expression()));
 
7679
  HValue* value = Pop();
 
7680
  HValue* context = environment()->LookupContext();
 
7681
  HInstruction* instr =
 
7682
      new(zone()) HMul(context, value, graph_->GetConstantMinus1());
 
7683
  TypeInfo info = oracle()->UnaryType(expr);
 
7684
  if (info.IsUninitialized()) {
 
7685
    AddInstruction(new(zone()) HSoftDeoptimize);
 
7686
    current_block()->MarkAsDeoptimizing();
 
7687
    info = TypeInfo::Unknown();
 
7688
  }
 
7689
  Representation rep = ToRepresentation(info);
 
7690
  TraceRepresentation(expr->op(), info, instr, rep);
 
7691
  instr->AssumeRepresentation(rep);
 
7692
  return ast_context()->ReturnInstruction(instr, expr->id());
 
7693
}
 
7694
 
 
7695
 
 
7696
void HGraphBuilder::VisitBitNot(UnaryOperation* expr) {
 
7697
  CHECK_ALIVE(VisitForValue(expr->expression()));
 
7698
  HValue* value = Pop();
 
7699
  TypeInfo info = oracle()->UnaryType(expr);
 
7700
  if (info.IsUninitialized()) {
 
7701
    AddInstruction(new(zone()) HSoftDeoptimize);
 
7702
    current_block()->MarkAsDeoptimizing();
 
7703
  }
 
7704
  HInstruction* instr = new(zone()) HBitNot(value);
 
7705
  return ast_context()->ReturnInstruction(instr, expr->id());
 
7706
}
 
7707
 
 
7708
 
 
7709
void HGraphBuilder::VisitNot(UnaryOperation* expr) {
 
7710
  if (ast_context()->IsTest()) {
 
7711
    TestContext* context = TestContext::cast(ast_context());
 
7712
    VisitForControl(expr->expression(),
 
7713
                    context->if_false(),
 
7714
                    context->if_true());
 
7715
    return;
 
7716
  }
 
7717
 
 
7718
  if (ast_context()->IsEffect()) {
 
7719
    VisitForEffect(expr->expression());
 
7720
    return;
 
7721
  }
 
7722
 
 
7723
  ASSERT(ast_context()->IsValue());
 
7724
  HBasicBlock* materialize_false = graph()->CreateBasicBlock();
 
7725
  HBasicBlock* materialize_true = graph()->CreateBasicBlock();
 
7726
  CHECK_BAILOUT(VisitForControl(expr->expression(),
 
7727
                                materialize_false,
 
7728
                                materialize_true));
 
7729
 
 
7730
  if (materialize_false->HasPredecessor()) {
 
7731
    materialize_false->SetJoinId(expr->MaterializeFalseId());
 
7732
    set_current_block(materialize_false);
 
7733
    Push(graph()->GetConstantFalse());
 
7734
  } else {
 
7735
    materialize_false = NULL;
 
7736
  }
 
7737
 
 
7738
  if (materialize_true->HasPredecessor()) {
 
7739
    materialize_true->SetJoinId(expr->MaterializeTrueId());
 
7740
    set_current_block(materialize_true);
 
7741
    Push(graph()->GetConstantTrue());
 
7742
  } else {
 
7743
    materialize_true = NULL;
 
7744
  }
 
7745
 
 
7746
  HBasicBlock* join =
 
7747
    CreateJoin(materialize_false, materialize_true, expr->id());
 
7748
  set_current_block(join);
 
7749
  if (join != NULL) return ast_context()->ReturnValue(Pop());
 
7750
}
 
7751
 
 
7752
 
 
7753
HInstruction* HGraphBuilder::BuildIncrement(bool returns_original_input,
 
7754
                                            CountOperation* expr) {
 
7755
  // The input to the count operation is on top of the expression stack.
 
7756
  TypeInfo info = oracle()->IncrementType(expr);
 
7757
  Representation rep = ToRepresentation(info);
 
7758
  if (rep.IsTagged()) {
 
7759
    rep = Representation::Integer32();
 
7760
  }
 
7761
 
 
7762
  if (returns_original_input) {
 
7763
    // We need an explicit HValue representing ToNumber(input).  The
 
7764
    // actual HChange instruction we need is (sometimes) added in a later
 
7765
    // phase, so it is not available now to be used as an input to HAdd and
 
7766
    // as the return value.
 
7767
    HInstruction* number_input = new(zone()) HForceRepresentation(Pop(), rep);
 
7768
    AddInstruction(number_input);
 
7769
    Push(number_input);
 
7770
  }
 
7771
 
 
7772
  // The addition has no side effects, so we do not need
 
7773
  // to simulate the expression stack after this instruction.
 
7774
  // Any later failures deopt to the load of the input or earlier.
 
7775
  HConstant* delta = (expr->op() == Token::INC)
 
7776
      ? graph_->GetConstant1()
 
7777
      : graph_->GetConstantMinus1();
 
7778
  HValue* context = environment()->LookupContext();
 
7779
  HInstruction* instr = new(zone()) HAdd(context, Top(), delta);
 
7780
  TraceRepresentation(expr->op(), info, instr, rep);
 
7781
  instr->AssumeRepresentation(rep);
 
7782
  AddInstruction(instr);
 
7783
  return instr;
 
7784
}
 
7785
 
 
7786
 
 
7787
void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
 
7788
  ASSERT(!HasStackOverflow());
 
7789
  ASSERT(current_block() != NULL);
 
7790
  ASSERT(current_block()->HasPredecessor());
 
7791
  Expression* target = expr->expression();
 
7792
  VariableProxy* proxy = target->AsVariableProxy();
 
7793
  Property* prop = target->AsProperty();
 
7794
  if (proxy == NULL && prop == NULL) {
 
7795
    return Bailout("invalid lhs in count operation");
 
7796
  }
 
7797
 
 
7798
  // Match the full code generator stack by simulating an extra stack
 
7799
  // element for postfix operations in a non-effect context.  The return
 
7800
  // value is ToNumber(input).
 
7801
  bool returns_original_input =
 
7802
      expr->is_postfix() && !ast_context()->IsEffect();
 
7803
  HValue* input = NULL;  // ToNumber(original_input).
 
7804
  HValue* after = NULL;  // The result after incrementing or decrementing.
 
7805
 
 
7806
  if (proxy != NULL) {
 
7807
    Variable* var = proxy->var();
 
7808
    if (var->mode() == CONST)  {
 
7809
      return Bailout("unsupported count operation with const");
 
7810
    }
 
7811
    // Argument of the count operation is a variable, not a property.
 
7812
    ASSERT(prop == NULL);
 
7813
    CHECK_ALIVE(VisitForValue(target));
 
7814
 
 
7815
    after = BuildIncrement(returns_original_input, expr);
 
7816
    input = returns_original_input ? Top() : Pop();
 
7817
    Push(after);
 
7818
 
 
7819
    switch (var->location()) {
 
7820
      case Variable::UNALLOCATED:
 
7821
        HandleGlobalVariableAssignment(var,
 
7822
                                       after,
 
7823
                                       expr->position(),
 
7824
                                       expr->AssignmentId());
 
7825
        break;
 
7826
 
 
7827
      case Variable::PARAMETER:
 
7828
      case Variable::LOCAL:
 
7829
        Bind(var, after);
 
7830
        break;
 
7831
 
 
7832
      case Variable::CONTEXT: {
 
7833
        // Bail out if we try to mutate a parameter value in a function
 
7834
        // using the arguments object.  We do not (yet) correctly handle the
 
7835
        // arguments property of the function.
 
7836
        if (info()->scope()->arguments() != NULL) {
 
7837
          // Parameters will rewrite to context slots.  We have no direct
 
7838
          // way to detect that the variable is a parameter so we use a
 
7839
          // linear search of the parameter list.
 
7840
          int count = info()->scope()->num_parameters();
 
7841
          for (int i = 0; i < count; ++i) {
 
7842
            if (var == info()->scope()->parameter(i)) {
 
7843
              return Bailout("assignment to parameter in arguments object");
 
7844
            }
 
7845
          }
 
7846
        }
 
7847
 
 
7848
        HValue* context = BuildContextChainWalk(var);
 
7849
        HStoreContextSlot::Mode mode =
 
7850
            (var->mode() == LET || var->mode() == CONST_HARMONY)
 
7851
            ? HStoreContextSlot::kCheckDeoptimize : HStoreContextSlot::kNoCheck;
 
7852
        HStoreContextSlot* instr =
 
7853
            new(zone()) HStoreContextSlot(context, var->index(), mode, after);
 
7854
        AddInstruction(instr);
 
7855
        if (instr->HasObservableSideEffects()) {
 
7856
          AddSimulate(expr->AssignmentId());
 
7857
        }
 
7858
        break;
 
7859
      }
 
7860
 
 
7861
      case Variable::LOOKUP:
 
7862
        return Bailout("lookup variable in count operation");
 
7863
    }
 
7864
 
 
7865
  } else {
 
7866
    // Argument of the count operation is a property.
 
7867
    ASSERT(prop != NULL);
 
7868
    prop->RecordTypeFeedback(oracle(), zone());
 
7869
 
 
7870
    if (prop->key()->IsPropertyName()) {
 
7871
      // Named property.
 
7872
      if (returns_original_input) Push(graph_->GetConstantUndefined());
 
7873
 
 
7874
      CHECK_ALIVE(VisitForValue(prop->obj()));
 
7875
      HValue* object = Top();
 
7876
 
 
7877
      Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
 
7878
      Handle<Map> map;
 
7879
      HInstruction* load;
 
7880
      bool monomorphic = prop->IsMonomorphic();
 
7881
      if (monomorphic) {
 
7882
        map = prop->GetReceiverTypes()->first();
 
7883
        if (map->is_dictionary_map()) monomorphic = false;
 
7884
      }
 
7885
      if (monomorphic) {
 
7886
        Handle<AccessorPair> accessors;
 
7887
        Handle<JSObject> holder;
 
7888
        if (LookupAccessorPair(map, name, &accessors, &holder)) {
 
7889
          load = BuildCallGetter(object, map, accessors, holder);
 
7890
        } else {
 
7891
          load = BuildLoadNamedMonomorphic(object, name, prop, map);
 
7892
        }
 
7893
      } else {
 
7894
        load = BuildLoadNamedGeneric(object, name, prop);
 
7895
      }
 
7896
      PushAndAdd(load);
 
7897
      if (load->HasObservableSideEffects()) AddSimulate(expr->CountId());
 
7898
 
 
7899
      after = BuildIncrement(returns_original_input, expr);
 
7900
      input = Pop();
 
7901
 
 
7902
      HInstruction* store;
 
7903
      if (!monomorphic) {
 
7904
        // If we don't know the monomorphic type, do a generic store.
 
7905
        CHECK_ALIVE(store = BuildStoreNamedGeneric(object, name, after));
 
7906
      } else {
 
7907
        Handle<AccessorPair> accessors;
 
7908
        Handle<JSObject> holder;
 
7909
        // Because we re-use the load type feedback, there might be no setter.
 
7910
        if (LookupAccessorPair(map, name, &accessors, &holder) &&
 
7911
            accessors->setter()->IsJSFunction()) {
 
7912
          store = BuildCallSetter(object, after, map, accessors, holder);
 
7913
        } else {
 
7914
          CHECK_ALIVE(store = BuildStoreNamedMonomorphic(object,
 
7915
                                                         name,
 
7916
                                                         after,
 
7917
                                                         map));
 
7918
        }
 
7919
      }
 
7920
      AddInstruction(store);
 
7921
 
 
7922
      // Overwrite the receiver in the bailout environment with the result
 
7923
      // of the operation, and the placeholder with the original value if
 
7924
      // necessary.
 
7925
      environment()->SetExpressionStackAt(0, after);
 
7926
      if (returns_original_input) environment()->SetExpressionStackAt(1, input);
 
7927
      if (store->HasObservableSideEffects()) AddSimulate(expr->AssignmentId());
 
7928
 
 
7929
    } else {
 
7930
      // Keyed property.
 
7931
      if (returns_original_input) Push(graph_->GetConstantUndefined());
 
7932
 
 
7933
      CHECK_ALIVE(VisitForValue(prop->obj()));
 
7934
      CHECK_ALIVE(VisitForValue(prop->key()));
 
7935
      HValue* obj = environment()->ExpressionStackAt(1);
 
7936
      HValue* key = environment()->ExpressionStackAt(0);
 
7937
 
 
7938
      bool has_side_effects = false;
 
7939
      HValue* load = HandleKeyedElementAccess(
 
7940
          obj, key, NULL, prop, expr->CountId(), RelocInfo::kNoPosition,
 
7941
          false,  // is_store
 
7942
          &has_side_effects);
 
7943
      Push(load);
 
7944
      if (has_side_effects) AddSimulate(expr->CountId());
 
7945
 
 
7946
      after = BuildIncrement(returns_original_input, expr);
 
7947
      input = Pop();
 
7948
 
 
7949
      expr->RecordTypeFeedback(oracle(), zone());
 
7950
      HandleKeyedElementAccess(obj, key, after, expr, expr->AssignmentId(),
 
7951
                               RelocInfo::kNoPosition,
 
7952
                               true,  // is_store
 
7953
                               &has_side_effects);
 
7954
 
 
7955
      // Drop the key from the bailout environment.  Overwrite the receiver
 
7956
      // with the result of the operation, and the placeholder with the
 
7957
      // original value if necessary.
 
7958
      Drop(1);
 
7959
      environment()->SetExpressionStackAt(0, after);
 
7960
      if (returns_original_input) environment()->SetExpressionStackAt(1, input);
 
7961
      ASSERT(has_side_effects);  // Stores always have side effects.
 
7962
      AddSimulate(expr->AssignmentId());
 
7963
    }
 
7964
  }
 
7965
 
 
7966
  Drop(returns_original_input ? 2 : 1);
 
7967
  return ast_context()->ReturnValue(expr->is_postfix() ? input : after);
 
7968
}
 
7969
 
 
7970
 
 
7971
HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* context,
 
7972
                                                        HValue* string,
 
7973
                                                        HValue* index) {
 
7974
  AddInstruction(new(zone()) HCheckNonSmi(string));
 
7975
  AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
 
7976
  HStringLength* length = new(zone()) HStringLength(string);
 
7977
  AddInstruction(length);
 
7978
  HInstruction* checked_index =
 
7979
      AddInstruction(new(zone()) HBoundsCheck(index, length));
 
7980
  return new(zone()) HStringCharCodeAt(context, string, checked_index);
 
7981
}
 
7982
 
 
7983
 
 
7984
HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr,
 
7985
                                                  HValue* left,
 
7986
                                                  HValue* right) {
 
7987
  HValue* context = environment()->LookupContext();
 
7988
  TypeInfo info = oracle()->BinaryType(expr);
 
7989
  if (info.IsUninitialized()) {
 
7990
    AddInstruction(new(zone()) HSoftDeoptimize);
 
7991
    current_block()->MarkAsDeoptimizing();
 
7992
    info = TypeInfo::Unknown();
 
7993
  }
 
7994
  HInstruction* instr = NULL;
 
7995
  switch (expr->op()) {
 
7996
    case Token::ADD:
 
7997
      if (info.IsString()) {
 
7998
        AddInstruction(new(zone()) HCheckNonSmi(left));
 
7999
        AddInstruction(HCheckInstanceType::NewIsString(left, zone()));
 
8000
        AddInstruction(new(zone()) HCheckNonSmi(right));
 
8001
        AddInstruction(HCheckInstanceType::NewIsString(right, zone()));
 
8002
        instr = new(zone()) HStringAdd(context, left, right);
 
8003
      } else {
 
8004
        instr = HAdd::NewHAdd(zone(), context, left, right);
 
8005
      }
 
8006
      break;
 
8007
    case Token::SUB:
 
8008
      instr = HSub::NewHSub(zone(), context, left, right);
 
8009
      break;
 
8010
    case Token::MUL:
 
8011
      instr = HMul::NewHMul(zone(), context, left, right);
 
8012
      break;
 
8013
    case Token::MOD:
 
8014
      instr = HMod::NewHMod(zone(), context, left, right);
 
8015
      break;
 
8016
    case Token::DIV:
 
8017
      instr = HDiv::NewHDiv(zone(), context, left, right);
 
8018
      break;
 
8019
    case Token::BIT_XOR:
 
8020
    case Token::BIT_AND:
 
8021
    case Token::BIT_OR:
 
8022
      instr = HBitwise::NewHBitwise(zone(), expr->op(), context, left, right);
 
8023
      break;
 
8024
    case Token::SAR:
 
8025
      instr = HSar::NewHSar(zone(), context, left, right);
 
8026
      break;
 
8027
    case Token::SHR:
 
8028
      instr = HShr::NewHShr(zone(), context, left, right);
 
8029
      break;
 
8030
    case Token::SHL:
 
8031
      instr = HShl::NewHShl(zone(), context, left, right);
 
8032
      break;
 
8033
    default:
 
8034
      UNREACHABLE();
 
8035
  }
 
8036
 
 
8037
  // If we hit an uninitialized binary op stub we will get type info
 
8038
  // for a smi operation. If one of the operands is a constant string
 
8039
  // do not generate code assuming it is a smi operation.
 
8040
  if (info.IsSmi() &&
 
8041
      ((left->IsConstant() && HConstant::cast(left)->handle()->IsString()) ||
 
8042
       (right->IsConstant() && HConstant::cast(right)->handle()->IsString()))) {
 
8043
    return instr;
 
8044
  }
 
8045
  Representation rep = ToRepresentation(info);
 
8046
  // We only generate either int32 or generic tagged bitwise operations.
 
8047
  if (instr->IsBitwiseBinaryOperation()) {
 
8048
    HBitwiseBinaryOperation::cast(instr)->
 
8049
         InitializeObservedInputRepresentation(rep);
 
8050
    if (rep.IsDouble()) rep = Representation::Integer32();
 
8051
  }
 
8052
  TraceRepresentation(expr->op(), info, instr, rep);
 
8053
  instr->AssumeRepresentation(rep);
 
8054
  return instr;
 
8055
}
 
8056
 
 
8057
 
 
8058
// Check for the form (%_ClassOf(foo) === 'BarClass').
 
8059
static bool IsClassOfTest(CompareOperation* expr) {
 
8060
  if (expr->op() != Token::EQ_STRICT) return false;
 
8061
  CallRuntime* call = expr->left()->AsCallRuntime();
 
8062
  if (call == NULL) return false;
 
8063
  Literal* literal = expr->right()->AsLiteral();
 
8064
  if (literal == NULL) return false;
 
8065
  if (!literal->handle()->IsString()) return false;
 
8066
  if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false;
 
8067
  ASSERT(call->arguments()->length() == 1);
 
8068
  return true;
 
8069
}
 
8070
 
 
8071
 
 
8072
void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
 
8073
  ASSERT(!HasStackOverflow());
 
8074
  ASSERT(current_block() != NULL);
 
8075
  ASSERT(current_block()->HasPredecessor());
 
8076
  switch (expr->op()) {
 
8077
    case Token::COMMA:
 
8078
      return VisitComma(expr);
 
8079
    case Token::OR:
 
8080
    case Token::AND:
 
8081
      return VisitLogicalExpression(expr);
 
8082
    default:
 
8083
      return VisitArithmeticExpression(expr);
 
8084
  }
 
8085
}
 
8086
 
 
8087
 
 
8088
void HGraphBuilder::VisitComma(BinaryOperation* expr) {
 
8089
  CHECK_ALIVE(VisitForEffect(expr->left()));
 
8090
  // Visit the right subexpression in the same AST context as the entire
 
8091
  // expression.
 
8092
  Visit(expr->right());
 
8093
}
 
8094
 
 
8095
 
 
8096
void HGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
 
8097
  bool is_logical_and = expr->op() == Token::AND;
 
8098
  if (ast_context()->IsTest()) {
 
8099
    TestContext* context = TestContext::cast(ast_context());
 
8100
    // Translate left subexpression.
 
8101
    HBasicBlock* eval_right = graph()->CreateBasicBlock();
 
8102
    if (is_logical_and) {
 
8103
      CHECK_BAILOUT(VisitForControl(expr->left(),
 
8104
                                    eval_right,
 
8105
                                    context->if_false()));
 
8106
    } else {
 
8107
      CHECK_BAILOUT(VisitForControl(expr->left(),
 
8108
                                    context->if_true(),
 
8109
                                    eval_right));
 
8110
    }
 
8111
 
 
8112
    // Translate right subexpression by visiting it in the same AST
 
8113
    // context as the entire expression.
 
8114
    if (eval_right->HasPredecessor()) {
 
8115
      eval_right->SetJoinId(expr->RightId());
 
8116
      set_current_block(eval_right);
 
8117
      Visit(expr->right());
 
8118
    }
 
8119
 
 
8120
  } else if (ast_context()->IsValue()) {
 
8121
    CHECK_ALIVE(VisitForValue(expr->left()));
 
8122
    ASSERT(current_block() != NULL);
 
8123
 
 
8124
    // We need an extra block to maintain edge-split form.
 
8125
    HBasicBlock* empty_block = graph()->CreateBasicBlock();
 
8126
    HBasicBlock* eval_right = graph()->CreateBasicBlock();
 
8127
    unsigned test_id = expr->left()->test_id();
 
8128
    ToBooleanStub::Types expected(oracle()->ToBooleanTypes(test_id));
 
8129
    HBranch* test = is_logical_and
 
8130
      ? new(zone()) HBranch(Top(), eval_right, empty_block, expected)
 
8131
      : new(zone()) HBranch(Top(), empty_block, eval_right, expected);
 
8132
    current_block()->Finish(test);
 
8133
 
 
8134
    set_current_block(eval_right);
 
8135
    Drop(1);  // Value of the left subexpression.
 
8136
    CHECK_BAILOUT(VisitForValue(expr->right()));
 
8137
 
 
8138
    HBasicBlock* join_block =
 
8139
      CreateJoin(empty_block, current_block(), expr->id());
 
8140
    set_current_block(join_block);
 
8141
    return ast_context()->ReturnValue(Pop());
 
8142
 
 
8143
  } else {
 
8144
    ASSERT(ast_context()->IsEffect());
 
8145
    // In an effect context, we don't need the value of the left subexpression,
 
8146
    // only its control flow and side effects.  We need an extra block to
 
8147
    // maintain edge-split form.
 
8148
    HBasicBlock* empty_block = graph()->CreateBasicBlock();
 
8149
    HBasicBlock* right_block = graph()->CreateBasicBlock();
 
8150
    if (is_logical_and) {
 
8151
      CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block));
 
8152
    } else {
 
8153
      CHECK_BAILOUT(VisitForControl(expr->left(), empty_block, right_block));
 
8154
    }
 
8155
 
 
8156
    // TODO(kmillikin): Find a way to fix this.  It's ugly that there are
 
8157
    // actually two empty blocks (one here and one inserted by
 
8158
    // TestContext::BuildBranch, and that they both have an HSimulate though the
 
8159
    // second one is not a merge node, and that we really have no good AST ID to
 
8160
    // put on that first HSimulate.
 
8161
 
 
8162
    if (empty_block->HasPredecessor()) {
 
8163
      empty_block->SetJoinId(expr->id());
 
8164
    } else {
 
8165
      empty_block = NULL;
 
8166
    }
 
8167
 
 
8168
    if (right_block->HasPredecessor()) {
 
8169
      right_block->SetJoinId(expr->RightId());
 
8170
      set_current_block(right_block);
 
8171
      CHECK_BAILOUT(VisitForEffect(expr->right()));
 
8172
      right_block = current_block();
 
8173
    } else {
 
8174
      right_block = NULL;
 
8175
    }
 
8176
 
 
8177
    HBasicBlock* join_block =
 
8178
      CreateJoin(empty_block, right_block, expr->id());
 
8179
    set_current_block(join_block);
 
8180
    // We did not materialize any value in the predecessor environments,
 
8181
    // so there is no need to handle it here.
 
8182
  }
 
8183
}
 
8184
 
 
8185
 
 
8186
void HGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) {
 
8187
  CHECK_ALIVE(VisitForValue(expr->left()));
 
8188
  CHECK_ALIVE(VisitForValue(expr->right()));
 
8189
  HValue* right = Pop();
 
8190
  HValue* left = Pop();
 
8191
  HInstruction* instr = BuildBinaryOperation(expr, left, right);
 
8192
  instr->set_position(expr->position());
 
8193
  return ast_context()->ReturnInstruction(instr, expr->id());
 
8194
}
 
8195
 
 
8196
 
 
8197
void HGraphBuilder::TraceRepresentation(Token::Value op,
 
8198
                                        TypeInfo info,
 
8199
                                        HValue* value,
 
8200
                                        Representation rep) {
 
8201
  if (!FLAG_trace_representation) return;
 
8202
  // TODO(svenpanne) Under which circumstances are we actually not flexible?
 
8203
  // At first glance, this looks a bit weird...
 
8204
  bool flexible = value->CheckFlag(HValue::kFlexibleRepresentation);
 
8205
  PrintF("Operation %s has type info %s, %schange representation assumption "
 
8206
         "for %s (ID %d) from %s to %s\n",
 
8207
         Token::Name(op),
 
8208
         info.ToString(),
 
8209
         flexible ? "" : " DO NOT ",
 
8210
         value->Mnemonic(),
 
8211
         graph_->GetMaximumValueID(),
 
8212
         value->representation().Mnemonic(),
 
8213
         rep.Mnemonic());
 
8214
}
 
8215
 
 
8216
 
 
8217
Representation HGraphBuilder::ToRepresentation(TypeInfo info) {
 
8218
  if (info.IsSmi()) return Representation::Integer32();
 
8219
  if (info.IsInteger32()) return Representation::Integer32();
 
8220
  if (info.IsDouble()) return Representation::Double();
 
8221
  if (info.IsNumber()) return Representation::Double();
 
8222
  return Representation::Tagged();
 
8223
}
 
8224
 
 
8225
 
 
8226
void HGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr,
 
8227
                                               HTypeof* typeof_expr,
 
8228
                                               Handle<String> check) {
 
8229
  // Note: The HTypeof itself is removed during canonicalization, if possible.
 
8230
  HValue* value = typeof_expr->value();
 
8231
  HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(value, check);
 
8232
  instr->set_position(expr->position());
 
8233
  return ast_context()->ReturnControl(instr, expr->id());
 
8234
}
 
8235
 
 
8236
 
 
8237
static bool MatchLiteralCompareNil(HValue* left,
 
8238
                                   Token::Value op,
 
8239
                                   HValue* right,
 
8240
                                   Handle<Object> nil,
 
8241
                                   HValue** expr) {
 
8242
  if (left->IsConstant() &&
 
8243
      HConstant::cast(left)->handle().is_identical_to(nil) &&
 
8244
      Token::IsEqualityOp(op)) {
 
8245
    *expr = right;
 
8246
    return true;
 
8247
  }
 
8248
  return false;
 
8249
}
 
8250
 
 
8251
 
 
8252
static bool MatchLiteralCompareTypeof(HValue* left,
 
8253
                                      Token::Value op,
 
8254
                                      HValue* right,
 
8255
                                      HTypeof** typeof_expr,
 
8256
                                      Handle<String>* check) {
 
8257
  if (left->IsTypeof() &&
 
8258
      Token::IsEqualityOp(op) &&
 
8259
      right->IsConstant() &&
 
8260
      HConstant::cast(right)->handle()->IsString()) {
 
8261
    *typeof_expr = HTypeof::cast(left);
 
8262
    *check = Handle<String>::cast(HConstant::cast(right)->handle());
 
8263
    return true;
 
8264
  }
 
8265
  return false;
 
8266
}
 
8267
 
 
8268
 
 
8269
static bool IsLiteralCompareTypeof(HValue* left,
 
8270
                                   Token::Value op,
 
8271
                                   HValue* right,
 
8272
                                   HTypeof** typeof_expr,
 
8273
                                   Handle<String>* check) {
 
8274
  return MatchLiteralCompareTypeof(left, op, right, typeof_expr, check) ||
 
8275
      MatchLiteralCompareTypeof(right, op, left, typeof_expr, check);
 
8276
}
 
8277
 
 
8278
 
 
8279
static bool IsLiteralCompareNil(HValue* left,
 
8280
                                Token::Value op,
 
8281
                                HValue* right,
 
8282
                                Handle<Object> nil,
 
8283
                                HValue** expr) {
 
8284
  return MatchLiteralCompareNil(left, op, right, nil, expr) ||
 
8285
      MatchLiteralCompareNil(right, op, left, nil, expr);
 
8286
}
 
8287
 
 
8288
 
 
8289
static bool IsLiteralCompareBool(HValue* left,
 
8290
                                 Token::Value op,
 
8291
                                 HValue* right) {
 
8292
  return op == Token::EQ_STRICT &&
 
8293
      ((left->IsConstant() && HConstant::cast(left)->handle()->IsBoolean()) ||
 
8294
       (right->IsConstant() && HConstant::cast(right)->handle()->IsBoolean()));
 
8295
}
 
8296
 
 
8297
 
 
8298
void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
 
8299
  ASSERT(!HasStackOverflow());
 
8300
  ASSERT(current_block() != NULL);
 
8301
  ASSERT(current_block()->HasPredecessor());
 
8302
  if (IsClassOfTest(expr)) {
 
8303
    CallRuntime* call = expr->left()->AsCallRuntime();
 
8304
    ASSERT(call->arguments()->length() == 1);
 
8305
    CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
8306
    HValue* value = Pop();
 
8307
    Literal* literal = expr->right()->AsLiteral();
 
8308
    Handle<String> rhs = Handle<String>::cast(literal->handle());
 
8309
    HClassOfTestAndBranch* instr =
 
8310
        new(zone()) HClassOfTestAndBranch(value, rhs);
 
8311
    instr->set_position(expr->position());
 
8312
    return ast_context()->ReturnControl(instr, expr->id());
 
8313
  }
 
8314
 
 
8315
  TypeInfo type_info = oracle()->CompareType(expr);
 
8316
  // Check if this expression was ever executed according to type feedback.
 
8317
  // Note that for the special typeof/null/undefined cases we get unknown here.
 
8318
  if (type_info.IsUninitialized()) {
 
8319
    AddInstruction(new(zone()) HSoftDeoptimize);
 
8320
    current_block()->MarkAsDeoptimizing();
 
8321
    type_info = TypeInfo::Unknown();
 
8322
  }
 
8323
 
 
8324
  CHECK_ALIVE(VisitForValue(expr->left()));
 
8325
  CHECK_ALIVE(VisitForValue(expr->right()));
 
8326
 
 
8327
  HValue* context = environment()->LookupContext();
 
8328
  HValue* right = Pop();
 
8329
  HValue* left = Pop();
 
8330
  Token::Value op = expr->op();
 
8331
 
 
8332
  HTypeof* typeof_expr = NULL;
 
8333
  Handle<String> check;
 
8334
  if (IsLiteralCompareTypeof(left, op, right, &typeof_expr, &check)) {
 
8335
    return HandleLiteralCompareTypeof(expr, typeof_expr, check);
 
8336
  }
 
8337
  HValue* sub_expr = NULL;
 
8338
  Factory* f = graph()->isolate()->factory();
 
8339
  if (IsLiteralCompareNil(left, op, right, f->undefined_value(), &sub_expr)) {
 
8340
    return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue);
 
8341
  }
 
8342
  if (IsLiteralCompareNil(left, op, right, f->null_value(), &sub_expr)) {
 
8343
    return HandleLiteralCompareNil(expr, sub_expr, kNullValue);
 
8344
  }
 
8345
  if (IsLiteralCompareBool(left, op, right)) {
 
8346
    HCompareObjectEqAndBranch* result =
 
8347
        new(zone()) HCompareObjectEqAndBranch(left, right);
 
8348
    result->set_position(expr->position());
 
8349
    return ast_context()->ReturnControl(result, expr->id());
 
8350
  }
 
8351
 
 
8352
  if (op == Token::INSTANCEOF) {
 
8353
    // Check to see if the rhs of the instanceof is a global function not
 
8354
    // residing in new space. If it is we assume that the function will stay the
 
8355
    // same.
 
8356
    Handle<JSFunction> target = Handle<JSFunction>::null();
 
8357
    VariableProxy* proxy = expr->right()->AsVariableProxy();
 
8358
    bool global_function = (proxy != NULL) && proxy->var()->IsUnallocated();
 
8359
    if (global_function &&
 
8360
        info()->has_global_object() &&
 
8361
        !info()->global_object()->IsAccessCheckNeeded()) {
 
8362
      Handle<String> name = proxy->name();
 
8363
      Handle<GlobalObject> global(info()->global_object());
 
8364
      LookupResult lookup(isolate());
 
8365
      global->Lookup(*name, &lookup);
 
8366
      if (lookup.IsNormal() && lookup.GetValue()->IsJSFunction()) {
 
8367
        Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue()));
 
8368
        // If the function is in new space we assume it's more likely to
 
8369
        // change and thus prefer the general IC code.
 
8370
        if (!isolate()->heap()->InNewSpace(*candidate)) {
 
8371
          target = candidate;
 
8372
        }
 
8373
      }
 
8374
    }
 
8375
 
 
8376
    // If the target is not null we have found a known global function that is
 
8377
    // assumed to stay the same for this instanceof.
 
8378
    if (target.is_null()) {
 
8379
      HInstanceOf* result = new(zone()) HInstanceOf(context, left, right);
 
8380
      result->set_position(expr->position());
 
8381
      return ast_context()->ReturnInstruction(result, expr->id());
 
8382
    } else {
 
8383
      AddInstruction(new(zone()) HCheckFunction(right, target));
 
8384
      HInstanceOfKnownGlobal* result =
 
8385
          new(zone()) HInstanceOfKnownGlobal(context, left, target);
 
8386
      result->set_position(expr->position());
 
8387
      return ast_context()->ReturnInstruction(result, expr->id());
 
8388
    }
 
8389
  } else if (op == Token::IN) {
 
8390
    HIn* result = new(zone()) HIn(context, left, right);
 
8391
    result->set_position(expr->position());
 
8392
    return ast_context()->ReturnInstruction(result, expr->id());
 
8393
  } else if (type_info.IsNonPrimitive()) {
 
8394
    switch (op) {
 
8395
      case Token::EQ:
 
8396
      case Token::EQ_STRICT: {
 
8397
        // Can we get away with map check and not instance type check?
 
8398
        Handle<Map> map = oracle()->GetCompareMap(expr);
 
8399
        if (!map.is_null()) {
 
8400
          AddInstruction(new(zone()) HCheckNonSmi(left));
 
8401
          AddInstruction(HCheckMaps::NewWithTransitions(left, map, zone()));
 
8402
          AddInstruction(new(zone()) HCheckNonSmi(right));
 
8403
          AddInstruction(HCheckMaps::NewWithTransitions(right, map, zone()));
 
8404
          HCompareObjectEqAndBranch* result =
 
8405
              new(zone()) HCompareObjectEqAndBranch(left, right);
 
8406
          result->set_position(expr->position());
 
8407
          return ast_context()->ReturnControl(result, expr->id());
 
8408
        } else {
 
8409
          AddInstruction(new(zone()) HCheckNonSmi(left));
 
8410
          AddInstruction(HCheckInstanceType::NewIsSpecObject(left, zone()));
 
8411
          AddInstruction(new(zone()) HCheckNonSmi(right));
 
8412
          AddInstruction(HCheckInstanceType::NewIsSpecObject(right, zone()));
 
8413
          HCompareObjectEqAndBranch* result =
 
8414
              new(zone()) HCompareObjectEqAndBranch(left, right);
 
8415
          result->set_position(expr->position());
 
8416
          return ast_context()->ReturnControl(result, expr->id());
 
8417
        }
 
8418
      }
 
8419
      default:
 
8420
        return Bailout("Unsupported non-primitive compare");
 
8421
    }
 
8422
  } else if (type_info.IsString() && oracle()->IsSymbolCompare(expr) &&
 
8423
             (op == Token::EQ || op == Token::EQ_STRICT)) {
 
8424
    AddInstruction(new(zone()) HCheckNonSmi(left));
 
8425
    AddInstruction(HCheckInstanceType::NewIsSymbol(left, zone()));
 
8426
    AddInstruction(new(zone()) HCheckNonSmi(right));
 
8427
    AddInstruction(HCheckInstanceType::NewIsSymbol(right, zone()));
 
8428
    HCompareObjectEqAndBranch* result =
 
8429
        new(zone()) HCompareObjectEqAndBranch(left, right);
 
8430
    result->set_position(expr->position());
 
8431
    return ast_context()->ReturnControl(result, expr->id());
 
8432
  } else {
 
8433
    Representation r = ToRepresentation(type_info);
 
8434
    if (r.IsTagged()) {
 
8435
      HCompareGeneric* result =
 
8436
          new(zone()) HCompareGeneric(context, left, right, op);
 
8437
      result->set_position(expr->position());
 
8438
      return ast_context()->ReturnInstruction(result, expr->id());
 
8439
    } else {
 
8440
      HCompareIDAndBranch* result =
 
8441
          new(zone()) HCompareIDAndBranch(left, right, op);
 
8442
      result->set_position(expr->position());
 
8443
      result->SetInputRepresentation(r);
 
8444
      return ast_context()->ReturnControl(result, expr->id());
 
8445
    }
 
8446
  }
 
8447
}
 
8448
 
 
8449
 
 
8450
void HGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
 
8451
                                            HValue* value,
 
8452
                                            NilValue nil) {
 
8453
  ASSERT(!HasStackOverflow());
 
8454
  ASSERT(current_block() != NULL);
 
8455
  ASSERT(current_block()->HasPredecessor());
 
8456
  EqualityKind kind =
 
8457
      expr->op() == Token::EQ_STRICT ? kStrictEquality : kNonStrictEquality;
 
8458
  HIsNilAndBranch* instr = new(zone()) HIsNilAndBranch(value, kind, nil);
 
8459
  instr->set_position(expr->position());
 
8460
  return ast_context()->ReturnControl(instr, expr->id());
 
8461
}
 
8462
 
 
8463
 
 
8464
HInstruction* HGraphBuilder::BuildThisFunction() {
 
8465
  // If we share optimized code between different closures, the
 
8466
  // this-function is not a constant, except inside an inlined body.
 
8467
  if (function_state()->outer() != NULL) {
 
8468
      return new(zone()) HConstant(
 
8469
          function_state()->compilation_info()->closure(),
 
8470
          Representation::Tagged());
 
8471
  } else {
 
8472
      return new(zone()) HThisFunction;
 
8473
  }
 
8474
}
 
8475
 
 
8476
 
 
8477
void HGraphBuilder::VisitThisFunction(ThisFunction* expr) {
 
8478
  ASSERT(!HasStackOverflow());
 
8479
  ASSERT(current_block() != NULL);
 
8480
  ASSERT(current_block()->HasPredecessor());
 
8481
  HInstruction* instr = BuildThisFunction();
 
8482
  return ast_context()->ReturnInstruction(instr, expr->id());
 
8483
}
 
8484
 
 
8485
 
 
8486
void HGraphBuilder::VisitDeclarations(ZoneList<Declaration*>* declarations) {
 
8487
  ASSERT(globals_.is_empty());
 
8488
  AstVisitor::VisitDeclarations(declarations);
 
8489
  if (!globals_.is_empty()) {
 
8490
    Handle<FixedArray> array =
 
8491
       isolate()->factory()->NewFixedArray(globals_.length(), TENURED);
 
8492
    for (int i = 0; i < globals_.length(); ++i) array->set(i, *globals_.at(i));
 
8493
    int flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) |
 
8494
                DeclareGlobalsNativeFlag::encode(info()->is_native()) |
 
8495
                DeclareGlobalsLanguageMode::encode(info()->language_mode());
 
8496
    HInstruction* result = new(zone()) HDeclareGlobals(
 
8497
        environment()->LookupContext(), array, flags);
 
8498
    AddInstruction(result);
 
8499
    globals_.Clear();
 
8500
  }
 
8501
}
 
8502
 
 
8503
 
 
8504
void HGraphBuilder::VisitVariableDeclaration(VariableDeclaration* declaration) {
 
8505
  VariableProxy* proxy = declaration->proxy();
 
8506
  VariableMode mode = declaration->mode();
 
8507
  Variable* variable = proxy->var();
 
8508
  bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
 
8509
  switch (variable->location()) {
 
8510
    case Variable::UNALLOCATED:
 
8511
      globals_.Add(variable->name(), zone());
 
8512
      globals_.Add(variable->binding_needs_init()
 
8513
                       ? isolate()->factory()->the_hole_value()
 
8514
                       : isolate()->factory()->undefined_value(), zone());
 
8515
      return;
 
8516
    case Variable::PARAMETER:
 
8517
    case Variable::LOCAL:
 
8518
      if (hole_init) {
 
8519
        HValue* value = graph()->GetConstantHole();
 
8520
        environment()->Bind(variable, value);
 
8521
      }
 
8522
      break;
 
8523
    case Variable::CONTEXT:
 
8524
      if (hole_init) {
 
8525
        HValue* value = graph()->GetConstantHole();
 
8526
        HValue* context = environment()->LookupContext();
 
8527
        HStoreContextSlot* store = new(zone()) HStoreContextSlot(
 
8528
            context, variable->index(), HStoreContextSlot::kNoCheck, value);
 
8529
        AddInstruction(store);
 
8530
        if (store->HasObservableSideEffects()) AddSimulate(proxy->id());
 
8531
      }
 
8532
      break;
 
8533
    case Variable::LOOKUP:
 
8534
      return Bailout("unsupported lookup slot in declaration");
 
8535
  }
 
8536
}
 
8537
 
 
8538
 
 
8539
void HGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* declaration) {
 
8540
  VariableProxy* proxy = declaration->proxy();
 
8541
  Variable* variable = proxy->var();
 
8542
  switch (variable->location()) {
 
8543
    case Variable::UNALLOCATED: {
 
8544
      globals_.Add(variable->name(), zone());
 
8545
      Handle<SharedFunctionInfo> function =
 
8546
          Compiler::BuildFunctionInfo(declaration->fun(), info()->script());
 
8547
      // Check for stack-overflow exception.
 
8548
      if (function.is_null()) return SetStackOverflow();
 
8549
      globals_.Add(function, zone());
 
8550
      return;
 
8551
    }
 
8552
    case Variable::PARAMETER:
 
8553
    case Variable::LOCAL: {
 
8554
      CHECK_ALIVE(VisitForValue(declaration->fun()));
 
8555
      HValue* value = Pop();
 
8556
      environment()->Bind(variable, value);
 
8557
      break;
 
8558
    }
 
8559
    case Variable::CONTEXT: {
 
8560
      CHECK_ALIVE(VisitForValue(declaration->fun()));
 
8561
      HValue* value = Pop();
 
8562
      HValue* context = environment()->LookupContext();
 
8563
      HStoreContextSlot* store = new(zone()) HStoreContextSlot(
 
8564
          context, variable->index(), HStoreContextSlot::kNoCheck, value);
 
8565
      AddInstruction(store);
 
8566
      if (store->HasObservableSideEffects()) AddSimulate(proxy->id());
 
8567
      break;
 
8568
    }
 
8569
    case Variable::LOOKUP:
 
8570
      return Bailout("unsupported lookup slot in declaration");
 
8571
  }
 
8572
}
 
8573
 
 
8574
 
 
8575
void HGraphBuilder::VisitModuleDeclaration(ModuleDeclaration* declaration) {
 
8576
  UNREACHABLE();
 
8577
}
 
8578
 
 
8579
 
 
8580
void HGraphBuilder::VisitImportDeclaration(ImportDeclaration* declaration) {
 
8581
  UNREACHABLE();
 
8582
}
 
8583
 
 
8584
 
 
8585
void HGraphBuilder::VisitExportDeclaration(ExportDeclaration* declaration) {
 
8586
  UNREACHABLE();
 
8587
}
 
8588
 
 
8589
 
 
8590
void HGraphBuilder::VisitModuleLiteral(ModuleLiteral* module) {
 
8591
  UNREACHABLE();
 
8592
}
 
8593
 
 
8594
 
 
8595
void HGraphBuilder::VisitModuleVariable(ModuleVariable* module) {
 
8596
  UNREACHABLE();
 
8597
}
 
8598
 
 
8599
 
 
8600
void HGraphBuilder::VisitModulePath(ModulePath* module) {
 
8601
  UNREACHABLE();
 
8602
}
 
8603
 
 
8604
 
 
8605
void HGraphBuilder::VisitModuleUrl(ModuleUrl* module) {
 
8606
  UNREACHABLE();
 
8607
}
 
8608
 
 
8609
 
 
8610
// Generators for inline runtime functions.
 
8611
// Support for types.
 
8612
void HGraphBuilder::GenerateIsSmi(CallRuntime* call) {
 
8613
  ASSERT(call->arguments()->length() == 1);
 
8614
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
8615
  HValue* value = Pop();
 
8616
  HIsSmiAndBranch* result = new(zone()) HIsSmiAndBranch(value);
 
8617
  return ast_context()->ReturnControl(result, call->id());
 
8618
}
 
8619
 
 
8620
 
 
8621
void HGraphBuilder::GenerateIsSpecObject(CallRuntime* call) {
 
8622
  ASSERT(call->arguments()->length() == 1);
 
8623
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
8624
  HValue* value = Pop();
 
8625
  HHasInstanceTypeAndBranch* result =
 
8626
      new(zone()) HHasInstanceTypeAndBranch(value,
 
8627
                                            FIRST_SPEC_OBJECT_TYPE,
 
8628
                                            LAST_SPEC_OBJECT_TYPE);
 
8629
  return ast_context()->ReturnControl(result, call->id());
 
8630
}
 
8631
 
 
8632
 
 
8633
void HGraphBuilder::GenerateIsFunction(CallRuntime* call) {
 
8634
  ASSERT(call->arguments()->length() == 1);
 
8635
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
8636
  HValue* value = Pop();
 
8637
  HHasInstanceTypeAndBranch* result =
 
8638
      new(zone()) HHasInstanceTypeAndBranch(value, JS_FUNCTION_TYPE);
 
8639
  return ast_context()->ReturnControl(result, call->id());
 
8640
}
 
8641
 
 
8642
 
 
8643
void HGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) {
 
8644
  ASSERT(call->arguments()->length() == 1);
 
8645
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
8646
  HValue* value = Pop();
 
8647
  HHasCachedArrayIndexAndBranch* result =
 
8648
      new(zone()) HHasCachedArrayIndexAndBranch(value);
 
8649
  return ast_context()->ReturnControl(result, call->id());
 
8650
}
 
8651
 
 
8652
 
 
8653
void HGraphBuilder::GenerateIsArray(CallRuntime* call) {
 
8654
  ASSERT(call->arguments()->length() == 1);
 
8655
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
8656
  HValue* value = Pop();
 
8657
  HHasInstanceTypeAndBranch* result =
 
8658
      new(zone()) HHasInstanceTypeAndBranch(value, JS_ARRAY_TYPE);
 
8659
  return ast_context()->ReturnControl(result, call->id());
 
8660
}
 
8661
 
 
8662
 
 
8663
void HGraphBuilder::GenerateIsRegExp(CallRuntime* call) {
 
8664
  ASSERT(call->arguments()->length() == 1);
 
8665
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
8666
  HValue* value = Pop();
 
8667
  HHasInstanceTypeAndBranch* result =
 
8668
      new(zone()) HHasInstanceTypeAndBranch(value, JS_REGEXP_TYPE);
 
8669
  return ast_context()->ReturnControl(result, call->id());
 
8670
}
 
8671
 
 
8672
 
 
8673
void HGraphBuilder::GenerateIsObject(CallRuntime* call) {
 
8674
  ASSERT(call->arguments()->length() == 1);
 
8675
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
8676
  HValue* value = Pop();
 
8677
  HIsObjectAndBranch* result = new(zone()) HIsObjectAndBranch(value);
 
8678
  return ast_context()->ReturnControl(result, call->id());
 
8679
}
 
8680
 
 
8681
 
 
8682
void HGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) {
 
8683
  return Bailout("inlined runtime function: IsNonNegativeSmi");
 
8684
}
 
8685
 
 
8686
 
 
8687
void HGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) {
 
8688
  ASSERT(call->arguments()->length() == 1);
 
8689
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
8690
  HValue* value = Pop();
 
8691
  HIsUndetectableAndBranch* result =
 
8692
      new(zone()) HIsUndetectableAndBranch(value);
 
8693
  return ast_context()->ReturnControl(result, call->id());
 
8694
}
 
8695
 
 
8696
 
 
8697
void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf(
 
8698
    CallRuntime* call) {
 
8699
  return Bailout(
 
8700
      "inlined runtime function: IsStringWrapperSafeForDefaultValueOf");
 
8701
}
 
8702
 
 
8703
 
 
8704
// Support for construct call checks.
 
8705
void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) {
 
8706
  ASSERT(call->arguments()->length() == 0);
 
8707
  if (function_state()->outer() != NULL) {
 
8708
    // We are generating graph for inlined function.
 
8709
    HValue* value = function_state()->is_construct()
 
8710
        ? graph()->GetConstantTrue()
 
8711
        : graph()->GetConstantFalse();
 
8712
    return ast_context()->ReturnValue(value);
 
8713
  } else {
 
8714
    return ast_context()->ReturnControl(new(zone()) HIsConstructCallAndBranch,
 
8715
                                        call->id());
 
8716
  }
 
8717
}
 
8718
 
 
8719
 
 
8720
// Support for arguments.length and arguments[?].
 
8721
void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) {
 
8722
  // Our implementation of arguments (based on this stack frame or an
 
8723
  // adapter below it) does not work for inlined functions.  This runtime
 
8724
  // function is blacklisted by AstNode::IsInlineable.
 
8725
  ASSERT(function_state()->outer() == NULL);
 
8726
  ASSERT(call->arguments()->length() == 0);
 
8727
  HInstruction* elements = AddInstruction(
 
8728
      new(zone()) HArgumentsElements(false));
 
8729
  HArgumentsLength* result = new(zone()) HArgumentsLength(elements);
 
8730
  return ast_context()->ReturnInstruction(result, call->id());
 
8731
}
 
8732
 
 
8733
 
 
8734
void HGraphBuilder::GenerateArguments(CallRuntime* call) {
 
8735
  // Our implementation of arguments (based on this stack frame or an
 
8736
  // adapter below it) does not work for inlined functions.  This runtime
 
8737
  // function is blacklisted by AstNode::IsInlineable.
 
8738
  ASSERT(function_state()->outer() == NULL);
 
8739
  ASSERT(call->arguments()->length() == 1);
 
8740
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
8741
  HValue* index = Pop();
 
8742
  HInstruction* elements = AddInstruction(
 
8743
      new(zone()) HArgumentsElements(false));
 
8744
  HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements));
 
8745
  HAccessArgumentsAt* result =
 
8746
      new(zone()) HAccessArgumentsAt(elements, length, index);
 
8747
  return ast_context()->ReturnInstruction(result, call->id());
 
8748
}
 
8749
 
 
8750
 
 
8751
// Support for accessing the class and value fields of an object.
 
8752
void HGraphBuilder::GenerateClassOf(CallRuntime* call) {
 
8753
  // The special form detected by IsClassOfTest is detected before we get here
 
8754
  // and does not cause a bailout.
 
8755
  return Bailout("inlined runtime function: ClassOf");
 
8756
}
 
8757
 
 
8758
 
 
8759
void HGraphBuilder::GenerateValueOf(CallRuntime* call) {
 
8760
  ASSERT(call->arguments()->length() == 1);
 
8761
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
8762
  HValue* value = Pop();
 
8763
  HValueOf* result = new(zone()) HValueOf(value);
 
8764
  return ast_context()->ReturnInstruction(result, call->id());
 
8765
}
 
8766
 
 
8767
 
 
8768
void HGraphBuilder::GenerateDateField(CallRuntime* call) {
 
8769
  ASSERT(call->arguments()->length() == 2);
 
8770
  ASSERT_NE(NULL, call->arguments()->at(1)->AsLiteral());
 
8771
  Smi* index = Smi::cast(*(call->arguments()->at(1)->AsLiteral()->handle()));
 
8772
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
8773
  HValue* date = Pop();
 
8774
  HDateField* result = new(zone()) HDateField(date, index);
 
8775
  return ast_context()->ReturnInstruction(result, call->id());
 
8776
}
 
8777
 
 
8778
 
 
8779
void HGraphBuilder::GenerateSetValueOf(CallRuntime* call) {
 
8780
  ASSERT(call->arguments()->length() == 2);
 
8781
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
8782
  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
 
8783
  HValue* value = Pop();
 
8784
  HValue* object = Pop();
 
8785
  // Check if object is a not a smi.
 
8786
  HIsSmiAndBranch* smicheck = new(zone()) HIsSmiAndBranch(object);
 
8787
  HBasicBlock* if_smi = graph()->CreateBasicBlock();
 
8788
  HBasicBlock* if_heap_object = graph()->CreateBasicBlock();
 
8789
  HBasicBlock* join = graph()->CreateBasicBlock();
 
8790
  smicheck->SetSuccessorAt(0, if_smi);
 
8791
  smicheck->SetSuccessorAt(1, if_heap_object);
 
8792
  current_block()->Finish(smicheck);
 
8793
  if_smi->Goto(join);
 
8794
 
 
8795
  // Check if object is a JSValue.
 
8796
  set_current_block(if_heap_object);
 
8797
  HHasInstanceTypeAndBranch* typecheck =
 
8798
      new(zone()) HHasInstanceTypeAndBranch(object, JS_VALUE_TYPE);
 
8799
  HBasicBlock* if_js_value = graph()->CreateBasicBlock();
 
8800
  HBasicBlock* not_js_value = graph()->CreateBasicBlock();
 
8801
  typecheck->SetSuccessorAt(0, if_js_value);
 
8802
  typecheck->SetSuccessorAt(1, not_js_value);
 
8803
  current_block()->Finish(typecheck);
 
8804
  not_js_value->Goto(join);
 
8805
 
 
8806
  // Create in-object property store to kValueOffset.
 
8807
  set_current_block(if_js_value);
 
8808
  Handle<String> name = isolate()->factory()->undefined_symbol();
 
8809
  AddInstruction(new(zone()) HStoreNamedField(object,
 
8810
                                              name,
 
8811
                                              value,
 
8812
                                              true,  // in-object store.
 
8813
                                              JSValue::kValueOffset));
 
8814
  if_js_value->Goto(join);
 
8815
  join->SetJoinId(call->id());
 
8816
  set_current_block(join);
 
8817
  return ast_context()->ReturnValue(value);
 
8818
}
 
8819
 
 
8820
 
 
8821
// Fast support for charCodeAt(n).
 
8822
void HGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) {
 
8823
  ASSERT(call->arguments()->length() == 2);
 
8824
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
8825
  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
 
8826
  HValue* index = Pop();
 
8827
  HValue* string = Pop();
 
8828
  HValue* context = environment()->LookupContext();
 
8829
  HStringCharCodeAt* result = BuildStringCharCodeAt(context, string, index);
 
8830
  return ast_context()->ReturnInstruction(result, call->id());
 
8831
}
 
8832
 
 
8833
 
 
8834
// Fast support for string.charAt(n) and string[n].
 
8835
void HGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) {
 
8836
  ASSERT(call->arguments()->length() == 1);
 
8837
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
8838
  HValue* char_code = Pop();
 
8839
  HValue* context = environment()->LookupContext();
 
8840
  HStringCharFromCode* result =
 
8841
      new(zone()) HStringCharFromCode(context, char_code);
 
8842
  return ast_context()->ReturnInstruction(result, call->id());
 
8843
}
 
8844
 
 
8845
 
 
8846
// Fast support for string.charAt(n) and string[n].
 
8847
void HGraphBuilder::GenerateStringCharAt(CallRuntime* call) {
 
8848
  ASSERT(call->arguments()->length() == 2);
 
8849
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
8850
  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
 
8851
  HValue* index = Pop();
 
8852
  HValue* string = Pop();
 
8853
  HValue* context = environment()->LookupContext();
 
8854
  HStringCharCodeAt* char_code = BuildStringCharCodeAt(context, string, index);
 
8855
  AddInstruction(char_code);
 
8856
  HStringCharFromCode* result =
 
8857
      new(zone()) HStringCharFromCode(context, char_code);
 
8858
  return ast_context()->ReturnInstruction(result, call->id());
 
8859
}
 
8860
 
 
8861
 
 
8862
// Fast support for object equality testing.
 
8863
void HGraphBuilder::GenerateObjectEquals(CallRuntime* call) {
 
8864
  ASSERT(call->arguments()->length() == 2);
 
8865
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
8866
  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
 
8867
  HValue* right = Pop();
 
8868
  HValue* left = Pop();
 
8869
  HCompareObjectEqAndBranch* result =
 
8870
      new(zone()) HCompareObjectEqAndBranch(left, right);
 
8871
  return ast_context()->ReturnControl(result, call->id());
 
8872
}
 
8873
 
 
8874
 
 
8875
void HGraphBuilder::GenerateLog(CallRuntime* call) {
 
8876
  // %_Log is ignored in optimized code.
 
8877
  return ast_context()->ReturnValue(graph()->GetConstantUndefined());
 
8878
}
 
8879
 
 
8880
 
 
8881
// Fast support for Math.random().
 
8882
void HGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) {
 
8883
  HValue* context = environment()->LookupContext();
 
8884
  HGlobalObject* global_object = new(zone()) HGlobalObject(context);
 
8885
  AddInstruction(global_object);
 
8886
  HRandom* result = new(zone()) HRandom(global_object);
 
8887
  return ast_context()->ReturnInstruction(result, call->id());
 
8888
}
 
8889
 
 
8890
 
 
8891
// Fast support for StringAdd.
 
8892
void HGraphBuilder::GenerateStringAdd(CallRuntime* call) {
 
8893
  ASSERT_EQ(2, call->arguments()->length());
 
8894
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
 
8895
  HValue* context = environment()->LookupContext();
 
8896
  HCallStub* result = new(zone()) HCallStub(context, CodeStub::StringAdd, 2);
 
8897
  Drop(2);
 
8898
  return ast_context()->ReturnInstruction(result, call->id());
 
8899
}
 
8900
 
 
8901
 
 
8902
// Fast support for SubString.
 
8903
void HGraphBuilder::GenerateSubString(CallRuntime* call) {
 
8904
  ASSERT_EQ(3, call->arguments()->length());
 
8905
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
 
8906
  HValue* context = environment()->LookupContext();
 
8907
  HCallStub* result = new(zone()) HCallStub(context, CodeStub::SubString, 3);
 
8908
  Drop(3);
 
8909
  return ast_context()->ReturnInstruction(result, call->id());
 
8910
}
 
8911
 
 
8912
 
 
8913
// Fast support for StringCompare.
 
8914
void HGraphBuilder::GenerateStringCompare(CallRuntime* call) {
 
8915
  ASSERT_EQ(2, call->arguments()->length());
 
8916
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
 
8917
  HValue* context = environment()->LookupContext();
 
8918
  HCallStub* result =
 
8919
      new(zone()) HCallStub(context, CodeStub::StringCompare, 2);
 
8920
  Drop(2);
 
8921
  return ast_context()->ReturnInstruction(result, call->id());
 
8922
}
 
8923
 
 
8924
 
 
8925
// Support for direct calls from JavaScript to native RegExp code.
 
8926
void HGraphBuilder::GenerateRegExpExec(CallRuntime* call) {
 
8927
  ASSERT_EQ(4, call->arguments()->length());
 
8928
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
 
8929
  HValue* context = environment()->LookupContext();
 
8930
  HCallStub* result = new(zone()) HCallStub(context, CodeStub::RegExpExec, 4);
 
8931
  Drop(4);
 
8932
  return ast_context()->ReturnInstruction(result, call->id());
 
8933
}
 
8934
 
 
8935
 
 
8936
// Construct a RegExp exec result with two in-object properties.
 
8937
void HGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) {
 
8938
  ASSERT_EQ(3, call->arguments()->length());
 
8939
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
 
8940
  HValue* context = environment()->LookupContext();
 
8941
  HCallStub* result =
 
8942
      new(zone()) HCallStub(context, CodeStub::RegExpConstructResult, 3);
 
8943
  Drop(3);
 
8944
  return ast_context()->ReturnInstruction(result, call->id());
 
8945
}
 
8946
 
 
8947
 
 
8948
// Support for fast native caches.
 
8949
void HGraphBuilder::GenerateGetFromCache(CallRuntime* call) {
 
8950
  return Bailout("inlined runtime function: GetFromCache");
 
8951
}
 
8952
 
 
8953
 
 
8954
// Fast support for number to string.
 
8955
void HGraphBuilder::GenerateNumberToString(CallRuntime* call) {
 
8956
  ASSERT_EQ(1, call->arguments()->length());
 
8957
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
 
8958
  HValue* context = environment()->LookupContext();
 
8959
  HCallStub* result =
 
8960
      new(zone()) HCallStub(context, CodeStub::NumberToString, 1);
 
8961
  Drop(1);
 
8962
  return ast_context()->ReturnInstruction(result, call->id());
 
8963
}
 
8964
 
 
8965
 
 
8966
// Fast call for custom callbacks.
 
8967
void HGraphBuilder::GenerateCallFunction(CallRuntime* call) {
 
8968
  // 1 ~ The function to call is not itself an argument to the call.
 
8969
  int arg_count = call->arguments()->length() - 1;
 
8970
  ASSERT(arg_count >= 1);  // There's always at least a receiver.
 
8971
 
 
8972
  for (int i = 0; i < arg_count; ++i) {
 
8973
    CHECK_ALIVE(VisitArgument(call->arguments()->at(i)));
 
8974
  }
 
8975
  CHECK_ALIVE(VisitForValue(call->arguments()->last()));
 
8976
 
 
8977
  HValue* function = Pop();
 
8978
  HValue* context = environment()->LookupContext();
 
8979
 
 
8980
  // Branch for function proxies, or other non-functions.
 
8981
  HHasInstanceTypeAndBranch* typecheck =
 
8982
      new(zone()) HHasInstanceTypeAndBranch(function, JS_FUNCTION_TYPE);
 
8983
  HBasicBlock* if_jsfunction = graph()->CreateBasicBlock();
 
8984
  HBasicBlock* if_nonfunction = graph()->CreateBasicBlock();
 
8985
  HBasicBlock* join = graph()->CreateBasicBlock();
 
8986
  typecheck->SetSuccessorAt(0, if_jsfunction);
 
8987
  typecheck->SetSuccessorAt(1, if_nonfunction);
 
8988
  current_block()->Finish(typecheck);
 
8989
 
 
8990
  set_current_block(if_jsfunction);
 
8991
  HInstruction* invoke_result = AddInstruction(
 
8992
      new(zone()) HInvokeFunction(context, function, arg_count));
 
8993
  Drop(arg_count);
 
8994
  Push(invoke_result);
 
8995
  if_jsfunction->Goto(join);
 
8996
 
 
8997
  set_current_block(if_nonfunction);
 
8998
  HInstruction* call_result = AddInstruction(
 
8999
      new(zone()) HCallFunction(context, function, arg_count));
 
9000
  Drop(arg_count);
 
9001
  Push(call_result);
 
9002
  if_nonfunction->Goto(join);
 
9003
 
 
9004
  set_current_block(join);
 
9005
  join->SetJoinId(call->id());
 
9006
  return ast_context()->ReturnValue(Pop());
 
9007
}
 
9008
 
 
9009
 
 
9010
// Fast call to math functions.
 
9011
void HGraphBuilder::GenerateMathPow(CallRuntime* call) {
 
9012
  ASSERT_EQ(2, call->arguments()->length());
 
9013
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
9014
  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
 
9015
  HValue* right = Pop();
 
9016
  HValue* left = Pop();
 
9017
  HPower* result = new(zone()) HPower(left, right);
 
9018
  return ast_context()->ReturnInstruction(result, call->id());
 
9019
}
 
9020
 
 
9021
 
 
9022
void HGraphBuilder::GenerateMathSin(CallRuntime* call) {
 
9023
  ASSERT_EQ(1, call->arguments()->length());
 
9024
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
 
9025
  HValue* context = environment()->LookupContext();
 
9026
  HCallStub* result =
 
9027
      new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
 
9028
  result->set_transcendental_type(TranscendentalCache::SIN);
 
9029
  Drop(1);
 
9030
  return ast_context()->ReturnInstruction(result, call->id());
 
9031
}
 
9032
 
 
9033
 
 
9034
void HGraphBuilder::GenerateMathCos(CallRuntime* call) {
 
9035
  ASSERT_EQ(1, call->arguments()->length());
 
9036
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
 
9037
  HValue* context = environment()->LookupContext();
 
9038
  HCallStub* result =
 
9039
      new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
 
9040
  result->set_transcendental_type(TranscendentalCache::COS);
 
9041
  Drop(1);
 
9042
  return ast_context()->ReturnInstruction(result, call->id());
 
9043
}
 
9044
 
 
9045
 
 
9046
void HGraphBuilder::GenerateMathTan(CallRuntime* call) {
 
9047
  ASSERT_EQ(1, call->arguments()->length());
 
9048
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
 
9049
  HValue* context = environment()->LookupContext();
 
9050
  HCallStub* result =
 
9051
      new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
 
9052
  result->set_transcendental_type(TranscendentalCache::TAN);
 
9053
  Drop(1);
 
9054
  return ast_context()->ReturnInstruction(result, call->id());
 
9055
}
 
9056
 
 
9057
 
 
9058
void HGraphBuilder::GenerateMathLog(CallRuntime* call) {
 
9059
  ASSERT_EQ(1, call->arguments()->length());
 
9060
  CHECK_ALIVE(VisitArgumentList(call->arguments()));
 
9061
  HValue* context = environment()->LookupContext();
 
9062
  HCallStub* result =
 
9063
      new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
 
9064
  result->set_transcendental_type(TranscendentalCache::LOG);
 
9065
  Drop(1);
 
9066
  return ast_context()->ReturnInstruction(result, call->id());
 
9067
}
 
9068
 
 
9069
 
 
9070
void HGraphBuilder::GenerateMathSqrt(CallRuntime* call) {
 
9071
  return Bailout("inlined runtime function: MathSqrt");
 
9072
}
 
9073
 
 
9074
 
 
9075
// Check whether two RegExps are equivalent
 
9076
void HGraphBuilder::GenerateIsRegExpEquivalent(CallRuntime* call) {
 
9077
  return Bailout("inlined runtime function: IsRegExpEquivalent");
 
9078
}
 
9079
 
 
9080
 
 
9081
void HGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) {
 
9082
  ASSERT(call->arguments()->length() == 1);
 
9083
  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
 
9084
  HValue* value = Pop();
 
9085
  HGetCachedArrayIndex* result = new(zone()) HGetCachedArrayIndex(value);
 
9086
  return ast_context()->ReturnInstruction(result, call->id());
 
9087
}
 
9088
 
 
9089
 
 
9090
void HGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) {
 
9091
  return Bailout("inlined runtime function: FastAsciiArrayJoin");
 
9092
}
 
9093
 
 
9094
 
 
9095
#undef CHECK_BAILOUT
 
9096
#undef CHECK_ALIVE
 
9097
 
 
9098
 
 
9099
HEnvironment::HEnvironment(HEnvironment* outer,
 
9100
                           Scope* scope,
 
9101
                           Handle<JSFunction> closure,
 
9102
                           Zone* zone)
 
9103
    : closure_(closure),
 
9104
      values_(0, zone),
 
9105
      assigned_variables_(4, zone),
 
9106
      frame_type_(JS_FUNCTION),
 
9107
      parameter_count_(0),
 
9108
      specials_count_(1),
 
9109
      local_count_(0),
 
9110
      outer_(outer),
 
9111
      pop_count_(0),
 
9112
      push_count_(0),
 
9113
      ast_id_(AstNode::kNoNumber),
 
9114
      zone_(zone) {
 
9115
  Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0);
 
9116
}
 
9117
 
 
9118
 
 
9119
HEnvironment::HEnvironment(const HEnvironment* other, Zone* zone)
 
9120
    : values_(0, zone),
 
9121
      assigned_variables_(0, zone),
 
9122
      frame_type_(JS_FUNCTION),
 
9123
      parameter_count_(0),
 
9124
      specials_count_(1),
 
9125
      local_count_(0),
 
9126
      outer_(NULL),
 
9127
      pop_count_(0),
 
9128
      push_count_(0),
 
9129
      ast_id_(other->ast_id()),
 
9130
      zone_(zone) {
 
9131
  Initialize(other);
 
9132
}
 
9133
 
 
9134
 
 
9135
HEnvironment::HEnvironment(HEnvironment* outer,
 
9136
                           Handle<JSFunction> closure,
 
9137
                           FrameType frame_type,
 
9138
                           int arguments,
 
9139
                           Zone* zone)
 
9140
    : closure_(closure),
 
9141
      values_(arguments, zone),
 
9142
      assigned_variables_(0, zone),
 
9143
      frame_type_(frame_type),
 
9144
      parameter_count_(arguments),
 
9145
      local_count_(0),
 
9146
      outer_(outer),
 
9147
      pop_count_(0),
 
9148
      push_count_(0),
 
9149
      ast_id_(AstNode::kNoNumber),
 
9150
      zone_(zone) {
 
9151
}
 
9152
 
 
9153
 
 
9154
void HEnvironment::Initialize(int parameter_count,
 
9155
                              int local_count,
 
9156
                              int stack_height) {
 
9157
  parameter_count_ = parameter_count;
 
9158
  local_count_ = local_count;
 
9159
 
 
9160
  // Avoid reallocating the temporaries' backing store on the first Push.
 
9161
  int total = parameter_count + specials_count_ + local_count + stack_height;
 
9162
  values_.Initialize(total + 4, zone());
 
9163
  for (int i = 0; i < total; ++i) values_.Add(NULL, zone());
 
9164
}
 
9165
 
 
9166
 
 
9167
void HEnvironment::Initialize(const HEnvironment* other) {
 
9168
  closure_ = other->closure();
 
9169
  values_.AddAll(other->values_, zone());
 
9170
  assigned_variables_.AddAll(other->assigned_variables_, zone());
 
9171
  frame_type_ = other->frame_type_;
 
9172
  parameter_count_ = other->parameter_count_;
 
9173
  local_count_ = other->local_count_;
 
9174
  if (other->outer_ != NULL) outer_ = other->outer_->Copy();  // Deep copy.
 
9175
  pop_count_ = other->pop_count_;
 
9176
  push_count_ = other->push_count_;
 
9177
  ast_id_ = other->ast_id_;
 
9178
}
 
9179
 
 
9180
 
 
9181
void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) {
 
9182
  ASSERT(!block->IsLoopHeader());
 
9183
  ASSERT(values_.length() == other->values_.length());
 
9184
 
 
9185
  int length = values_.length();
 
9186
  for (int i = 0; i < length; ++i) {
 
9187
    HValue* value = values_[i];
 
9188
    if (value != NULL && value->IsPhi() && value->block() == block) {
 
9189
      // There is already a phi for the i'th value.
 
9190
      HPhi* phi = HPhi::cast(value);
 
9191
      // Assert index is correct and that we haven't missed an incoming edge.
 
9192
      ASSERT(phi->merged_index() == i);
 
9193
      ASSERT(phi->OperandCount() == block->predecessors()->length());
 
9194
      phi->AddInput(other->values_[i]);
 
9195
    } else if (values_[i] != other->values_[i]) {
 
9196
      // There is a fresh value on the incoming edge, a phi is needed.
 
9197
      ASSERT(values_[i] != NULL && other->values_[i] != NULL);
 
9198
      HPhi* phi = new(zone()) HPhi(i, zone());
 
9199
      HValue* old_value = values_[i];
 
9200
      for (int j = 0; j < block->predecessors()->length(); j++) {
 
9201
        phi->AddInput(old_value);
 
9202
      }
 
9203
      phi->AddInput(other->values_[i]);
 
9204
      this->values_[i] = phi;
 
9205
      block->AddPhi(phi);
 
9206
    }
 
9207
  }
 
9208
}
 
9209
 
 
9210
 
 
9211
void HEnvironment::Bind(int index, HValue* value) {
 
9212
  ASSERT(value != NULL);
 
9213
  if (!assigned_variables_.Contains(index)) {
 
9214
    assigned_variables_.Add(index, zone());
 
9215
  }
 
9216
  values_[index] = value;
 
9217
}
 
9218
 
 
9219
 
 
9220
bool HEnvironment::HasExpressionAt(int index) const {
 
9221
  return index >= parameter_count_ + specials_count_ + local_count_;
 
9222
}
 
9223
 
 
9224
 
 
9225
bool HEnvironment::ExpressionStackIsEmpty() const {
 
9226
  ASSERT(length() >= first_expression_index());
 
9227
  return length() == first_expression_index();
 
9228
}
 
9229
 
 
9230
 
 
9231
void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) {
 
9232
  int count = index_from_top + 1;
 
9233
  int index = values_.length() - count;
 
9234
  ASSERT(HasExpressionAt(index));
 
9235
  // The push count must include at least the element in question or else
 
9236
  // the new value will not be included in this environment's history.
 
9237
  if (push_count_ < count) {
 
9238
    // This is the same effect as popping then re-pushing 'count' elements.
 
9239
    pop_count_ += (count - push_count_);
 
9240
    push_count_ = count;
 
9241
  }
 
9242
  values_[index] = value;
 
9243
}
 
9244
 
 
9245
 
 
9246
void HEnvironment::Drop(int count) {
 
9247
  for (int i = 0; i < count; ++i) {
 
9248
    Pop();
 
9249
  }
 
9250
}
 
9251
 
 
9252
 
 
9253
HEnvironment* HEnvironment::Copy() const {
 
9254
  return new(zone()) HEnvironment(this, zone());
 
9255
}
 
9256
 
 
9257
 
 
9258
HEnvironment* HEnvironment::CopyWithoutHistory() const {
 
9259
  HEnvironment* result = Copy();
 
9260
  result->ClearHistory();
 
9261
  return result;
 
9262
}
 
9263
 
 
9264
 
 
9265
HEnvironment* HEnvironment::CopyAsLoopHeader(HBasicBlock* loop_header) const {
 
9266
  HEnvironment* new_env = Copy();
 
9267
  for (int i = 0; i < values_.length(); ++i) {
 
9268
    HPhi* phi = new(zone()) HPhi(i, zone());
 
9269
    phi->AddInput(values_[i]);
 
9270
    new_env->values_[i] = phi;
 
9271
    loop_header->AddPhi(phi);
 
9272
  }
 
9273
  new_env->ClearHistory();
 
9274
  return new_env;
 
9275
}
 
9276
 
 
9277
 
 
9278
HEnvironment* HEnvironment::CreateStubEnvironment(HEnvironment* outer,
 
9279
                                                  Handle<JSFunction> target,
 
9280
                                                  FrameType frame_type,
 
9281
                                                  int arguments) const {
 
9282
  HEnvironment* new_env =
 
9283
      new(zone()) HEnvironment(outer, target, frame_type,
 
9284
                               arguments + 1, zone());
 
9285
  for (int i = 0; i <= arguments; ++i) {  // Include receiver.
 
9286
    new_env->Push(ExpressionStackAt(arguments - i));
 
9287
  }
 
9288
  new_env->ClearHistory();
 
9289
  return new_env;
 
9290
}
 
9291
 
 
9292
 
 
9293
HEnvironment* HEnvironment::CopyForInlining(
 
9294
    Handle<JSFunction> target,
 
9295
    int arguments,
 
9296
    FunctionLiteral* function,
 
9297
    HConstant* undefined,
 
9298
    CallKind call_kind,
 
9299
    bool is_construct) const {
 
9300
  ASSERT(frame_type() == JS_FUNCTION);
 
9301
 
 
9302
  // Outer environment is a copy of this one without the arguments.
 
9303
  int arity = function->scope()->num_parameters();
 
9304
 
 
9305
  HEnvironment* outer = Copy();
 
9306
  outer->Drop(arguments + 1);  // Including receiver.
 
9307
  outer->ClearHistory();
 
9308
 
 
9309
  if (is_construct) {
 
9310
    // Create artificial constructor stub environment.  The receiver should
 
9311
    // actually be the constructor function, but we pass the newly allocated
 
9312
    // object instead, DoComputeConstructStubFrame() relies on that.
 
9313
    outer = CreateStubEnvironment(outer, target, JS_CONSTRUCT, arguments);
 
9314
  }
 
9315
 
 
9316
  if (arity != arguments) {
 
9317
    // Create artificial arguments adaptation environment.
 
9318
    outer = CreateStubEnvironment(outer, target, ARGUMENTS_ADAPTOR, arguments);
 
9319
  }
 
9320
 
 
9321
  HEnvironment* inner =
 
9322
      new(zone()) HEnvironment(outer, function->scope(), target, zone());
 
9323
  // Get the argument values from the original environment.
 
9324
  for (int i = 0; i <= arity; ++i) {  // Include receiver.
 
9325
    HValue* push = (i <= arguments) ?
 
9326
        ExpressionStackAt(arguments - i) : undefined;
 
9327
    inner->SetValueAt(i, push);
 
9328
  }
 
9329
  // If the function we are inlining is a strict mode function or a
 
9330
  // builtin function, pass undefined as the receiver for function
 
9331
  // calls (instead of the global receiver).
 
9332
  if ((target->shared()->native() || !function->is_classic_mode()) &&
 
9333
      call_kind == CALL_AS_FUNCTION && !is_construct) {
 
9334
    inner->SetValueAt(0, undefined);
 
9335
  }
 
9336
  inner->SetValueAt(arity + 1, LookupContext());
 
9337
  for (int i = arity + 2; i < inner->length(); ++i) {
 
9338
    inner->SetValueAt(i, undefined);
 
9339
  }
 
9340
 
 
9341
  inner->set_ast_id(AstNode::kFunctionEntryId);
 
9342
  return inner;
 
9343
}
 
9344
 
 
9345
 
 
9346
void HEnvironment::PrintTo(StringStream* stream) {
 
9347
  for (int i = 0; i < length(); i++) {
 
9348
    if (i == 0) stream->Add("parameters\n");
 
9349
    if (i == parameter_count()) stream->Add("specials\n");
 
9350
    if (i == parameter_count() + specials_count()) stream->Add("locals\n");
 
9351
    if (i == parameter_count() + specials_count() + local_count()) {
 
9352
      stream->Add("expressions\n");
 
9353
    }
 
9354
    HValue* val = values_.at(i);
 
9355
    stream->Add("%d: ", i);
 
9356
    if (val != NULL) {
 
9357
      val->PrintNameTo(stream);
 
9358
    } else {
 
9359
      stream->Add("NULL");
 
9360
    }
 
9361
    stream->Add("\n");
 
9362
  }
 
9363
  PrintF("\n");
 
9364
}
 
9365
 
 
9366
 
 
9367
void HEnvironment::PrintToStd() {
 
9368
  HeapStringAllocator string_allocator;
 
9369
  StringStream trace(&string_allocator);
 
9370
  PrintTo(&trace);
 
9371
  PrintF("%s", *trace.ToCString());
 
9372
}
 
9373
 
 
9374
 
 
9375
void HTracer::TraceCompilation(FunctionLiteral* function) {
 
9376
  Tag tag(this, "compilation");
 
9377
  Handle<String> name = function->debug_name();
 
9378
  PrintStringProperty("name", *name->ToCString());
 
9379
  PrintStringProperty("method", *name->ToCString());
 
9380
  PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis()));
 
9381
}
 
9382
 
 
9383
 
 
9384
void HTracer::TraceLithium(const char* name, LChunk* chunk) {
 
9385
  Trace(name, chunk->graph(), chunk);
 
9386
}
 
9387
 
 
9388
 
 
9389
void HTracer::TraceHydrogen(const char* name, HGraph* graph) {
 
9390
  Trace(name, graph, NULL);
 
9391
}
 
9392
 
 
9393
 
 
9394
void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
 
9395
  Tag tag(this, "cfg");
 
9396
  PrintStringProperty("name", name);
 
9397
  const ZoneList<HBasicBlock*>* blocks = graph->blocks();
 
9398
  for (int i = 0; i < blocks->length(); i++) {
 
9399
    HBasicBlock* current = blocks->at(i);
 
9400
    Tag block_tag(this, "block");
 
9401
    PrintBlockProperty("name", current->block_id());
 
9402
    PrintIntProperty("from_bci", -1);
 
9403
    PrintIntProperty("to_bci", -1);
 
9404
 
 
9405
    if (!current->predecessors()->is_empty()) {
 
9406
      PrintIndent();
 
9407
      trace_.Add("predecessors");
 
9408
      for (int j = 0; j < current->predecessors()->length(); ++j) {
 
9409
        trace_.Add(" \"B%d\"", current->predecessors()->at(j)->block_id());
 
9410
      }
 
9411
      trace_.Add("\n");
 
9412
    } else {
 
9413
      PrintEmptyProperty("predecessors");
 
9414
    }
 
9415
 
 
9416
    if (current->end()->SuccessorCount() == 0) {
 
9417
      PrintEmptyProperty("successors");
 
9418
    } else  {
 
9419
      PrintIndent();
 
9420
      trace_.Add("successors");
 
9421
      for (HSuccessorIterator it(current->end()); !it.Done(); it.Advance()) {
 
9422
        trace_.Add(" \"B%d\"", it.Current()->block_id());
 
9423
      }
 
9424
      trace_.Add("\n");
 
9425
    }
 
9426
 
 
9427
    PrintEmptyProperty("xhandlers");
 
9428
    const char* flags = current->IsLoopSuccessorDominator()
 
9429
        ? "dom-loop-succ"
 
9430
        : "";
 
9431
    PrintStringProperty("flags", flags);
 
9432
 
 
9433
    if (current->dominator() != NULL) {
 
9434
      PrintBlockProperty("dominator", current->dominator()->block_id());
 
9435
    }
 
9436
 
 
9437
    PrintIntProperty("loop_depth", current->LoopNestingDepth());
 
9438
 
 
9439
    if (chunk != NULL) {
 
9440
      int first_index = current->first_instruction_index();
 
9441
      int last_index = current->last_instruction_index();
 
9442
      PrintIntProperty(
 
9443
          "first_lir_id",
 
9444
          LifetimePosition::FromInstructionIndex(first_index).Value());
 
9445
      PrintIntProperty(
 
9446
          "last_lir_id",
 
9447
          LifetimePosition::FromInstructionIndex(last_index).Value());
 
9448
    }
 
9449
 
 
9450
    {
 
9451
      Tag states_tag(this, "states");
 
9452
      Tag locals_tag(this, "locals");
 
9453
      int total = current->phis()->length();
 
9454
      PrintIntProperty("size", current->phis()->length());
 
9455
      PrintStringProperty("method", "None");
 
9456
      for (int j = 0; j < total; ++j) {
 
9457
        HPhi* phi = current->phis()->at(j);
 
9458
        PrintIndent();
 
9459
        trace_.Add("%d ", phi->merged_index());
 
9460
        phi->PrintNameTo(&trace_);
 
9461
        trace_.Add(" ");
 
9462
        phi->PrintTo(&trace_);
 
9463
        trace_.Add("\n");
 
9464
      }
 
9465
    }
 
9466
 
 
9467
    {
 
9468
      Tag HIR_tag(this, "HIR");
 
9469
      HInstruction* instruction = current->first();
 
9470
      while (instruction != NULL) {
 
9471
        int bci = 0;
 
9472
        int uses = instruction->UseCount();
 
9473
        PrintIndent();
 
9474
        trace_.Add("%d %d ", bci, uses);
 
9475
        instruction->PrintNameTo(&trace_);
 
9476
        trace_.Add(" ");
 
9477
        instruction->PrintTo(&trace_);
 
9478
        trace_.Add(" <|@\n");
 
9479
        instruction = instruction->next();
 
9480
      }
 
9481
    }
 
9482
 
 
9483
 
 
9484
    if (chunk != NULL) {
 
9485
      Tag LIR_tag(this, "LIR");
 
9486
      int first_index = current->first_instruction_index();
 
9487
      int last_index = current->last_instruction_index();
 
9488
      if (first_index != -1 && last_index != -1) {
 
9489
        const ZoneList<LInstruction*>* instructions = chunk->instructions();
 
9490
        for (int i = first_index; i <= last_index; ++i) {
 
9491
          LInstruction* linstr = instructions->at(i);
 
9492
          if (linstr != NULL) {
 
9493
            PrintIndent();
 
9494
            trace_.Add("%d ",
 
9495
                       LifetimePosition::FromInstructionIndex(i).Value());
 
9496
            linstr->PrintTo(&trace_);
 
9497
            trace_.Add(" <|@\n");
 
9498
          }
 
9499
        }
 
9500
      }
 
9501
    }
 
9502
  }
 
9503
}
 
9504
 
 
9505
 
 
9506
void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) {
 
9507
  Tag tag(this, "intervals");
 
9508
  PrintStringProperty("name", name);
 
9509
 
 
9510
  const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges();
 
9511
  for (int i = 0; i < fixed_d->length(); ++i) {
 
9512
    TraceLiveRange(fixed_d->at(i), "fixed", allocator->zone());
 
9513
  }
 
9514
 
 
9515
  const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges();
 
9516
  for (int i = 0; i < fixed->length(); ++i) {
 
9517
    TraceLiveRange(fixed->at(i), "fixed", allocator->zone());
 
9518
  }
 
9519
 
 
9520
  const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges();
 
9521
  for (int i = 0; i < live_ranges->length(); ++i) {
 
9522
    TraceLiveRange(live_ranges->at(i), "object", allocator->zone());
 
9523
  }
 
9524
}
 
9525
 
 
9526
 
 
9527
void HTracer::TraceLiveRange(LiveRange* range, const char* type,
 
9528
                             Zone* zone) {
 
9529
  if (range != NULL && !range->IsEmpty()) {
 
9530
    PrintIndent();
 
9531
    trace_.Add("%d %s", range->id(), type);
 
9532
    if (range->HasRegisterAssigned()) {
 
9533
      LOperand* op = range->CreateAssignedOperand(zone);
 
9534
      int assigned_reg = op->index();
 
9535
      if (op->IsDoubleRegister()) {
 
9536
        trace_.Add(" \"%s\"",
 
9537
                   DoubleRegister::AllocationIndexToString(assigned_reg));
 
9538
      } else {
 
9539
        ASSERT(op->IsRegister());
 
9540
        trace_.Add(" \"%s\"", Register::AllocationIndexToString(assigned_reg));
 
9541
      }
 
9542
    } else if (range->IsSpilled()) {
 
9543
      LOperand* op = range->TopLevel()->GetSpillOperand();
 
9544
      if (op->IsDoubleStackSlot()) {
 
9545
        trace_.Add(" \"double_stack:%d\"", op->index());
 
9546
      } else {
 
9547
        ASSERT(op->IsStackSlot());
 
9548
        trace_.Add(" \"stack:%d\"", op->index());
 
9549
      }
 
9550
    }
 
9551
    int parent_index = -1;
 
9552
    if (range->IsChild()) {
 
9553
      parent_index = range->parent()->id();
 
9554
    } else {
 
9555
      parent_index = range->id();
 
9556
    }
 
9557
    LOperand* op = range->FirstHint();
 
9558
    int hint_index = -1;
 
9559
    if (op != NULL && op->IsUnallocated()) {
 
9560
      hint_index = LUnallocated::cast(op)->virtual_register();
 
9561
    }
 
9562
    trace_.Add(" %d %d", parent_index, hint_index);
 
9563
    UseInterval* cur_interval = range->first_interval();
 
9564
    while (cur_interval != NULL && range->Covers(cur_interval->start())) {
 
9565
      trace_.Add(" [%d, %d[",
 
9566
                 cur_interval->start().Value(),
 
9567
                 cur_interval->end().Value());
 
9568
      cur_interval = cur_interval->next();
 
9569
    }
 
9570
 
 
9571
    UsePosition* current_pos = range->first_pos();
 
9572
    while (current_pos != NULL) {
 
9573
      if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
 
9574
        trace_.Add(" %d M", current_pos->pos().Value());
 
9575
      }
 
9576
      current_pos = current_pos->next();
 
9577
    }
 
9578
 
 
9579
    trace_.Add(" \"\"\n");
 
9580
  }
 
9581
}
 
9582
 
 
9583
 
 
9584
void HTracer::FlushToFile() {
 
9585
  AppendChars(filename_, *trace_.ToCString(), trace_.length(), false);
 
9586
  trace_.Reset();
 
9587
}
 
9588
 
 
9589
 
 
9590
void HStatistics::Initialize(CompilationInfo* info) {
 
9591
  source_size_ += info->shared_info()->SourceSize();
 
9592
}
 
9593
 
 
9594
 
 
9595
void HStatistics::Print() {
 
9596
  PrintF("Timing results:\n");
 
9597
  int64_t sum = 0;
 
9598
  for (int i = 0; i < timing_.length(); ++i) {
 
9599
    sum += timing_[i];
 
9600
  }
 
9601
 
 
9602
  for (int i = 0; i < names_.length(); ++i) {
 
9603
    PrintF("%30s", names_[i]);
 
9604
    double ms = static_cast<double>(timing_[i]) / 1000;
 
9605
    double percent = static_cast<double>(timing_[i]) * 100 / sum;
 
9606
    PrintF(" - %7.3f ms / %4.1f %% ", ms, percent);
 
9607
 
 
9608
    unsigned size = sizes_[i];
 
9609
    double size_percent = static_cast<double>(size) * 100 / total_size_;
 
9610
    PrintF(" %8u bytes / %4.1f %%\n", size, size_percent);
 
9611
  }
 
9612
  double source_size_in_kb = static_cast<double>(source_size_) / 1024;
 
9613
  double normalized_time =  source_size_in_kb > 0
 
9614
      ? (static_cast<double>(sum) / 1000) / source_size_in_kb
 
9615
      : 0;
 
9616
  double normalized_bytes = source_size_in_kb > 0
 
9617
      ? total_size_ / source_size_in_kb
 
9618
      : 0;
 
9619
  PrintF("%30s - %7.3f ms           %7.3f bytes\n", "Sum",
 
9620
         normalized_time, normalized_bytes);
 
9621
  PrintF("---------------------------------------------------------------\n");
 
9622
  PrintF("%30s - %7.3f ms (%.1f times slower than full code gen)\n",
 
9623
         "Total",
 
9624
         static_cast<double>(total_) / 1000,
 
9625
         static_cast<double>(total_) / full_code_gen_);
 
9626
}
 
9627
 
 
9628
 
 
9629
void HStatistics::SaveTiming(const char* name, int64_t ticks, unsigned size) {
 
9630
  if (name == HPhase::kFullCodeGen) {
 
9631
    full_code_gen_ += ticks;
 
9632
  } else if (name == HPhase::kTotal) {
 
9633
    total_ += ticks;
 
9634
  } else {
 
9635
    total_size_ += size;
 
9636
    for (int i = 0; i < names_.length(); ++i) {
 
9637
      if (names_[i] == name) {
 
9638
        timing_[i] += ticks;
 
9639
        sizes_[i] += size;
 
9640
        return;
 
9641
      }
 
9642
    }
 
9643
    names_.Add(name);
 
9644
    timing_.Add(ticks);
 
9645
    sizes_.Add(size);
 
9646
  }
 
9647
}
 
9648
 
 
9649
 
 
9650
const char* const HPhase::kFullCodeGen = "Full code generator";
 
9651
const char* const HPhase::kTotal = "Total";
 
9652
 
 
9653
 
 
9654
void HPhase::Begin(const char* name,
 
9655
                   HGraph* graph,
 
9656
                   LChunk* chunk,
 
9657
                   LAllocator* allocator) {
 
9658
  name_ = name;
 
9659
  graph_ = graph;
 
9660
  chunk_ = chunk;
 
9661
  allocator_ = allocator;
 
9662
  if (allocator != NULL && chunk_ == NULL) {
 
9663
    chunk_ = allocator->chunk();
 
9664
  }
 
9665
  if (FLAG_hydrogen_stats) start_ = OS::Ticks();
 
9666
  start_allocation_size_ = Zone::allocation_size_;
 
9667
}
 
9668
 
 
9669
 
 
9670
void HPhase::End() const {
 
9671
  if (FLAG_hydrogen_stats) {
 
9672
    int64_t end = OS::Ticks();
 
9673
    unsigned size = Zone::allocation_size_ - start_allocation_size_;
 
9674
    HStatistics::Instance()->SaveTiming(name_, end - start_, size);
 
9675
  }
 
9676
 
 
9677
  // Produce trace output if flag is set so that the first letter of the
 
9678
  // phase name matches the command line parameter FLAG_trace_phase.
 
9679
  if (FLAG_trace_hydrogen &&
 
9680
      OS::StrChr(const_cast<char*>(FLAG_trace_phase), name_[0]) != NULL) {
 
9681
    if (graph_ != NULL) HTracer::Instance()->TraceHydrogen(name_, graph_);
 
9682
    if (chunk_ != NULL) HTracer::Instance()->TraceLithium(name_, chunk_);
 
9683
    if (allocator_ != NULL) {
 
9684
      HTracer::Instance()->TraceLiveRanges(name_, allocator_);
 
9685
    }
 
9686
  }
 
9687
 
 
9688
#ifdef DEBUG
 
9689
  if (graph_ != NULL) graph_->Verify(false);  // No full verify.
 
9690
  if (allocator_ != NULL) allocator_->Verify();
 
9691
#endif
 
9692
}
 
9693
 
 
9694
} }  // namespace v8::internal