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 / x64 / lithium-x64.cc @ f230a1cf

History | View | Annotate | Download (84.3 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_X64
31

    
32
#include "lithium-allocator-inl.h"
33
#include "x64/lithium-x64.h"
34
#include "x64/lithium-codegen-x64.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
void LInstruction::PrintTo(StringStream* stream) {
71
  stream->Add("%s ", this->Mnemonic());
72

    
73
  PrintOutputOperandTo(stream);
74

    
75
  PrintDataTo(stream);
76

    
77
  if (HasEnvironment()) {
78
    stream->Add(" ");
79
    environment()->PrintTo(stream);
80
  }
81

    
82
  if (HasPointerMap()) {
83
    stream->Add(" ");
84
    pointer_map()->PrintTo(stream);
85
  }
86
}
87

    
88

    
89
void LInstruction::PrintDataTo(StringStream* stream) {
90
  stream->Add("= ");
91
  for (int i = 0; i < InputCount(); i++) {
92
    if (i > 0) stream->Add(" ");
93
    if (InputAt(i) == NULL) {
94
      stream->Add("NULL");
95
    } else {
96
      InputAt(i)->PrintTo(stream);
97
    }
98
  }
99
}
100

    
101

    
102
void LInstruction::PrintOutputOperandTo(StringStream* stream) {
103
  if (HasResult()) result()->PrintTo(stream);
104
}
105

    
106

    
107
void LLabel::PrintDataTo(StringStream* stream) {
108
  LGap::PrintDataTo(stream);
109
  LLabel* rep = replacement();
110
  if (rep != NULL) {
111
    stream->Add(" Dead block replaced with B%d", rep->block_id());
112
  }
113
}
114

    
115

    
116
bool LGap::IsRedundant() const {
117
  for (int i = 0; i < 4; i++) {
118
    if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
119
      return false;
120
    }
121
  }
122

    
123
  return true;
124
}
125

    
126

    
127
void LGap::PrintDataTo(StringStream* stream) {
128
  for (int i = 0; i < 4; i++) {
129
    stream->Add("(");
130
    if (parallel_moves_[i] != NULL) {
131
      parallel_moves_[i]->PrintDataTo(stream);
132
    }
133
    stream->Add(") ");
134
  }
135
}
136

    
137

    
138
const char* LArithmeticD::Mnemonic() const {
139
  switch (op()) {
140
    case Token::ADD: return "add-d";
141
    case Token::SUB: return "sub-d";
142
    case Token::MUL: return "mul-d";
143
    case Token::DIV: return "div-d";
144
    case Token::MOD: return "mod-d";
145
    default:
146
      UNREACHABLE();
147
      return NULL;
148
  }
149
}
150

    
151

    
152
const char* LArithmeticT::Mnemonic() const {
153
  switch (op()) {
154
    case Token::ADD: return "add-t";
155
    case Token::SUB: return "sub-t";
156
    case Token::MUL: return "mul-t";
157
    case Token::MOD: return "mod-t";
158
    case Token::DIV: return "div-t";
159
    case Token::BIT_AND: return "bit-and-t";
160
    case Token::BIT_OR: return "bit-or-t";
161
    case Token::BIT_XOR: return "bit-xor-t";
162
    case Token::ROR: return "ror-t";
163
    case Token::SHL: return "sal-t";
164
    case Token::SAR: return "sar-t";
165
    case Token::SHR: return "shr-t";
166
    default:
167
      UNREACHABLE();
168
      return NULL;
169
  }
170
}
171

    
172

    
173
bool LGoto::HasInterestingComment(LCodeGen* gen) const {
174
  return !gen->IsNextEmittedBlock(block_id());
175
}
176

    
177

    
178
void LGoto::PrintDataTo(StringStream* stream) {
179
  stream->Add("B%d", block_id());
180
}
181

    
182

    
183
void LBranch::PrintDataTo(StringStream* stream) {
184
  stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
185
  value()->PrintTo(stream);
186
}
187

    
188

    
189
void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
190
  stream->Add("if ");
191
  left()->PrintTo(stream);
192
  stream->Add(" %s ", Token::String(op()));
193
  right()->PrintTo(stream);
194
  stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
195
}
196

    
197

    
198
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
199
  stream->Add("if is_object(");
200
  value()->PrintTo(stream);
201
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
202
}
203

    
204

    
205
void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
206
  stream->Add("if is_string(");
207
  value()->PrintTo(stream);
208
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
209
}
210

    
211

    
212
void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
213
  stream->Add("if is_smi(");
214
  value()->PrintTo(stream);
215
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
216
}
217

    
218

    
219
void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
220
  stream->Add("if is_undetectable(");
221
  value()->PrintTo(stream);
222
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
223
}
224

    
225

    
226
void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
227
  stream->Add("if string_compare(");
228
  left()->PrintTo(stream);
229
  right()->PrintTo(stream);
230
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
231
}
232

    
233

    
234
void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
235
  stream->Add("if has_instance_type(");
236
  value()->PrintTo(stream);
237
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
238
}
239

    
240

    
241
void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
242
  stream->Add("if has_cached_array_index(");
243
  value()->PrintTo(stream);
244
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
245
}
246

    
247

    
248
void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
249
  stream->Add("if class_of_test(");
250
  value()->PrintTo(stream);
251
  stream->Add(", \"%o\") then B%d else B%d",
252
              *hydrogen()->class_name(),
253
              true_block_id(),
254
              false_block_id());
255
}
256

    
257

    
258
void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
259
  stream->Add("if typeof ");
260
  value()->PrintTo(stream);
261
  stream->Add(" == \"%s\" then B%d else B%d",
262
              *hydrogen()->type_literal()->ToCString(),
263
              true_block_id(), false_block_id());
264
}
265

    
266

    
267
void LStoreCodeEntry::PrintDataTo(StringStream* stream) {
268
  stream->Add(" = ");
269
  function()->PrintTo(stream);
270
  stream->Add(".code_entry = ");
271
  code_object()->PrintTo(stream);
272
}
273

    
274

    
275
void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
276
  stream->Add(" = ");
277
  base_object()->PrintTo(stream);
278
  stream->Add(" + %d", offset());
279
}
280

    
281

    
282
void LCallConstantFunction::PrintDataTo(StringStream* stream) {
283
  stream->Add("#%d / ", arity());
284
}
285

    
286

    
287
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
288
  context()->PrintTo(stream);
289
  stream->Add("[%d]", slot_index());
290
}
291

    
292

    
293
void LStoreContextSlot::PrintDataTo(StringStream* stream) {
294
  context()->PrintTo(stream);
295
  stream->Add("[%d] <- ", slot_index());
296
  value()->PrintTo(stream);
297
}
298

    
299

    
300
void LInvokeFunction::PrintDataTo(StringStream* stream) {
301
  stream->Add("= ");
302
  function()->PrintTo(stream);
303
  stream->Add(" #%d / ", arity());
304
}
305

    
306

    
307
void LCallKeyed::PrintDataTo(StringStream* stream) {
308
  stream->Add("[rcx] #%d / ", arity());
309
}
310

    
311

    
312
void LCallNamed::PrintDataTo(StringStream* stream) {
313
  SmartArrayPointer<char> name_string = name()->ToCString();
314
  stream->Add("%s #%d / ", *name_string, arity());
315
}
316

    
317

    
318
void LCallGlobal::PrintDataTo(StringStream* stream) {
319
  SmartArrayPointer<char> name_string = name()->ToCString();
320
  stream->Add("%s #%d / ", *name_string, arity());
321
}
322

    
323

    
324
void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
325
  stream->Add("#%d / ", arity());
326
}
327

    
328

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

    
335

    
336
void LCallNewArray::PrintDataTo(StringStream* stream) {
337
  stream->Add("= ");
338
  constructor()->PrintTo(stream);
339
  stream->Add(" #%d / ", arity());
340
  ElementsKind kind = hydrogen()->elements_kind();
341
  stream->Add(" (%s) ", ElementsKindToString(kind));
342
}
343

    
344

    
345
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
346
  arguments()->PrintTo(stream);
347

    
348
  stream->Add(" length ");
349
  length()->PrintTo(stream);
350

    
351
  stream->Add(" index ");
352
  index()->PrintTo(stream);
353
}
354

    
355

    
356
int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
357
  return spill_slot_count_++;
358
}
359

    
360

    
361
LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
362
  // All stack slots are Double stack slots on x64.
363
  // Alternatively, at some point, start using half-size
364
  // stack slots for int32 values.
365
  int index = GetNextSpillIndex(kind);
366
  if (kind == DOUBLE_REGISTERS) {
367
    return LDoubleStackSlot::Create(index, zone());
368
  } else {
369
    ASSERT(kind == GENERAL_REGISTERS);
370
    return LStackSlot::Create(index, zone());
371
  }
372
}
373

    
374

    
375
void LStoreNamedField::PrintDataTo(StringStream* stream) {
376
  object()->PrintTo(stream);
377
  hydrogen()->access().PrintTo(stream);
378
  stream->Add(" <- ");
379
  value()->PrintTo(stream);
380
}
381

    
382

    
383
void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
384
  object()->PrintTo(stream);
385
  stream->Add(".");
386
  stream->Add(*String::cast(*name())->ToCString());
387
  stream->Add(" <- ");
388
  value()->PrintTo(stream);
389
}
390

    
391

    
392
void LLoadKeyed::PrintDataTo(StringStream* stream) {
393
  elements()->PrintTo(stream);
394
  stream->Add("[");
395
  key()->PrintTo(stream);
396
  if (hydrogen()->IsDehoisted()) {
397
    stream->Add(" + %d]", additional_index());
398
  } else {
399
    stream->Add("]");
400
  }
401
}
402

    
403

    
404
void LStoreKeyed::PrintDataTo(StringStream* stream) {
405
  elements()->PrintTo(stream);
406
  stream->Add("[");
407
  key()->PrintTo(stream);
408
  if (hydrogen()->IsDehoisted()) {
409
    stream->Add(" + %d] <-", additional_index());
410
  } else {
411
    stream->Add("] <- ");
412
  }
413

    
414
  if (value() == NULL) {
415
    ASSERT(hydrogen()->IsConstantHoleStore() &&
416
           hydrogen()->value()->representation().IsDouble());
417
    stream->Add("<the hole(nan)>");
418
  } else {
419
    value()->PrintTo(stream);
420
  }
421
}
422

    
423

    
424
void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
425
  object()->PrintTo(stream);
426
  stream->Add("[");
427
  key()->PrintTo(stream);
428
  stream->Add("] <- ");
429
  value()->PrintTo(stream);
430
}
431

    
432

    
433
void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
434
  object()->PrintTo(stream);
435
  stream->Add(" %p -> %p", *original_map(), *transitioned_map());
436
}
437

    
438

    
439
LPlatformChunk* LChunkBuilder::Build() {
440
  ASSERT(is_unused());
441
  chunk_ = new(zone()) LPlatformChunk(info(), graph());
442
  LPhase phase("L_Building chunk", chunk_);
443
  status_ = BUILDING;
444

    
445
  // If compiling for OSR, reserve space for the unoptimized frame,
446
  // which will be subsumed into this frame.
447
  if (graph()->has_osr()) {
448
    for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
449
      chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
450
    }
451
  }
452

    
453
  const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
454
  for (int i = 0; i < blocks->length(); i++) {
455
    HBasicBlock* next = NULL;
456
    if (i < blocks->length() - 1) next = blocks->at(i + 1);
457
    DoBasicBlock(blocks->at(i), next);
458
    if (is_aborted()) return NULL;
459
  }
460
  status_ = DONE;
461
  return chunk_;
462
}
463

    
464

    
465
void LCodeGen::Abort(BailoutReason reason) {
466
  info()->set_bailout_reason(reason);
467
  status_ = ABORTED;
468
}
469

    
470

    
471
LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
472
  return new(zone()) LUnallocated(LUnallocated::FIXED_REGISTER,
473
                                  Register::ToAllocationIndex(reg));
474
}
475

    
476

    
477
LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
478
  return new(zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
479
                                  XMMRegister::ToAllocationIndex(reg));
480
}
481

    
482

    
483
LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
484
  return Use(value, ToUnallocated(fixed_register));
485
}
486

    
487

    
488
LOperand* LChunkBuilder::UseFixedDouble(HValue* value, XMMRegister reg) {
489
  return Use(value, ToUnallocated(reg));
490
}
491

    
492

    
493
LOperand* LChunkBuilder::UseRegister(HValue* value) {
494
  return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
495
}
496

    
497

    
498
LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
499
  return Use(value,
500
             new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
501
                              LUnallocated::USED_AT_START));
502
}
503

    
504

    
505
LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
506
  return Use(value, new(zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
507
}
508

    
509

    
510
LOperand* LChunkBuilder::Use(HValue* value) {
511
  return Use(value, new(zone()) LUnallocated(LUnallocated::NONE));
512
}
513

    
514

    
515
LOperand* LChunkBuilder::UseAtStart(HValue* value) {
516
  return Use(value, new(zone()) LUnallocated(LUnallocated::NONE,
517
                                     LUnallocated::USED_AT_START));
518
}
519

    
520

    
521
LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
522
  return value->IsConstant()
523
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
524
      : Use(value);
525
}
526

    
527

    
528
LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
529
  return value->IsConstant()
530
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
531
      : UseAtStart(value);
532
}
533

    
534

    
535
LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
536
  return value->IsConstant()
537
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
538
      : UseRegister(value);
539
}
540

    
541

    
542
LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
543
  return value->IsConstant()
544
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
545
      : UseRegisterAtStart(value);
546
}
547

    
548

    
549
LOperand* LChunkBuilder::UseConstant(HValue* value) {
550
  return chunk_->DefineConstantOperand(HConstant::cast(value));
551
}
552

    
553

    
554
LOperand* LChunkBuilder::UseAny(HValue* value) {
555
  return value->IsConstant()
556
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
557
      :  Use(value, new(zone()) LUnallocated(LUnallocated::ANY));
558
}
559

    
560

    
561
LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
562
  if (value->EmitAtUses()) {
563
    HInstruction* instr = HInstruction::cast(value);
564
    VisitInstruction(instr);
565
  }
566
  operand->set_virtual_register(value->id());
567
  return operand;
568
}
569

    
570

    
571
template<int I, int T>
572
LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
573
                                    LUnallocated* result) {
574
  result->set_virtual_register(current_instruction_->id());
575
  instr->set_result(result);
576
  return instr;
577
}
578

    
579

    
580
template<int I, int T>
581
LInstruction* LChunkBuilder::DefineAsRegister(
582
    LTemplateInstruction<1, I, T>* instr) {
583
  return Define(instr,
584
                new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
585
}
586

    
587

    
588
template<int I, int T>
589
LInstruction* LChunkBuilder::DefineAsSpilled(
590
    LTemplateInstruction<1, I, T>* instr,
591
    int index) {
592
  return Define(instr,
593
                new(zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
594
}
595

    
596

    
597
template<int I, int T>
598
LInstruction* LChunkBuilder::DefineSameAsFirst(
599
    LTemplateInstruction<1, I, T>* instr) {
600
  return Define(instr,
601
                new(zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
602
}
603

    
604

    
605
template<int I, int T>
606
LInstruction* LChunkBuilder::DefineFixed(LTemplateInstruction<1, I, T>* instr,
607
                                         Register reg) {
608
  return Define(instr, ToUnallocated(reg));
609
}
610

    
611

    
612
template<int I, int T>
613
LInstruction* LChunkBuilder::DefineFixedDouble(
614
    LTemplateInstruction<1, I, T>* instr,
615
    XMMRegister reg) {
616
  return Define(instr, ToUnallocated(reg));
617
}
618

    
619

    
620
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
621
  HEnvironment* hydrogen_env = current_block_->last_environment();
622
  int argument_index_accumulator = 0;
623
  ZoneList<HValue*> objects_to_materialize(0, zone());
624
  instr->set_environment(CreateEnvironment(hydrogen_env,
625
                                           &argument_index_accumulator,
626
                                           &objects_to_materialize));
627
  return instr;
628
}
629

    
630

    
631
LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
632
                                        HInstruction* hinstr,
633
                                        CanDeoptimize can_deoptimize) {
634
  info()->MarkAsNonDeferredCalling();
635

    
636
#ifdef DEBUG
637
  instr->VerifyCall();
638
#endif
639
  instr->MarkAsCall();
640
  instr = AssignPointerMap(instr);
641

    
642
  if (hinstr->HasObservableSideEffects()) {
643
    ASSERT(hinstr->next()->IsSimulate());
644
    HSimulate* sim = HSimulate::cast(hinstr->next());
645
    ASSERT(instruction_pending_deoptimization_environment_ == NULL);
646
    ASSERT(pending_deoptimization_ast_id_.IsNone());
647
    instruction_pending_deoptimization_environment_ = instr;
648
    pending_deoptimization_ast_id_ = sim->ast_id();
649
  }
650

    
651
  // If instruction does not have side-effects lazy deoptimization
652
  // after the call will try to deoptimize to the point before the call.
653
  // Thus we still need to attach environment to this call even if
654
  // call sequence can not deoptimize eagerly.
655
  bool needs_environment =
656
      (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
657
      !hinstr->HasObservableSideEffects();
658
  if (needs_environment && !instr->HasEnvironment()) {
659
    instr = AssignEnvironment(instr);
660
  }
661

    
662
  return instr;
663
}
664

    
665

    
666
LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
667
  ASSERT(!instr->HasPointerMap());
668
  instr->set_pointer_map(new(zone()) LPointerMap(zone()));
669
  return instr;
670
}
671

    
672

    
673
LUnallocated* LChunkBuilder::TempRegister() {
674
  LUnallocated* operand =
675
      new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
676
  int vreg = allocator_->GetVirtualRegister();
677
  if (!allocator_->AllocationOk()) {
678
    Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
679
    vreg = 0;
680
  }
681
  operand->set_virtual_register(vreg);
682
  return operand;
683
}
684

    
685

    
686
LOperand* LChunkBuilder::FixedTemp(Register reg) {
687
  LUnallocated* operand = ToUnallocated(reg);
688
  ASSERT(operand->HasFixedPolicy());
689
  return operand;
690
}
691

    
692

    
693
LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) {
694
  LUnallocated* operand = ToUnallocated(reg);
695
  ASSERT(operand->HasFixedPolicy());
696
  return operand;
697
}
698

    
699

    
700
LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
701
  return new(zone()) LLabel(instr->block());
702
}
703

    
704

    
705
LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
706
  return DefineAsRegister(new(zone()) LDummyUse(UseAny(instr->value())));
707
}
708

    
709

    
710
LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
711
  UNREACHABLE();
712
  return NULL;
713
}
714

    
715

    
716
LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
717
  return AssignEnvironment(new(zone()) LDeoptimize);
718
}
719

    
720

    
721
LInstruction* LChunkBuilder::DoShift(Token::Value op,
722
                                     HBitwiseBinaryOperation* instr) {
723
  if (instr->representation().IsSmiOrInteger32()) {
724
    ASSERT(instr->left()->representation().Equals(instr->representation()));
725
    ASSERT(instr->right()->representation().Equals(instr->representation()));
726
    LOperand* left = UseRegisterAtStart(instr->left());
727

    
728
    HValue* right_value = instr->right();
729
    LOperand* right = NULL;
730
    int constant_value = 0;
731
    if (right_value->IsConstant()) {
732
      HConstant* constant = HConstant::cast(right_value);
733
      right = chunk_->DefineConstantOperand(constant);
734
      constant_value = constant->Integer32Value() & 0x1f;
735
    } else {
736
      right = UseFixed(right_value, rcx);
737
    }
738

    
739
    // Shift operations can only deoptimize if we do a logical shift by 0 and
740
    // the result cannot be truncated to int32.
741
    bool does_deopt = false;
742
    if (op == Token::SHR && constant_value == 0) {
743
      if (FLAG_opt_safe_uint32_operations) {
744
        does_deopt = !instr->CheckFlag(HInstruction::kUint32);
745
      } else {
746
        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32);
747
      }
748
    }
749

    
750
    LInstruction* result =
751
        DefineSameAsFirst(new(zone()) LShiftI(op, left, right, does_deopt));
752
    return does_deopt ? AssignEnvironment(result) : result;
753
  } else {
754
    return DoArithmeticT(op, instr);
755
  }
756
}
757

    
758

    
759
LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
760
                                           HArithmeticBinaryOperation* instr) {
761
  ASSERT(instr->representation().IsDouble());
762
  ASSERT(instr->left()->representation().IsDouble());
763
  ASSERT(instr->right()->representation().IsDouble());
764
  if (op == Token::MOD) {
765
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
766
    LOperand* right = UseFixedDouble(instr->BetterRightOperand(), xmm1);
767
    LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
768
    return MarkAsCall(DefineSameAsFirst(result), instr);
769
  } else {
770
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
771
    LOperand* right = UseRegisterAtStart(instr->BetterRightOperand());
772
    LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
773
    return DefineSameAsFirst(result);
774
  }
775
}
776

    
777

    
778
LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
779
                                           HBinaryOperation* instr) {
780
  HValue* left = instr->left();
781
  HValue* right = instr->right();
782
  ASSERT(left->representation().IsTagged());
783
  ASSERT(right->representation().IsTagged());
784
  LOperand* left_operand = UseFixed(left, rdx);
785
  LOperand* right_operand = UseFixed(right, rax);
786
  LArithmeticT* result =
787
      new(zone()) LArithmeticT(op, left_operand, right_operand);
788
  return MarkAsCall(DefineFixed(result, rax), instr);
789
}
790

    
791

    
792
void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
793
  ASSERT(is_building());
794
  current_block_ = block;
795
  next_block_ = next_block;
796
  if (block->IsStartBlock()) {
797
    block->UpdateEnvironment(graph_->start_environment());
798
    argument_count_ = 0;
799
  } else if (block->predecessors()->length() == 1) {
800
    // We have a single predecessor => copy environment and outgoing
801
    // argument count from the predecessor.
802
    ASSERT(block->phis()->length() == 0);
803
    HBasicBlock* pred = block->predecessors()->at(0);
804
    HEnvironment* last_environment = pred->last_environment();
805
    ASSERT(last_environment != NULL);
806
    // Only copy the environment, if it is later used again.
807
    if (pred->end()->SecondSuccessor() == NULL) {
808
      ASSERT(pred->end()->FirstSuccessor() == block);
809
    } else {
810
      if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
811
          pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
812
        last_environment = last_environment->Copy();
813
      }
814
    }
815
    block->UpdateEnvironment(last_environment);
816
    ASSERT(pred->argument_count() >= 0);
817
    argument_count_ = pred->argument_count();
818
  } else {
819
    // We are at a state join => process phis.
820
    HBasicBlock* pred = block->predecessors()->at(0);
821
    // No need to copy the environment, it cannot be used later.
822
    HEnvironment* last_environment = pred->last_environment();
823
    for (int i = 0; i < block->phis()->length(); ++i) {
824
      HPhi* phi = block->phis()->at(i);
825
      if (phi->HasMergedIndex()) {
826
        last_environment->SetValueAt(phi->merged_index(), phi);
827
      }
828
    }
829
    for (int i = 0; i < block->deleted_phis()->length(); ++i) {
830
      if (block->deleted_phis()->at(i) < last_environment->length()) {
831
        last_environment->SetValueAt(block->deleted_phis()->at(i),
832
                                     graph_->GetConstantUndefined());
833
      }
834
    }
835
    block->UpdateEnvironment(last_environment);
836
    // Pick up the outgoing argument count of one of the predecessors.
837
    argument_count_ = pred->argument_count();
838
  }
839
  HInstruction* current = block->first();
840
  int start = chunk_->instructions()->length();
841
  while (current != NULL && !is_aborted()) {
842
    // Code for constants in registers is generated lazily.
843
    if (!current->EmitAtUses()) {
844
      VisitInstruction(current);
845
    }
846
    current = current->next();
847
  }
848
  int end = chunk_->instructions()->length() - 1;
849
  if (end >= start) {
850
    block->set_first_instruction_index(start);
851
    block->set_last_instruction_index(end);
852
  }
853
  block->set_argument_count(argument_count_);
854
  next_block_ = NULL;
855
  current_block_ = NULL;
856
}
857

    
858

    
859
void LChunkBuilder::VisitInstruction(HInstruction* current) {
860
  HInstruction* old_current = current_instruction_;
861
  current_instruction_ = current;
862

    
863
  LInstruction* instr = NULL;
864
  if (current->CanReplaceWithDummyUses()) {
865
    HValue* first_operand = current->OperandCount() == 0
866
        ? graph()->GetConstant1()
867
        : current->OperandAt(0);
868
    instr = DefineAsRegister(new(zone()) LDummyUse(UseAny(first_operand)));
869
    for (int i = 1; i < current->OperandCount(); ++i) {
870
      LInstruction* dummy =
871
          new(zone()) LDummyUse(UseAny(current->OperandAt(i)));
872
      dummy->set_hydrogen_value(current);
873
      chunk_->AddInstruction(dummy, current_block_);
874
    }
875
  } else {
876
    instr = current->CompileToLithium(this);
877
  }
878

    
879
  argument_count_ += current->argument_delta();
880
  ASSERT(argument_count_ >= 0);
881

    
882
  if (instr != NULL) {
883
    // Associate the hydrogen instruction first, since we may need it for
884
    // the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
885
    instr->set_hydrogen_value(current);
886

    
887
#if DEBUG
888
    // Make sure that the lithium instruction has either no fixed register
889
    // constraints in temps or the result OR no uses that are only used at
890
    // start. If this invariant doesn't hold, the register allocator can decide
891
    // to insert a split of a range immediately before the instruction due to an
892
    // already allocated register needing to be used for the instruction's fixed
893
    // register constraint. In this case, The register allocator won't see an
894
    // interference between the split child and the use-at-start (it would if
895
    // the it was just a plain use), so it is free to move the split child into
896
    // the same register that is used for the use-at-start.
897
    // See https://code.google.com/p/chromium/issues/detail?id=201590
898
    if (!(instr->ClobbersRegisters() && instr->ClobbersDoubleRegisters())) {
899
      int fixed = 0;
900
      int used_at_start = 0;
901
      for (UseIterator it(instr); !it.Done(); it.Advance()) {
902
        LUnallocated* operand = LUnallocated::cast(it.Current());
903
        if (operand->IsUsedAtStart()) ++used_at_start;
904
      }
905
      if (instr->Output() != NULL) {
906
        if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
907
      }
908
      for (TempIterator it(instr); !it.Done(); it.Advance()) {
909
        LUnallocated* operand = LUnallocated::cast(it.Current());
910
        if (operand->HasFixedPolicy()) ++fixed;
911
      }
912
      ASSERT(fixed == 0 || used_at_start == 0);
913
    }
914
#endif
915

    
916
    if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
917
      instr = AssignPointerMap(instr);
918
    }
919
    if (FLAG_stress_environments && !instr->HasEnvironment()) {
920
      instr = AssignEnvironment(instr);
921
    }
922
    chunk_->AddInstruction(instr, current_block_);
923
  }
924
  current_instruction_ = old_current;
925
}
926

    
927

    
928
LEnvironment* LChunkBuilder::CreateEnvironment(
929
    HEnvironment* hydrogen_env,
930
    int* argument_index_accumulator,
931
    ZoneList<HValue*>* objects_to_materialize) {
932
  if (hydrogen_env == NULL) return NULL;
933

    
934
  LEnvironment* outer = CreateEnvironment(hydrogen_env->outer(),
935
                                          argument_index_accumulator,
936
                                          objects_to_materialize);
937
  BailoutId ast_id = hydrogen_env->ast_id();
938
  ASSERT(!ast_id.IsNone() ||
939
         hydrogen_env->frame_type() != JS_FUNCTION);
940
  int value_count = hydrogen_env->length() - hydrogen_env->specials_count();
941
  LEnvironment* result = new(zone()) LEnvironment(
942
      hydrogen_env->closure(),
943
      hydrogen_env->frame_type(),
944
      ast_id,
945
      hydrogen_env->parameter_count(),
946
      argument_count_,
947
      value_count,
948
      outer,
949
      hydrogen_env->entry(),
950
      zone());
951
  int argument_index = *argument_index_accumulator;
952
  int object_index = objects_to_materialize->length();
953
  for (int i = 0; i < hydrogen_env->length(); ++i) {
954
    if (hydrogen_env->is_special_index(i)) continue;
955

    
956
    LOperand* op;
957
    HValue* value = hydrogen_env->values()->at(i);
958
    if (value->IsArgumentsObject() || value->IsCapturedObject()) {
959
      objects_to_materialize->Add(value, zone());
960
      op = LEnvironment::materialization_marker();
961
    } else if (value->IsPushArgument()) {
962
      op = new(zone()) LArgument(argument_index++);
963
    } else {
964
      op = UseAny(value);
965
    }
966
    result->AddValue(op,
967
                     value->representation(),
968
                     value->CheckFlag(HInstruction::kUint32));
969
  }
970

    
971
  for (int i = object_index; i < objects_to_materialize->length(); ++i) {
972
    HValue* object_to_materialize = objects_to_materialize->at(i);
973
    int previously_materialized_object = -1;
974
    for (int prev = 0; prev < i; ++prev) {
975
      if (objects_to_materialize->at(prev) == objects_to_materialize->at(i)) {
976
        previously_materialized_object = prev;
977
        break;
978
      }
979
    }
980
    int length = object_to_materialize->OperandCount();
981
    bool is_arguments = object_to_materialize->IsArgumentsObject();
982
    if (previously_materialized_object >= 0) {
983
      result->AddDuplicateObject(previously_materialized_object);
984
      continue;
985
    } else {
986
      result->AddNewObject(is_arguments ? length - 1 : length, is_arguments);
987
    }
988
    for (int i = is_arguments ? 1 : 0; i < length; ++i) {
989
      LOperand* op;
990
      HValue* value = object_to_materialize->OperandAt(i);
991
      if (value->IsArgumentsObject() || value->IsCapturedObject()) {
992
        objects_to_materialize->Add(value, zone());
993
        op = LEnvironment::materialization_marker();
994
      } else {
995
        ASSERT(!value->IsPushArgument());
996
        op = UseAny(value);
997
      }
998
      result->AddValue(op,
999
                       value->representation(),
1000
                       value->CheckFlag(HInstruction::kUint32));
1001
    }
1002
  }
1003

    
1004
  if (hydrogen_env->frame_type() == JS_FUNCTION) {
1005
    *argument_index_accumulator = argument_index;
1006
  }
1007

    
1008
  return result;
1009
}
1010

    
1011

    
1012
LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
1013
  return new(zone()) LGoto(instr->FirstSuccessor());
1014
}
1015

    
1016

    
1017
LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
1018
  return new(zone()) LDebugBreak();
1019
}
1020

    
1021

    
1022
LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
1023
  LInstruction* goto_instr = CheckElideControlInstruction(instr);
1024
  if (goto_instr != NULL) return goto_instr;
1025

    
1026
  HValue* value = instr->value();
1027
  LBranch* result = new(zone()) LBranch(UseRegister(value));
1028
  // Tagged values that are not known smis or booleans require a
1029
  // deoptimization environment. If the instruction is generic no
1030
  // environment is needed since all cases are handled.
1031
  ToBooleanStub::Types expected = instr->expected_input_types();
1032
  Representation rep = value->representation();
1033
  HType type = value->type();
1034
  if (rep.IsTagged() && !type.IsSmi() && !type.IsBoolean() &&
1035
      !expected.IsGeneric()) {
1036
    return AssignEnvironment(result);
1037
  }
1038
  return result;
1039
}
1040

    
1041

    
1042
LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
1043
  ASSERT(instr->value()->representation().IsTagged());
1044
  LOperand* value = UseRegisterAtStart(instr->value());
1045
  return new(zone()) LCmpMapAndBranch(value);
1046
}
1047

    
1048

    
1049
LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
1050
  info()->MarkAsRequiresFrame();
1051
  return DefineAsRegister(new(zone()) LArgumentsLength(Use(length->value())));
1052
}
1053

    
1054

    
1055
LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
1056
  info()->MarkAsRequiresFrame();
1057
  return DefineAsRegister(new(zone()) LArgumentsElements);
1058
}
1059

    
1060

    
1061
LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
1062
  LOperand* left = UseFixed(instr->left(), rax);
1063
  LOperand* right = UseFixed(instr->right(), rdx);
1064
  LInstanceOf* result = new(zone()) LInstanceOf(left, right);
1065
  return MarkAsCall(DefineFixed(result, rax), instr);
1066
}
1067

    
1068

    
1069
LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
1070
    HInstanceOfKnownGlobal* instr) {
1071
  LInstanceOfKnownGlobal* result =
1072
      new(zone()) LInstanceOfKnownGlobal(UseFixed(instr->left(), rax),
1073
                                         FixedTemp(rdi));
1074
  return MarkAsCall(DefineFixed(result, rax), instr);
1075
}
1076

    
1077

    
1078
LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
1079
  LOperand* receiver = UseRegister(instr->receiver());
1080
  LOperand* function = UseRegisterAtStart(instr->function());
1081
  LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function);
1082
  return AssignEnvironment(DefineSameAsFirst(result));
1083
}
1084

    
1085

    
1086
LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
1087
  LOperand* function = UseFixed(instr->function(), rdi);
1088
  LOperand* receiver = UseFixed(instr->receiver(), rax);
1089
  LOperand* length = UseFixed(instr->length(), rbx);
1090
  LOperand* elements = UseFixed(instr->elements(), rcx);
1091
  LApplyArguments* result = new(zone()) LApplyArguments(function,
1092
                                                receiver,
1093
                                                length,
1094
                                                elements);
1095
  return MarkAsCall(DefineFixed(result, rax), instr, CAN_DEOPTIMIZE_EAGERLY);
1096
}
1097

    
1098

    
1099
LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
1100
  LOperand* argument = UseOrConstant(instr->argument());
1101
  return new(zone()) LPushArgument(argument);
1102
}
1103

    
1104

    
1105
LInstruction* LChunkBuilder::DoStoreCodeEntry(
1106
    HStoreCodeEntry* store_code_entry) {
1107
  LOperand* function = UseRegister(store_code_entry->function());
1108
  LOperand* code_object = UseTempRegister(store_code_entry->code_object());
1109
  return new(zone()) LStoreCodeEntry(function, code_object);
1110
}
1111

    
1112

    
1113
LInstruction* LChunkBuilder::DoInnerAllocatedObject(
1114
    HInnerAllocatedObject* inner_object) {
1115
  LOperand* base_object = UseRegisterAtStart(inner_object->base_object());
1116
  LInnerAllocatedObject* result =
1117
    new(zone()) LInnerAllocatedObject(base_object);
1118
  return DefineAsRegister(result);
1119
}
1120

    
1121

    
1122
LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
1123
  return instr->HasNoUses()
1124
      ? NULL
1125
      : DefineAsRegister(new(zone()) LThisFunction);
1126
}
1127

    
1128

    
1129
LInstruction* LChunkBuilder::DoContext(HContext* instr) {
1130
  // If there is a non-return use, the context must be allocated in a register.
1131
  for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
1132
    if (!it.value()->IsReturn()) {
1133
      return DefineAsRegister(new(zone()) LContext);
1134
    }
1135
  }
1136

    
1137
  return NULL;
1138
}
1139

    
1140

    
1141
LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
1142
  LOperand* context = UseRegisterAtStart(instr->value());
1143
  return DefineAsRegister(new(zone()) LOuterContext(context));
1144
}
1145

    
1146

    
1147
LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
1148
  return MarkAsCall(new(zone()) LDeclareGlobals, instr);
1149
}
1150

    
1151

    
1152
LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
1153
  return DefineAsRegister(new(zone()) LGlobalObject);
1154
}
1155

    
1156

    
1157
LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
1158
  LOperand* global_object = UseRegisterAtStart(instr->value());
1159
  return DefineAsRegister(new(zone()) LGlobalReceiver(global_object));
1160
}
1161

    
1162

    
1163
LInstruction* LChunkBuilder::DoCallConstantFunction(
1164
    HCallConstantFunction* instr) {
1165
  return MarkAsCall(DefineFixed(new(zone()) LCallConstantFunction, rax), instr);
1166
}
1167

    
1168

    
1169
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
1170
  LOperand* function = UseFixed(instr->function(), rdi);
1171
  LInvokeFunction* result = new(zone()) LInvokeFunction(function);
1172
  return MarkAsCall(DefineFixed(result, rax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
1173
}
1174

    
1175

    
1176
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1177
  switch (instr->op()) {
1178
    case kMathFloor: return DoMathFloor(instr);
1179
    case kMathRound: return DoMathRound(instr);
1180
    case kMathAbs: return DoMathAbs(instr);
1181
    case kMathLog: return DoMathLog(instr);
1182
    case kMathSin: return DoMathSin(instr);
1183
    case kMathCos: return DoMathCos(instr);
1184
    case kMathTan: return DoMathTan(instr);
1185
    case kMathExp: return DoMathExp(instr);
1186
    case kMathSqrt: return DoMathSqrt(instr);
1187
    case kMathPowHalf: return DoMathPowHalf(instr);
1188
    default:
1189
      UNREACHABLE();
1190
      return NULL;
1191
  }
1192
}
1193

    
1194

    
1195
LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
1196
  LOperand* input = UseRegisterAtStart(instr->value());
1197
  LMathFloor* result = new(zone()) LMathFloor(input);
1198
  return AssignEnvironment(DefineAsRegister(result));
1199
}
1200

    
1201

    
1202
LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
1203
  LOperand* input = UseRegisterAtStart(instr->value());
1204
  LMathRound* result = new(zone()) LMathRound(input);
1205
  return AssignEnvironment(DefineAsRegister(result));
1206
}
1207

    
1208

    
1209
LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
1210
  LOperand* input = UseRegisterAtStart(instr->value());
1211
  LMathAbs* result = new(zone()) LMathAbs(input);
1212
  return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1213
}
1214

    
1215

    
1216
LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
1217
  ASSERT(instr->representation().IsDouble());
1218
  ASSERT(instr->value()->representation().IsDouble());
1219
  LOperand* input = UseRegisterAtStart(instr->value());
1220
  LMathLog* result = new(zone()) LMathLog(input);
1221
  return DefineSameAsFirst(result);
1222
}
1223

    
1224

    
1225
LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
1226
  LOperand* input = UseFixedDouble(instr->value(), xmm1);
1227
  LMathSin* result = new(zone()) LMathSin(input);
1228
  return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
1229
}
1230

    
1231

    
1232
LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
1233
  LOperand* input = UseFixedDouble(instr->value(), xmm1);
1234
  LMathCos* result = new(zone()) LMathCos(input);
1235
  return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
1236
}
1237

    
1238

    
1239
LInstruction* LChunkBuilder::DoMathTan(HUnaryMathOperation* instr) {
1240
  LOperand* input = UseFixedDouble(instr->value(), xmm1);
1241
  LMathTan* result = new(zone()) LMathTan(input);
1242
  return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
1243
}
1244

    
1245

    
1246
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
1247
  ASSERT(instr->representation().IsDouble());
1248
  ASSERT(instr->value()->representation().IsDouble());
1249
  LOperand* value = UseTempRegister(instr->value());
1250
  LOperand* temp1 = TempRegister();
1251
  LOperand* temp2 = TempRegister();
1252
  LMathExp* result = new(zone()) LMathExp(value, temp1, temp2);
1253
  return DefineAsRegister(result);
1254
}
1255

    
1256

    
1257
LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
1258
  LOperand* input = UseRegisterAtStart(instr->value());
1259
  LMathSqrt* result = new(zone()) LMathSqrt(input);
1260
  return DefineSameAsFirst(result);
1261
}
1262

    
1263

    
1264
LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
1265
  LOperand* input = UseRegisterAtStart(instr->value());
1266
  LMathPowHalf* result = new(zone()) LMathPowHalf(input);
1267
  return DefineSameAsFirst(result);
1268
}
1269

    
1270

    
1271
LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
1272
  ASSERT(instr->key()->representation().IsTagged());
1273
  LOperand* key = UseFixed(instr->key(), rcx);
1274
  LCallKeyed* result = new(zone()) LCallKeyed(key);
1275
  return MarkAsCall(DefineFixed(result, rax), instr);
1276
}
1277

    
1278

    
1279
LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
1280
  return MarkAsCall(DefineFixed(new(zone()) LCallNamed, rax), instr);
1281
}
1282

    
1283

    
1284
LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
1285
  return MarkAsCall(DefineFixed(new(zone()) LCallGlobal, rax), instr);
1286
}
1287

    
1288

    
1289
LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
1290
  return MarkAsCall(DefineFixed(new(zone()) LCallKnownGlobal, rax), instr);
1291
}
1292

    
1293

    
1294
LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
1295
  LOperand* constructor = UseFixed(instr->constructor(), rdi);
1296
  LCallNew* result = new(zone()) LCallNew(constructor);
1297
  return MarkAsCall(DefineFixed(result, rax), instr);
1298
}
1299

    
1300

    
1301
LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
1302
  LOperand* constructor = UseFixed(instr->constructor(), rdi);
1303
  LCallNewArray* result = new(zone()) LCallNewArray(constructor);
1304
  return MarkAsCall(DefineFixed(result, rax), instr);
1305
}
1306

    
1307

    
1308
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1309
  LOperand* function = UseFixed(instr->function(), rdi);
1310
  LCallFunction* result = new(zone()) LCallFunction(function);
1311
  return MarkAsCall(DefineFixed(result, rax), instr);
1312
}
1313

    
1314

    
1315
LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1316
  return MarkAsCall(DefineFixed(new(zone()) LCallRuntime, rax), instr);
1317
}
1318

    
1319

    
1320
LInstruction* LChunkBuilder::DoRor(HRor* instr) {
1321
  return DoShift(Token::ROR, instr);
1322
}
1323

    
1324

    
1325
LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1326
  return DoShift(Token::SHR, instr);
1327
}
1328

    
1329

    
1330
LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1331
  return DoShift(Token::SAR, instr);
1332
}
1333

    
1334

    
1335
LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1336
  return DoShift(Token::SHL, instr);
1337
}
1338

    
1339

    
1340
LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
1341
  if (instr->representation().IsSmiOrInteger32()) {
1342
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1343
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1344
    ASSERT(instr->CheckFlag(HValue::kTruncatingToInt32));
1345

    
1346
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1347
    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1348
    return DefineSameAsFirst(new(zone()) LBitI(left, right));
1349
  } else {
1350
    return DoArithmeticT(instr->op(), instr);
1351
  }
1352
}
1353

    
1354

    
1355
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1356
  if (instr->representation().IsSmiOrInteger32()) {
1357
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1358
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1359
    if (instr->HasPowerOf2Divisor()) {
1360
      ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
1361
      LOperand* value = UseRegisterAtStart(instr->left());
1362
      LDivI* div =
1363
          new(zone()) LDivI(value, UseOrConstant(instr->right()), NULL);
1364
      return AssignEnvironment(DefineSameAsFirst(div));
1365
    }
1366
    // The temporary operand is necessary to ensure that right is not allocated
1367
    // into rdx.
1368
    LOperand* temp = FixedTemp(rdx);
1369
    LOperand* dividend = UseFixed(instr->left(), rax);
1370
    LOperand* divisor = UseRegister(instr->right());
1371
    LDivI* result = new(zone()) LDivI(dividend, divisor, temp);
1372
    return AssignEnvironment(DefineFixed(result, rax));
1373
  } else if (instr->representation().IsDouble()) {
1374
    return DoArithmeticD(Token::DIV, instr);
1375
  } else {
1376
    return DoArithmeticT(Token::DIV, instr);
1377
  }
1378
}
1379

    
1380

    
1381
HValue* LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(HValue* divisor) {
1382
  if (divisor->IsConstant() &&
1383
      HConstant::cast(divisor)->HasInteger32Value()) {
1384
    HConstant* constant_val = HConstant::cast(divisor);
1385
    return constant_val->CopyToRepresentation(Representation::Integer32(),
1386
                                              divisor->block()->zone());
1387
  }
1388
  // A value with an integer representation does not need to be transformed.
1389
  if (divisor->representation().IsInteger32()) {
1390
    return divisor;
1391
  // A change from an integer32 can be replaced by the integer32 value.
1392
  } else if (divisor->IsChange() &&
1393
             HChange::cast(divisor)->from().IsInteger32()) {
1394
    return HChange::cast(divisor)->value();
1395
  }
1396
  return NULL;
1397
}
1398

    
1399

    
1400
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
1401
  HValue* right = instr->right();
1402
  if (!right->IsConstant()) {
1403
    ASSERT(right->representation().IsInteger32());
1404
    // The temporary operand is necessary to ensure that right is not allocated
1405
    // into rdx.
1406
    LOperand* temp = FixedTemp(rdx);
1407
    LOperand* dividend = UseFixed(instr->left(), rax);
1408
    LOperand* divisor = UseRegister(instr->right());
1409
    LDivI* flooring_div = new(zone()) LDivI(dividend, divisor, temp);
1410
    return AssignEnvironment(DefineFixed(flooring_div, rax));
1411
  }
1412

    
1413
  ASSERT(right->IsConstant() && HConstant::cast(right)->HasInteger32Value());
1414
  LOperand* divisor = chunk_->DefineConstantOperand(HConstant::cast(right));
1415
  int32_t divisor_si = HConstant::cast(right)->Integer32Value();
1416
  if (divisor_si == 0) {
1417
    LOperand* dividend = UseRegister(instr->left());
1418
    return AssignEnvironment(DefineAsRegister(
1419
        new(zone()) LMathFloorOfDiv(dividend, divisor, NULL)));
1420
  } else if (IsPowerOf2(abs(divisor_si))) {
1421
    LOperand* dividend = UseRegisterAtStart(instr->left());
1422
    LInstruction* result = DefineAsRegister(
1423
        new(zone()) LMathFloorOfDiv(dividend, divisor, NULL));
1424
    return divisor_si < 0 ? AssignEnvironment(result) : result;
1425
  } else {
1426
    // use two r64
1427
    LOperand* dividend = UseRegisterAtStart(instr->left());
1428
    LOperand* temp = TempRegister();
1429
    LInstruction* result = DefineAsRegister(
1430
        new(zone()) LMathFloorOfDiv(dividend, divisor, temp));
1431
    return divisor_si < 0 ? AssignEnvironment(result) : result;
1432
  }
1433
}
1434

    
1435

    
1436
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1437
  HValue* left = instr->left();
1438
  HValue* right = instr->right();
1439
  if (instr->representation().IsSmiOrInteger32()) {
1440
    ASSERT(left->representation().Equals(instr->representation()));
1441
    ASSERT(right->representation().Equals(instr->representation()));
1442
    if (instr->HasPowerOf2Divisor()) {
1443
      ASSERT(!right->CanBeZero());
1444
      LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
1445
                                     UseOrConstant(right),
1446
                                     NULL);
1447
      LInstruction* result = DefineSameAsFirst(mod);
1448
      return (left->CanBeNegative() &&
1449
              instr->CheckFlag(HValue::kBailoutOnMinusZero))
1450
          ? AssignEnvironment(result)
1451
          : result;
1452
    } else if (instr->fixed_right_arg().has_value) {
1453
      LModI* mod = new(zone()) LModI(UseRegister(left),
1454
                                     UseRegisterAtStart(right),
1455
                                     NULL);
1456
      return AssignEnvironment(DefineSameAsFirst(mod));
1457
    } else {
1458
      // The temporary operand is necessary to ensure that right is not
1459
      // allocated into edx.
1460
      LModI* mod = new(zone()) LModI(UseFixed(left, rax),
1461
                                     UseRegister(right),
1462
                                     FixedTemp(rdx));
1463
      LInstruction* result = DefineFixed(mod, rdx);
1464
      return (right->CanBeZero() ||
1465
              (left->RangeCanInclude(kMinInt) &&
1466
               right->RangeCanInclude(-1) &&
1467
               instr->CheckFlag(HValue::kBailoutOnMinusZero)) ||
1468
              (left->CanBeNegative() &&
1469
               instr->CanBeZero() &&
1470
               instr->CheckFlag(HValue::kBailoutOnMinusZero)))
1471
          ? AssignEnvironment(result)
1472
          : result;
1473
    }
1474
  } else if (instr->representation().IsDouble()) {
1475
    return DoArithmeticD(Token::MOD, instr);
1476
  } else {
1477
    return DoArithmeticT(Token::MOD, instr);
1478
  }
1479
}
1480

    
1481

    
1482
LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1483
  if (instr->representation().IsSmiOrInteger32()) {
1484
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1485
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1486
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1487
    LOperand* right = UseOrConstant(instr->BetterRightOperand());
1488
    LMulI* mul = new(zone()) LMulI(left, right);
1489
    if (instr->CheckFlag(HValue::kCanOverflow) ||
1490
        instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1491
      AssignEnvironment(mul);
1492
    }
1493
    return DefineSameAsFirst(mul);
1494
  } else if (instr->representation().IsDouble()) {
1495
    return DoArithmeticD(Token::MUL, instr);
1496
  } else {
1497
    return DoArithmeticT(Token::MUL, instr);
1498
  }
1499
}
1500

    
1501

    
1502
LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1503
  if (instr->representation().IsSmiOrInteger32()) {
1504
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1505
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1506
    LOperand* left = UseRegisterAtStart(instr->left());
1507
    LOperand* right = UseOrConstantAtStart(instr->right());
1508
    LSubI* sub = new(zone()) LSubI(left, right);
1509
    LInstruction* result = DefineSameAsFirst(sub);
1510
    if (instr->CheckFlag(HValue::kCanOverflow)) {
1511
      result = AssignEnvironment(result);
1512
    }
1513
    return result;
1514
  } else if (instr->representation().IsDouble()) {
1515
    return DoArithmeticD(Token::SUB, instr);
1516
  } else {
1517
    return DoArithmeticT(Token::SUB, instr);
1518
  }
1519
}
1520

    
1521

    
1522
LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1523
  if (instr->representation().IsSmiOrInteger32()) {
1524
    // Check to see if it would be advantageous to use an lea instruction rather
1525
    // than an add. This is the case when no overflow check is needed and there
1526
    // are multiple uses of the add's inputs, so using a 3-register add will
1527
    // preserve all input values for later uses.
1528
    bool use_lea = LAddI::UseLea(instr);
1529
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1530
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1531
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1532
    HValue* right_candidate = instr->BetterRightOperand();
1533
    LOperand* right = use_lea
1534
        ? UseRegisterOrConstantAtStart(right_candidate)
1535
        : UseOrConstantAtStart(right_candidate);
1536
    LAddI* add = new(zone()) LAddI(left, right);
1537
    bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
1538
    LInstruction* result = use_lea
1539
        ? DefineAsRegister(add)
1540
        : DefineSameAsFirst(add);
1541
    if (can_overflow) {
1542
      result = AssignEnvironment(result);
1543
    }
1544
    return result;
1545
  } else if (instr->representation().IsDouble()) {
1546
    return DoArithmeticD(Token::ADD, instr);
1547
  } else {
1548
    return DoArithmeticT(Token::ADD, instr);
1549
  }
1550
  return NULL;
1551
}
1552

    
1553

    
1554
LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
1555
  LOperand* left = NULL;
1556
  LOperand* right = NULL;
1557
  if (instr->representation().IsSmiOrInteger32()) {
1558
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1559
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1560
    left = UseRegisterAtStart(instr->BetterLeftOperand());
1561
    right = UseOrConstantAtStart(instr->BetterRightOperand());
1562
  } else {
1563
    ASSERT(instr->representation().IsDouble());
1564
    ASSERT(instr->left()->representation().IsDouble());
1565
    ASSERT(instr->right()->representation().IsDouble());
1566
    left = UseRegisterAtStart(instr->left());
1567
    right = UseRegisterAtStart(instr->right());
1568
  }
1569
  LMathMinMax* minmax = new(zone()) LMathMinMax(left, right);
1570
  return DefineSameAsFirst(minmax);
1571
}
1572

    
1573

    
1574
LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1575
  ASSERT(instr->representation().IsDouble());
1576
  // We call a C function for double power. It can't trigger a GC.
1577
  // We need to use fixed result register for the call.
1578
  Representation exponent_type = instr->right()->representation();
1579
  ASSERT(instr->left()->representation().IsDouble());
1580
  LOperand* left = UseFixedDouble(instr->left(), xmm2);
1581
  LOperand* right = exponent_type.IsDouble() ?
1582
      UseFixedDouble(instr->right(), xmm1) : UseFixed(instr->right(), rdx);
1583
  LPower* result = new(zone()) LPower(left, right);
1584
  return MarkAsCall(DefineFixedDouble(result, xmm3), instr,
1585
                    CAN_DEOPTIMIZE_EAGERLY);
1586
}
1587

    
1588

    
1589
LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
1590
  ASSERT(instr->representation().IsDouble());
1591
  ASSERT(instr->global_object()->representation().IsTagged());
1592
  LOperand* global_object = UseTempRegister(instr->global_object());
1593
  LOperand* scratch = TempRegister();
1594
  LOperand* scratch2 = TempRegister();
1595
  LOperand* scratch3 = TempRegister();
1596
  LRandom* result = new(zone()) LRandom(
1597
      global_object, scratch, scratch2, scratch3);
1598
  return DefineFixedDouble(result, xmm1);
1599
}
1600

    
1601

    
1602
LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1603
  ASSERT(instr->left()->representation().IsTagged());
1604
  ASSERT(instr->right()->representation().IsTagged());
1605
  LOperand* left = UseFixed(instr->left(), rdx);
1606
  LOperand* right = UseFixed(instr->right(), rax);
1607
  LCmpT* result = new(zone()) LCmpT(left, right);
1608
  return MarkAsCall(DefineFixed(result, rax), instr);
1609
}
1610

    
1611

    
1612
LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
1613
    HCompareNumericAndBranch* instr) {
1614
  Representation r = instr->representation();
1615
  if (r.IsSmiOrInteger32()) {
1616
    ASSERT(instr->left()->representation().Equals(r));
1617
    ASSERT(instr->right()->representation().Equals(r));
1618
    LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1619
    LOperand* right = UseOrConstantAtStart(instr->right());
1620
    return new(zone()) LCompareNumericAndBranch(left, right);
1621
  } else {
1622
    ASSERT(r.IsDouble());
1623
    ASSERT(instr->left()->representation().IsDouble());
1624
    ASSERT(instr->right()->representation().IsDouble());
1625
    LOperand* left;
1626
    LOperand* right;
1627
    if (instr->left()->IsConstant() && instr->right()->IsConstant()) {
1628
      left = UseRegisterOrConstantAtStart(instr->left());
1629
      right = UseRegisterOrConstantAtStart(instr->right());
1630
    } else {
1631
      left = UseRegisterAtStart(instr->left());
1632
      right = UseRegisterAtStart(instr->right());
1633
    }
1634
    return new(zone()) LCompareNumericAndBranch(left, right);
1635
  }
1636
}
1637

    
1638

    
1639
LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
1640
    HCompareObjectEqAndBranch* instr) {
1641
  LInstruction* goto_instr = CheckElideControlInstruction(instr);
1642
  if (goto_instr != NULL) return goto_instr;
1643
  LOperand* left = UseRegisterAtStart(instr->left());
1644
  LOperand* right = UseRegisterOrConstantAtStart(instr->right());
1645
  return new(zone()) LCmpObjectEqAndBranch(left, right);
1646
}
1647

    
1648

    
1649
LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
1650
    HCompareHoleAndBranch* instr) {
1651
  LOperand* value = UseRegisterAtStart(instr->value());
1652
  return new(zone()) LCmpHoleAndBranch(value);
1653
}
1654

    
1655

    
1656
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
1657
  ASSERT(instr->value()->representation().IsTagged());
1658
  return new(zone()) LIsObjectAndBranch(UseRegisterAtStart(instr->value()));
1659
}
1660

    
1661

    
1662
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1663
  ASSERT(instr->value()->representation().IsTagged());
1664
  LOperand* value = UseRegisterAtStart(instr->value());
1665
  LOperand* temp = TempRegister();
1666
  return new(zone()) LIsStringAndBranch(value, temp);
1667
}
1668

    
1669

    
1670
LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1671
  ASSERT(instr->value()->representation().IsTagged());
1672
  return new(zone()) LIsSmiAndBranch(Use(instr->value()));
1673
}
1674

    
1675

    
1676
LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1677
    HIsUndetectableAndBranch* instr) {
1678
  ASSERT(instr->value()->representation().IsTagged());
1679
  LOperand* value = UseRegisterAtStart(instr->value());
1680
  LOperand* temp = TempRegister();
1681
  return new(zone()) LIsUndetectableAndBranch(value, temp);
1682
}
1683

    
1684

    
1685
LInstruction* LChunkBuilder::DoStringCompareAndBranch(
1686
    HStringCompareAndBranch* instr) {
1687

    
1688
  ASSERT(instr->left()->representation().IsTagged());
1689
  ASSERT(instr->right()->representation().IsTagged());
1690
  LOperand* left = UseFixed(instr->left(), rdx);
1691
  LOperand* right = UseFixed(instr->right(), rax);
1692
  LStringCompareAndBranch* result =
1693
      new(zone()) LStringCompareAndBranch(left, right);
1694

    
1695
  return MarkAsCall(result, instr);
1696
}
1697

    
1698

    
1699
LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1700
    HHasInstanceTypeAndBranch* instr) {
1701
  ASSERT(instr->value()->representation().IsTagged());
1702
  LOperand* value = UseRegisterAtStart(instr->value());
1703
  return new(zone()) LHasInstanceTypeAndBranch(value);
1704
}
1705

    
1706

    
1707
LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
1708
    HGetCachedArrayIndex* instr)  {
1709
  ASSERT(instr->value()->representation().IsTagged());
1710
  LOperand* value = UseRegisterAtStart(instr->value());
1711

    
1712
  return DefineAsRegister(new(zone()) LGetCachedArrayIndex(value));
1713
}
1714

    
1715

    
1716
LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
1717
    HHasCachedArrayIndexAndBranch* instr) {
1718
  ASSERT(instr->value()->representation().IsTagged());
1719
  LOperand* value = UseRegisterAtStart(instr->value());
1720
  return new(zone()) LHasCachedArrayIndexAndBranch(value);
1721
}
1722

    
1723

    
1724
LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1725
    HClassOfTestAndBranch* instr) {
1726
  LOperand* value = UseRegister(instr->value());
1727
  return new(zone()) LClassOfTestAndBranch(value,
1728
                                           TempRegister(),
1729
                                           TempRegister());
1730
}
1731

    
1732

    
1733
LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) {
1734
  LOperand* map = UseRegisterAtStart(instr->value());
1735
  return DefineAsRegister(new(zone()) LMapEnumLength(map));
1736
}
1737

    
1738

    
1739
LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
1740
  LOperand* object = UseRegisterAtStart(instr->value());
1741
  return DefineAsRegister(new(zone()) LElementsKind(object));
1742
}
1743

    
1744

    
1745
LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
1746
  LOperand* object = UseRegister(instr->value());
1747
  LValueOf* result = new(zone()) LValueOf(object);
1748
  return DefineSameAsFirst(result);
1749
}
1750

    
1751

    
1752
LInstruction* LChunkBuilder::DoDateField(HDateField* instr) {
1753
  LOperand* object = UseFixed(instr->value(), rax);
1754
  LDateField* result = new(zone()) LDateField(object, instr->index());
1755
  return MarkAsCall(DefineFixed(result, rax), instr, CAN_DEOPTIMIZE_EAGERLY);
1756
}
1757

    
1758

    
1759
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
1760
  LOperand* string = UseRegister(instr->string());
1761
  LOperand* index = UseRegister(instr->index());
1762
  ASSERT(rcx.is_byte_register());
1763
  LOperand* value = UseFixed(instr->value(), rcx);
1764
  LSeqStringSetChar* result =
1765
      new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
1766
  return DefineSameAsFirst(result);
1767
}
1768

    
1769

    
1770
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1771
  LOperand* value = UseRegisterOrConstantAtStart(instr->index());
1772
  LOperand* length = Use(instr->length());
1773
  return AssignEnvironment(new(zone()) LBoundsCheck(value, length));
1774
}
1775

    
1776

    
1777
LInstruction* LChunkBuilder::DoBoundsCheckBaseIndexInformation(
1778
    HBoundsCheckBaseIndexInformation* instr) {
1779
  UNREACHABLE();
1780
  return NULL;
1781
}
1782

    
1783

    
1784
LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1785
  // The control instruction marking the end of a block that completed
1786
  // abruptly (e.g., threw an exception).  There is nothing specific to do.
1787
  return NULL;
1788
}
1789

    
1790

    
1791
LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
1792
  LOperand* value = UseFixed(instr->value(), rax);
1793
  return MarkAsCall(new(zone()) LThrow(value), instr);
1794
}
1795

    
1796

    
1797
LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) {
1798
  return NULL;
1799
}
1800

    
1801

    
1802
LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
1803
  // All HForceRepresentation instructions should be eliminated in the
1804
  // representation change phase of Hydrogen.
1805
  UNREACHABLE();
1806
  return NULL;
1807
}
1808

    
1809

    
1810
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1811
  Representation from = instr->from();
1812
  Representation to = instr->to();
1813
  if (from.IsSmi()) {
1814
    if (to.IsTagged()) {
1815
      LOperand* value = UseRegister(instr->value());
1816
      return DefineSameAsFirst(new(zone()) LDummyUse(value));
1817
    }
1818
    from = Representation::Tagged();
1819
  }
1820
  // Only mark conversions that might need to allocate as calling rather than
1821
  // all changes. This makes simple, non-allocating conversion not have to force
1822
  // building a stack frame.
1823
  if (from.IsTagged()) {
1824
    if (to.IsDouble()) {
1825
      LOperand* value = UseRegister(instr->value());
1826
      LNumberUntagD* res = new(zone()) LNumberUntagD(value);
1827
      return AssignEnvironment(DefineAsRegister(res));
1828
    } else if (to.IsSmi()) {
1829
      HValue* val = instr->value();
1830
      LOperand* value = UseRegister(val);
1831
      if (val->type().IsSmi()) {
1832
        return DefineSameAsFirst(new(zone()) LDummyUse(value));
1833
      }
1834
      return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
1835
    } else {
1836
      ASSERT(to.IsInteger32());
1837
      HValue* val = instr->value();
1838
      LOperand* value = UseRegister(val);
1839
      if (val->type().IsSmi() || val->representation().IsSmi()) {
1840
        return DefineSameAsFirst(new(zone()) LSmiUntag(value, false));
1841
      } else {
1842
        bool truncating = instr->CanTruncateToInt32();
1843
        LOperand* xmm_temp = truncating ? NULL : FixedTemp(xmm1);
1844
        LTaggedToI* res = new(zone()) LTaggedToI(value, xmm_temp);
1845
        return AssignEnvironment(DefineSameAsFirst(res));
1846
      }
1847
    }
1848
  } else if (from.IsDouble()) {
1849
    if (to.IsTagged()) {
1850
      info()->MarkAsDeferredCalling();
1851
      LOperand* value = UseRegister(instr->value());
1852
      LOperand* temp = TempRegister();
1853

    
1854
      // Make sure that temp and result_temp are different registers.
1855
      LUnallocated* result_temp = TempRegister();
1856
      LNumberTagD* result = new(zone()) LNumberTagD(value, temp);
1857
      return AssignPointerMap(Define(result, result_temp));
1858
    } else if (to.IsSmi()) {
1859
      LOperand* value = UseRegister(instr->value());
1860
      return AssignEnvironment(
1861
          DefineAsRegister(new(zone()) LDoubleToSmi(value)));
1862
    } else {
1863
      ASSERT(to.IsInteger32());
1864
      LOperand* value = UseRegister(instr->value());
1865
      return AssignEnvironment(
1866
          DefineAsRegister(new(zone()) LDoubleToI(value)));
1867
    }
1868
  } else if (from.IsInteger32()) {
1869
    info()->MarkAsDeferredCalling();
1870
    if (to.IsTagged()) {
1871
      HValue* val = instr->value();
1872
      LOperand* value = UseRegister(val);
1873
      if (val->CheckFlag(HInstruction::kUint32)) {
1874
        LOperand* temp = FixedTemp(xmm1);
1875
        LNumberTagU* result = new(zone()) LNumberTagU(value, temp);
1876
        return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1877
      } else if (val->HasRange() && val->range()->IsInSmiRange()) {
1878
        return DefineSameAsFirst(new(zone()) LSmiTag(value));
1879
      } else {
1880
        LNumberTagI* result = new(zone()) LNumberTagI(value);
1881
        return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1882
      }
1883
    } else if (to.IsSmi()) {
1884
      HValue* val = instr->value();
1885
      LOperand* value = UseRegister(val);
1886
      LInstruction* result = NULL;
1887
      if (val->CheckFlag(HInstruction::kUint32)) {
1888
        result = DefineAsRegister(new(zone()) LUint32ToSmi(value));
1889
        if (val->HasRange() && val->range()->IsInSmiRange() &&
1890
            val->range()->upper() != kMaxInt) {
1891
          return result;
1892
        }
1893
      } else {
1894
        result = DefineAsRegister(new(zone()) LInteger32ToSmi(value));
1895
        if (val->HasRange() && val->range()->IsInSmiRange()) {
1896
          return result;
1897
        }
1898
      }
1899
      return AssignEnvironment(result);
1900
    } else {
1901
      if (instr->value()->CheckFlag(HInstruction::kUint32)) {
1902
        LOperand* temp = FixedTemp(xmm1);
1903
        return DefineAsRegister(
1904
            new(zone()) LUint32ToDouble(UseRegister(instr->value()), temp));
1905
      } else {
1906
        ASSERT(to.IsDouble());
1907
        LOperand* value = Use(instr->value());
1908
        return DefineAsRegister(new(zone()) LInteger32ToDouble(value));
1909
      }
1910
    }
1911
  }
1912
  UNREACHABLE();
1913
  return NULL;
1914
}
1915

    
1916

    
1917
LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
1918
  LOperand* value = UseRegisterAtStart(instr->value());
1919
  return AssignEnvironment(new(zone()) LCheckNonSmi(value));
1920
}
1921

    
1922

    
1923
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1924
  LOperand* value = UseRegisterAtStart(instr->value());
1925
  return AssignEnvironment(new(zone()) LCheckSmi(value));
1926
}
1927

    
1928

    
1929
LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1930
  LOperand* value = UseRegisterAtStart(instr->value());
1931
  LCheckInstanceType* result = new(zone()) LCheckInstanceType(value);
1932
  return AssignEnvironment(result);
1933
}
1934

    
1935

    
1936
LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
1937
  LOperand* value = UseRegisterAtStart(instr->value());
1938
  return AssignEnvironment(new(zone()) LCheckValue(value));
1939
}
1940

    
1941

    
1942
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
1943
  LOperand* value = NULL;
1944
  if (!instr->CanOmitMapChecks()) {
1945
    value = UseRegisterAtStart(instr->value());
1946
    if (instr->has_migration_target()) info()->MarkAsDeferredCalling();
1947
  }
1948
  LCheckMaps* result = new(zone()) LCheckMaps(value);
1949
  if (!instr->CanOmitMapChecks()) {
1950
    AssignEnvironment(result);
1951
    if (instr->has_migration_target()) return AssignPointerMap(result);
1952
  }
1953
  return result;
1954
}
1955

    
1956

    
1957
LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
1958
  HValue* value = instr->value();
1959
  Representation input_rep = value->representation();
1960
  LOperand* reg = UseRegister(value);
1961
  if (input_rep.IsDouble()) {
1962
    return DefineAsRegister(new(zone()) LClampDToUint8(reg));
1963
  } else if (input_rep.IsInteger32()) {
1964
    return DefineSameAsFirst(new(zone()) LClampIToUint8(reg));
1965
  } else {
1966
    ASSERT(input_rep.IsSmiOrTagged());
1967
    // Register allocator doesn't (yet) support allocation of double
1968
    // temps. Reserve xmm1 explicitly.
1969
    LClampTToUint8* result = new(zone()) LClampTToUint8(reg,
1970
                                                        FixedTemp(xmm1));
1971
    return AssignEnvironment(DefineSameAsFirst(result));
1972
  }
1973
}
1974

    
1975

    
1976
LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1977
  LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
1978
  return new(zone()) LReturn(UseFixed(instr->value(), rax),
1979
                             parameter_count);
1980
}
1981

    
1982

    
1983
LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1984
  Representation r = instr->representation();
1985
  if (r.IsSmi()) {
1986
    return DefineAsRegister(new(zone()) LConstantS);
1987
  } else if (r.IsInteger32()) {
1988
    return DefineAsRegister(new(zone()) LConstantI);
1989
  } else if (r.IsDouble()) {
1990
    LOperand* temp = TempRegister();
1991
    return DefineAsRegister(new(zone()) LConstantD(temp));
1992
  } else if (r.IsExternal()) {
1993
    return DefineAsRegister(new(zone()) LConstantE);
1994
  } else if (r.IsTagged()) {
1995
    return DefineAsRegister(new(zone()) LConstantT);
1996
  } else {
1997
    UNREACHABLE();
1998
    return NULL;
1999
  }
2000
}
2001

    
2002

    
2003
LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
2004
  LLoadGlobalCell* result = new(zone()) LLoadGlobalCell;
2005
  return instr->RequiresHoleCheck()
2006
      ? AssignEnvironment(DefineAsRegister(result))
2007
      : DefineAsRegister(result);
2008
}
2009

    
2010

    
2011
LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
2012
  LOperand* global_object = UseFixed(instr->global_object(), rax);
2013
  LLoadGlobalGeneric* result = new(zone()) LLoadGlobalGeneric(global_object);
2014
  return MarkAsCall(DefineFixed(result, rax), instr);
2015
}
2016

    
2017

    
2018
LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
2019
  LOperand* value = UseRegister(instr->value());
2020
  // Use a temp to avoid reloading the cell value address in the case where
2021
  // we perform a hole check.
2022
  return instr->RequiresHoleCheck()
2023
      ? AssignEnvironment(new(zone()) LStoreGlobalCell(value, TempRegister()))
2024
      : new(zone()) LStoreGlobalCell(value, NULL);
2025
}
2026

    
2027

    
2028
LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
2029
  LOperand* global_object = UseFixed(instr->global_object(), rdx);
2030
  LOperand* value = UseFixed(instr->value(), rax);
2031
  LStoreGlobalGeneric* result =  new(zone()) LStoreGlobalGeneric(global_object,
2032
                                                                 value);
2033
  return MarkAsCall(result, instr);
2034
}
2035

    
2036

    
2037
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
2038
  LOperand* context = UseRegisterAtStart(instr->value());
2039
  LInstruction* result =
2040
      DefineAsRegister(new(zone()) LLoadContextSlot(context));
2041
  return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
2042
}
2043

    
2044

    
2045
LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
2046
  LOperand* context;
2047
  LOperand* value;
2048
  LOperand* temp;
2049
  if (instr->NeedsWriteBarrier()) {
2050
    context = UseTempRegister(instr->context());
2051
    value = UseTempRegister(instr->value());
2052
    temp = TempRegister();
2053
  } else {
2054
    context = UseRegister(instr->context());
2055
    value = UseRegister(instr->value());
2056
    temp = NULL;
2057
  }
2058
  LInstruction* result = new(zone()) LStoreContextSlot(context, value, temp);
2059
  return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
2060
}
2061

    
2062

    
2063
LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
2064
  // Use the special mov rax, moffs64 encoding for external
2065
  // memory accesses with 64-bit word-sized values.
2066
  if (instr->access().IsExternalMemory() &&
2067
      instr->access().offset() == 0 &&
2068
      (instr->access().representation().IsSmi() ||
2069
       instr->access().representation().IsTagged() ||
2070
       instr->access().representation().IsHeapObject() ||
2071
       instr->access().representation().IsExternal())) {
2072
    LOperand* obj = UseRegisterOrConstantAtStart(instr->object());
2073
    return DefineFixed(new(zone()) LLoadNamedField(obj), rax);
2074
  }
2075
  LOperand* obj = UseRegisterAtStart(instr->object());
2076
  return DefineAsRegister(new(zone()) LLoadNamedField(obj));
2077
}
2078

    
2079

    
2080
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
2081
  LOperand* object = UseFixed(instr->object(), rax);
2082
  LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric(object);
2083
  return MarkAsCall(DefineFixed(result, rax), instr);
2084
}
2085

    
2086

    
2087
LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
2088
    HLoadFunctionPrototype* instr) {
2089
  return AssignEnvironment(DefineAsRegister(
2090
      new(zone()) LLoadFunctionPrototype(UseRegister(instr->function()))));
2091
}
2092

    
2093

    
2094
LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
2095
  return DefineAsRegister(new(zone()) LLoadRoot);
2096
}
2097

    
2098

    
2099
LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
2100
    HLoadExternalArrayPointer* instr) {
2101
  LOperand* input = UseRegisterAtStart(instr->value());
2102
  return DefineAsRegister(new(zone()) LLoadExternalArrayPointer(input));
2103
}
2104

    
2105

    
2106
LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
2107
  ASSERT(instr->key()->representation().IsInteger32());
2108
  ElementsKind elements_kind = instr->elements_kind();
2109
  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2110
  LLoadKeyed* result = NULL;
2111

    
2112
  if (!instr->is_external()) {
2113
    LOperand* obj = UseRegisterAtStart(instr->elements());
2114
    result = new(zone()) LLoadKeyed(obj, key);
2115
  } else {
2116
    ASSERT(
2117
        (instr->representation().IsInteger32() &&
2118
         (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
2119
         (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
2120
        (instr->representation().IsDouble() &&
2121
         ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
2122
          (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
2123
    LOperand* external_pointer = UseRegister(instr->elements());
2124
    result = new(zone()) LLoadKeyed(external_pointer, key);
2125
  }
2126

    
2127
  DefineAsRegister(result);
2128
  bool can_deoptimize = instr->RequiresHoleCheck() ||
2129
      (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS);
2130
  // An unsigned int array load might overflow and cause a deopt, make sure it
2131
  // has an environment.
2132
  return can_deoptimize ? AssignEnvironment(result) : result;
2133
}
2134

    
2135

    
2136
LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
2137
  LOperand* object = UseFixed(instr->object(), rdx);
2138
  LOperand* key = UseFixed(instr->key(), rax);
2139

    
2140
  LLoadKeyedGeneric* result = new(zone()) LLoadKeyedGeneric(object, key);
2141
  return MarkAsCall(DefineFixed(result, rax), instr);
2142
}
2143

    
2144

    
2145
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
2146
  ElementsKind elements_kind = instr->elements_kind();
2147

    
2148
  if (!instr->is_external()) {
2149
    ASSERT(instr->elements()->representation().IsTagged());
2150
    bool needs_write_barrier = instr->NeedsWriteBarrier();
2151
    LOperand* object = NULL;
2152
    LOperand* key = NULL;
2153
    LOperand* val = NULL;
2154

    
2155
    if (instr->value()->representation().IsDouble()) {
2156
      object = UseRegisterAtStart(instr->elements());
2157
      val = UseTempRegister(instr->value());
2158
      key = UseRegisterOrConstantAtStart(instr->key());
2159
    } else {
2160
      ASSERT(instr->value()->representation().IsSmiOrTagged());
2161
      object = UseTempRegister(instr->elements());
2162
      if (needs_write_barrier) {
2163
        val = UseTempRegister(instr->value());
2164
        key = UseTempRegister(instr->key());
2165
      } else {
2166
        val = UseRegisterOrConstantAtStart(instr->value());
2167
        key = UseRegisterOrConstantAtStart(instr->key());
2168
      }
2169
    }
2170

    
2171
    return new(zone()) LStoreKeyed(object, key, val);
2172
  }
2173

    
2174
  ASSERT(
2175
      (instr->value()->representation().IsInteger32() &&
2176
       (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
2177
       (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
2178
      (instr->value()->representation().IsDouble() &&
2179
       ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
2180
        (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
2181
  ASSERT(instr->elements()->representation().IsExternal());
2182
  bool val_is_temp_register =
2183
      elements_kind == EXTERNAL_PIXEL_ELEMENTS ||
2184
      elements_kind == EXTERNAL_FLOAT_ELEMENTS;
2185
  LOperand* val = val_is_temp_register ? UseTempRegister(instr->value())
2186
      : UseRegister(instr->value());
2187
  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2188
  LOperand* external_pointer = UseRegister(instr->elements());
2189
  return new(zone()) LStoreKeyed(external_pointer, key, val);
2190
}
2191

    
2192

    
2193
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
2194
  LOperand* object = UseFixed(instr->object(), rdx);
2195
  LOperand* key = UseFixed(instr->key(), rcx);
2196
  LOperand* value = UseFixed(instr->value(), rax);
2197

    
2198
  ASSERT(instr->object()->representation().IsTagged());
2199
  ASSERT(instr->key()->representation().IsTagged());
2200
  ASSERT(instr->value()->representation().IsTagged());
2201

    
2202
  LStoreKeyedGeneric* result =
2203
      new(zone()) LStoreKeyedGeneric(object, key, value);
2204
  return MarkAsCall(result, instr);
2205
}
2206

    
2207

    
2208
LInstruction* LChunkBuilder::DoTransitionElementsKind(
2209
    HTransitionElementsKind* instr) {
2210
  LOperand* object = UseRegister(instr->object());
2211
  if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
2212
    LOperand* object = UseRegister(instr->object());
2213
    LOperand* new_map_reg = TempRegister();
2214
    LOperand* temp_reg = TempRegister();
2215
    LTransitionElementsKind* result =
2216
        new(zone()) LTransitionElementsKind(object, new_map_reg, temp_reg);
2217
    return result;
2218
  } else {
2219
    LTransitionElementsKind* result =
2220
        new(zone()) LTransitionElementsKind(object, NULL, NULL);
2221
    return AssignPointerMap(result);
2222
  }
2223
}
2224

    
2225

    
2226
LInstruction* LChunkBuilder::DoTrapAllocationMemento(
2227
    HTrapAllocationMemento* instr) {
2228
  LOperand* object = UseRegister(instr->object());
2229
  LOperand* temp = TempRegister();
2230
  LTrapAllocationMemento* result =
2231
      new(zone()) LTrapAllocationMemento(object, temp);
2232
  return AssignEnvironment(result);
2233
}
2234

    
2235

    
2236
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2237
  bool is_in_object = instr->access().IsInobject();
2238
  bool is_external_location = instr->access().IsExternalMemory() &&
2239
      instr->access().offset() == 0;
2240
  bool needs_write_barrier = instr->NeedsWriteBarrier();
2241
  bool needs_write_barrier_for_map = instr->has_transition() &&
2242
      instr->NeedsWriteBarrierForMap();
2243

    
2244
  LOperand* obj;
2245
  if (needs_write_barrier) {
2246
    obj = is_in_object
2247
        ? UseRegister(instr->object())
2248
        : UseTempRegister(instr->object());
2249
  } else if (is_external_location) {
2250
    ASSERT(!is_in_object);
2251
    ASSERT(!needs_write_barrier);
2252
    ASSERT(!needs_write_barrier_for_map);
2253
    obj = UseRegisterOrConstant(instr->object());
2254
  } else {
2255
    obj = needs_write_barrier_for_map
2256
        ? UseRegister(instr->object())
2257
        : UseRegisterAtStart(instr->object());
2258
  }
2259

    
2260
  bool can_be_constant = instr->value()->IsConstant() &&
2261
      HConstant::cast(instr->value())->NotInNewSpace() &&
2262
      !(FLAG_track_double_fields && instr->field_representation().IsDouble());
2263

    
2264
  LOperand* val;
2265
  if (needs_write_barrier) {
2266
    val = UseTempRegister(instr->value());
2267
  } else if (is_external_location) {
2268
    val = UseFixed(instr->value(), rax);
2269
  } else if (can_be_constant) {
2270
    val = UseRegisterOrConstant(instr->value());
2271
  } else if (FLAG_track_fields && instr->field_representation().IsSmi()) {
2272
    val = UseTempRegister(instr->value());
2273
  } else if (FLAG_track_double_fields &&
2274
             instr->field_representation().IsDouble()) {
2275
    val = UseRegisterAtStart(instr->value());
2276
  } else {
2277
    val = UseRegister(instr->value());
2278
  }
2279

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

    
2285
  LStoreNamedField* result = new(zone()) LStoreNamedField(obj, val, temp);
2286
  if (FLAG_track_heap_object_fields &&
2287
      instr->field_representation().IsHeapObject()) {
2288
    if (!instr->value()->type().IsHeapObject()) {
2289
      return AssignEnvironment(result);
2290
    }
2291
  }
2292
  return result;
2293
}
2294

    
2295

    
2296
LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
2297
  LOperand* object = UseFixed(instr->object(), rdx);
2298
  LOperand* value = UseFixed(instr->value(), rax);
2299

    
2300
  LStoreNamedGeneric* result = new(zone()) LStoreNamedGeneric(object, value);
2301
  return MarkAsCall(result, instr);
2302
}
2303

    
2304

    
2305
LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2306
  LOperand* left = UseOrConstantAtStart(instr->left());
2307
  LOperand* right = UseOrConstantAtStart(instr->right());
2308
  return MarkAsCall(DefineFixed(new(zone()) LStringAdd(left, right), rax),
2309
                    instr);
2310
}
2311

    
2312

    
2313
LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2314
  LOperand* string = UseTempRegister(instr->string());
2315
  LOperand* index = UseTempRegister(instr->index());
2316
  LStringCharCodeAt* result = new(zone()) LStringCharCodeAt(string, index);
2317
  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
2318
}
2319

    
2320

    
2321
LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
2322
  LOperand* char_code = UseRegister(instr->value());
2323
  LStringCharFromCode* result = new(zone()) LStringCharFromCode(char_code);
2324
  return AssignPointerMap(DefineAsRegister(result));
2325
}
2326

    
2327

    
2328
LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
2329
  info()->MarkAsDeferredCalling();
2330
  LOperand* size = instr->size()->IsConstant()
2331
      ? UseConstant(instr->size())
2332
      : UseTempRegister(instr->size());
2333
  LOperand* temp = TempRegister();
2334
  LAllocate* result = new(zone()) LAllocate(size, temp);
2335
  return AssignPointerMap(DefineAsRegister(result));
2336
}
2337

    
2338

    
2339
LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
2340
  return MarkAsCall(DefineFixed(new(zone()) LRegExpLiteral, rax), instr);
2341
}
2342

    
2343

    
2344
LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
2345
  return MarkAsCall(DefineFixed(new(zone()) LFunctionLiteral, rax), instr);
2346
}
2347

    
2348

    
2349
LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2350
  ASSERT(argument_count_ == 0);
2351
  allocator_->MarkAsOsrEntry();
2352
  current_block_->last_environment()->set_ast_id(instr->ast_id());
2353
  return AssignEnvironment(new(zone()) LOsrEntry);
2354
}
2355

    
2356

    
2357
LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2358
  LParameter* result = new(zone()) LParameter;
2359
  if (instr->kind() == HParameter::STACK_PARAMETER) {
2360
    int spill_index = chunk()->GetParameterStackSlot(instr->index());
2361
    return DefineAsSpilled(result, spill_index);
2362
  } else {
2363
    ASSERT(info()->IsStub());
2364
    CodeStubInterfaceDescriptor* descriptor =
2365
        info()->code_stub()->GetInterfaceDescriptor(info()->isolate());
2366
    int index = static_cast<int>(instr->index());
2367
    Register reg = DESCRIPTOR_GET_PARAMETER_REGISTER(descriptor, index);
2368
    return DefineFixed(result, reg);
2369
  }
2370
}
2371

    
2372

    
2373
LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2374
  // Use an index that corresponds to the location in the unoptimized frame,
2375
  // which the optimized frame will subsume.
2376
  int env_index = instr->index();
2377
  int spill_index = 0;
2378
  if (instr->environment()->is_parameter_index(env_index)) {
2379
    spill_index = chunk()->GetParameterStackSlot(env_index);
2380
  } else {
2381
    spill_index = env_index - instr->environment()->first_local_index();
2382
    if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
2383
      Abort(kTooManySpillSlotsNeededForOSR);
2384
      spill_index = 0;
2385
    }
2386
  }
2387
  return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
2388
}
2389

    
2390

    
2391
LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
2392
  return MarkAsCall(DefineFixed(new(zone()) LCallStub, rax), instr);
2393
}
2394

    
2395

    
2396
LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2397
  // There are no real uses of the arguments object.
2398
  // arguments.length and element access are supported directly on
2399
  // stack arguments, and any real arguments object use causes a bailout.
2400
  // So this value is never used.
2401
  return NULL;
2402
}
2403

    
2404

    
2405
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
2406
  instr->ReplayEnvironment(current_block_->last_environment());
2407

    
2408
  // There are no real uses of a captured object.
2409
  return NULL;
2410
}
2411

    
2412

    
2413
LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2414
  info()->MarkAsRequiresFrame();
2415
  LOperand* args = UseRegister(instr->arguments());
2416
  LOperand* length;
2417
  LOperand* index;
2418
  if (instr->length()->IsConstant() && instr->index()->IsConstant()) {
2419
    length = UseRegisterOrConstant(instr->length());
2420
    index = UseOrConstant(instr->index());
2421
  } else {
2422
    length = UseTempRegister(instr->length());
2423
    index = Use(instr->index());
2424
  }
2425
  return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
2426
}
2427

    
2428

    
2429
LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
2430
  LOperand* object = UseFixed(instr->value(), rax);
2431
  LToFastProperties* result = new(zone()) LToFastProperties(object);
2432
  return MarkAsCall(DefineFixed(result, rax), instr);
2433
}
2434

    
2435

    
2436
LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2437
  LTypeof* result = new(zone()) LTypeof(UseAtStart(instr->value()));
2438
  return MarkAsCall(DefineFixed(result, rax), instr);
2439
}
2440

    
2441

    
2442
LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2443
  return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value()));
2444
}
2445

    
2446

    
2447
LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
2448
    HIsConstructCallAndBranch* instr) {
2449
  return new(zone()) LIsConstructCallAndBranch(TempRegister());
2450
}
2451

    
2452

    
2453
LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2454
  instr->ReplayEnvironment(current_block_->last_environment());
2455

    
2456
  // If there is an instruction pending deoptimization environment create a
2457
  // lazy bailout instruction to capture the environment.
2458
  if (pending_deoptimization_ast_id_ == instr->ast_id()) {
2459
    LLazyBailout* lazy_bailout = new(zone()) LLazyBailout;
2460
    LInstruction* result = AssignEnvironment(lazy_bailout);
2461
    // Store the lazy deopt environment with the instruction if needed. Right
2462
    // now it is only used for LInstanceOfKnownGlobal.
2463
    instruction_pending_deoptimization_environment_->
2464
        SetDeferredLazyDeoptimizationEnvironment(result->environment());
2465
    instruction_pending_deoptimization_environment_ = NULL;
2466
    pending_deoptimization_ast_id_ = BailoutId::None();
2467
    return result;
2468
  }
2469

    
2470
  return NULL;
2471
}
2472

    
2473

    
2474
LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2475
  info()->MarkAsDeferredCalling();
2476
  if (instr->is_function_entry()) {
2477
    return MarkAsCall(new(zone()) LStackCheck, instr);
2478
  } else {
2479
    ASSERT(instr->is_backwards_branch());
2480
    return AssignEnvironment(AssignPointerMap(new(zone()) LStackCheck));
2481
  }
2482
}
2483

    
2484

    
2485
LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2486
  HEnvironment* outer = current_block_->last_environment();
2487
  HConstant* undefined = graph()->GetConstantUndefined();
2488
  HEnvironment* inner = outer->CopyForInlining(instr->closure(),
2489
                                               instr->arguments_count(),
2490
                                               instr->function(),
2491
                                               undefined,
2492
                                               instr->inlining_kind(),
2493
                                               instr->undefined_receiver());
2494
  // Only replay binding of arguments object if it wasn't removed from graph.
2495
  if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
2496
    inner->Bind(instr->arguments_var(), instr->arguments_object());
2497
  }
2498
  inner->set_entry(instr);
2499
  current_block_->UpdateEnvironment(inner);
2500
  chunk_->AddInlinedClosure(instr->closure());
2501
  return NULL;
2502
}
2503

    
2504

    
2505
LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2506
  LInstruction* pop = NULL;
2507

    
2508
  HEnvironment* env = current_block_->last_environment();
2509

    
2510
  if (env->entry()->arguments_pushed()) {
2511
    int argument_count = env->arguments_environment()->parameter_count();
2512
    pop = new(zone()) LDrop(argument_count);
2513
    ASSERT(instr->argument_delta() == -argument_count);
2514
  }
2515

    
2516
  HEnvironment* outer = current_block_->last_environment()->
2517
      DiscardInlined(false);
2518
  current_block_->UpdateEnvironment(outer);
2519

    
2520
  return pop;
2521
}
2522

    
2523

    
2524
LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
2525
  LOperand* object = UseFixed(instr->enumerable(), rax);
2526
  LForInPrepareMap* result = new(zone()) LForInPrepareMap(object);
2527
  return MarkAsCall(DefineFixed(result, rax), instr, CAN_DEOPTIMIZE_EAGERLY);
2528
}
2529

    
2530

    
2531
LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
2532
  LOperand* map = UseRegister(instr->map());
2533
  return AssignEnvironment(DefineAsRegister(
2534
      new(zone()) LForInCacheArray(map)));
2535
}
2536

    
2537

    
2538
LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
2539
  LOperand* value = UseRegisterAtStart(instr->value());
2540
  LOperand* map = UseRegisterAtStart(instr->map());
2541
  return AssignEnvironment(new(zone()) LCheckMapValue(value, map));
2542
}
2543

    
2544

    
2545
LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
2546
  LOperand* object = UseRegister(instr->object());
2547
  LOperand* index = UseTempRegister(instr->index());
2548
  return DefineSameAsFirst(new(zone()) LLoadFieldByIndex(object, index));
2549
}
2550

    
2551

    
2552
} }  // namespace v8::internal
2553

    
2554
#endif  // V8_TARGET_ARCH_X64