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

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / ia32 / lithium-ia32.cc @ f230a1cf

History | View | Annotate | Download (92.2 KB)

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

    
30
#if V8_TARGET_ARCH_IA32
31

    
32
#include "lithium-allocator-inl.h"
33
#include "ia32/lithium-ia32.h"
34
#include "ia32/lithium-codegen-ia32.h"
35
#include "hydrogen-osr.h"
36

    
37
namespace v8 {
38
namespace internal {
39

    
40
#define DEFINE_COMPILE(type)                            \
41
  void L##type::CompileToNative(LCodeGen* generator) {  \
42
    generator->Do##type(this);                          \
43
  }
44
LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
45
#undef DEFINE_COMPILE
46

    
47

    
48
#ifdef DEBUG
49
void LInstruction::VerifyCall() {
50
  // Call instructions can use only fixed registers as temporaries and
51
  // outputs because all registers are blocked by the calling convention.
52
  // Inputs operands must use a fixed register or use-at-start policy or
53
  // a non-register policy.
54
  ASSERT(Output() == NULL ||
55
         LUnallocated::cast(Output())->HasFixedPolicy() ||
56
         !LUnallocated::cast(Output())->HasRegisterPolicy());
57
  for (UseIterator it(this); !it.Done(); it.Advance()) {
58
    LUnallocated* operand = LUnallocated::cast(it.Current());
59
    ASSERT(operand->HasFixedPolicy() ||
60
           operand->IsUsedAtStart());
61
  }
62
  for (TempIterator it(this); !it.Done(); it.Advance()) {
63
    LUnallocated* operand = LUnallocated::cast(it.Current());
64
    ASSERT(operand->HasFixedPolicy() ||!operand->HasRegisterPolicy());
65
  }
66
}
67
#endif
68

    
69

    
70
bool LInstruction::HasDoubleRegisterResult() {
71
  return HasResult() && result()->IsDoubleRegister();
72
}
73

    
74

    
75
bool LInstruction::HasDoubleRegisterInput() {
76
  for (int i = 0; i < InputCount(); i++) {
77
    LOperand* op = InputAt(i);
78
    if (op != NULL && op->IsDoubleRegister()) {
79
      return true;
80
    }
81
  }
82
  return false;
83
}
84

    
85

    
86
bool LInstruction::IsDoubleInput(X87Register reg, LCodeGen* cgen) {
87
  for (int i = 0; i < InputCount(); i++) {
88
    LOperand* op = InputAt(i);
89
    if (op != NULL && op->IsDoubleRegister()) {
90
      if (cgen->ToX87Register(op).is(reg)) return true;
91
    }
92
  }
93
  return false;
94
}
95

    
96

    
97
void LInstruction::PrintTo(StringStream* stream) {
98
  stream->Add("%s ", this->Mnemonic());
99

    
100
  PrintOutputOperandTo(stream);
101

    
102
  PrintDataTo(stream);
103

    
104
  if (HasEnvironment()) {
105
    stream->Add(" ");
106
    environment()->PrintTo(stream);
107
  }
108

    
109
  if (HasPointerMap()) {
110
    stream->Add(" ");
111
    pointer_map()->PrintTo(stream);
112
  }
113
}
114

    
115

    
116
void LInstruction::PrintDataTo(StringStream* stream) {
117
  stream->Add("= ");
118
  for (int i = 0; i < InputCount(); i++) {
119
    if (i > 0) stream->Add(" ");
120
    if (InputAt(i) == NULL) {
121
      stream->Add("NULL");
122
    } else {
123
      InputAt(i)->PrintTo(stream);
124
    }
125
  }
126
}
127

    
128

    
129
void LInstruction::PrintOutputOperandTo(StringStream* stream) {
130
  if (HasResult()) result()->PrintTo(stream);
131
}
132

    
133

    
134
void LLabel::PrintDataTo(StringStream* stream) {
135
  LGap::PrintDataTo(stream);
136
  LLabel* rep = replacement();
137
  if (rep != NULL) {
138
    stream->Add(" Dead block replaced with B%d", rep->block_id());
139
  }
140
}
141

    
142

    
143
bool LGap::IsRedundant() const {
144
  for (int i = 0; i < 4; i++) {
145
    if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
146
      return false;
147
    }
148
  }
149

    
150
  return true;
151
}
152

    
153

    
154
void LGap::PrintDataTo(StringStream* stream) {
155
  for (int i = 0; i < 4; i++) {
156
    stream->Add("(");
157
    if (parallel_moves_[i] != NULL) {
158
      parallel_moves_[i]->PrintDataTo(stream);
159
    }
160
    stream->Add(") ");
161
  }
162
}
163

    
164

    
165
const char* LArithmeticD::Mnemonic() const {
166
  switch (op()) {
167
    case Token::ADD: return "add-d";
168
    case Token::SUB: return "sub-d";
169
    case Token::MUL: return "mul-d";
170
    case Token::DIV: return "div-d";
171
    case Token::MOD: return "mod-d";
172
    default:
173
      UNREACHABLE();
174
      return NULL;
175
  }
176
}
177

    
178

    
179
const char* LArithmeticT::Mnemonic() const {
180
  switch (op()) {
181
    case Token::ADD: return "add-t";
182
    case Token::SUB: return "sub-t";
183
    case Token::MUL: return "mul-t";
184
    case Token::MOD: return "mod-t";
185
    case Token::DIV: return "div-t";
186
    case Token::BIT_AND: return "bit-and-t";
187
    case Token::BIT_OR: return "bit-or-t";
188
    case Token::BIT_XOR: return "bit-xor-t";
189
    case Token::ROR: return "ror-t";
190
    case Token::SHL: return "sal-t";
191
    case Token::SAR: return "sar-t";
192
    case Token::SHR: return "shr-t";
193
    default:
194
      UNREACHABLE();
195
      return NULL;
196
  }
197
}
198

    
199

    
200
bool LGoto::HasInterestingComment(LCodeGen* gen) const {
201
  return !gen->IsNextEmittedBlock(block_id());
202
}
203

    
204

    
205
void LGoto::PrintDataTo(StringStream* stream) {
206
  stream->Add("B%d", block_id());
207
}
208

    
209

    
210
void LBranch::PrintDataTo(StringStream* stream) {
211
  stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
212
  value()->PrintTo(stream);
213
}
214

    
215

    
216
void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
217
  stream->Add("if ");
218
  left()->PrintTo(stream);
219
  stream->Add(" %s ", Token::String(op()));
220
  right()->PrintTo(stream);
221
  stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
222
}
223

    
224

    
225
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
226
  stream->Add("if is_object(");
227
  value()->PrintTo(stream);
228
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
229
}
230

    
231

    
232
void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
233
  stream->Add("if is_string(");
234
  value()->PrintTo(stream);
235
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
236
}
237

    
238

    
239
void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
240
  stream->Add("if is_smi(");
241
  value()->PrintTo(stream);
242
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
243
}
244

    
245

    
246
void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
247
  stream->Add("if is_undetectable(");
248
  value()->PrintTo(stream);
249
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
250
}
251

    
252

    
253
void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
254
  stream->Add("if string_compare(");
255
  left()->PrintTo(stream);
256
  right()->PrintTo(stream);
257
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
258
}
259

    
260

    
261
void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
262
  stream->Add("if has_instance_type(");
263
  value()->PrintTo(stream);
264
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
265
}
266

    
267

    
268
void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
269
  stream->Add("if has_cached_array_index(");
270
  value()->PrintTo(stream);
271
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
272
}
273

    
274

    
275
void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
276
  stream->Add("if class_of_test(");
277
  value()->PrintTo(stream);
278
  stream->Add(", \"%o\") then B%d else B%d",
279
              *hydrogen()->class_name(),
280
              true_block_id(),
281
              false_block_id());
282
}
283

    
284

    
285
void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
286
  stream->Add("if typeof ");
287
  value()->PrintTo(stream);
288
  stream->Add(" == \"%s\" then B%d else B%d",
289
              *hydrogen()->type_literal()->ToCString(),
290
              true_block_id(), false_block_id());
291
}
292

    
293

    
294
void LStoreCodeEntry::PrintDataTo(StringStream* stream) {
295
  stream->Add(" = ");
296
  function()->PrintTo(stream);
297
  stream->Add(".code_entry = ");
298
  code_object()->PrintTo(stream);
299
}
300

    
301

    
302
void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
303
  stream->Add(" = ");
304
  base_object()->PrintTo(stream);
305
  stream->Add(" + %d", offset());
306
}
307

    
308

    
309
void LCallConstantFunction::PrintDataTo(StringStream* stream) {
310
  stream->Add("#%d / ", arity());
311
}
312

    
313

    
314
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
315
  context()->PrintTo(stream);
316
  stream->Add("[%d]", slot_index());
317
}
318

    
319

    
320
void LStoreContextSlot::PrintDataTo(StringStream* stream) {
321
  context()->PrintTo(stream);
322
  stream->Add("[%d] <- ", slot_index());
323
  value()->PrintTo(stream);
324
}
325

    
326

    
327
void LInvokeFunction::PrintDataTo(StringStream* stream) {
328
  stream->Add("= ");
329
  context()->PrintTo(stream);
330
  stream->Add(" ");
331
  function()->PrintTo(stream);
332
  stream->Add(" #%d / ", arity());
333
}
334

    
335

    
336
void LCallKeyed::PrintDataTo(StringStream* stream) {
337
  stream->Add("[ecx] #%d / ", arity());
338
}
339

    
340

    
341
void LCallNamed::PrintDataTo(StringStream* stream) {
342
  SmartArrayPointer<char> name_string = name()->ToCString();
343
  stream->Add("%s #%d / ", *name_string, arity());
344
}
345

    
346

    
347
void LCallGlobal::PrintDataTo(StringStream* stream) {
348
  SmartArrayPointer<char> name_string = name()->ToCString();
349
  stream->Add("%s #%d / ", *name_string, arity());
350
}
351

    
352

    
353
void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
354
  stream->Add("#%d / ", arity());
355
}
356

    
357

    
358
void LCallNew::PrintDataTo(StringStream* stream) {
359
  stream->Add("= ");
360
  context()->PrintTo(stream);
361
  stream->Add(" ");
362
  constructor()->PrintTo(stream);
363
  stream->Add(" #%d / ", arity());
364
}
365

    
366

    
367
void LCallNewArray::PrintDataTo(StringStream* stream) {
368
  stream->Add("= ");
369
  context()->PrintTo(stream);
370
  stream->Add(" ");
371
  constructor()->PrintTo(stream);
372
  stream->Add(" #%d / ", arity());
373
  ElementsKind kind = hydrogen()->elements_kind();
374
  stream->Add(" (%s) ", ElementsKindToString(kind));
375
}
376

    
377

    
378
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
379
  arguments()->PrintTo(stream);
380

    
381
  stream->Add(" length ");
382
  length()->PrintTo(stream);
383

    
384
  stream->Add(" index ");
385
  index()->PrintTo(stream);
386
}
387

    
388

    
389
int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
390
  // Skip a slot if for a double-width slot.
391
  if (kind == DOUBLE_REGISTERS) {
392
    spill_slot_count_++;
393
    spill_slot_count_ |= 1;
394
    num_double_slots_++;
395
  }
396
  return spill_slot_count_++;
397
}
398

    
399

    
400
LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
401
  int index = GetNextSpillIndex(kind);
402
  if (kind == DOUBLE_REGISTERS) {
403
    return LDoubleStackSlot::Create(index, zone());
404
  } else {
405
    ASSERT(kind == GENERAL_REGISTERS);
406
    return LStackSlot::Create(index, zone());
407
  }
408
}
409

    
410

    
411
void LStoreNamedField::PrintDataTo(StringStream* stream) {
412
  object()->PrintTo(stream);
413
  hydrogen()->access().PrintTo(stream);
414
  stream->Add(" <- ");
415
  value()->PrintTo(stream);
416
}
417

    
418

    
419
void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
420
  object()->PrintTo(stream);
421
  stream->Add(".");
422
  stream->Add(*String::cast(*name())->ToCString());
423
  stream->Add(" <- ");
424
  value()->PrintTo(stream);
425
}
426

    
427

    
428
void LLoadKeyed::PrintDataTo(StringStream* stream) {
429
  elements()->PrintTo(stream);
430
  stream->Add("[");
431
  key()->PrintTo(stream);
432
  if (hydrogen()->IsDehoisted()) {
433
    stream->Add(" + %d]", additional_index());
434
  } else {
435
    stream->Add("]");
436
  }
437
}
438

    
439

    
440
void LStoreKeyed::PrintDataTo(StringStream* stream) {
441
  elements()->PrintTo(stream);
442
  stream->Add("[");
443
  key()->PrintTo(stream);
444
  if (hydrogen()->IsDehoisted()) {
445
    stream->Add(" + %d] <-", additional_index());
446
  } else {
447
    stream->Add("] <- ");
448
  }
449

    
450
  if (value() == NULL) {
451
    ASSERT(hydrogen()->IsConstantHoleStore() &&
452
           hydrogen()->value()->representation().IsDouble());
453
    stream->Add("<the hole(nan)>");
454
  } else {
455
    value()->PrintTo(stream);
456
  }
457
}
458

    
459

    
460
void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
461
  object()->PrintTo(stream);
462
  stream->Add("[");
463
  key()->PrintTo(stream);
464
  stream->Add("] <- ");
465
  value()->PrintTo(stream);
466
}
467

    
468

    
469
void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
470
  object()->PrintTo(stream);
471
  stream->Add(" %p -> %p", *original_map(), *transitioned_map());
472
}
473

    
474

    
475
LPlatformChunk* LChunkBuilder::Build() {
476
  ASSERT(is_unused());
477
  chunk_ = new(zone()) LPlatformChunk(info(), graph());
478
  LPhase phase("L_Building chunk", chunk_);
479
  status_ = BUILDING;
480

    
481
  // Reserve the first spill slot for the state of dynamic alignment.
482
  if (info()->IsOptimizing()) {
483
    int alignment_state_index = chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
484
    ASSERT_EQ(alignment_state_index, 0);
485
    USE(alignment_state_index);
486
  }
487

    
488
  // If compiling for OSR, reserve space for the unoptimized frame,
489
  // which will be subsumed into this frame.
490
  if (graph()->has_osr()) {
491
    for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
492
      chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
493
    }
494
  }
495

    
496
  const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
497
  for (int i = 0; i < blocks->length(); i++) {
498
    HBasicBlock* next = NULL;
499
    if (i < blocks->length() - 1) next = blocks->at(i + 1);
500
    DoBasicBlock(blocks->at(i), next);
501
    if (is_aborted()) return NULL;
502
  }
503
  status_ = DONE;
504
  return chunk_;
505
}
506

    
507

    
508
void LChunkBuilder::Abort(BailoutReason reason) {
509
  info()->set_bailout_reason(reason);
510
  status_ = ABORTED;
511
}
512

    
513

    
514
LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
515
  return new(zone()) LUnallocated(LUnallocated::FIXED_REGISTER,
516
                                  Register::ToAllocationIndex(reg));
517
}
518

    
519

    
520
LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
521
  return new(zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
522
                                  XMMRegister::ToAllocationIndex(reg));
523
}
524

    
525

    
526
LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
527
  return Use(value, ToUnallocated(fixed_register));
528
}
529

    
530

    
531
LOperand* LChunkBuilder::UseFixedDouble(HValue* value, XMMRegister reg) {
532
  return Use(value, ToUnallocated(reg));
533
}
534

    
535

    
536
LOperand* LChunkBuilder::UseRegister(HValue* value) {
537
  return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
538
}
539

    
540

    
541
LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
542
  return Use(value,
543
             new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
544
                                      LUnallocated::USED_AT_START));
545
}
546

    
547

    
548
LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
549
  return Use(value, new(zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
550
}
551

    
552

    
553
LOperand* LChunkBuilder::Use(HValue* value) {
554
  return Use(value, new(zone()) LUnallocated(LUnallocated::NONE));
555
}
556

    
557

    
558
LOperand* LChunkBuilder::UseAtStart(HValue* value) {
559
  return Use(value, new(zone()) LUnallocated(LUnallocated::NONE,
560
                                             LUnallocated::USED_AT_START));
561
}
562

    
563

    
564
static inline bool CanBeImmediateConstant(HValue* value) {
565
  return value->IsConstant() && HConstant::cast(value)->NotInNewSpace();
566
}
567

    
568

    
569
LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
570
  return CanBeImmediateConstant(value)
571
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
572
      : Use(value);
573
}
574

    
575

    
576
LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
577
  return CanBeImmediateConstant(value)
578
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
579
      : UseAtStart(value);
580
}
581

    
582

    
583
LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
584
  return CanBeImmediateConstant(value)
585
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
586
      : UseRegister(value);
587
}
588

    
589

    
590
LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
591
  return CanBeImmediateConstant(value)
592
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
593
      : UseRegisterAtStart(value);
594
}
595

    
596

    
597
LOperand* LChunkBuilder::UseConstant(HValue* value) {
598
  return chunk_->DefineConstantOperand(HConstant::cast(value));
599
}
600

    
601

    
602
LOperand* LChunkBuilder::UseAny(HValue* value) {
603
  return value->IsConstant()
604
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
605
      :  Use(value, new(zone()) LUnallocated(LUnallocated::ANY));
606
}
607

    
608

    
609
LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
610
  if (value->EmitAtUses()) {
611
    HInstruction* instr = HInstruction::cast(value);
612
    VisitInstruction(instr);
613
  }
614
  operand->set_virtual_register(value->id());
615
  return operand;
616
}
617

    
618

    
619
template<int I, int T>
620
LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
621
                                    LUnallocated* result) {
622
  result->set_virtual_register(current_instruction_->id());
623
  instr->set_result(result);
624
  return instr;
625
}
626

    
627

    
628
template<int I, int T>
629
LInstruction* LChunkBuilder::DefineAsRegister(
630
    LTemplateInstruction<1, I, T>* instr) {
631
  return Define(instr,
632
                new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
633
}
634

    
635

    
636
template<int I, int T>
637
LInstruction* LChunkBuilder::DefineAsSpilled(
638
    LTemplateInstruction<1, I, T>* instr,
639
    int index) {
640
  return Define(instr,
641
                new(zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
642
}
643

    
644

    
645
template<int I, int T>
646
LInstruction* LChunkBuilder::DefineSameAsFirst(
647
    LTemplateInstruction<1, I, T>* instr) {
648
  return Define(instr,
649
                new(zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
650
}
651

    
652

    
653
template<int I, int T>
654
LInstruction* LChunkBuilder::DefineFixed(LTemplateInstruction<1, I, T>* instr,
655
                                         Register reg) {
656
  return Define(instr, ToUnallocated(reg));
657
}
658

    
659

    
660
template<int I, int T>
661
LInstruction* LChunkBuilder::DefineFixedDouble(
662
    LTemplateInstruction<1, I, T>* instr,
663
    XMMRegister reg) {
664
  return Define(instr, ToUnallocated(reg));
665
}
666

    
667

    
668
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
669
  HEnvironment* hydrogen_env = current_block_->last_environment();
670
  int argument_index_accumulator = 0;
671
  ZoneList<HValue*> objects_to_materialize(0, zone());
672
  instr->set_environment(CreateEnvironment(hydrogen_env,
673
                                           &argument_index_accumulator,
674
                                           &objects_to_materialize));
675
  return instr;
676
}
677

    
678

    
679
LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
680
                                        HInstruction* hinstr,
681
                                        CanDeoptimize can_deoptimize) {
682
  info()->MarkAsNonDeferredCalling();
683

    
684
#ifdef DEBUG
685
  instr->VerifyCall();
686
#endif
687
  instr->MarkAsCall();
688
  instr = AssignPointerMap(instr);
689

    
690
  if (hinstr->HasObservableSideEffects()) {
691
    ASSERT(hinstr->next()->IsSimulate());
692
    HSimulate* sim = HSimulate::cast(hinstr->next());
693
    ASSERT(instruction_pending_deoptimization_environment_ == NULL);
694
    ASSERT(pending_deoptimization_ast_id_.IsNone());
695
    instruction_pending_deoptimization_environment_ = instr;
696
    pending_deoptimization_ast_id_ = sim->ast_id();
697
  }
698

    
699
  // If instruction does not have side-effects lazy deoptimization
700
  // after the call will try to deoptimize to the point before the call.
701
  // Thus we still need to attach environment to this call even if
702
  // call sequence can not deoptimize eagerly.
703
  bool needs_environment =
704
      (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
705
      !hinstr->HasObservableSideEffects();
706
  if (needs_environment && !instr->HasEnvironment()) {
707
    instr = AssignEnvironment(instr);
708
  }
709

    
710
  return instr;
711
}
712

    
713

    
714
LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
715
  ASSERT(!instr->HasPointerMap());
716
  instr->set_pointer_map(new(zone()) LPointerMap(zone()));
717
  return instr;
718
}
719

    
720

    
721
LUnallocated* LChunkBuilder::TempRegister() {
722
  LUnallocated* operand =
723
      new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
724
  int vreg = allocator_->GetVirtualRegister();
725
  if (!allocator_->AllocationOk()) {
726
    Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
727
    vreg = 0;
728
  }
729
  operand->set_virtual_register(vreg);
730
  return operand;
731
}
732

    
733

    
734
LOperand* LChunkBuilder::FixedTemp(Register reg) {
735
  LUnallocated* operand = ToUnallocated(reg);
736
  ASSERT(operand->HasFixedPolicy());
737
  return operand;
738
}
739

    
740

    
741
LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) {
742
  LUnallocated* operand = ToUnallocated(reg);
743
  ASSERT(operand->HasFixedPolicy());
744
  return operand;
745
}
746

    
747

    
748
LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
749
  return new(zone()) LLabel(instr->block());
750
}
751

    
752

    
753
LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
754
  return DefineAsRegister(new(zone()) LDummyUse(UseAny(instr->value())));
755
}
756

    
757

    
758
LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
759
  UNREACHABLE();
760
  return NULL;
761
}
762

    
763

    
764
LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
765
  return AssignEnvironment(new(zone()) LDeoptimize);
766
}
767

    
768

    
769
LInstruction* LChunkBuilder::DoShift(Token::Value op,
770
                                     HBitwiseBinaryOperation* instr) {
771
  if (instr->representation().IsSmiOrInteger32()) {
772
    ASSERT(instr->left()->representation().Equals(instr->representation()));
773
    ASSERT(instr->right()->representation().Equals(instr->representation()));
774
    LOperand* left = UseRegisterAtStart(instr->left());
775

    
776
    HValue* right_value = instr->right();
777
    LOperand* right = NULL;
778
    int constant_value = 0;
779
    bool does_deopt = false;
780
    if (right_value->IsConstant()) {
781
      HConstant* constant = HConstant::cast(right_value);
782
      right = chunk_->DefineConstantOperand(constant);
783
      constant_value = constant->Integer32Value() & 0x1f;
784
      // Left shifts can deoptimize if we shift by > 0 and the result cannot be
785
      // truncated to smi.
786
      if (instr->representation().IsSmi() && constant_value > 0) {
787
        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi);
788
      }
789
    } else {
790
      right = UseFixed(right_value, ecx);
791
    }
792

    
793
    // Shift operations can only deoptimize if we do a logical shift by 0 and
794
    // the result cannot be truncated to int32.
795
    if (op == Token::SHR && constant_value == 0) {
796
      if (FLAG_opt_safe_uint32_operations) {
797
        does_deopt = !instr->CheckFlag(HInstruction::kUint32);
798
      } else {
799
        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32);
800
      }
801
    }
802

    
803
    LInstruction* result =
804
        DefineSameAsFirst(new(zone()) LShiftI(op, left, right, does_deopt));
805
    return does_deopt ? AssignEnvironment(result) : result;
806
  } else {
807
    return DoArithmeticT(op, instr);
808
  }
809
}
810

    
811

    
812
LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
813
                                           HArithmeticBinaryOperation* instr) {
814
  ASSERT(instr->representation().IsDouble());
815
  ASSERT(instr->left()->representation().IsDouble());
816
  ASSERT(instr->right()->representation().IsDouble());
817
  if (op == Token::MOD) {
818
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
819
    LOperand* right = UseRegisterAtStart(instr->BetterRightOperand());
820
    LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
821
    return MarkAsCall(DefineSameAsFirst(result), instr);
822
  } else {
823
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
824
    LOperand* right = UseRegisterAtStart(instr->BetterRightOperand());
825
    LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
826
    return DefineSameAsFirst(result);
827
  }
828
}
829

    
830

    
831
LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
832
                                           HBinaryOperation* instr) {
833
  HValue* left = instr->left();
834
  HValue* right = instr->right();
835
  ASSERT(left->representation().IsTagged());
836
  ASSERT(right->representation().IsTagged());
837
  LOperand* context = UseFixed(instr->context(), esi);
838
  LOperand* left_operand = UseFixed(left, edx);
839
  LOperand* right_operand = UseFixed(right, eax);
840
  LArithmeticT* result =
841
      new(zone()) LArithmeticT(op, context, left_operand, right_operand);
842
  return MarkAsCall(DefineFixed(result, eax), instr);
843
}
844

    
845

    
846
void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
847
  ASSERT(is_building());
848
  current_block_ = block;
849
  next_block_ = next_block;
850
  if (block->IsStartBlock()) {
851
    block->UpdateEnvironment(graph_->start_environment());
852
    argument_count_ = 0;
853
  } else if (block->predecessors()->length() == 1) {
854
    // We have a single predecessor => copy environment and outgoing
855
    // argument count from the predecessor.
856
    ASSERT(block->phis()->length() == 0);
857
    HBasicBlock* pred = block->predecessors()->at(0);
858
    HEnvironment* last_environment = pred->last_environment();
859
    ASSERT(last_environment != NULL);
860
    // Only copy the environment, if it is later used again.
861
    if (pred->end()->SecondSuccessor() == NULL) {
862
      ASSERT(pred->end()->FirstSuccessor() == block);
863
    } else {
864
      if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
865
          pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
866
        last_environment = last_environment->Copy();
867
      }
868
    }
869
    block->UpdateEnvironment(last_environment);
870
    ASSERT(pred->argument_count() >= 0);
871
    argument_count_ = pred->argument_count();
872
  } else {
873
    // We are at a state join => process phis.
874
    HBasicBlock* pred = block->predecessors()->at(0);
875
    // No need to copy the environment, it cannot be used later.
876
    HEnvironment* last_environment = pred->last_environment();
877
    for (int i = 0; i < block->phis()->length(); ++i) {
878
      HPhi* phi = block->phis()->at(i);
879
      if (phi->HasMergedIndex()) {
880
        last_environment->SetValueAt(phi->merged_index(), phi);
881
      }
882
    }
883
    for (int i = 0; i < block->deleted_phis()->length(); ++i) {
884
      if (block->deleted_phis()->at(i) < last_environment->length()) {
885
        last_environment->SetValueAt(block->deleted_phis()->at(i),
886
                                     graph_->GetConstantUndefined());
887
      }
888
    }
889
    block->UpdateEnvironment(last_environment);
890
    // Pick up the outgoing argument count of one of the predecessors.
891
    argument_count_ = pred->argument_count();
892
  }
893
  HInstruction* current = block->first();
894
  int start = chunk_->instructions()->length();
895
  while (current != NULL && !is_aborted()) {
896
    // Code for constants in registers is generated lazily.
897
    if (!current->EmitAtUses()) {
898
      VisitInstruction(current);
899
    }
900
    current = current->next();
901
  }
902
  int end = chunk_->instructions()->length() - 1;
903
  if (end >= start) {
904
    block->set_first_instruction_index(start);
905
    block->set_last_instruction_index(end);
906
  }
907
  block->set_argument_count(argument_count_);
908
  next_block_ = NULL;
909
  current_block_ = NULL;
910
}
911

    
912

    
913
void LChunkBuilder::VisitInstruction(HInstruction* current) {
914
  HInstruction* old_current = current_instruction_;
915
  current_instruction_ = current;
916

    
917
  LInstruction* instr = NULL;
918
  if (current->CanReplaceWithDummyUses()) {
919
    HValue* first_operand = current->OperandCount() == 0
920
        ? graph()->GetConstant1()
921
        : current->OperandAt(0);
922
    instr = DefineAsRegister(new(zone()) LDummyUse(UseAny(first_operand)));
923
    for (int i = 1; i < current->OperandCount(); ++i) {
924
      LInstruction* dummy =
925
          new(zone()) LDummyUse(UseAny(current->OperandAt(i)));
926
      dummy->set_hydrogen_value(current);
927
      chunk_->AddInstruction(dummy, current_block_);
928
    }
929
  } else {
930
    instr = current->CompileToLithium(this);
931
  }
932

    
933
  argument_count_ += current->argument_delta();
934
  ASSERT(argument_count_ >= 0);
935

    
936
  if (instr != NULL) {
937
    // Associate the hydrogen instruction first, since we may need it for
938
    // the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
939
    instr->set_hydrogen_value(current);
940

    
941
#if DEBUG
942
    // Make sure that the lithium instruction has either no fixed register
943
    // constraints in temps or the result OR no uses that are only used at
944
    // start. If this invariant doesn't hold, the register allocator can decide
945
    // to insert a split of a range immediately before the instruction due to an
946
    // already allocated register needing to be used for the instruction's fixed
947
    // register constraint. In this case, The register allocator won't see an
948
    // interference between the split child and the use-at-start (it would if
949
    // the it was just a plain use), so it is free to move the split child into
950
    // the same register that is used for the use-at-start.
951
    // See https://code.google.com/p/chromium/issues/detail?id=201590
952
    if (!(instr->ClobbersRegisters() && instr->ClobbersDoubleRegisters())) {
953
      int fixed = 0;
954
      int used_at_start = 0;
955
      for (UseIterator it(instr); !it.Done(); it.Advance()) {
956
        LUnallocated* operand = LUnallocated::cast(it.Current());
957
        if (operand->IsUsedAtStart()) ++used_at_start;
958
      }
959
      if (instr->Output() != NULL) {
960
        if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
961
      }
962
      for (TempIterator it(instr); !it.Done(); it.Advance()) {
963
        LUnallocated* operand = LUnallocated::cast(it.Current());
964
        if (operand->HasFixedPolicy()) ++fixed;
965
      }
966
      ASSERT(fixed == 0 || used_at_start == 0);
967
    }
968
#endif
969

    
970
    if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
971
      instr = AssignPointerMap(instr);
972
    }
973
    if (FLAG_stress_environments && !instr->HasEnvironment()) {
974
      instr = AssignEnvironment(instr);
975
    }
976
    if (!CpuFeatures::IsSafeForSnapshot(SSE2) && instr->IsGoto() &&
977
        LGoto::cast(instr)->jumps_to_join()) {
978
      // TODO(olivf) Since phis of spilled values are joined as registers
979
      // (not in the stack slot), we need to allow the goto gaps to keep one
980
      // x87 register alive. To ensure all other values are still spilled, we
981
      // insert a fpu register barrier right before.
982
      LClobberDoubles* clobber = new(zone()) LClobberDoubles();
983
      clobber->set_hydrogen_value(current);
984
      chunk_->AddInstruction(clobber, current_block_);
985
    }
986
    chunk_->AddInstruction(instr, current_block_);
987
  }
988
  current_instruction_ = old_current;
989
}
990

    
991

    
992
LEnvironment* LChunkBuilder::CreateEnvironment(
993
    HEnvironment* hydrogen_env,
994
    int* argument_index_accumulator,
995
    ZoneList<HValue*>* objects_to_materialize) {
996
  if (hydrogen_env == NULL) return NULL;
997

    
998
  LEnvironment* outer = CreateEnvironment(hydrogen_env->outer(),
999
                                          argument_index_accumulator,
1000
                                          objects_to_materialize);
1001
  BailoutId ast_id = hydrogen_env->ast_id();
1002
  ASSERT(!ast_id.IsNone() ||
1003
         hydrogen_env->frame_type() != JS_FUNCTION);
1004
  int value_count = hydrogen_env->length() - hydrogen_env->specials_count();
1005
  LEnvironment* result =
1006
      new(zone()) LEnvironment(hydrogen_env->closure(),
1007
                               hydrogen_env->frame_type(),
1008
                               ast_id,
1009
                               hydrogen_env->parameter_count(),
1010
                               argument_count_,
1011
                               value_count,
1012
                               outer,
1013
                               hydrogen_env->entry(),
1014
                               zone());
1015
  int argument_index = *argument_index_accumulator;
1016
  int object_index = objects_to_materialize->length();
1017
  for (int i = 0; i < hydrogen_env->length(); ++i) {
1018
    if (hydrogen_env->is_special_index(i)) continue;
1019

    
1020
    LOperand* op;
1021
    HValue* value = hydrogen_env->values()->at(i);
1022
    if (value->IsArgumentsObject() || value->IsCapturedObject()) {
1023
      objects_to_materialize->Add(value, zone());
1024
      op = LEnvironment::materialization_marker();
1025
    } else if (value->IsPushArgument()) {
1026
      op = new(zone()) LArgument(argument_index++);
1027
    } else {
1028
      op = UseAny(value);
1029
    }
1030
    result->AddValue(op,
1031
                     value->representation(),
1032
                     value->CheckFlag(HInstruction::kUint32));
1033
  }
1034

    
1035
  for (int i = object_index; i < objects_to_materialize->length(); ++i) {
1036
    HValue* object_to_materialize = objects_to_materialize->at(i);
1037
    int previously_materialized_object = -1;
1038
    for (int prev = 0; prev < i; ++prev) {
1039
      if (objects_to_materialize->at(prev) == objects_to_materialize->at(i)) {
1040
        previously_materialized_object = prev;
1041
        break;
1042
      }
1043
    }
1044
    int length = object_to_materialize->OperandCount();
1045
    bool is_arguments = object_to_materialize->IsArgumentsObject();
1046
    if (previously_materialized_object >= 0) {
1047
      result->AddDuplicateObject(previously_materialized_object);
1048
      continue;
1049
    } else {
1050
      result->AddNewObject(is_arguments ? length - 1 : length, is_arguments);
1051
    }
1052
    for (int i = is_arguments ? 1 : 0; i < length; ++i) {
1053
      LOperand* op;
1054
      HValue* value = object_to_materialize->OperandAt(i);
1055
      if (value->IsArgumentsObject() || value->IsCapturedObject()) {
1056
        objects_to_materialize->Add(value, zone());
1057
        op = LEnvironment::materialization_marker();
1058
      } else {
1059
        ASSERT(!value->IsPushArgument());
1060
        op = UseAny(value);
1061
      }
1062
      result->AddValue(op,
1063
                       value->representation(),
1064
                       value->CheckFlag(HInstruction::kUint32));
1065
    }
1066
  }
1067

    
1068
  if (hydrogen_env->frame_type() == JS_FUNCTION) {
1069
    *argument_index_accumulator = argument_index;
1070
  }
1071

    
1072
  return result;
1073
}
1074

    
1075

    
1076
LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
1077
  return new(zone()) LGoto(instr->FirstSuccessor());
1078
}
1079

    
1080

    
1081
LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
1082
  LInstruction* goto_instr = CheckElideControlInstruction(instr);
1083
  if (goto_instr != NULL) return goto_instr;
1084

    
1085
  ToBooleanStub::Types expected = instr->expected_input_types();
1086

    
1087
  // Tagged values that are not known smis or booleans require a
1088
  // deoptimization environment. If the instruction is generic no
1089
  // environment is needed since all cases are handled.
1090
  HValue* value = instr->value();
1091
  Representation rep = value->representation();
1092
  HType type = value->type();
1093
  if (!rep.IsTagged() || type.IsSmi() || type.IsBoolean()) {
1094
    return new(zone()) LBranch(UseRegister(value), NULL);
1095
  }
1096

    
1097
  bool needs_temp = expected.NeedsMap() || expected.IsEmpty();
1098
  LOperand* temp = needs_temp ? TempRegister() : NULL;
1099

    
1100
  // The Generic stub does not have a deopt, so we need no environment.
1101
  if (expected.IsGeneric()) {
1102
    return new(zone()) LBranch(UseRegister(value), temp);
1103
  }
1104

    
1105
  // We need a temporary register when we have to access the map *or* we have
1106
  // no type info yet, in which case we handle all cases (including the ones
1107
  // involving maps).
1108
  return AssignEnvironment(new(zone()) LBranch(UseRegister(value), temp));
1109
}
1110

    
1111

    
1112
LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
1113
  return new(zone()) LDebugBreak();
1114
}
1115

    
1116

    
1117
LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
1118
  ASSERT(instr->value()->representation().IsTagged());
1119
  LOperand* value = UseRegisterAtStart(instr->value());
1120
  return new(zone()) LCmpMapAndBranch(value);
1121
}
1122

    
1123

    
1124
LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
1125
  info()->MarkAsRequiresFrame();
1126
  return DefineAsRegister(new(zone()) LArgumentsLength(Use(length->value())));
1127
}
1128

    
1129

    
1130
LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
1131
  info()->MarkAsRequiresFrame();
1132
  return DefineAsRegister(new(zone()) LArgumentsElements);
1133
}
1134

    
1135

    
1136
LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
1137
  LOperand* left = UseFixed(instr->left(), InstanceofStub::left());
1138
  LOperand* right = UseFixed(instr->right(), InstanceofStub::right());
1139
  LOperand* context = UseFixed(instr->context(), esi);
1140
  LInstanceOf* result = new(zone()) LInstanceOf(context, left, right);
1141
  return MarkAsCall(DefineFixed(result, eax), instr);
1142
}
1143

    
1144

    
1145
LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
1146
    HInstanceOfKnownGlobal* instr) {
1147
  LInstanceOfKnownGlobal* result =
1148
      new(zone()) LInstanceOfKnownGlobal(
1149
          UseFixed(instr->context(), esi),
1150
          UseFixed(instr->left(), InstanceofStub::left()),
1151
          FixedTemp(edi));
1152
  return MarkAsCall(DefineFixed(result, eax), instr);
1153
}
1154

    
1155

    
1156
LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
1157
  LOperand* receiver = UseRegister(instr->receiver());
1158
  LOperand* function = UseRegisterAtStart(instr->function());
1159
  LOperand* temp = TempRegister();
1160
  LWrapReceiver* result =
1161
      new(zone()) LWrapReceiver(receiver, function, temp);
1162
  return AssignEnvironment(DefineSameAsFirst(result));
1163
}
1164

    
1165

    
1166
LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
1167
  LOperand* function = UseFixed(instr->function(), edi);
1168
  LOperand* receiver = UseFixed(instr->receiver(), eax);
1169
  LOperand* length = UseFixed(instr->length(), ebx);
1170
  LOperand* elements = UseFixed(instr->elements(), ecx);
1171
  LApplyArguments* result = new(zone()) LApplyArguments(function,
1172
                                                        receiver,
1173
                                                        length,
1174
                                                        elements);
1175
  return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY);
1176
}
1177

    
1178

    
1179
LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
1180
  LOperand* argument = UseAny(instr->argument());
1181
  return new(zone()) LPushArgument(argument);
1182
}
1183

    
1184

    
1185
LInstruction* LChunkBuilder::DoStoreCodeEntry(
1186
    HStoreCodeEntry* store_code_entry) {
1187
  LOperand* function = UseRegister(store_code_entry->function());
1188
  LOperand* code_object = UseTempRegister(store_code_entry->code_object());
1189
  return new(zone()) LStoreCodeEntry(function, code_object);
1190
}
1191

    
1192

    
1193
LInstruction* LChunkBuilder::DoInnerAllocatedObject(
1194
    HInnerAllocatedObject* inner_object) {
1195
  LOperand* base_object = UseRegisterAtStart(inner_object->base_object());
1196
  LInnerAllocatedObject* result =
1197
    new(zone()) LInnerAllocatedObject(base_object);
1198
  return DefineAsRegister(result);
1199
}
1200

    
1201

    
1202
LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
1203
  return instr->HasNoUses()
1204
      ? NULL
1205
      : DefineAsRegister(new(zone()) LThisFunction);
1206
}
1207

    
1208

    
1209
LInstruction* LChunkBuilder::DoContext(HContext* instr) {
1210
  if (instr->HasNoUses()) return NULL;
1211

    
1212
  if (info()->IsStub()) {
1213
    return DefineFixed(new(zone()) LContext, esi);
1214
  }
1215

    
1216
  return DefineAsRegister(new(zone()) LContext);
1217
}
1218

    
1219

    
1220
LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
1221
  LOperand* context = UseRegisterAtStart(instr->value());
1222
  return DefineAsRegister(new(zone()) LOuterContext(context));
1223
}
1224

    
1225

    
1226
LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
1227
  LOperand* context = UseFixed(instr->context(), esi);
1228
  return MarkAsCall(new(zone()) LDeclareGlobals(context), instr);
1229
}
1230

    
1231

    
1232
LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
1233
  LOperand* context = UseRegisterAtStart(instr->value());
1234
  return DefineAsRegister(new(zone()) LGlobalObject(context));
1235
}
1236

    
1237

    
1238
LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
1239
  LOperand* global_object = UseRegisterAtStart(instr->value());
1240
  return DefineAsRegister(new(zone()) LGlobalReceiver(global_object));
1241
}
1242

    
1243

    
1244
LInstruction* LChunkBuilder::DoCallConstantFunction(
1245
    HCallConstantFunction* instr) {
1246
  return MarkAsCall(DefineFixed(new(zone()) LCallConstantFunction, eax), instr);
1247
}
1248

    
1249

    
1250
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
1251
  LOperand* context = UseFixed(instr->context(), esi);
1252
  LOperand* function = UseFixed(instr->function(), edi);
1253
  LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
1254
  return MarkAsCall(DefineFixed(result, eax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
1255
}
1256

    
1257

    
1258
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1259
  switch (instr->op()) {
1260
    case kMathFloor: return DoMathFloor(instr);
1261
    case kMathRound: return DoMathRound(instr);
1262
    case kMathAbs: return DoMathAbs(instr);
1263
    case kMathLog: return DoMathLog(instr);
1264
    case kMathSin: return DoMathSin(instr);
1265
    case kMathCos: return DoMathCos(instr);
1266
    case kMathTan: return DoMathTan(instr);
1267
    case kMathExp: return DoMathExp(instr);
1268
    case kMathSqrt: return DoMathSqrt(instr);
1269
    case kMathPowHalf: return DoMathPowHalf(instr);
1270
    default:
1271
      UNREACHABLE();
1272
      return NULL;
1273
  }
1274
}
1275

    
1276

    
1277
LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
1278
  LOperand* input = UseRegisterAtStart(instr->value());
1279
  LMathFloor* result = new(zone()) LMathFloor(input);
1280
  return AssignEnvironment(DefineAsRegister(result));
1281
}
1282

    
1283

    
1284
LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
1285
  LOperand* context = UseAny(instr->context());
1286
  LOperand* input = UseRegister(instr->value());
1287
  LOperand* temp = FixedTemp(xmm4);
1288
  LMathRound* result = new(zone()) LMathRound(context, input, temp);
1289
  return AssignEnvironment(DefineAsRegister(result));
1290
}
1291

    
1292

    
1293
LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
1294
  LOperand* context = UseAny(instr->context());  // Deferred use.
1295
  LOperand* input = UseRegisterAtStart(instr->value());
1296
  LMathAbs* result = new(zone()) LMathAbs(context, input);
1297
  return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1298
}
1299

    
1300

    
1301
LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
1302
  ASSERT(instr->representation().IsDouble());
1303
  ASSERT(instr->value()->representation().IsDouble());
1304
  LOperand* input = UseRegisterAtStart(instr->value());
1305
  LMathLog* result = new(zone()) LMathLog(input);
1306
  return DefineSameAsFirst(result);
1307
}
1308

    
1309

    
1310
LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
1311
  LOperand* input = UseFixedDouble(instr->value(), xmm1);
1312
  LMathSin* result = new(zone()) LMathSin(input);
1313
  return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
1314
}
1315

    
1316

    
1317
LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
1318
  LOperand* input = UseFixedDouble(instr->value(), xmm1);
1319
  LMathCos* result = new(zone()) LMathCos(input);
1320
  return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
1321
}
1322

    
1323

    
1324
LInstruction* LChunkBuilder::DoMathTan(HUnaryMathOperation* instr) {
1325
  LOperand* input = UseFixedDouble(instr->value(), xmm1);
1326
  LMathTan* result = new(zone()) LMathTan(input);
1327
  return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
1328
}
1329

    
1330

    
1331
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
1332
  ASSERT(instr->representation().IsDouble());
1333
  ASSERT(instr->value()->representation().IsDouble());
1334
  LOperand* value = UseTempRegister(instr->value());
1335
  LOperand* temp1 = TempRegister();
1336
  LOperand* temp2 = TempRegister();
1337
  LMathExp* result = new(zone()) LMathExp(value, temp1, temp2);
1338
  return DefineAsRegister(result);
1339
}
1340

    
1341

    
1342
LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
1343
  LOperand* input = UseRegisterAtStart(instr->value());
1344
  LMathSqrt* result = new(zone()) LMathSqrt(input);
1345
  return DefineSameAsFirst(result);
1346
}
1347

    
1348

    
1349
LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
1350
  LOperand* context = UseAny(instr->context());
1351
  LOperand* input = UseRegisterAtStart(instr->value());
1352
  LOperand* temp = TempRegister();
1353
  LMathPowHalf* result = new(zone()) LMathPowHalf(context, input, temp);
1354
  return DefineSameAsFirst(result);
1355
}
1356

    
1357

    
1358
LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
1359
  ASSERT(instr->key()->representation().IsTagged());
1360
  LOperand* context = UseFixed(instr->context(), esi);
1361
  LOperand* key = UseFixed(instr->key(), ecx);
1362
  LCallKeyed* result = new(zone()) LCallKeyed(context, key);
1363
  return MarkAsCall(DefineFixed(result, eax), instr);
1364
}
1365

    
1366

    
1367
LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
1368
  LOperand* context = UseFixed(instr->context(), esi);
1369
  LCallNamed* result = new(zone()) LCallNamed(context);
1370
  return MarkAsCall(DefineFixed(result, eax), instr);
1371
}
1372

    
1373

    
1374
LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
1375
  LOperand* context = UseFixed(instr->context(), esi);
1376
  LCallGlobal* result = new(zone()) LCallGlobal(context);
1377
  return MarkAsCall(DefineFixed(result, eax), instr);
1378
}
1379

    
1380

    
1381
LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
1382
  return MarkAsCall(DefineFixed(new(zone()) LCallKnownGlobal, eax), instr);
1383
}
1384

    
1385

    
1386
LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
1387
  LOperand* context = UseFixed(instr->context(), esi);
1388
  LOperand* constructor = UseFixed(instr->constructor(), edi);
1389
  LCallNew* result = new(zone()) LCallNew(context, constructor);
1390
  return MarkAsCall(DefineFixed(result, eax), instr);
1391
}
1392

    
1393

    
1394
LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
1395
  LOperand* context = UseFixed(instr->context(), esi);
1396
  LOperand* constructor = UseFixed(instr->constructor(), edi);
1397
  LCallNewArray* result = new(zone()) LCallNewArray(context, constructor);
1398
  return MarkAsCall(DefineFixed(result, eax), instr);
1399
}
1400

    
1401

    
1402
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1403
  LOperand* context = UseFixed(instr->context(), esi);
1404
  LOperand* function = UseFixed(instr->function(), edi);
1405
  LCallFunction* result = new(zone()) LCallFunction(context, function);
1406
  return MarkAsCall(DefineFixed(result, eax), instr);
1407
}
1408

    
1409

    
1410
LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1411
  LOperand* context = UseFixed(instr->context(), esi);
1412
  return MarkAsCall(DefineFixed(new(zone()) LCallRuntime(context), eax), instr);
1413
}
1414

    
1415

    
1416
LInstruction* LChunkBuilder::DoRor(HRor* instr) {
1417
  return DoShift(Token::ROR, instr);
1418
}
1419

    
1420

    
1421
LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1422
  return DoShift(Token::SHR, instr);
1423
}
1424

    
1425

    
1426
LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1427
  return DoShift(Token::SAR, instr);
1428
}
1429

    
1430

    
1431
LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1432
  return DoShift(Token::SHL, instr);
1433
}
1434

    
1435

    
1436
LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
1437
  if (instr->representation().IsSmiOrInteger32()) {
1438
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1439
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1440
    ASSERT(instr->CheckFlag(HValue::kTruncatingToInt32));
1441

    
1442
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1443
    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1444
    return DefineSameAsFirst(new(zone()) LBitI(left, right));
1445
  } else {
1446
    return DoArithmeticT(instr->op(), instr);
1447
  }
1448
}
1449

    
1450

    
1451
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1452
  if (instr->representation().IsSmiOrInteger32()) {
1453
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1454
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1455
    if (instr->HasPowerOf2Divisor()) {
1456
      ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
1457
      LOperand* value = UseRegisterAtStart(instr->left());
1458
      LDivI* div =
1459
          new(zone()) LDivI(value, UseOrConstant(instr->right()), NULL);
1460
      return AssignEnvironment(DefineSameAsFirst(div));
1461
    }
1462
    // The temporary operand is necessary to ensure that right is not allocated
1463
    // into edx.
1464
    LOperand* temp = FixedTemp(edx);
1465
    LOperand* dividend = UseFixed(instr->left(), eax);
1466
    LOperand* divisor = UseRegister(instr->right());
1467
    LDivI* result = new(zone()) LDivI(dividend, divisor, temp);
1468
    return AssignEnvironment(DefineFixed(result, eax));
1469
  } else if (instr->representation().IsDouble()) {
1470
    return DoArithmeticD(Token::DIV, instr);
1471
  } else {
1472
    return DoArithmeticT(Token::DIV, instr);
1473
  }
1474
}
1475

    
1476

    
1477
HValue* LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(HValue* divisor) {
1478
  if (divisor->IsConstant() &&
1479
      HConstant::cast(divisor)->HasInteger32Value()) {
1480
    HConstant* constant_val = HConstant::cast(divisor);
1481
    return constant_val->CopyToRepresentation(Representation::Integer32(),
1482
                                              divisor->block()->zone());
1483
  }
1484
  // A value with an integer representation does not need to be transformed.
1485
  if (divisor->representation().IsInteger32()) {
1486
    return divisor;
1487
  // A change from an integer32 can be replaced by the integer32 value.
1488
  } else if (divisor->IsChange() &&
1489
             HChange::cast(divisor)->from().IsInteger32()) {
1490
    return HChange::cast(divisor)->value();
1491
  }
1492
  return NULL;
1493
}
1494

    
1495

    
1496
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
1497
  HValue* right = instr->right();
1498
  if (!right->IsConstant()) {
1499
    ASSERT(right->representation().IsInteger32());
1500
    // The temporary operand is necessary to ensure that right is not allocated
1501
    // into edx.
1502
    LOperand* temp = FixedTemp(edx);
1503
    LOperand* dividend = UseFixed(instr->left(), eax);
1504
    LOperand* divisor = UseRegister(instr->right());
1505
    LDivI* flooring_div = new(zone()) LDivI(dividend, divisor, temp);
1506
    return AssignEnvironment(DefineFixed(flooring_div, eax));
1507
  }
1508

    
1509
  ASSERT(right->IsConstant() && HConstant::cast(right)->HasInteger32Value());
1510
  LOperand* divisor = chunk_->DefineConstantOperand(HConstant::cast(right));
1511
  int32_t divisor_si = HConstant::cast(right)->Integer32Value();
1512
  if (divisor_si == 0) {
1513
    LOperand* dividend = UseRegister(instr->left());
1514
    return AssignEnvironment(DefineAsRegister(
1515
        new(zone()) LMathFloorOfDiv(dividend, divisor, NULL)));
1516
  } else if (IsPowerOf2(abs(divisor_si))) {
1517
    // use dividend as temp if divisor < 0 && divisor != -1
1518
    LOperand* dividend = divisor_si < -1 ? UseTempRegister(instr->left()) :
1519
                         UseRegisterAtStart(instr->left());
1520
    LInstruction* result = DefineAsRegister(
1521
        new(zone()) LMathFloorOfDiv(dividend, divisor, NULL));
1522
    return divisor_si < 0 ? AssignEnvironment(result) : result;
1523
  } else {
1524
    // needs edx:eax, plus a temp
1525
    LOperand* dividend = UseFixed(instr->left(), eax);
1526
    LOperand* temp = TempRegister();
1527
    LInstruction* result = DefineFixed(
1528
        new(zone()) LMathFloorOfDiv(dividend, divisor, temp), edx);
1529
    return divisor_si < 0 ? AssignEnvironment(result) : result;
1530
  }
1531
}
1532

    
1533

    
1534
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1535
  HValue* left = instr->left();
1536
  HValue* right = instr->right();
1537
  if (instr->representation().IsSmiOrInteger32()) {
1538
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1539
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1540

    
1541
    if (instr->HasPowerOf2Divisor()) {
1542
      ASSERT(!right->CanBeZero());
1543
      LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
1544
                                     UseOrConstant(right),
1545
                                     NULL);
1546
      LInstruction* result = DefineSameAsFirst(mod);
1547
      return (left->CanBeNegative() &&
1548
              instr->CheckFlag(HValue::kBailoutOnMinusZero))
1549
          ? AssignEnvironment(result)
1550
          : result;
1551
    } else if (instr->fixed_right_arg().has_value) {
1552
      LModI* mod = new(zone()) LModI(UseRegister(left),
1553
                                     UseRegisterAtStart(right),
1554
                                     NULL);
1555
      return AssignEnvironment(DefineSameAsFirst(mod));
1556
    } else {
1557
      // The temporary operand is necessary to ensure that right is not
1558
      // allocated into edx.
1559
      LModI* mod = new(zone()) LModI(UseFixed(left, eax),
1560
                                     UseRegister(right),
1561
                                     FixedTemp(edx));
1562
      LInstruction* result = DefineFixed(mod, edx);
1563
      return (right->CanBeZero() ||
1564
              (left->RangeCanInclude(kMinInt) &&
1565
               right->RangeCanInclude(-1) &&
1566
               instr->CheckFlag(HValue::kBailoutOnMinusZero)) ||
1567
              (left->CanBeNegative() &&
1568
               instr->CanBeZero() &&
1569
               instr->CheckFlag(HValue::kBailoutOnMinusZero)))
1570
          ? AssignEnvironment(result)
1571
          : result;
1572
    }
1573
  } else if (instr->representation().IsDouble()) {
1574
    return DoArithmeticD(Token::MOD, instr);
1575
  } else {
1576
    return DoArithmeticT(Token::MOD, instr);
1577
  }
1578
}
1579

    
1580

    
1581
LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1582
  if (instr->representation().IsSmiOrInteger32()) {
1583
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1584
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1585
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1586
    LOperand* right = UseOrConstant(instr->BetterRightOperand());
1587
    LOperand* temp = NULL;
1588
    if (instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1589
      temp = TempRegister();
1590
    }
1591
    LMulI* mul = new(zone()) LMulI(left, right, temp);
1592
    if (instr->CheckFlag(HValue::kCanOverflow) ||
1593
        instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1594
      AssignEnvironment(mul);
1595
    }
1596
    return DefineSameAsFirst(mul);
1597
  } else if (instr->representation().IsDouble()) {
1598
    return DoArithmeticD(Token::MUL, instr);
1599
  } else {
1600
    return DoArithmeticT(Token::MUL, instr);
1601
  }
1602
}
1603

    
1604

    
1605
LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1606
  if (instr->representation().IsSmiOrInteger32()) {
1607
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1608
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1609
    LOperand* left = UseRegisterAtStart(instr->left());
1610
    LOperand* right = UseOrConstantAtStart(instr->right());
1611
    LSubI* sub = new(zone()) LSubI(left, right);
1612
    LInstruction* result = DefineSameAsFirst(sub);
1613
    if (instr->CheckFlag(HValue::kCanOverflow)) {
1614
      result = AssignEnvironment(result);
1615
    }
1616
    return result;
1617
  } else if (instr->representation().IsDouble()) {
1618
    return DoArithmeticD(Token::SUB, instr);
1619
  } else {
1620
    return DoArithmeticT(Token::SUB, instr);
1621
  }
1622
}
1623

    
1624

    
1625
LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1626
  if (instr->representation().IsSmiOrInteger32()) {
1627
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1628
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1629
    // Check to see if it would be advantageous to use an lea instruction rather
1630
    // than an add. This is the case when no overflow check is needed and there
1631
    // are multiple uses of the add's inputs, so using a 3-register add will
1632
    // preserve all input values for later uses.
1633
    bool use_lea = LAddI::UseLea(instr);
1634
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1635
    HValue* right_candidate = instr->BetterRightOperand();
1636
    LOperand* right = use_lea
1637
        ? UseRegisterOrConstantAtStart(right_candidate)
1638
        : UseOrConstantAtStart(right_candidate);
1639
    LAddI* add = new(zone()) LAddI(left, right);
1640
    bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
1641
    LInstruction* result = use_lea
1642
        ? DefineAsRegister(add)
1643
        : DefineSameAsFirst(add);
1644
    if (can_overflow) {
1645
      result = AssignEnvironment(result);
1646
    }
1647
    return result;
1648
  } else if (instr->representation().IsDouble()) {
1649
    return DoArithmeticD(Token::ADD, instr);
1650
  } else {
1651
    return DoArithmeticT(Token::ADD, instr);
1652
  }
1653
}
1654

    
1655

    
1656
LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
1657
  LOperand* left = NULL;
1658
  LOperand* right = NULL;
1659
  if (instr->representation().IsSmiOrInteger32()) {
1660
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1661
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1662
    left = UseRegisterAtStart(instr->BetterLeftOperand());
1663
    right = UseOrConstantAtStart(instr->BetterRightOperand());
1664
  } else {
1665
    ASSERT(instr->representation().IsDouble());
1666
    ASSERT(instr->left()->representation().IsDouble());
1667
    ASSERT(instr->right()->representation().IsDouble());
1668
    left = UseRegisterAtStart(instr->left());
1669
    right = UseRegisterAtStart(instr->right());
1670
  }
1671
  LMathMinMax* minmax = new(zone()) LMathMinMax(left, right);
1672
  return DefineSameAsFirst(minmax);
1673
}
1674

    
1675

    
1676
LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1677
  ASSERT(instr->representation().IsDouble());
1678
  // We call a C function for double power. It can't trigger a GC.
1679
  // We need to use fixed result register for the call.
1680
  Representation exponent_type = instr->right()->representation();
1681
  ASSERT(instr->left()->representation().IsDouble());
1682
  LOperand* left = UseFixedDouble(instr->left(), xmm2);
1683
  LOperand* right = exponent_type.IsDouble() ?
1684
      UseFixedDouble(instr->right(), xmm1) :
1685
      UseFixed(instr->right(), eax);
1686
  LPower* result = new(zone()) LPower(left, right);
1687
  return MarkAsCall(DefineFixedDouble(result, xmm3), instr,
1688
                    CAN_DEOPTIMIZE_EAGERLY);
1689
}
1690

    
1691

    
1692
LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
1693
  ASSERT(instr->representation().IsDouble());
1694
  ASSERT(instr->global_object()->representation().IsTagged());
1695
  LOperand* global_object = UseTempRegister(instr->global_object());
1696
  LOperand* scratch = TempRegister();
1697
  LOperand* scratch2 = TempRegister();
1698
  LOperand* scratch3 = TempRegister();
1699
  LRandom* result = new(zone()) LRandom(
1700
      global_object, scratch, scratch2, scratch3);
1701
  return DefineFixedDouble(result, xmm1);
1702
}
1703

    
1704

    
1705
LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1706
  ASSERT(instr->left()->representation().IsSmiOrTagged());
1707
  ASSERT(instr->right()->representation().IsSmiOrTagged());
1708
  LOperand* context = UseFixed(instr->context(), esi);
1709
  LOperand* left = UseFixed(instr->left(), edx);
1710
  LOperand* right = UseFixed(instr->right(), eax);
1711
  LCmpT* result = new(zone()) LCmpT(context, left, right);
1712
  return MarkAsCall(DefineFixed(result, eax), instr);
1713
}
1714

    
1715

    
1716
LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
1717
    HCompareNumericAndBranch* instr) {
1718
  Representation r = instr->representation();
1719
  if (r.IsSmiOrInteger32()) {
1720
    ASSERT(instr->left()->representation().Equals(r));
1721
    ASSERT(instr->right()->representation().Equals(r));
1722
    LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1723
    LOperand* right = UseOrConstantAtStart(instr->right());
1724
    return new(zone()) LCompareNumericAndBranch(left, right);
1725
  } else {
1726
    ASSERT(r.IsDouble());
1727
    ASSERT(instr->left()->representation().IsDouble());
1728
    ASSERT(instr->right()->representation().IsDouble());
1729
    LOperand* left;
1730
    LOperand* right;
1731
    if (CanBeImmediateConstant(instr->left()) &&
1732
        CanBeImmediateConstant(instr->right())) {
1733
      // The code generator requires either both inputs to be constant
1734
      // operands, or neither.
1735
      left = UseConstant(instr->left());
1736
      right = UseConstant(instr->right());
1737
    } else {
1738
      left = UseRegisterAtStart(instr->left());
1739
      right = UseRegisterAtStart(instr->right());
1740
    }
1741
    return new(zone()) LCompareNumericAndBranch(left, right);
1742
  }
1743
}
1744

    
1745

    
1746
LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
1747
    HCompareObjectEqAndBranch* instr) {
1748
  LInstruction* goto_instr = CheckElideControlInstruction(instr);
1749
  if (goto_instr != NULL) return goto_instr;
1750
  LOperand* left = UseRegisterAtStart(instr->left());
1751
  LOperand* right = UseOrConstantAtStart(instr->right());
1752
  return new(zone()) LCmpObjectEqAndBranch(left, right);
1753
}
1754

    
1755

    
1756
LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
1757
    HCompareHoleAndBranch* instr) {
1758
  LOperand* value = UseRegisterAtStart(instr->value());
1759
  return new(zone()) LCmpHoleAndBranch(value);
1760
}
1761

    
1762

    
1763
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
1764
  ASSERT(instr->value()->representation().IsSmiOrTagged());
1765
  LOperand* temp = TempRegister();
1766
  return new(zone()) LIsObjectAndBranch(UseRegister(instr->value()), temp);
1767
}
1768

    
1769

    
1770
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1771
  ASSERT(instr->value()->representation().IsTagged());
1772
  LOperand* temp = TempRegister();
1773
  return new(zone()) LIsStringAndBranch(UseRegister(instr->value()), temp);
1774
}
1775

    
1776

    
1777
LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1778
  ASSERT(instr->value()->representation().IsTagged());
1779
  return new(zone()) LIsSmiAndBranch(Use(instr->value()));
1780
}
1781

    
1782

    
1783
LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1784
    HIsUndetectableAndBranch* instr) {
1785
  ASSERT(instr->value()->representation().IsTagged());
1786
  return new(zone()) LIsUndetectableAndBranch(
1787
      UseRegisterAtStart(instr->value()), TempRegister());
1788
}
1789

    
1790

    
1791
LInstruction* LChunkBuilder::DoStringCompareAndBranch(
1792
    HStringCompareAndBranch* instr) {
1793
  ASSERT(instr->left()->representation().IsTagged());
1794
  ASSERT(instr->right()->representation().IsTagged());
1795
  LOperand* context = UseFixed(instr->context(), esi);
1796
  LOperand* left = UseFixed(instr->left(), edx);
1797
  LOperand* right = UseFixed(instr->right(), eax);
1798

    
1799
  LStringCompareAndBranch* result = new(zone())
1800
      LStringCompareAndBranch(context, left, right);
1801

    
1802
  return MarkAsCall(result, instr);
1803
}
1804

    
1805

    
1806
LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1807
    HHasInstanceTypeAndBranch* instr) {
1808
  ASSERT(instr->value()->representation().IsTagged());
1809
  return new(zone()) LHasInstanceTypeAndBranch(
1810
      UseRegisterAtStart(instr->value()),
1811
      TempRegister());
1812
}
1813

    
1814

    
1815
LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
1816
    HGetCachedArrayIndex* instr)  {
1817
  ASSERT(instr->value()->representation().IsTagged());
1818
  LOperand* value = UseRegisterAtStart(instr->value());
1819

    
1820
  return DefineAsRegister(new(zone()) LGetCachedArrayIndex(value));
1821
}
1822

    
1823

    
1824
LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
1825
    HHasCachedArrayIndexAndBranch* instr) {
1826
  ASSERT(instr->value()->representation().IsTagged());
1827
  return new(zone()) LHasCachedArrayIndexAndBranch(
1828
      UseRegisterAtStart(instr->value()));
1829
}
1830

    
1831

    
1832
LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1833
    HClassOfTestAndBranch* instr) {
1834
  ASSERT(instr->value()->representation().IsTagged());
1835
  return new(zone()) LClassOfTestAndBranch(UseRegister(instr->value()),
1836
                                           TempRegister(),
1837
                                           TempRegister());
1838
}
1839

    
1840

    
1841
LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) {
1842
  LOperand* map = UseRegisterAtStart(instr->value());
1843
  return DefineAsRegister(new(zone()) LMapEnumLength(map));
1844
}
1845

    
1846

    
1847
LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
1848
  LOperand* object = UseRegisterAtStart(instr->value());
1849
  return DefineAsRegister(new(zone()) LElementsKind(object));
1850
}
1851

    
1852

    
1853
LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
1854
  LOperand* object = UseRegister(instr->value());
1855
  LValueOf* result = new(zone()) LValueOf(object, TempRegister());
1856
  return DefineSameAsFirst(result);
1857
}
1858

    
1859

    
1860
LInstruction* LChunkBuilder::DoDateField(HDateField* instr) {
1861
  LOperand* date = UseFixed(instr->value(), eax);
1862
  LDateField* result =
1863
      new(zone()) LDateField(date, FixedTemp(ecx), instr->index());
1864
  return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY);
1865
}
1866

    
1867

    
1868
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
1869
  LOperand* string = UseRegister(instr->string());
1870
  LOperand* index = UseRegister(instr->index());
1871
  ASSERT(ecx.is_byte_register());
1872
  LOperand* value = UseFixed(instr->value(), ecx);
1873
  LSeqStringSetChar* result =
1874
      new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
1875
  return DefineSameAsFirst(result);
1876
}
1877

    
1878

    
1879
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1880
  return AssignEnvironment(new(zone()) LBoundsCheck(
1881
      UseRegisterOrConstantAtStart(instr->index()),
1882
      UseAtStart(instr->length())));
1883
}
1884

    
1885

    
1886
LInstruction* LChunkBuilder::DoBoundsCheckBaseIndexInformation(
1887
    HBoundsCheckBaseIndexInformation* instr) {
1888
  UNREACHABLE();
1889
  return NULL;
1890
}
1891

    
1892

    
1893
LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1894
  // The control instruction marking the end of a block that completed
1895
  // abruptly (e.g., threw an exception).  There is nothing specific to do.
1896
  return NULL;
1897
}
1898

    
1899

    
1900
LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
1901
  LOperand* context = UseFixed(instr->context(), esi);
1902
  LOperand* value = UseFixed(instr->value(), eax);
1903
  return MarkAsCall(new(zone()) LThrow(context, value), instr);
1904
}
1905

    
1906

    
1907
LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) {
1908
  return NULL;
1909
}
1910

    
1911

    
1912
LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
1913
  // All HForceRepresentation instructions should be eliminated in the
1914
  // representation change phase of Hydrogen.
1915
  UNREACHABLE();
1916
  return NULL;
1917
}
1918

    
1919

    
1920
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1921
  Representation from = instr->from();
1922
  Representation to = instr->to();
1923
  if (from.IsSmi()) {
1924
    if (to.IsTagged()) {
1925
      LOperand* value = UseRegister(instr->value());
1926
      return DefineSameAsFirst(new(zone()) LDummyUse(value));
1927
    }
1928
    from = Representation::Tagged();
1929
  }
1930
  // Only mark conversions that might need to allocate as calling rather than
1931
  // all changes. This makes simple, non-allocating conversion not have to force
1932
  // building a stack frame.
1933
  if (from.IsTagged()) {
1934
    if (to.IsDouble()) {
1935
      LOperand* value = UseRegister(instr->value());
1936
      // Temp register only necessary for minus zero check.
1937
      LOperand* temp = TempRegister();
1938
      LNumberUntagD* res = new(zone()) LNumberUntagD(value, temp);
1939
      return AssignEnvironment(DefineAsRegister(res));
1940
    } else if (to.IsSmi()) {
1941
      HValue* val = instr->value();
1942
      LOperand* value = UseRegister(val);
1943
      if (val->type().IsSmi()) {
1944
        return DefineSameAsFirst(new(zone()) LDummyUse(value));
1945
      }
1946
      return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
1947
    } else {
1948
      ASSERT(to.IsInteger32());
1949
      HValue* val = instr->value();
1950
      if (val->type().IsSmi() || val->representation().IsSmi()) {
1951
        LOperand* value = UseRegister(val);
1952
        return DefineSameAsFirst(new(zone()) LSmiUntag(value, false));
1953
      } else {
1954
        bool truncating = instr->CanTruncateToInt32();
1955
        LOperand* xmm_temp =
1956
            (CpuFeatures::IsSafeForSnapshot(SSE2) && !truncating)
1957
                ? FixedTemp(xmm1) : NULL;
1958
        LTaggedToI* res = new(zone()) LTaggedToI(UseRegister(val), xmm_temp);
1959
        return AssignEnvironment(DefineSameAsFirst(res));
1960
      }
1961
    }
1962
  } else if (from.IsDouble()) {
1963
    if (to.IsTagged()) {
1964
      info()->MarkAsDeferredCalling();
1965
      LOperand* value = UseRegisterAtStart(instr->value());
1966
      LOperand* temp = FLAG_inline_new ? TempRegister() : NULL;
1967

    
1968
      // Make sure that temp and result_temp are different registers.
1969
      LUnallocated* result_temp = TempRegister();
1970
      LNumberTagD* result = new(zone()) LNumberTagD(value, temp);
1971
      return AssignPointerMap(Define(result, result_temp));
1972
    } else if (to.IsSmi()) {
1973
      LOperand* value = UseRegister(instr->value());
1974
      return AssignEnvironment(
1975
          DefineAsRegister(new(zone()) LDoubleToSmi(value)));
1976
    } else {
1977
      ASSERT(to.IsInteger32());
1978
      bool truncating = instr->CanTruncateToInt32();
1979
      bool needs_temp = CpuFeatures::IsSafeForSnapshot(SSE2) && !truncating;
1980
      LOperand* value = needs_temp ?
1981
          UseTempRegister(instr->value()) : UseRegister(instr->value());
1982
      LOperand* temp = needs_temp ? TempRegister() : NULL;
1983
      return AssignEnvironment(
1984
          DefineAsRegister(new(zone()) LDoubleToI(value, temp)));
1985
    }
1986
  } else if (from.IsInteger32()) {
1987
    info()->MarkAsDeferredCalling();
1988
    if (to.IsTagged()) {
1989
      HValue* val = instr->value();
1990
      LOperand* value = UseRegister(val);
1991
      if (val->HasRange() && val->range()->IsInSmiRange()) {
1992
        return DefineSameAsFirst(new(zone()) LSmiTag(value));
1993
      } else if (val->CheckFlag(HInstruction::kUint32)) {
1994
        LOperand* temp = CpuFeatures::IsSupported(SSE2) ? FixedTemp(xmm1)
1995
                                                        : NULL;
1996
        LNumberTagU* result = new(zone()) LNumberTagU(value, temp);
1997
        return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1998
      } else {
1999
        LNumberTagI* result = new(zone()) LNumberTagI(value);
2000
        return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
2001
      }
2002
    } else if (to.IsSmi()) {
2003
      HValue* val = instr->value();
2004
      LOperand* value = UseRegister(val);
2005
      LInstruction* result = val->CheckFlag(HInstruction::kUint32)
2006
           ? DefineSameAsFirst(new(zone()) LUint32ToSmi(value))
2007
           : DefineSameAsFirst(new(zone()) LInteger32ToSmi(value));
2008
      if (val->HasRange() && val->range()->IsInSmiRange()) {
2009
        return result;
2010
      }
2011
      return AssignEnvironment(result);
2012
    } else {
2013
      ASSERT(to.IsDouble());
2014
      if (instr->value()->CheckFlag(HInstruction::kUint32)) {
2015
        LOperand* temp = FixedTemp(xmm1);
2016
        return DefineAsRegister(
2017
            new(zone()) LUint32ToDouble(UseRegister(instr->value()), temp));
2018
      } else {
2019
        return DefineAsRegister(
2020
            new(zone()) LInteger32ToDouble(Use(instr->value())));
2021
      }
2022
    }
2023
  }
2024
  UNREACHABLE();
2025
  return NULL;
2026
}
2027

    
2028

    
2029
LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
2030
  LOperand* value = UseAtStart(instr->value());
2031
  return AssignEnvironment(new(zone()) LCheckNonSmi(value));
2032
}
2033

    
2034

    
2035
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
2036
  LOperand* value = UseRegisterAtStart(instr->value());
2037
  return AssignEnvironment(new(zone()) LCheckSmi(value));
2038
}
2039

    
2040

    
2041
LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
2042
  LOperand* value = UseRegisterAtStart(instr->value());
2043
  LOperand* temp = TempRegister();
2044
  LCheckInstanceType* result = new(zone()) LCheckInstanceType(value, temp);
2045
  return AssignEnvironment(result);
2046
}
2047

    
2048

    
2049
LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
2050
  // If the object is in new space, we'll emit a global cell compare and so
2051
  // want the value in a register.  If the object gets promoted before we
2052
  // emit code, we will still get the register but will do an immediate
2053
  // compare instead of the cell compare.  This is safe.
2054
  LOperand* value = instr->object_in_new_space()
2055
      ? UseRegisterAtStart(instr->value()) : UseAtStart(instr->value());
2056
  return AssignEnvironment(new(zone()) LCheckValue(value));
2057
}
2058

    
2059

    
2060
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
2061
  LOperand* value = NULL;
2062
  if (!instr->CanOmitMapChecks()) {
2063
    value = UseRegisterAtStart(instr->value());
2064
    if (instr->has_migration_target()) info()->MarkAsDeferredCalling();
2065
  }
2066
  LCheckMaps* result = new(zone()) LCheckMaps(value);
2067
  if (!instr->CanOmitMapChecks()) {
2068
    AssignEnvironment(result);
2069
    if (instr->has_migration_target()) return AssignPointerMap(result);
2070
  }
2071
  return result;
2072
}
2073

    
2074

    
2075
LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
2076
  HValue* value = instr->value();
2077
  Representation input_rep = value->representation();
2078
  if (input_rep.IsDouble()) {
2079
    LOperand* reg = UseRegister(value);
2080
    return DefineFixed(new(zone()) LClampDToUint8(reg), eax);
2081
  } else if (input_rep.IsInteger32()) {
2082
    LOperand* reg = UseFixed(value, eax);
2083
    return DefineFixed(new(zone()) LClampIToUint8(reg), eax);
2084
  } else {
2085
    ASSERT(input_rep.IsSmiOrTagged());
2086
    if (CpuFeatures::IsSupported(SSE2)) {
2087
      LOperand* reg = UseFixed(value, eax);
2088
      // Register allocator doesn't (yet) support allocation of double
2089
      // temps. Reserve xmm1 explicitly.
2090
      LOperand* temp = FixedTemp(xmm1);
2091
      LClampTToUint8* result = new(zone()) LClampTToUint8(reg, temp);
2092
      return AssignEnvironment(DefineFixed(result, eax));
2093
    } else {
2094
      LOperand* value = UseRegister(instr->value());
2095
      LClampTToUint8NoSSE2* res =
2096
          new(zone()) LClampTToUint8NoSSE2(value, TempRegister(),
2097
                                           TempRegister(), TempRegister());
2098
      return AssignEnvironment(DefineFixed(res, ecx));
2099
    }
2100
  }
2101
}
2102

    
2103

    
2104
LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
2105
  LOperand* context = info()->IsStub()
2106
      ? UseFixed(instr->context(), esi)
2107
      : NULL;
2108
  LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
2109
  return new(zone()) LReturn(UseFixed(instr->value(), eax), context,
2110
                             parameter_count);
2111
}
2112

    
2113

    
2114
LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
2115
  Representation r = instr->representation();
2116
  if (r.IsSmi()) {
2117
    return DefineAsRegister(new(zone()) LConstantS);
2118
  } else if (r.IsInteger32()) {
2119
    return DefineAsRegister(new(zone()) LConstantI);
2120
  } else if (r.IsDouble()) {
2121
    double value = instr->DoubleValue();
2122
    bool value_is_zero = BitCast<uint64_t, double>(value) == 0;
2123
    LOperand* temp = value_is_zero ? NULL : TempRegister();
2124
    return DefineAsRegister(new(zone()) LConstantD(temp));
2125
  } else if (r.IsExternal()) {
2126
    return DefineAsRegister(new(zone()) LConstantE);
2127
  } else if (r.IsTagged()) {
2128
    return DefineAsRegister(new(zone()) LConstantT);
2129
  } else {
2130
    UNREACHABLE();
2131
    return NULL;
2132
  }
2133
}
2134

    
2135

    
2136
LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
2137
  LLoadGlobalCell* result = new(zone()) LLoadGlobalCell;
2138
  return instr->RequiresHoleCheck()
2139
      ? AssignEnvironment(DefineAsRegister(result))
2140
      : DefineAsRegister(result);
2141
}
2142

    
2143

    
2144
LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
2145
  LOperand* context = UseFixed(instr->context(), esi);
2146
  LOperand* global_object = UseFixed(instr->global_object(), edx);
2147
  LLoadGlobalGeneric* result =
2148
      new(zone()) LLoadGlobalGeneric(context, global_object);
2149
  return MarkAsCall(DefineFixed(result, eax), instr);
2150
}
2151

    
2152

    
2153
LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
2154
  LStoreGlobalCell* result =
2155
      new(zone()) LStoreGlobalCell(UseRegister(instr->value()));
2156
  return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
2157
}
2158

    
2159

    
2160
LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
2161
  LOperand* context = UseFixed(instr->context(), esi);
2162
  LOperand* global_object = UseFixed(instr->global_object(), edx);
2163
  LOperand* value = UseFixed(instr->value(), eax);
2164
  LStoreGlobalGeneric* result =
2165
      new(zone()) LStoreGlobalGeneric(context, global_object, value);
2166
  return MarkAsCall(result, instr);
2167
}
2168

    
2169

    
2170
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
2171
  LOperand* context = UseRegisterAtStart(instr->value());
2172
  LInstruction* result =
2173
      DefineAsRegister(new(zone()) LLoadContextSlot(context));
2174
  return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
2175
}
2176

    
2177

    
2178
LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
2179
  LOperand* value;
2180
  LOperand* temp;
2181
  LOperand* context = UseRegister(instr->context());
2182
  if (instr->NeedsWriteBarrier()) {
2183
    value = UseTempRegister(instr->value());
2184
    temp = TempRegister();
2185
  } else {
2186
    value = UseRegister(instr->value());
2187
    temp = NULL;
2188
  }
2189
  LInstruction* result = new(zone()) LStoreContextSlot(context, value, temp);
2190
  return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
2191
}
2192

    
2193

    
2194
LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
2195
  LOperand* obj = (instr->access().IsExternalMemory() &&
2196
                   instr->access().offset() == 0)
2197
      ? UseRegisterOrConstantAtStart(instr->object())
2198
      : UseRegisterAtStart(instr->object());
2199
  return DefineAsRegister(new(zone()) LLoadNamedField(obj));
2200
}
2201

    
2202

    
2203
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
2204
  LOperand* context = UseFixed(instr->context(), esi);
2205
  LOperand* object = UseFixed(instr->object(), edx);
2206
  LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric(context, object);
2207
  return MarkAsCall(DefineFixed(result, eax), instr);
2208
}
2209

    
2210

    
2211
LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
2212
    HLoadFunctionPrototype* instr) {
2213
  return AssignEnvironment(DefineAsRegister(
2214
      new(zone()) LLoadFunctionPrototype(UseRegister(instr->function()),
2215
                                         TempRegister())));
2216
}
2217

    
2218

    
2219
LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
2220
  return DefineAsRegister(new(zone()) LLoadRoot);
2221
}
2222

    
2223

    
2224
LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
2225
    HLoadExternalArrayPointer* instr) {
2226
  LOperand* input = UseRegisterAtStart(instr->value());
2227
  return DefineAsRegister(new(zone()) LLoadExternalArrayPointer(input));
2228
}
2229

    
2230

    
2231
LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
2232
  ASSERT(instr->key()->representation().IsSmiOrInteger32());
2233
  ElementsKind elements_kind = instr->elements_kind();
2234
  bool clobbers_key = ExternalArrayOpRequiresTemp(
2235
      instr->key()->representation(), elements_kind);
2236
  LOperand* key = clobbers_key
2237
      ? UseTempRegister(instr->key())
2238
      : UseRegisterOrConstantAtStart(instr->key());
2239
  LLoadKeyed* result = NULL;
2240

    
2241
  if (!instr->is_external()) {
2242
    LOperand* obj = UseRegisterAtStart(instr->elements());
2243
    result = new(zone()) LLoadKeyed(obj, key);
2244
  } else {
2245
    ASSERT(
2246
        (instr->representation().IsInteger32() &&
2247
         (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
2248
         (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
2249
        (instr->representation().IsDouble() &&
2250
         ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
2251
          (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
2252
    LOperand* external_pointer = UseRegister(instr->elements());
2253
    result = new(zone()) LLoadKeyed(external_pointer, key);
2254
  }
2255

    
2256
  DefineAsRegister(result);
2257
  bool can_deoptimize = instr->RequiresHoleCheck() ||
2258
      (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS);
2259
  // An unsigned int array load might overflow and cause a deopt, make sure it
2260
  // has an environment.
2261
  return can_deoptimize ? AssignEnvironment(result) : result;
2262
}
2263

    
2264

    
2265
LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
2266
  LOperand* context = UseFixed(instr->context(), esi);
2267
  LOperand* object = UseFixed(instr->object(), edx);
2268
  LOperand* key = UseFixed(instr->key(), ecx);
2269

    
2270
  LLoadKeyedGeneric* result =
2271
      new(zone()) LLoadKeyedGeneric(context, object, key);
2272
  return MarkAsCall(DefineFixed(result, eax), instr);
2273
}
2274

    
2275

    
2276
LOperand* LChunkBuilder::GetStoreKeyedValueOperand(HStoreKeyed* instr) {
2277
  ElementsKind elements_kind = instr->elements_kind();
2278

    
2279
  // Determine if we need a byte register in this case for the value.
2280
  bool val_is_fixed_register =
2281
      elements_kind == EXTERNAL_BYTE_ELEMENTS ||
2282
      elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
2283
      elements_kind == EXTERNAL_PIXEL_ELEMENTS;
2284
  if (val_is_fixed_register) {
2285
    return UseFixed(instr->value(), eax);
2286
  }
2287

    
2288
  if (!CpuFeatures::IsSafeForSnapshot(SSE2) &&
2289
      IsDoubleOrFloatElementsKind(elements_kind)) {
2290
    return UseRegisterAtStart(instr->value());
2291
  }
2292

    
2293
  return UseRegister(instr->value());
2294
}
2295

    
2296

    
2297
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
2298
  if (!instr->is_external()) {
2299
    ASSERT(instr->elements()->representation().IsTagged());
2300
    ASSERT(instr->key()->representation().IsInteger32() ||
2301
           instr->key()->representation().IsSmi());
2302

    
2303
    if (instr->value()->representation().IsDouble()) {
2304
      LOperand* object = UseRegisterAtStart(instr->elements());
2305
      LOperand* val = NULL;
2306
      val = UseRegisterAtStart(instr->value());
2307
      LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2308
      return new(zone()) LStoreKeyed(object, key, val);
2309
    } else {
2310
      ASSERT(instr->value()->representation().IsSmiOrTagged());
2311
      bool needs_write_barrier = instr->NeedsWriteBarrier();
2312

    
2313
      LOperand* obj = UseRegister(instr->elements());
2314
      LOperand* val;
2315
      LOperand* key;
2316
      if (needs_write_barrier) {
2317
        val = UseTempRegister(instr->value());
2318
        key = UseTempRegister(instr->key());
2319
      } else {
2320
        val = UseRegisterOrConstantAtStart(instr->value());
2321
        key = UseRegisterOrConstantAtStart(instr->key());
2322
      }
2323
      return new(zone()) LStoreKeyed(obj, key, val);
2324
    }
2325
  }
2326

    
2327
  ElementsKind elements_kind = instr->elements_kind();
2328
  ASSERT(
2329
      (instr->value()->representation().IsInteger32() &&
2330
       (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
2331
       (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
2332
      (instr->value()->representation().IsDouble() &&
2333
       ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
2334
        (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
2335
  ASSERT(instr->elements()->representation().IsExternal());
2336

    
2337
  LOperand* external_pointer = UseRegister(instr->elements());
2338
  LOperand* val = GetStoreKeyedValueOperand(instr);
2339
  bool clobbers_key = ExternalArrayOpRequiresTemp(
2340
      instr->key()->representation(), elements_kind);
2341
  LOperand* key = clobbers_key
2342
      ? UseTempRegister(instr->key())
2343
      : UseRegisterOrConstantAtStart(instr->key());
2344
  return new(zone()) LStoreKeyed(external_pointer,
2345
                                 key,
2346
                                 val);
2347
}
2348

    
2349

    
2350
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
2351
  LOperand* context = UseFixed(instr->context(), esi);
2352
  LOperand* object = UseFixed(instr->object(), edx);
2353
  LOperand* key = UseFixed(instr->key(), ecx);
2354
  LOperand* value = UseFixed(instr->value(), eax);
2355

    
2356
  ASSERT(instr->object()->representation().IsTagged());
2357
  ASSERT(instr->key()->representation().IsTagged());
2358
  ASSERT(instr->value()->representation().IsTagged());
2359

    
2360
  LStoreKeyedGeneric* result =
2361
      new(zone()) LStoreKeyedGeneric(context, object, key, value);
2362
  return MarkAsCall(result, instr);
2363
}
2364

    
2365

    
2366
LInstruction* LChunkBuilder::DoTransitionElementsKind(
2367
    HTransitionElementsKind* instr) {
2368
  LOperand* object = UseRegister(instr->object());
2369
  if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
2370
    LOperand* object = UseRegister(instr->object());
2371
    LOperand* new_map_reg = TempRegister();
2372
    LOperand* temp_reg = TempRegister();
2373
    LTransitionElementsKind* result =
2374
        new(zone()) LTransitionElementsKind(object, NULL,
2375
                                            new_map_reg, temp_reg);
2376
    return result;
2377
  } else {
2378
    LOperand* context = UseRegister(instr->context());
2379
    LTransitionElementsKind* result =
2380
        new(zone()) LTransitionElementsKind(object, context, NULL, NULL);
2381
    return AssignPointerMap(result);
2382
  }
2383
}
2384

    
2385

    
2386
LInstruction* LChunkBuilder::DoTrapAllocationMemento(
2387
    HTrapAllocationMemento* instr) {
2388
  LOperand* object = UseRegister(instr->object());
2389
  LOperand* temp = TempRegister();
2390
  LTrapAllocationMemento* result =
2391
      new(zone()) LTrapAllocationMemento(object, temp);
2392
  return AssignEnvironment(result);
2393
}
2394

    
2395

    
2396
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2397
  bool is_in_object = instr->access().IsInobject();
2398
  bool is_external_location = instr->access().IsExternalMemory() &&
2399
      instr->access().offset() == 0;
2400
  bool needs_write_barrier = instr->NeedsWriteBarrier();
2401
  bool needs_write_barrier_for_map = instr->has_transition() &&
2402
      instr->NeedsWriteBarrierForMap();
2403

    
2404
  LOperand* obj;
2405
  if (needs_write_barrier) {
2406
    obj = is_in_object
2407
        ? UseRegister(instr->object())
2408
        : UseTempRegister(instr->object());
2409
  } else if (is_external_location) {
2410
    ASSERT(!is_in_object);
2411
    ASSERT(!needs_write_barrier);
2412
    ASSERT(!needs_write_barrier_for_map);
2413
    obj = UseRegisterOrConstant(instr->object());
2414
  } else {
2415
    obj = needs_write_barrier_for_map
2416
        ? UseRegister(instr->object())
2417
        : UseRegisterAtStart(instr->object());
2418
  }
2419

    
2420
  bool can_be_constant = instr->value()->IsConstant() &&
2421
      HConstant::cast(instr->value())->NotInNewSpace() &&
2422
      !(FLAG_track_double_fields && instr->field_representation().IsDouble());
2423

    
2424
  LOperand* val;
2425
  if (instr->field_representation().IsByte()) {
2426
    // mov_b requires a byte register (i.e. any of eax, ebx, ecx, edx).
2427
    // Just force the value to be in eax and we're safe here.
2428
    val = UseFixed(instr->value(), eax);
2429
  } else if (needs_write_barrier) {
2430
    val = UseTempRegister(instr->value());
2431
  } else if (can_be_constant) {
2432
    val = UseRegisterOrConstant(instr->value());
2433
  } else if (FLAG_track_fields && instr->field_representation().IsSmi()) {
2434
    val = UseTempRegister(instr->value());
2435
  } else if (FLAG_track_double_fields &&
2436
             instr->field_representation().IsDouble()) {
2437
    val = UseRegisterAtStart(instr->value());
2438
  } else {
2439
    val = UseRegister(instr->value());
2440
  }
2441

    
2442
  // We only need a scratch register if we have a write barrier or we
2443
  // have a store into the properties array (not in-object-property).
2444
  LOperand* temp = (!is_in_object || needs_write_barrier ||
2445
                    needs_write_barrier_for_map) ? TempRegister() : NULL;
2446

    
2447
  // We need a temporary register for write barrier of the map field.
2448
  LOperand* temp_map = needs_write_barrier_for_map ? TempRegister() : NULL;
2449

    
2450
  LStoreNamedField* result =
2451
      new(zone()) LStoreNamedField(obj, val, temp, temp_map);
2452
  if (FLAG_track_heap_object_fields &&
2453
      instr->field_representation().IsHeapObject()) {
2454
    if (!instr->value()->type().IsHeapObject()) {
2455
      return AssignEnvironment(result);
2456
    }
2457
  }
2458
  return result;
2459
}
2460

    
2461

    
2462
LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
2463
  LOperand* context = UseFixed(instr->context(), esi);
2464
  LOperand* object = UseFixed(instr->object(), edx);
2465
  LOperand* value = UseFixed(instr->value(), eax);
2466

    
2467
  LStoreNamedGeneric* result =
2468
      new(zone()) LStoreNamedGeneric(context, object, value);
2469
  return MarkAsCall(result, instr);
2470
}
2471

    
2472

    
2473
LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2474
  LOperand* context = UseFixed(instr->context(), esi);
2475
  LOperand* left = UseOrConstantAtStart(instr->left());
2476
  LOperand* right = UseOrConstantAtStart(instr->right());
2477
  LStringAdd* string_add = new(zone()) LStringAdd(context, left, right);
2478
  return MarkAsCall(DefineFixed(string_add, eax), instr);
2479
}
2480

    
2481

    
2482
LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2483
  LOperand* string = UseTempRegister(instr->string());
2484
  LOperand* index = UseTempRegister(instr->index());
2485
  LOperand* context = UseAny(instr->context());
2486
  LStringCharCodeAt* result =
2487
      new(zone()) LStringCharCodeAt(context, string, index);
2488
  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
2489
}
2490

    
2491

    
2492
LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
2493
  LOperand* char_code = UseRegister(instr->value());
2494
  LOperand* context = UseAny(instr->context());
2495
  LStringCharFromCode* result =
2496
      new(zone()) LStringCharFromCode(context, char_code);
2497
  return AssignPointerMap(DefineAsRegister(result));
2498
}
2499

    
2500

    
2501
LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
2502
  info()->MarkAsDeferredCalling();
2503
  LOperand* context = UseAny(instr->context());
2504
  LOperand* size = instr->size()->IsConstant()
2505
      ? UseConstant(instr->size())
2506
      : UseTempRegister(instr->size());
2507
  LOperand* temp = TempRegister();
2508
  LAllocate* result = new(zone()) LAllocate(context, size, temp);
2509
  return AssignPointerMap(DefineAsRegister(result));
2510
}
2511

    
2512

    
2513
LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
2514
  LOperand* context = UseFixed(instr->context(), esi);
2515
  return MarkAsCall(
2516
      DefineFixed(new(zone()) LRegExpLiteral(context), eax), instr);
2517
}
2518

    
2519

    
2520
LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
2521
  LOperand* context = UseFixed(instr->context(), esi);
2522
  return MarkAsCall(
2523
      DefineFixed(new(zone()) LFunctionLiteral(context), eax), instr);
2524
}
2525

    
2526

    
2527
LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2528
  ASSERT(argument_count_ == 0);
2529
  allocator_->MarkAsOsrEntry();
2530
  current_block_->last_environment()->set_ast_id(instr->ast_id());
2531
  return AssignEnvironment(new(zone()) LOsrEntry);
2532
}
2533

    
2534

    
2535
LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2536
  LParameter* result = new(zone()) LParameter;
2537
  if (instr->kind() == HParameter::STACK_PARAMETER) {
2538
    int spill_index = chunk()->GetParameterStackSlot(instr->index());
2539
    return DefineAsSpilled(result, spill_index);
2540
  } else {
2541
    ASSERT(info()->IsStub());
2542
    CodeStubInterfaceDescriptor* descriptor =
2543
        info()->code_stub()->GetInterfaceDescriptor(info()->isolate());
2544
    int index = static_cast<int>(instr->index());
2545
    Register reg = DESCRIPTOR_GET_PARAMETER_REGISTER(descriptor, index);
2546
    return DefineFixed(result, reg);
2547
  }
2548
}
2549

    
2550

    
2551
LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2552
  // Use an index that corresponds to the location in the unoptimized frame,
2553
  // which the optimized frame will subsume.
2554
  int env_index = instr->index();
2555
  int spill_index = 0;
2556
  if (instr->environment()->is_parameter_index(env_index)) {
2557
    spill_index = chunk()->GetParameterStackSlot(env_index);
2558
  } else {
2559
    spill_index = env_index - instr->environment()->first_local_index();
2560
    if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
2561
      Abort(kNotEnoughSpillSlotsForOsr);
2562
      spill_index = 0;
2563
    }
2564
    if (spill_index == 0) {
2565
      // The dynamic frame alignment state overwrites the first local.
2566
      // The first local is saved at the end of the unoptimized frame.
2567
      spill_index = graph()->osr()->UnoptimizedFrameSlots();
2568
    }
2569
  }
2570
  return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
2571
}
2572

    
2573

    
2574
LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
2575
  LOperand* context = UseFixed(instr->context(), esi);
2576
  LCallStub* result = new(zone()) LCallStub(context);
2577
  return MarkAsCall(DefineFixed(result, eax), instr);
2578
}
2579

    
2580

    
2581
LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2582
  // There are no real uses of the arguments object.
2583
  // arguments.length and element access are supported directly on
2584
  // stack arguments, and any real arguments object use causes a bailout.
2585
  // So this value is never used.
2586
  return NULL;
2587
}
2588

    
2589

    
2590
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
2591
  instr->ReplayEnvironment(current_block_->last_environment());
2592

    
2593
  // There are no real uses of a captured object.
2594
  return NULL;
2595
}
2596

    
2597

    
2598
LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2599
  info()->MarkAsRequiresFrame();
2600
  LOperand* args = UseRegister(instr->arguments());
2601
  LOperand* length;
2602
  LOperand* index;
2603
  if (instr->length()->IsConstant() && instr->index()->IsConstant()) {
2604
    length = UseRegisterOrConstant(instr->length());
2605
    index = UseOrConstant(instr->index());
2606
  } else {
2607
    length = UseTempRegister(instr->length());
2608
    index = Use(instr->index());
2609
  }
2610
  return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
2611
}
2612

    
2613

    
2614
LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
2615
  LOperand* object = UseFixed(instr->value(), eax);
2616
  LToFastProperties* result = new(zone()) LToFastProperties(object);
2617
  return MarkAsCall(DefineFixed(result, eax), instr);
2618
}
2619

    
2620

    
2621
LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2622
  LOperand* context = UseFixed(instr->context(), esi);
2623
  LOperand* value = UseAtStart(instr->value());
2624
  LTypeof* result = new(zone()) LTypeof(context, value);
2625
  return MarkAsCall(DefineFixed(result, eax), instr);
2626
}
2627

    
2628

    
2629
LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2630
  return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value()));
2631
}
2632

    
2633

    
2634
LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
2635
    HIsConstructCallAndBranch* instr) {
2636
  return new(zone()) LIsConstructCallAndBranch(TempRegister());
2637
}
2638

    
2639

    
2640
LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2641
  instr->ReplayEnvironment(current_block_->last_environment());
2642

    
2643
  // If there is an instruction pending deoptimization environment create a
2644
  // lazy bailout instruction to capture the environment.
2645
  if (!pending_deoptimization_ast_id_.IsNone()) {
2646
    ASSERT(pending_deoptimization_ast_id_ == instr->ast_id());
2647
    LLazyBailout* lazy_bailout = new(zone()) LLazyBailout;
2648
    LInstruction* result = AssignEnvironment(lazy_bailout);
2649
    // Store the lazy deopt environment with the instruction if needed. Right
2650
    // now it is only used for LInstanceOfKnownGlobal.
2651
    instruction_pending_deoptimization_environment_->
2652
        SetDeferredLazyDeoptimizationEnvironment(result->environment());
2653
    instruction_pending_deoptimization_environment_ = NULL;
2654
    pending_deoptimization_ast_id_ = BailoutId::None();
2655
    return result;
2656
  }
2657

    
2658
  return NULL;
2659
}
2660

    
2661

    
2662
LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2663
  info()->MarkAsDeferredCalling();
2664
  if (instr->is_function_entry()) {
2665
    LOperand* context = UseFixed(instr->context(), esi);
2666
    return MarkAsCall(new(zone()) LStackCheck(context), instr);
2667
  } else {
2668
    ASSERT(instr->is_backwards_branch());
2669
    LOperand* context = UseAny(instr->context());
2670
    return AssignEnvironment(
2671
        AssignPointerMap(new(zone()) LStackCheck(context)));
2672
  }
2673
}
2674

    
2675

    
2676
LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2677
  HEnvironment* outer = current_block_->last_environment();
2678
  HConstant* undefined = graph()->GetConstantUndefined();
2679
  HEnvironment* inner = outer->CopyForInlining(instr->closure(),
2680
                                               instr->arguments_count(),
2681
                                               instr->function(),
2682
                                               undefined,
2683
                                               instr->inlining_kind(),
2684
                                               instr->undefined_receiver());
2685
  // Only replay binding of arguments object if it wasn't removed from graph.
2686
  if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
2687
    inner->Bind(instr->arguments_var(), instr->arguments_object());
2688
  }
2689
  inner->set_entry(instr);
2690
  current_block_->UpdateEnvironment(inner);
2691
  chunk_->AddInlinedClosure(instr->closure());
2692
  return NULL;
2693
}
2694

    
2695

    
2696
LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2697
  LInstruction* pop = NULL;
2698

    
2699
  HEnvironment* env = current_block_->last_environment();
2700

    
2701
  if (env->entry()->arguments_pushed()) {
2702
    int argument_count = env->arguments_environment()->parameter_count();
2703
    pop = new(zone()) LDrop(argument_count);
2704
    ASSERT(instr->argument_delta() == -argument_count);
2705
  }
2706

    
2707
  HEnvironment* outer = current_block_->last_environment()->
2708
      DiscardInlined(false);
2709
  current_block_->UpdateEnvironment(outer);
2710
  return pop;
2711
}
2712

    
2713

    
2714
LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
2715
  LOperand* context = UseFixed(instr->context(), esi);
2716
  LOperand* object = UseFixed(instr->enumerable(), eax);
2717
  LForInPrepareMap* result = new(zone()) LForInPrepareMap(context, object);
2718
  return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY);
2719
}
2720

    
2721

    
2722
LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
2723
  LOperand* map = UseRegister(instr->map());
2724
  return AssignEnvironment(DefineAsRegister(
2725
      new(zone()) LForInCacheArray(map)));
2726
}
2727

    
2728

    
2729
LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
2730
  LOperand* value = UseRegisterAtStart(instr->value());
2731
  LOperand* map = UseRegisterAtStart(instr->map());
2732
  return AssignEnvironment(new(zone()) LCheckMapValue(value, map));
2733
}
2734

    
2735

    
2736
LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
2737
  LOperand* object = UseRegister(instr->object());
2738
  LOperand* index = UseTempRegister(instr->index());
2739
  return DefineSameAsFirst(new(zone()) LLoadFieldByIndex(object, index));
2740
}
2741

    
2742

    
2743
} }  // namespace v8::internal
2744

    
2745
#endif  // V8_TARGET_ARCH_IA32