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

History | View | Annotate | Download (85.2 KB)

1
// Copyright 2012 the V8 project authors. All rights reserved.
2
// Redistribution and use in source and binary forms, with or without
3
// modification, are permitted provided that the following conditions are
4
// met:
5
//
6
//     * Redistributions of source code must retain the above copyright
7
//       notice, this list of conditions and the following disclaimer.
8
//     * Redistributions in binary form must reproduce the above
9
//       copyright notice, this list of conditions and the following
10
//       disclaimer in the documentation and/or other materials provided
11
//       with the distribution.
12
//     * Neither the name of Google Inc. nor the names of its
13
//       contributors may be used to endorse or promote products derived
14
//       from this software without specific prior written permission.
15
//
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27

    
28
#include "v8.h"
29

    
30
#include "lithium-allocator-inl.h"
31
#include "mips/lithium-mips.h"
32
#include "mips/lithium-codegen-mips.h"
33
#include "hydrogen-osr.h"
34

    
35
namespace v8 {
36
namespace internal {
37

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

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

    
66

    
67
void LInstruction::PrintTo(StringStream* stream) {
68
  stream->Add("%s ", this->Mnemonic());
69

    
70
  PrintOutputOperandTo(stream);
71

    
72
  PrintDataTo(stream);
73

    
74
  if (HasEnvironment()) {
75
    stream->Add(" ");
76
    environment()->PrintTo(stream);
77
  }
78

    
79
  if (HasPointerMap()) {
80
    stream->Add(" ");
81
    pointer_map()->PrintTo(stream);
82
  }
83
}
84

    
85

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

    
98

    
99
void LInstruction::PrintOutputOperandTo(StringStream* stream) {
100
  if (HasResult()) result()->PrintTo(stream);
101
}
102

    
103

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

    
112

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

    
120
  return true;
121
}
122

    
123

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

    
134

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

    
148

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

    
169

    
170
bool LGoto::HasInterestingComment(LCodeGen* gen) const {
171
  return !gen->IsNextEmittedBlock(block_id());
172
}
173

    
174

    
175
void LGoto::PrintDataTo(StringStream* stream) {
176
  stream->Add("B%d", block_id());
177
}
178

    
179

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

    
185

    
186
LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
187
  return new(zone()) LDebugBreak();
188
}
189

    
190

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

    
199

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

    
206

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

    
213

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

    
220

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

    
227

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

    
235

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

    
242

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

    
249

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

    
259

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

    
268

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

    
276

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

    
283

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

    
288

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

    
294

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

    
301

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

    
308

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

    
313

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

    
319

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

    
325

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

    
330

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

    
337

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

    
346

    
347
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
348
  arguments()->PrintTo(stream);
349
  stream->Add(" length ");
350
  length()->PrintTo(stream);
351
  stream->Add(" index ");
352
  index()->PrintTo(stream);
353
}
354

    
355

    
356
void LStoreNamedField::PrintDataTo(StringStream* stream) {
357
  object()->PrintTo(stream);
358
  hydrogen()->access().PrintTo(stream);
359
  stream->Add(" <- ");
360
  value()->PrintTo(stream);
361
}
362

    
363

    
364
void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
365
  object()->PrintTo(stream);
366
  stream->Add(".");
367
  stream->Add(*String::cast(*name())->ToCString());
368
  stream->Add(" <- ");
369
  value()->PrintTo(stream);
370
}
371

    
372

    
373
void LLoadKeyed::PrintDataTo(StringStream* stream) {
374
  elements()->PrintTo(stream);
375
  stream->Add("[");
376
  key()->PrintTo(stream);
377
  if (hydrogen()->IsDehoisted()) {
378
    stream->Add(" + %d]", additional_index());
379
  } else {
380
    stream->Add("]");
381
  }
382
}
383

    
384

    
385
void LStoreKeyed::PrintDataTo(StringStream* stream) {
386
  elements()->PrintTo(stream);
387
  stream->Add("[");
388
  key()->PrintTo(stream);
389
  if (hydrogen()->IsDehoisted()) {
390
    stream->Add(" + %d] <-", additional_index());
391
  } else {
392
    stream->Add("] <- ");
393
  }
394

    
395
  if (value() == NULL) {
396
    ASSERT(hydrogen()->IsConstantHoleStore() &&
397
           hydrogen()->value()->representation().IsDouble());
398
    stream->Add("<the hole(nan)>");
399
  } else {
400
    value()->PrintTo(stream);
401
  }
402
}
403

    
404

    
405
void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
406
  object()->PrintTo(stream);
407
  stream->Add("[");
408
  key()->PrintTo(stream);
409
  stream->Add("] <- ");
410
  value()->PrintTo(stream);
411
}
412

    
413

    
414
void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
415
  object()->PrintTo(stream);
416
  stream->Add(" %p -> %p", *original_map(), *transitioned_map());
417
}
418

    
419

    
420
int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
421
  // Skip a slot if for a double-width slot.
422
  if (kind == DOUBLE_REGISTERS) spill_slot_count_++;
423
  return spill_slot_count_++;
424
}
425

    
426

    
427
LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind)  {
428
  int index = GetNextSpillIndex(kind);
429
  if (kind == DOUBLE_REGISTERS) {
430
    return LDoubleStackSlot::Create(index, zone());
431
  } else {
432
    ASSERT(kind == GENERAL_REGISTERS);
433
    return LStackSlot::Create(index, zone());
434
  }
435
}
436

    
437

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

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

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

    
463

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

    
469

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

    
475

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

    
481

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

    
486

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

    
491

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

    
496

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

    
503

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

    
508

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

    
513

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

    
519

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

    
526

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

    
533

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

    
540

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

    
547

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

    
552

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

    
559

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

    
569

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

    
578

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

    
586

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

    
594

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

    
602

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

    
609

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

    
616

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

    
627

    
628
LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
629
                                        HInstruction* hinstr,
630
                                        CanDeoptimize can_deoptimize) {
631
  info()->MarkAsNonDeferredCalling();
632
#ifdef DEBUG
633
  instr->VerifyCall();
634
#endif
635
  instr->MarkAsCall();
636
  instr = AssignPointerMap(instr);
637

    
638
  if (hinstr->HasObservableSideEffects()) {
639
    ASSERT(hinstr->next()->IsSimulate());
640
    HSimulate* sim = HSimulate::cast(hinstr->next());
641
    ASSERT(instruction_pending_deoptimization_environment_ == NULL);
642
    ASSERT(pending_deoptimization_ast_id_.IsNone());
643
    instruction_pending_deoptimization_environment_ = instr;
644
    pending_deoptimization_ast_id_ = sim->ast_id();
645
  }
646

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

    
658
  return instr;
659
}
660

    
661

    
662
LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
663
  ASSERT(!instr->HasPointerMap());
664
  instr->set_pointer_map(new(zone()) LPointerMap(zone()));
665
  return instr;
666
}
667

    
668

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

    
681

    
682
LOperand* LChunkBuilder::FixedTemp(Register reg) {
683
  LUnallocated* operand = ToUnallocated(reg);
684
  ASSERT(operand->HasFixedPolicy());
685
  return operand;
686
}
687

    
688

    
689
LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
690
  LUnallocated* operand = ToUnallocated(reg);
691
  ASSERT(operand->HasFixedPolicy());
692
  return operand;
693
}
694

    
695

    
696
LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
697
  return new(zone()) LLabel(instr->block());
698
}
699

    
700

    
701
LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
702
  return DefineAsRegister(new(zone()) LDummyUse(UseAny(instr->value())));
703
}
704

    
705

    
706
LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
707
  UNREACHABLE();
708
  return NULL;
709
}
710

    
711

    
712
LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
713
  return AssignEnvironment(new(zone()) LDeoptimize);
714
}
715

    
716

    
717
LInstruction* LChunkBuilder::DoShift(Token::Value op,
718
                                     HBitwiseBinaryOperation* instr) {
719
  if (instr->representation().IsSmiOrInteger32()) {
720
    ASSERT(instr->left()->representation().Equals(instr->representation()));
721
    ASSERT(instr->right()->representation().Equals(instr->representation()));
722
    LOperand* left = UseRegisterAtStart(instr->left());
723

    
724
    HValue* right_value = instr->right();
725
    LOperand* right = NULL;
726
    int constant_value = 0;
727
    bool does_deopt = false;
728
    if (right_value->IsConstant()) {
729
      HConstant* constant = HConstant::cast(right_value);
730
      right = chunk_->DefineConstantOperand(constant);
731
      constant_value = constant->Integer32Value() & 0x1f;
732
      // Left shifts can deoptimize if we shift by > 0 and the result cannot be
733
      // truncated to smi.
734
      if (instr->representation().IsSmi() && constant_value > 0) {
735
        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi);
736
      }
737
    } else {
738
      right = UseRegisterAtStart(right_value);
739
    }
740

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

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

    
759

    
760
LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
761
                                           HArithmeticBinaryOperation* instr) {
762
  ASSERT(instr->representation().IsDouble());
763
  ASSERT(instr->left()->representation().IsDouble());
764
  ASSERT(instr->right()->representation().IsDouble());
765
  if (op == Token::MOD) {
766
    LOperand* left = UseFixedDouble(instr->left(), f2);
767
    LOperand* right = UseFixedDouble(instr->right(), f4);
768
    LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
769
    // We call a C function for double modulo. It can't trigger a GC. We need
770
    // to use fixed result register for the call.
771
    // TODO(fschneider): Allow any register as input registers.
772
    return MarkAsCall(DefineFixedDouble(result, f2), instr);
773
  } else {
774
    LOperand* left = UseRegisterAtStart(instr->left());
775
    LOperand* right = UseRegisterAtStart(instr->right());
776
    LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
777
    return DefineAsRegister(result);
778
  }
779
}
780

    
781

    
782
LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
783
                                           HBinaryOperation* instr) {
784
  HValue* left = instr->left();
785
  HValue* right = instr->right();
786
  ASSERT(left->representation().IsTagged());
787
  ASSERT(right->representation().IsTagged());
788
  LOperand* context = UseFixed(instr->context(), cp);
789
  LOperand* left_operand = UseFixed(left, a1);
790
  LOperand* right_operand = UseFixed(right, a0);
791
  LArithmeticT* result =
792
      new(zone()) LArithmeticT(op, context, left_operand, right_operand);
793
  return MarkAsCall(DefineFixed(result, v0), instr);
794
}
795

    
796

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

    
863

    
864
void LChunkBuilder::VisitInstruction(HInstruction* current) {
865
  HInstruction* old_current = current_instruction_;
866
  current_instruction_ = current;
867
  if (current->has_position()) position_ = current->position();
868

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

    
885
  argument_count_ += current->argument_delta();
886
  ASSERT(argument_count_ >= 0);
887

    
888
  if (instr != NULL) {
889
    // Associate the hydrogen instruction first, since we may need it for
890
    // the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
891
    instr->set_hydrogen_value(current);
892

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

    
922
    if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
923
      instr = AssignPointerMap(instr);
924
    }
925
    if (FLAG_stress_environments && !instr->HasEnvironment()) {
926
      instr = AssignEnvironment(instr);
927
    }
928
    chunk_->AddInstruction(instr, current_block_);
929
  }
930
  current_instruction_ = old_current;
931
}
932

    
933

    
934
LEnvironment* LChunkBuilder::CreateEnvironment(
935
    HEnvironment* hydrogen_env,
936
    int* argument_index_accumulator,
937
    ZoneList<HValue*>* objects_to_materialize) {
938
  if (hydrogen_env == NULL) return NULL;
939

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

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

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

    
1010
  if (hydrogen_env->frame_type() == JS_FUNCTION) {
1011
    *argument_index_accumulator = argument_index;
1012
  }
1013

    
1014
  return result;
1015
}
1016

    
1017

    
1018
LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
1019
  return new(zone()) LGoto(instr->FirstSuccessor());
1020
}
1021

    
1022

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

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

    
1042

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

    
1050

    
1051
LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
1052
  info()->MarkAsRequiresFrame();
1053
  return DefineAsRegister(
1054
      new(zone()) LArgumentsLength(UseRegister(length->value())));
1055
}
1056

    
1057

    
1058
LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
1059
  info()->MarkAsRequiresFrame();
1060
  return DefineAsRegister(new(zone()) LArgumentsElements);
1061
}
1062

    
1063

    
1064
LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
1065
  LOperand* context = UseFixed(instr->context(), cp);
1066
  LInstanceOf* result =
1067
      new(zone()) LInstanceOf(context, UseFixed(instr->left(), a0),
1068
                              UseFixed(instr->right(), a1));
1069
  return MarkAsCall(DefineFixed(result, v0), instr);
1070
}
1071

    
1072

    
1073
LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
1074
    HInstanceOfKnownGlobal* instr) {
1075
  LInstanceOfKnownGlobal* result =
1076
      new(zone()) LInstanceOfKnownGlobal(
1077
          UseFixed(instr->context(), cp),
1078
          UseFixed(instr->left(), a0),
1079
          FixedTemp(t0));
1080
  return MarkAsCall(DefineFixed(result, v0), instr);
1081
}
1082

    
1083

    
1084
LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
1085
  LOperand* receiver = UseRegisterAtStart(instr->receiver());
1086
  LOperand* function = UseRegisterAtStart(instr->function());
1087
  LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function);
1088
  return AssignEnvironment(DefineSameAsFirst(result));
1089
}
1090

    
1091

    
1092
LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
1093
  LOperand* function = UseFixed(instr->function(), a1);
1094
  LOperand* receiver = UseFixed(instr->receiver(), a0);
1095
  LOperand* length = UseFixed(instr->length(), a2);
1096
  LOperand* elements = UseFixed(instr->elements(), a3);
1097
  LApplyArguments* result = new(zone()) LApplyArguments(function,
1098
                                                        receiver,
1099
                                                        length,
1100
                                                        elements);
1101
  return MarkAsCall(DefineFixed(result, v0), instr, CAN_DEOPTIMIZE_EAGERLY);
1102
}
1103

    
1104

    
1105
LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
1106
  LOperand* argument = Use(instr->argument());
1107
  return new(zone()) LPushArgument(argument);
1108
}
1109

    
1110

    
1111
LInstruction* LChunkBuilder::DoStoreCodeEntry(
1112
    HStoreCodeEntry* store_code_entry) {
1113
  LOperand* function = UseRegister(store_code_entry->function());
1114
  LOperand* code_object = UseTempRegister(store_code_entry->code_object());
1115
  return new(zone()) LStoreCodeEntry(function, code_object);
1116
}
1117

    
1118

    
1119
LInstruction* LChunkBuilder::DoInnerAllocatedObject(
1120
    HInnerAllocatedObject* inner_object) {
1121
  LOperand* base_object = UseRegisterAtStart(inner_object->base_object());
1122
  LInnerAllocatedObject* result =
1123
    new(zone()) LInnerAllocatedObject(base_object);
1124
  return DefineAsRegister(result);
1125
}
1126

    
1127

    
1128
LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
1129
  return instr->HasNoUses()
1130
      ? NULL
1131
      : DefineAsRegister(new(zone()) LThisFunction);
1132
}
1133

    
1134

    
1135
LInstruction* LChunkBuilder::DoContext(HContext* instr) {
1136
  if (instr->HasNoUses()) return NULL;
1137

    
1138
  if (info()->IsStub()) {
1139
    return DefineFixed(new(zone()) LContext, cp);
1140
  }
1141

    
1142
  return DefineAsRegister(new(zone()) LContext);
1143
}
1144

    
1145

    
1146
LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
1147
  LOperand* context = UseRegisterAtStart(instr->value());
1148
  return DefineAsRegister(new(zone()) LOuterContext(context));
1149
}
1150

    
1151

    
1152
LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
1153
  LOperand* context = UseFixed(instr->context(), cp);
1154
  return MarkAsCall(new(zone()) LDeclareGlobals(context), instr);
1155
}
1156

    
1157

    
1158
LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
1159
  LOperand* context = UseRegisterAtStart(instr->value());
1160
  return DefineAsRegister(new(zone()) LGlobalObject(context));
1161
}
1162

    
1163

    
1164
LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
1165
  LOperand* global_object = UseRegisterAtStart(instr->value());
1166
  return DefineAsRegister(new(zone()) LGlobalReceiver(global_object));
1167
}
1168

    
1169

    
1170
LInstruction* LChunkBuilder::DoCallConstantFunction(
1171
    HCallConstantFunction* instr) {
1172
  return MarkAsCall(DefineFixed(new(zone()) LCallConstantFunction, v0), instr);
1173
}
1174

    
1175

    
1176
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
1177
  LOperand* context = UseFixed(instr->context(), cp);
1178
  LOperand* function = UseFixed(instr->function(), a1);
1179
  LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
1180
  return MarkAsCall(DefineFixed(result, v0), instr, CANNOT_DEOPTIMIZE_EAGERLY);
1181
}
1182

    
1183

    
1184
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1185
  switch (instr->op()) {
1186
    case kMathFloor: return DoMathFloor(instr);
1187
    case kMathRound: return DoMathRound(instr);
1188
    case kMathAbs: return DoMathAbs(instr);
1189
    case kMathLog: return DoMathLog(instr);
1190
    case kMathSin: return DoMathSin(instr);
1191
    case kMathCos: return DoMathCos(instr);
1192
    case kMathTan: return DoMathTan(instr);
1193
    case kMathExp: return DoMathExp(instr);
1194
    case kMathSqrt: return DoMathSqrt(instr);
1195
    case kMathPowHalf: return DoMathPowHalf(instr);
1196
    default:
1197
      UNREACHABLE();
1198
      return NULL;
1199
  }
1200
}
1201

    
1202

    
1203
LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
1204
  LOperand* input = UseFixedDouble(instr->value(), f4);
1205
  LMathLog* result = new(zone()) LMathLog(input);
1206
  return MarkAsCall(DefineFixedDouble(result, f4), instr);
1207
}
1208

    
1209

    
1210
LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
1211
  LOperand* input = UseFixedDouble(instr->value(), f4);
1212
  LMathSin* result = new(zone()) LMathSin(input);
1213
  return MarkAsCall(DefineFixedDouble(result, f4), instr);
1214
}
1215

    
1216

    
1217
LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
1218
  LOperand* input = UseFixedDouble(instr->value(), f4);
1219
  LMathCos* result = new(zone()) LMathCos(input);
1220
  return MarkAsCall(DefineFixedDouble(result, f4), instr);
1221
}
1222

    
1223

    
1224
LInstruction* LChunkBuilder::DoMathTan(HUnaryMathOperation* instr) {
1225
  LOperand* input = UseFixedDouble(instr->value(), f4);
1226
  LMathTan* result = new(zone()) LMathTan(input);
1227
  return MarkAsCall(DefineFixedDouble(result, f4), instr);
1228
}
1229

    
1230

    
1231
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
1232
  ASSERT(instr->representation().IsDouble());
1233
  ASSERT(instr->value()->representation().IsDouble());
1234
  LOperand* input = UseRegister(instr->value());
1235
  LOperand* temp1 = TempRegister();
1236
  LOperand* temp2 = TempRegister();
1237
  LOperand* double_temp = FixedTemp(f6);  // Chosen by fair dice roll.
1238
  LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2);
1239
  return DefineAsRegister(result);
1240
}
1241

    
1242

    
1243
LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
1244
  // Input cannot be the same as the result, see LCodeGen::DoMathPowHalf.
1245
  LOperand* input = UseFixedDouble(instr->value(), f8);
1246
  LOperand* temp = FixedTemp(f6);
1247
  LMathPowHalf* result = new(zone()) LMathPowHalf(input, temp);
1248
  return DefineFixedDouble(result, f4);
1249
}
1250

    
1251

    
1252
LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
1253
  Representation r = instr->value()->representation();
1254
  LOperand* context = (r.IsDouble() || r.IsSmiOrInteger32())
1255
      ? NULL
1256
      : UseFixed(instr->context(), cp);
1257
  LOperand* input = UseRegister(instr->value());
1258
  LMathAbs* result = new(zone()) LMathAbs(context, input);
1259
  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1260
}
1261

    
1262

    
1263
LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
1264
  LOperand* input = UseRegister(instr->value());
1265
  LOperand* temp = TempRegister();
1266
  LMathFloor* result = new(zone()) LMathFloor(input, temp);
1267
  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1268
}
1269

    
1270

    
1271
LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
1272
  LOperand* input = UseRegister(instr->value());
1273
  LMathSqrt* result = new(zone()) LMathSqrt(input);
1274
  return DefineAsRegister(result);
1275
}
1276

    
1277

    
1278
LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
1279
  LOperand* input = UseRegister(instr->value());
1280
  LOperand* temp = FixedTemp(f6);
1281
  LMathRound* result = new(zone()) LMathRound(input, temp);
1282
  return AssignEnvironment(DefineAsRegister(result));
1283
}
1284

    
1285

    
1286
LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
1287
  ASSERT(instr->key()->representation().IsTagged());
1288
  LOperand* context = UseFixed(instr->context(), cp);
1289
  LOperand* key = UseFixed(instr->key(), a2);
1290
  return MarkAsCall(
1291
        DefineFixed(new(zone()) LCallKeyed(context, key), v0), instr);
1292
}
1293

    
1294

    
1295
LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
1296
  LOperand* context = UseFixed(instr->context(), cp);
1297
  return MarkAsCall(DefineFixed(new(zone()) LCallNamed(context), v0), instr);
1298
}
1299

    
1300

    
1301
LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
1302
  LOperand* context = UseFixed(instr->context(), cp);
1303
  return MarkAsCall(DefineFixed(new(zone()) LCallGlobal(context), v0), instr);
1304
}
1305

    
1306

    
1307
LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
1308
  return MarkAsCall(DefineFixed(new(zone()) LCallKnownGlobal, v0), instr);
1309
}
1310

    
1311

    
1312
LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
1313
  LOperand* context = UseFixed(instr->context(), cp);
1314
  LOperand* constructor = UseFixed(instr->constructor(), a1);
1315
  LCallNew* result = new(zone()) LCallNew(context, constructor);
1316
  return MarkAsCall(DefineFixed(result, v0), instr);
1317
}
1318

    
1319

    
1320
LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
1321
  LOperand* context = UseFixed(instr->context(), cp);
1322
  LOperand* constructor = UseFixed(instr->constructor(), a1);
1323
  LCallNewArray* result = new(zone()) LCallNewArray(context, constructor);
1324
  return MarkAsCall(DefineFixed(result, v0), instr);
1325
}
1326

    
1327

    
1328
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1329
  LOperand* context = UseFixed(instr->context(), cp);
1330
  LOperand* function = UseFixed(instr->function(), a1);
1331
  return MarkAsCall(
1332
      DefineFixed(new(zone()) LCallFunction(context, function), v0), instr);
1333
}
1334

    
1335

    
1336
LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1337
  LOperand* context = UseFixed(instr->context(), cp);
1338
  return MarkAsCall(DefineFixed(new(zone()) LCallRuntime(context), v0), instr);
1339
}
1340

    
1341

    
1342
LInstruction* LChunkBuilder::DoRor(HRor* instr) {
1343
  return DoShift(Token::ROR, instr);
1344
}
1345

    
1346

    
1347
LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1348
  return DoShift(Token::SHR, instr);
1349
}
1350

    
1351

    
1352
LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1353
  return DoShift(Token::SAR, instr);
1354
}
1355

    
1356

    
1357
LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1358
  return DoShift(Token::SHL, instr);
1359
}
1360

    
1361

    
1362
LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
1363
  if (instr->representation().IsSmiOrInteger32()) {
1364
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1365
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1366
    ASSERT(instr->CheckFlag(HValue::kTruncatingToInt32));
1367

    
1368
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1369
    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1370
    return DefineAsRegister(new(zone()) LBitI(left, right));
1371
  } else {
1372
    return DoArithmeticT(instr->op(), instr);
1373
  }
1374
}
1375

    
1376

    
1377
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1378
  if (instr->representation().IsSmiOrInteger32()) {
1379
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1380
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1381
    LOperand* dividend = UseRegister(instr->left());
1382
    LOperand* divisor = UseRegister(instr->right());
1383
    LDivI* div = new(zone()) LDivI(dividend, divisor);
1384
    return AssignEnvironment(DefineAsRegister(div));
1385
  } else if (instr->representation().IsDouble()) {
1386
    return DoArithmeticD(Token::DIV, instr);
1387
  } else {
1388
    return DoArithmeticT(Token::DIV, instr);
1389
  }
1390
}
1391

    
1392

    
1393
bool LChunkBuilder::HasMagicNumberForDivisor(int32_t divisor) {
1394
  uint32_t divisor_abs = abs(divisor);
1395
  // Dividing by 0, 1, and powers of 2 is easy.
1396
  // Note that IsPowerOf2(0) returns true;
1397
  ASSERT(IsPowerOf2(0) == true);
1398
  if (IsPowerOf2(divisor_abs)) return true;
1399

    
1400
  // We have magic numbers for a few specific divisors.
1401
  // Details and proofs can be found in:
1402
  // - Hacker's Delight, Henry S. Warren, Jr.
1403
  // - The PowerPC Compiler Writer's Guide
1404
  // and probably many others.
1405
  //
1406
  // We handle
1407
  //   <divisor with magic numbers> * <power of 2>
1408
  // but not
1409
  //   <divisor with magic numbers> * <other divisor with magic numbers>
1410
  int32_t power_of_2_factor =
1411
    CompilerIntrinsics::CountTrailingZeros(divisor_abs);
1412
  DivMagicNumbers magic_numbers =
1413
    DivMagicNumberFor(divisor_abs >> power_of_2_factor);
1414
  if (magic_numbers.M != InvalidDivMagicNumber.M) return true;
1415

    
1416
  return false;
1417
}
1418

    
1419

    
1420
HValue* LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(HValue* divisor) {
1421
  // Only optimize when we have magic numbers for the divisor.
1422
  // The standard integer division routine is usually slower than transitionning
1423
  // to FPU.
1424
  if (divisor->IsConstant() &&
1425
      HConstant::cast(divisor)->HasInteger32Value()) {
1426
    HConstant* constant_val = HConstant::cast(divisor);
1427
    return constant_val->CopyToRepresentation(Representation::Integer32(),
1428
                                                divisor->block()->zone());
1429
  }
1430
  return NULL;
1431
}
1432

    
1433

    
1434
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
1435
    HValue* right = instr->right();
1436
    LOperand* dividend = UseRegister(instr->left());
1437
    LOperand* divisor = UseRegisterOrConstant(right);
1438
    LOperand* remainder = TempRegister();
1439
    return AssignEnvironment(DefineAsRegister(
1440
          new(zone()) LMathFloorOfDiv(dividend, divisor, remainder)));
1441
}
1442

    
1443

    
1444
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1445
  HValue* left = instr->left();
1446
  HValue* right = instr->right();
1447
  if (instr->representation().IsSmiOrInteger32()) {
1448
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1449
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1450
    if (instr->HasPowerOf2Divisor()) {
1451
      ASSERT(!right->CanBeZero());
1452
      LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
1453
                                     UseOrConstant(right));
1454
      LInstruction* result = DefineAsRegister(mod);
1455
      return (left->CanBeNegative() &&
1456
              instr->CheckFlag(HValue::kBailoutOnMinusZero))
1457
          ? AssignEnvironment(result)
1458
          : result;
1459
    } else if (instr->fixed_right_arg().has_value) {
1460
      LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
1461
                                     UseRegisterAtStart(right));
1462
      return AssignEnvironment(DefineAsRegister(mod));
1463
    } else {
1464
      LModI* mod = new(zone()) LModI(UseRegister(left),
1465
                                     UseRegister(right),
1466
                                     TempRegister(),
1467
                                     FixedTemp(f20),
1468
                                     FixedTemp(f22));
1469
      LInstruction* result = DefineAsRegister(mod);
1470
      return (right->CanBeZero() ||
1471
              (left->RangeCanInclude(kMinInt) &&
1472
               right->RangeCanInclude(-1)) ||
1473
              instr->CheckFlag(HValue::kBailoutOnMinusZero))
1474
          ? AssignEnvironment(result)
1475
          : result;
1476
    }
1477
  } else if (instr->representation().IsDouble()) {
1478
    return DoArithmeticD(Token::MOD, instr);
1479
  } else {
1480
    return DoArithmeticT(Token::MOD, instr);
1481
  }
1482
}
1483

    
1484

    
1485
LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1486
  if (instr->representation().IsSmiOrInteger32()) {
1487
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1488
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1489
    HValue* left = instr->BetterLeftOperand();
1490
    HValue* right = instr->BetterRightOperand();
1491
    LOperand* left_op;
1492
    LOperand* right_op;
1493
    bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
1494
    bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero);
1495

    
1496
    if (right->IsConstant()) {
1497
      HConstant* constant = HConstant::cast(right);
1498
      int32_t constant_value = constant->Integer32Value();
1499
      // Constants -1, 0 and 1 can be optimized if the result can overflow.
1500
      // For other constants, it can be optimized only without overflow.
1501
      if (!can_overflow || ((constant_value >= -1) && (constant_value <= 1))) {
1502
        left_op = UseRegisterAtStart(left);
1503
        right_op = UseConstant(right);
1504
      } else {
1505
        if (bailout_on_minus_zero) {
1506
          left_op = UseRegister(left);
1507
        } else {
1508
          left_op = UseRegisterAtStart(left);
1509
        }
1510
        right_op = UseRegister(right);
1511
      }
1512
    } else {
1513
      if (bailout_on_minus_zero) {
1514
        left_op = UseRegister(left);
1515
      } else {
1516
        left_op = UseRegisterAtStart(left);
1517
      }
1518
      right_op = UseRegister(right);
1519
    }
1520
    LMulI* mul = new(zone()) LMulI(left_op, right_op);
1521
    if (can_overflow || bailout_on_minus_zero) {
1522
      AssignEnvironment(mul);
1523
    }
1524
    return DefineAsRegister(mul);
1525

    
1526
  } else if (instr->representation().IsDouble()) {
1527
    if (kArchVariant == kMips32r2) {
1528
      if (instr->UseCount() == 1 && instr->uses().value()->IsAdd()) {
1529
        HAdd* add = HAdd::cast(instr->uses().value());
1530
        if (instr == add->left()) {
1531
          // This mul is the lhs of an add. The add and mul will be folded
1532
          // into a multiply-add.
1533
          return NULL;
1534
        }
1535
        if (instr == add->right() && !add->left()->IsMul()) {
1536
          // This mul is the rhs of an add, where the lhs is not another mul.
1537
          // The add and mul will be folded into a multiply-add.
1538
          return NULL;
1539
        }
1540
      }
1541
    }
1542
    return DoArithmeticD(Token::MUL, instr);
1543
  } else {
1544
    return DoArithmeticT(Token::MUL, instr);
1545
  }
1546
}
1547

    
1548

    
1549
LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1550
  if (instr->representation().IsSmiOrInteger32()) {
1551
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1552
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1553
    LOperand* left = UseRegisterAtStart(instr->left());
1554
    LOperand* right = UseOrConstantAtStart(instr->right());
1555
    LSubI* sub = new(zone()) LSubI(left, right);
1556
    LInstruction* result = DefineAsRegister(sub);
1557
    if (instr->CheckFlag(HValue::kCanOverflow)) {
1558
      result = AssignEnvironment(result);
1559
    }
1560
    return result;
1561
  } else if (instr->representation().IsDouble()) {
1562
    return DoArithmeticD(Token::SUB, instr);
1563
  } else {
1564
    return DoArithmeticT(Token::SUB, instr);
1565
  }
1566
}
1567

    
1568

    
1569
LInstruction* LChunkBuilder::DoMultiplyAdd(HMul* mul, HValue* addend) {
1570
  LOperand* multiplier_op = UseRegisterAtStart(mul->left());
1571
  LOperand* multiplicand_op = UseRegisterAtStart(mul->right());
1572
  LOperand* addend_op = UseRegisterAtStart(addend);
1573
  return DefineSameAsFirst(new(zone()) LMultiplyAddD(addend_op, multiplier_op,
1574
                                                     multiplicand_op));
1575
}
1576

    
1577

    
1578
LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1579
  if (instr->representation().IsSmiOrInteger32()) {
1580
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1581
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1582
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1583
    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1584
    LAddI* add = new(zone()) LAddI(left, right);
1585
    LInstruction* result = DefineAsRegister(add);
1586
    if (instr->CheckFlag(HValue::kCanOverflow)) {
1587
      result = AssignEnvironment(result);
1588
    }
1589
    return result;
1590
  } else if (instr->representation().IsDouble()) {
1591
    if (kArchVariant == kMips32r2) {
1592
      if (instr->left()->IsMul())
1593
        return DoMultiplyAdd(HMul::cast(instr->left()), instr->right());
1594

    
1595
      if (instr->right()->IsMul()) {
1596
        ASSERT(!instr->left()->IsMul());
1597
        return DoMultiplyAdd(HMul::cast(instr->right()), instr->left());
1598
      }
1599
    }
1600
    return DoArithmeticD(Token::ADD, instr);
1601
  } else {
1602
    return DoArithmeticT(Token::ADD, instr);
1603
  }
1604
}
1605

    
1606

    
1607
LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
1608
  LOperand* left = NULL;
1609
  LOperand* right = NULL;
1610
  if (instr->representation().IsSmiOrInteger32()) {
1611
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1612
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1613
    left = UseRegisterAtStart(instr->BetterLeftOperand());
1614
    right = UseOrConstantAtStart(instr->BetterRightOperand());
1615
  } else {
1616
    ASSERT(instr->representation().IsDouble());
1617
    ASSERT(instr->left()->representation().IsDouble());
1618
    ASSERT(instr->right()->representation().IsDouble());
1619
    left = UseRegisterAtStart(instr->left());
1620
    right = UseRegisterAtStart(instr->right());
1621
  }
1622
  return DefineAsRegister(new(zone()) LMathMinMax(left, right));
1623
}
1624

    
1625

    
1626
LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1627
  ASSERT(instr->representation().IsDouble());
1628
  // We call a C function for double power. It can't trigger a GC.
1629
  // We need to use fixed result register for the call.
1630
  Representation exponent_type = instr->right()->representation();
1631
  ASSERT(instr->left()->representation().IsDouble());
1632
  LOperand* left = UseFixedDouble(instr->left(), f2);
1633
  LOperand* right = exponent_type.IsDouble() ?
1634
      UseFixedDouble(instr->right(), f4) :
1635
      UseFixed(instr->right(), a2);
1636
  LPower* result = new(zone()) LPower(left, right);
1637
  return MarkAsCall(DefineFixedDouble(result, f0),
1638
                    instr,
1639
                    CAN_DEOPTIMIZE_EAGERLY);
1640
}
1641

    
1642

    
1643
LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
1644
  ASSERT(instr->representation().IsDouble());
1645
  ASSERT(instr->global_object()->representation().IsTagged());
1646
  LOperand* global_object = UseTempRegister(instr->global_object());
1647
  LOperand* scratch = TempRegister();
1648
  LOperand* scratch2 = TempRegister();
1649
  LOperand* scratch3 = TempRegister();
1650
  LRandom* result = new(zone()) LRandom(
1651
      global_object, scratch, scratch2, scratch3);
1652
  return DefineFixedDouble(result, f0);
1653
}
1654

    
1655

    
1656
LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1657
  ASSERT(instr->left()->representation().IsTagged());
1658
  ASSERT(instr->right()->representation().IsTagged());
1659
  LOperand* context = UseFixed(instr->context(), cp);
1660
  LOperand* left = UseFixed(instr->left(), a1);
1661
  LOperand* right = UseFixed(instr->right(), a0);
1662
  LCmpT* result = new(zone()) LCmpT(context, left, right);
1663
  return MarkAsCall(DefineFixed(result, v0), instr);
1664
}
1665

    
1666

    
1667
LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
1668
    HCompareNumericAndBranch* instr) {
1669
  Representation r = instr->representation();
1670
  if (r.IsSmiOrInteger32()) {
1671
    ASSERT(instr->left()->representation().Equals(r));
1672
    ASSERT(instr->right()->representation().Equals(r));
1673
    LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1674
    LOperand* right = UseRegisterOrConstantAtStart(instr->right());
1675
    return new(zone()) LCompareNumericAndBranch(left, right);
1676
  } else {
1677
    ASSERT(r.IsDouble());
1678
    ASSERT(instr->left()->representation().IsDouble());
1679
    ASSERT(instr->right()->representation().IsDouble());
1680
    LOperand* left = UseRegisterAtStart(instr->left());
1681
    LOperand* right = UseRegisterAtStart(instr->right());
1682
    return new(zone()) LCompareNumericAndBranch(left, right);
1683
  }
1684
}
1685

    
1686

    
1687
LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
1688
    HCompareObjectEqAndBranch* instr) {
1689
  LInstruction* goto_instr = CheckElideControlInstruction(instr);
1690
  if (goto_instr != NULL) return goto_instr;
1691
  LOperand* left = UseRegisterAtStart(instr->left());
1692
  LOperand* right = UseRegisterAtStart(instr->right());
1693
  return new(zone()) LCmpObjectEqAndBranch(left, right);
1694
}
1695

    
1696

    
1697
LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
1698
    HCompareHoleAndBranch* instr) {
1699
  LOperand* value = UseRegisterAtStart(instr->value());
1700
  return new(zone()) LCmpHoleAndBranch(value);
1701
}
1702

    
1703

    
1704
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
1705
  ASSERT(instr->value()->representation().IsTagged());
1706
  LOperand* temp = TempRegister();
1707
  return new(zone()) LIsObjectAndBranch(UseRegisterAtStart(instr->value()),
1708
                                        temp);
1709
}
1710

    
1711

    
1712
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1713
  ASSERT(instr->value()->representation().IsTagged());
1714
  LOperand* temp = TempRegister();
1715
  return new(zone()) LIsStringAndBranch(UseRegisterAtStart(instr->value()),
1716
                                        temp);
1717
}
1718

    
1719

    
1720
LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1721
  ASSERT(instr->value()->representation().IsTagged());
1722
  return new(zone()) LIsSmiAndBranch(Use(instr->value()));
1723
}
1724

    
1725

    
1726
LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1727
    HIsUndetectableAndBranch* instr) {
1728
  ASSERT(instr->value()->representation().IsTagged());
1729
  return new(zone()) LIsUndetectableAndBranch(
1730
      UseRegisterAtStart(instr->value()), TempRegister());
1731
}
1732

    
1733

    
1734
LInstruction* LChunkBuilder::DoStringCompareAndBranch(
1735
    HStringCompareAndBranch* instr) {
1736
  ASSERT(instr->left()->representation().IsTagged());
1737
  ASSERT(instr->right()->representation().IsTagged());
1738
  LOperand* context = UseFixed(instr->context(), cp);
1739
  LOperand* left = UseFixed(instr->left(), a1);
1740
  LOperand* right = UseFixed(instr->right(), a0);
1741
  LStringCompareAndBranch* result =
1742
      new(zone()) LStringCompareAndBranch(context, left, right);
1743
  return MarkAsCall(result, instr);
1744
}
1745

    
1746

    
1747
LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1748
    HHasInstanceTypeAndBranch* instr) {
1749
  ASSERT(instr->value()->representation().IsTagged());
1750
  LOperand* value = UseRegisterAtStart(instr->value());
1751
  return new(zone()) LHasInstanceTypeAndBranch(value);
1752
}
1753

    
1754

    
1755
LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
1756
    HGetCachedArrayIndex* instr)  {
1757
  ASSERT(instr->value()->representation().IsTagged());
1758
  LOperand* value = UseRegisterAtStart(instr->value());
1759

    
1760
  return DefineAsRegister(new(zone()) LGetCachedArrayIndex(value));
1761
}
1762

    
1763

    
1764
LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
1765
    HHasCachedArrayIndexAndBranch* instr) {
1766
  ASSERT(instr->value()->representation().IsTagged());
1767
  return new(zone()) LHasCachedArrayIndexAndBranch(
1768
      UseRegisterAtStart(instr->value()));
1769
}
1770

    
1771

    
1772
LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1773
    HClassOfTestAndBranch* instr) {
1774
  ASSERT(instr->value()->representation().IsTagged());
1775
  return new(zone()) LClassOfTestAndBranch(UseRegister(instr->value()),
1776
                                           TempRegister());
1777
}
1778

    
1779

    
1780
LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) {
1781
  LOperand* map = UseRegisterAtStart(instr->value());
1782
  return DefineAsRegister(new(zone()) LMapEnumLength(map));
1783
}
1784

    
1785

    
1786
LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
1787
  LOperand* object = UseRegisterAtStart(instr->value());
1788
  return DefineAsRegister(new(zone()) LElementsKind(object));
1789
}
1790

    
1791

    
1792
LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
1793
  LOperand* object = UseRegister(instr->value());
1794
  LValueOf* result = new(zone()) LValueOf(object, TempRegister());
1795
  return DefineAsRegister(result);
1796
}
1797

    
1798

    
1799
LInstruction* LChunkBuilder::DoDateField(HDateField* instr) {
1800
  LOperand* object = UseFixed(instr->value(), a0);
1801
  LDateField* result =
1802
      new(zone()) LDateField(object, FixedTemp(a1), instr->index());
1803
  return MarkAsCall(DefineFixed(result, v0), instr, CAN_DEOPTIMIZE_EAGERLY);
1804
}
1805

    
1806

    
1807
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
1808
  LOperand* string = UseRegister(instr->string());
1809
  LOperand* index = UseRegisterOrConstant(instr->index());
1810
  LOperand* value = UseRegister(instr->value());
1811
  return new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
1812
}
1813

    
1814

    
1815
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1816
  LOperand* value = UseRegisterOrConstantAtStart(instr->index());
1817
  LOperand* length = UseRegister(instr->length());
1818
  return AssignEnvironment(new(zone()) LBoundsCheck(value, length));
1819
}
1820

    
1821

    
1822
LInstruction* LChunkBuilder::DoBoundsCheckBaseIndexInformation(
1823
    HBoundsCheckBaseIndexInformation* instr) {
1824
  UNREACHABLE();
1825
  return NULL;
1826
}
1827

    
1828

    
1829
LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1830
  // The control instruction marking the end of a block that completed
1831
  // abruptly (e.g., threw an exception).  There is nothing specific to do.
1832
  return NULL;
1833
}
1834

    
1835

    
1836
LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
1837
  LOperand* context = UseFixed(instr->context(), cp);
1838
  LOperand* value = UseFixed(instr->value(), a0);
1839
  return MarkAsCall(new(zone()) LThrow(context, value), instr);
1840
}
1841

    
1842

    
1843
LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) {
1844
  return NULL;
1845
}
1846

    
1847

    
1848
LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
1849
  // All HForceRepresentation instructions should be eliminated in the
1850
  // representation change phase of Hydrogen.
1851
  UNREACHABLE();
1852
  return NULL;
1853
}
1854

    
1855

    
1856
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1857
  Representation from = instr->from();
1858
  Representation to = instr->to();
1859
  if (from.IsSmi()) {
1860
    if (to.IsTagged()) {
1861
      LOperand* value = UseRegister(instr->value());
1862
      return DefineSameAsFirst(new(zone()) LDummyUse(value));
1863
    }
1864
    from = Representation::Tagged();
1865
  }
1866
  if (from.IsTagged()) {
1867
    if (to.IsDouble()) {
1868
      LOperand* value = UseRegister(instr->value());
1869
      LNumberUntagD* res = new(zone()) LNumberUntagD(value);
1870
      return AssignEnvironment(DefineAsRegister(res));
1871
    } else if (to.IsSmi()) {
1872
      HValue* val = instr->value();
1873
      LOperand* value = UseRegister(val);
1874
      if (val->type().IsSmi()) {
1875
        return DefineSameAsFirst(new(zone()) LDummyUse(value));
1876
      }
1877
      return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
1878
    } else {
1879
      ASSERT(to.IsInteger32());
1880
      LOperand* value = NULL;
1881
      LInstruction* res = NULL;
1882
      HValue* val = instr->value();
1883
      if (val->type().IsSmi() || val->representation().IsSmi()) {
1884
        value = UseRegisterAtStart(val);
1885
        res = DefineAsRegister(new(zone()) LSmiUntag(value, false));
1886
      } else {
1887
        value = UseRegister(val);
1888
        LOperand* temp1 = TempRegister();
1889
        LOperand* temp2 = FixedTemp(f22);
1890
        res = DefineSameAsFirst(new(zone()) LTaggedToI(value,
1891
                                                       temp1,
1892
                                                       temp2));
1893
        res = AssignEnvironment(res);
1894
      }
1895
      return res;
1896
    }
1897
  } else if (from.IsDouble()) {
1898
    if (to.IsTagged()) {
1899
      info()->MarkAsDeferredCalling();
1900
      LOperand* value = UseRegister(instr->value());
1901
      LOperand* temp1 = TempRegister();
1902
      LOperand* temp2 = TempRegister();
1903

    
1904
      // Make sure that the temp and result_temp registers are
1905
      // different.
1906
      LUnallocated* result_temp = TempRegister();
1907
      LNumberTagD* result = new(zone()) LNumberTagD(value, temp1, temp2);
1908
      Define(result, result_temp);
1909
      return AssignPointerMap(result);
1910
    } else if (to.IsSmi()) {
1911
      LOperand* value = UseRegister(instr->value());
1912
      return AssignEnvironment(
1913
          DefineAsRegister(new(zone()) LDoubleToSmi(value)));
1914
    } else {
1915
      ASSERT(to.IsInteger32());
1916
      LOperand* value = UseRegister(instr->value());
1917
      LDoubleToI* res = new(zone()) LDoubleToI(value);
1918
      return AssignEnvironment(DefineAsRegister(res));
1919
    }
1920
  } else if (from.IsInteger32()) {
1921
    info()->MarkAsDeferredCalling();
1922
    if (to.IsTagged()) {
1923
      HValue* val = instr->value();
1924
      LOperand* value = UseRegisterAtStart(val);
1925
      if (val->CheckFlag(HInstruction::kUint32)) {
1926
        LNumberTagU* result = new(zone()) LNumberTagU(value);
1927
        return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1928
      } else if (val->HasRange() && val->range()->IsInSmiRange()) {
1929
        return DefineAsRegister(new(zone()) LSmiTag(value));
1930
      } else {
1931
        LNumberTagI* result = new(zone()) LNumberTagI(value);
1932
        return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1933
      }
1934
    } else if (to.IsSmi()) {
1935
      HValue* val = instr->value();
1936
      LOperand* value = UseRegister(val);
1937
      LInstruction* result =
1938
          DefineSameAsFirst(new(zone()) LInteger32ToSmi(value));
1939
      if (val->HasRange() && val->range()->IsInSmiRange()) {
1940
        return result;
1941
      }
1942
      return AssignEnvironment(result);
1943
    } else {
1944
      ASSERT(to.IsDouble());
1945
      if (instr->value()->CheckFlag(HInstruction::kUint32)) {
1946
        return DefineAsRegister(
1947
            new(zone()) LUint32ToDouble(UseRegister(instr->value())));
1948
      } else {
1949
        return DefineAsRegister(
1950
            new(zone()) LInteger32ToDouble(Use(instr->value())));
1951
      }
1952
    }
1953
  }
1954
  UNREACHABLE();
1955
  return NULL;
1956
}
1957

    
1958

    
1959
LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
1960
  LOperand* value = UseRegisterAtStart(instr->value());
1961
  return AssignEnvironment(new(zone()) LCheckNonSmi(value));
1962
}
1963

    
1964

    
1965
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1966
  LOperand* value = UseRegisterAtStart(instr->value());
1967
  return AssignEnvironment(new(zone()) LCheckSmi(value));
1968
}
1969

    
1970

    
1971
LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1972
  LOperand* value = UseRegisterAtStart(instr->value());
1973
  LInstruction* result = new(zone()) LCheckInstanceType(value);
1974
  return AssignEnvironment(result);
1975
}
1976

    
1977

    
1978
LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
1979
  LOperand* value = UseRegisterAtStart(instr->value());
1980
  return AssignEnvironment(new(zone()) LCheckValue(value));
1981
}
1982

    
1983

    
1984
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
1985
  LOperand* value = NULL;
1986
  if (!instr->CanOmitMapChecks()) {
1987
    value = UseRegisterAtStart(instr->value());
1988
    if (instr->has_migration_target()) info()->MarkAsDeferredCalling();
1989
  }
1990
  LCheckMaps* result = new(zone()) LCheckMaps(value);
1991
  if (!instr->CanOmitMapChecks()) {
1992
    AssignEnvironment(result);
1993
    if (instr->has_migration_target()) return AssignPointerMap(result);
1994
  }
1995
  return result;
1996
}
1997

    
1998

    
1999
LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
2000
  HValue* value = instr->value();
2001
  Representation input_rep = value->representation();
2002
  LOperand* reg = UseRegister(value);
2003
  if (input_rep.IsDouble()) {
2004
    // Revisit this decision, here and 8 lines below.
2005
    return DefineAsRegister(new(zone()) LClampDToUint8(reg, FixedTemp(f22)));
2006
  } else if (input_rep.IsInteger32()) {
2007
    return DefineAsRegister(new(zone()) LClampIToUint8(reg));
2008
  } else {
2009
    ASSERT(input_rep.IsSmiOrTagged());
2010
    // Register allocator doesn't (yet) support allocation of double
2011
    // temps. Reserve f22 explicitly.
2012
    LClampTToUint8* result = new(zone()) LClampTToUint8(reg, FixedTemp(f22));
2013
    return AssignEnvironment(DefineAsRegister(result));
2014
  }
2015
}
2016

    
2017

    
2018
LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
2019
  LOperand* context = info()->IsStub()
2020
      ? UseFixed(instr->context(), cp)
2021
      : NULL;
2022
  LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
2023
  return new(zone()) LReturn(UseFixed(instr->value(), v0), context,
2024
                             parameter_count);
2025
}
2026

    
2027

    
2028
LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
2029
  Representation r = instr->representation();
2030
  if (r.IsSmi()) {
2031
    return DefineAsRegister(new(zone()) LConstantS);
2032
  } else if (r.IsInteger32()) {
2033
    return DefineAsRegister(new(zone()) LConstantI);
2034
  } else if (r.IsDouble()) {
2035
    return DefineAsRegister(new(zone()) LConstantD);
2036
  } else if (r.IsExternal()) {
2037
    return DefineAsRegister(new(zone()) LConstantE);
2038
  } else if (r.IsTagged()) {
2039
    return DefineAsRegister(new(zone()) LConstantT);
2040
  } else {
2041
    UNREACHABLE();
2042
    return NULL;
2043
  }
2044
}
2045

    
2046

    
2047
LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
2048
  LLoadGlobalCell* result = new(zone()) LLoadGlobalCell;
2049
  return instr->RequiresHoleCheck()
2050
      ? AssignEnvironment(DefineAsRegister(result))
2051
      : DefineAsRegister(result);
2052
}
2053

    
2054

    
2055
LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
2056
  LOperand* context = UseFixed(instr->context(), cp);
2057
  LOperand* global_object = UseFixed(instr->global_object(), a0);
2058
  LLoadGlobalGeneric* result =
2059
      new(zone()) LLoadGlobalGeneric(context, global_object);
2060
  return MarkAsCall(DefineFixed(result, v0), instr);
2061
}
2062

    
2063

    
2064
LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
2065
  LOperand* value = UseRegister(instr->value());
2066
  // Use a temp to check the value in the cell in the case where we perform
2067
  // a hole check.
2068
  return instr->RequiresHoleCheck()
2069
      ? AssignEnvironment(new(zone()) LStoreGlobalCell(value, TempRegister()))
2070
      : new(zone()) LStoreGlobalCell(value, NULL);
2071
}
2072

    
2073

    
2074
LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
2075
  LOperand* context = UseFixed(instr->context(), cp);
2076
  LOperand* global_object = UseFixed(instr->global_object(), a1);
2077
  LOperand* value = UseFixed(instr->value(), a0);
2078
  LStoreGlobalGeneric* result =
2079
      new(zone()) LStoreGlobalGeneric(context, global_object, value);
2080
  return MarkAsCall(result, instr);
2081
}
2082

    
2083

    
2084
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
2085
  LOperand* context = UseRegisterAtStart(instr->value());
2086
  LInstruction* result =
2087
      DefineAsRegister(new(zone()) LLoadContextSlot(context));
2088
  return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
2089
}
2090

    
2091

    
2092
LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
2093
  LOperand* context;
2094
  LOperand* value;
2095
  if (instr->NeedsWriteBarrier()) {
2096
    context = UseTempRegister(instr->context());
2097
    value = UseTempRegister(instr->value());
2098
  } else {
2099
    context = UseRegister(instr->context());
2100
    value = UseRegister(instr->value());
2101
  }
2102
  LInstruction* result = new(zone()) LStoreContextSlot(context, value);
2103
  return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
2104
}
2105

    
2106

    
2107
LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
2108
  LOperand* obj = UseRegisterAtStart(instr->object());
2109
  return DefineAsRegister(new(zone()) LLoadNamedField(obj));
2110
}
2111

    
2112

    
2113
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
2114
  LOperand* context = UseFixed(instr->context(), cp);
2115
  LOperand* object = UseFixed(instr->object(), a0);
2116
  LInstruction* result =
2117
      DefineFixed(new(zone()) LLoadNamedGeneric(context, object), v0);
2118
  return MarkAsCall(result, instr);
2119
}
2120

    
2121

    
2122
LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
2123
    HLoadFunctionPrototype* instr) {
2124
  return AssignEnvironment(DefineAsRegister(
2125
      new(zone()) LLoadFunctionPrototype(UseRegister(instr->function()))));
2126
}
2127

    
2128

    
2129
LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
2130
  return DefineAsRegister(new(zone()) LLoadRoot);
2131
}
2132

    
2133

    
2134
LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
2135
    HLoadExternalArrayPointer* instr) {
2136
  LOperand* input = UseRegisterAtStart(instr->value());
2137
  return DefineAsRegister(new(zone()) LLoadExternalArrayPointer(input));
2138
}
2139

    
2140

    
2141
LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
2142
  ASSERT(instr->key()->representation().IsSmiOrInteger32());
2143
  ElementsKind elements_kind = instr->elements_kind();
2144
  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2145
  LLoadKeyed* result = NULL;
2146

    
2147
  if (!instr->is_external()) {
2148
    LOperand* obj = NULL;
2149
    if (instr->representation().IsDouble()) {
2150
      obj = UseRegister(instr->elements());
2151
    } else {
2152
      ASSERT(instr->representation().IsSmiOrTagged());
2153
      obj = UseRegisterAtStart(instr->elements());
2154
    }
2155
    result = new(zone()) LLoadKeyed(obj, key);
2156
  } else {
2157
    ASSERT(
2158
        (instr->representation().IsInteger32() &&
2159
         (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
2160
         (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
2161
        (instr->representation().IsDouble() &&
2162
         ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
2163
          (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
2164
    LOperand* external_pointer = UseRegister(instr->elements());
2165
    result = new(zone()) LLoadKeyed(external_pointer, key);
2166
  }
2167

    
2168
  DefineAsRegister(result);
2169
  // An unsigned int array load might overflow and cause a deopt, make sure it
2170
  // has an environment.
2171
  bool can_deoptimize = instr->RequiresHoleCheck() ||
2172
      (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS);
2173
  return can_deoptimize ? AssignEnvironment(result) : result;
2174
}
2175

    
2176

    
2177
LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
2178
  LOperand* context = UseFixed(instr->context(), cp);
2179
  LOperand* object = UseFixed(instr->object(), a1);
2180
  LOperand* key = UseFixed(instr->key(), a0);
2181

    
2182
  LInstruction* result =
2183
      DefineFixed(new(zone()) LLoadKeyedGeneric(context, object, key), v0);
2184
  return MarkAsCall(result, instr);
2185
}
2186

    
2187

    
2188
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
2189
  if (!instr->is_external()) {
2190
    ASSERT(instr->elements()->representation().IsTagged());
2191
    bool needs_write_barrier = instr->NeedsWriteBarrier();
2192
    LOperand* object = NULL;
2193
    LOperand* val = NULL;
2194
    LOperand* key = NULL;
2195

    
2196
    if (instr->value()->representation().IsDouble()) {
2197
      object = UseRegisterAtStart(instr->elements());
2198
      key = UseRegisterOrConstantAtStart(instr->key());
2199
      val = UseRegister(instr->value());
2200
    } else {
2201
      ASSERT(instr->value()->representation().IsSmiOrTagged());
2202
      if (needs_write_barrier) {
2203
        object = UseTempRegister(instr->elements());
2204
        val = UseTempRegister(instr->value());
2205
        key = UseTempRegister(instr->key());
2206
      } else {
2207
        object = UseRegisterAtStart(instr->elements());
2208
        val = UseRegisterAtStart(instr->value());
2209
        key = UseRegisterOrConstantAtStart(instr->key());
2210
      }
2211
    }
2212

    
2213
    return new(zone()) LStoreKeyed(object, key, val);
2214
  }
2215

    
2216
  ASSERT(
2217
      (instr->value()->representation().IsInteger32() &&
2218
       (instr->elements_kind() != EXTERNAL_FLOAT_ELEMENTS) &&
2219
       (instr->elements_kind() != EXTERNAL_DOUBLE_ELEMENTS)) ||
2220
      (instr->value()->representation().IsDouble() &&
2221
       ((instr->elements_kind() == EXTERNAL_FLOAT_ELEMENTS) ||
2222
        (instr->elements_kind() == EXTERNAL_DOUBLE_ELEMENTS))));
2223
  ASSERT(instr->elements()->representation().IsExternal());
2224
  LOperand* val = UseRegister(instr->value());
2225
  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2226
  LOperand* external_pointer = UseRegister(instr->elements());
2227

    
2228
  return new(zone()) LStoreKeyed(external_pointer, key, val);
2229
}
2230

    
2231

    
2232
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
2233
  LOperand* context = UseFixed(instr->context(), cp);
2234
  LOperand* obj = UseFixed(instr->object(), a2);
2235
  LOperand* key = UseFixed(instr->key(), a1);
2236
  LOperand* val = UseFixed(instr->value(), a0);
2237

    
2238
  ASSERT(instr->object()->representation().IsTagged());
2239
  ASSERT(instr->key()->representation().IsTagged());
2240
  ASSERT(instr->value()->representation().IsTagged());
2241

    
2242
  return MarkAsCall(
2243
      new(zone()) LStoreKeyedGeneric(context, obj, key, val), instr);
2244
}
2245

    
2246

    
2247
LInstruction* LChunkBuilder::DoTransitionElementsKind(
2248
    HTransitionElementsKind* instr) {
2249
  LOperand* object = UseRegister(instr->object());
2250
  if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
2251
    LOperand* new_map_reg = TempRegister();
2252
    LTransitionElementsKind* result =
2253
        new(zone()) LTransitionElementsKind(object, NULL, new_map_reg);
2254
    return result;
2255
  } else {
2256
    LOperand* context = UseFixed(instr->context(), cp);
2257
    LTransitionElementsKind* result =
2258
        new(zone()) LTransitionElementsKind(object, context, NULL);
2259
    return AssignPointerMap(result);
2260
  }
2261
}
2262

    
2263

    
2264
LInstruction* LChunkBuilder::DoTrapAllocationMemento(
2265
    HTrapAllocationMemento* instr) {
2266
  LOperand* object = UseRegister(instr->object());
2267
  LOperand* temp = TempRegister();
2268
  LTrapAllocationMemento* result =
2269
      new(zone()) LTrapAllocationMemento(object, temp);
2270
  return AssignEnvironment(result);
2271
}
2272

    
2273

    
2274
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2275
  bool is_in_object = instr->access().IsInobject();
2276
  bool needs_write_barrier = instr->NeedsWriteBarrier();
2277
  bool needs_write_barrier_for_map = instr->has_transition() &&
2278
      instr->NeedsWriteBarrierForMap();
2279

    
2280
  LOperand* obj;
2281
  if (needs_write_barrier) {
2282
    obj = is_in_object
2283
        ? UseRegister(instr->object())
2284
        : UseTempRegister(instr->object());
2285
  } else {
2286
    obj = needs_write_barrier_for_map
2287
        ? UseRegister(instr->object())
2288
        : UseRegisterAtStart(instr->object());
2289
  }
2290

    
2291
  LOperand* val;
2292
  if (needs_write_barrier ||
2293
      (FLAG_track_fields && instr->field_representation().IsSmi())) {
2294
    val = UseTempRegister(instr->value());
2295
  } else if (FLAG_track_double_fields &&
2296
             instr->field_representation().IsDouble()) {
2297
    val = UseRegisterAtStart(instr->value());
2298
  } else {
2299
    val = UseRegister(instr->value());
2300
  }
2301

    
2302
  // We need a temporary register for write barrier of the map field.
2303
  LOperand* temp = needs_write_barrier_for_map ? TempRegister() : NULL;
2304

    
2305
  LStoreNamedField* result = new(zone()) LStoreNamedField(obj, val, temp);
2306
  if (FLAG_track_heap_object_fields &&
2307
      instr->field_representation().IsHeapObject()) {
2308
    if (!instr->value()->type().IsHeapObject()) {
2309
      return AssignEnvironment(result);
2310
    }
2311
  }
2312
  return result;
2313
}
2314

    
2315

    
2316
LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
2317
  LOperand* context = UseFixed(instr->context(), cp);
2318
  LOperand* obj = UseFixed(instr->object(), a1);
2319
  LOperand* val = UseFixed(instr->value(), a0);
2320

    
2321
  LInstruction* result = new(zone()) LStoreNamedGeneric(context, obj, val);
2322
  return MarkAsCall(result, instr);
2323
}
2324

    
2325

    
2326
LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2327
  LOperand* context = UseFixed(instr->context(), cp);
2328
  LOperand* left = UseRegisterAtStart(instr->left());
2329
  LOperand* right = UseRegisterAtStart(instr->right());
2330
  return MarkAsCall(
2331
      DefineFixed(new(zone()) LStringAdd(context, left, right), v0),
2332
      instr);
2333
}
2334

    
2335

    
2336
LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2337
  LOperand* string = UseTempRegister(instr->string());
2338
  LOperand* index = UseTempRegister(instr->index());
2339
  LOperand* context = UseAny(instr->context());
2340
  LStringCharCodeAt* result =
2341
      new(zone()) LStringCharCodeAt(context, string, index);
2342
  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
2343
}
2344

    
2345

    
2346
LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
2347
  LOperand* char_code = UseRegister(instr->value());
2348
  LOperand* context = UseAny(instr->context());
2349
  LStringCharFromCode* result =
2350
      new(zone()) LStringCharFromCode(context, char_code);
2351
  return AssignPointerMap(DefineAsRegister(result));
2352
}
2353

    
2354

    
2355
LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
2356
  info()->MarkAsDeferredCalling();
2357
  LOperand* context = UseAny(instr->context());
2358
  LOperand* size = instr->size()->IsConstant()
2359
      ? UseConstant(instr->size())
2360
      : UseTempRegister(instr->size());
2361
  LOperand* temp1 = TempRegister();
2362
  LOperand* temp2 = TempRegister();
2363
  LAllocate* result = new(zone()) LAllocate(context, size, temp1, temp2);
2364
  return AssignPointerMap(DefineAsRegister(result));
2365
}
2366

    
2367

    
2368
LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
2369
  LOperand* context = UseFixed(instr->context(), cp);
2370
  return MarkAsCall(
2371
      DefineFixed(new(zone()) LRegExpLiteral(context), v0), instr);
2372
}
2373

    
2374

    
2375
LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
2376
  LOperand* context = UseFixed(instr->context(), cp);
2377
  return MarkAsCall(
2378
      DefineFixed(new(zone()) LFunctionLiteral(context), v0), instr);
2379
}
2380

    
2381

    
2382
LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2383
  ASSERT(argument_count_ == 0);
2384
  allocator_->MarkAsOsrEntry();
2385
  current_block_->last_environment()->set_ast_id(instr->ast_id());
2386
  return AssignEnvironment(new(zone()) LOsrEntry);
2387
}
2388

    
2389

    
2390
LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2391
  LParameter* result = new(zone()) LParameter;
2392
  if (instr->kind() == HParameter::STACK_PARAMETER) {
2393
    int spill_index = chunk()->GetParameterStackSlot(instr->index());
2394
    return DefineAsSpilled(result, spill_index);
2395
  } else {
2396
    ASSERT(info()->IsStub());
2397
    CodeStubInterfaceDescriptor* descriptor =
2398
        info()->code_stub()->GetInterfaceDescriptor(info()->isolate());
2399
    int index = static_cast<int>(instr->index());
2400
    Register reg = DESCRIPTOR_GET_PARAMETER_REGISTER(descriptor, index);
2401
    return DefineFixed(result, reg);
2402
  }
2403
}
2404

    
2405

    
2406
LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2407
  // Use an index that corresponds to the location in the unoptimized frame,
2408
  // which the optimized frame will subsume.
2409
  int env_index = instr->index();
2410
  int spill_index = 0;
2411
  if (instr->environment()->is_parameter_index(env_index)) {
2412
    spill_index = chunk()->GetParameterStackSlot(env_index);
2413
  } else {
2414
    spill_index = env_index - instr->environment()->first_local_index();
2415
    if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
2416
      Abort(kTooManySpillSlotsNeededForOSR);
2417
      spill_index = 0;
2418
    }
2419
  }
2420
  return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
2421
}
2422

    
2423

    
2424
LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
2425
  LOperand* context = UseFixed(instr->context(), cp);
2426
  return MarkAsCall(DefineFixed(new(zone()) LCallStub(context), v0), instr);
2427
}
2428

    
2429

    
2430
LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2431
  // There are no real uses of the arguments object.
2432
  // arguments.length and element access are supported directly on
2433
  // stack arguments, and any real arguments object use causes a bailout.
2434
  // So this value is never used.
2435
  return NULL;
2436
}
2437

    
2438

    
2439
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
2440
  instr->ReplayEnvironment(current_block_->last_environment());
2441

    
2442
  // There are no real uses of a captured object.
2443
  return NULL;
2444
}
2445

    
2446

    
2447
LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2448
  info()->MarkAsRequiresFrame();
2449
  LOperand* args = UseRegister(instr->arguments());
2450
  LOperand* length;
2451
  LOperand* index;
2452
  if (instr->length()->IsConstant() && instr->index()->IsConstant()) {
2453
    length = UseRegisterOrConstant(instr->length());
2454
    index = UseOrConstant(instr->index());
2455
  } else {
2456
    length = UseTempRegister(instr->length());
2457
    index = UseRegisterAtStart(instr->index());
2458
  }
2459
  return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
2460
}
2461

    
2462

    
2463
LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
2464
  LOperand* object = UseFixed(instr->value(), a0);
2465
  LToFastProperties* result = new(zone()) LToFastProperties(object);
2466
  return MarkAsCall(DefineFixed(result, v0), instr);
2467
}
2468

    
2469

    
2470
LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2471
  LOperand* context = UseFixed(instr->context(), cp);
2472
  LTypeof* result = new(zone()) LTypeof(context, UseFixed(instr->value(), a0));
2473
  return MarkAsCall(DefineFixed(result, v0), instr);
2474
}
2475

    
2476

    
2477
LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2478
  return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value()));
2479
}
2480

    
2481

    
2482
LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
2483
    HIsConstructCallAndBranch* instr) {
2484
  return new(zone()) LIsConstructCallAndBranch(TempRegister());
2485
}
2486

    
2487

    
2488
LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2489
  instr->ReplayEnvironment(current_block_->last_environment());
2490

    
2491
  // If there is an instruction pending deoptimization environment create a
2492
  // lazy bailout instruction to capture the environment.
2493
  if (pending_deoptimization_ast_id_ == instr->ast_id()) {
2494
    LInstruction* result = new(zone()) LLazyBailout;
2495
    result = AssignEnvironment(result);
2496
    // Store the lazy deopt environment with the instruction if needed. Right
2497
    // now it is only used for LInstanceOfKnownGlobal.
2498
    instruction_pending_deoptimization_environment_->
2499
        SetDeferredLazyDeoptimizationEnvironment(result->environment());
2500
    instruction_pending_deoptimization_environment_ = NULL;
2501
    pending_deoptimization_ast_id_ = BailoutId::None();
2502
    return result;
2503
  }
2504

    
2505
  return NULL;
2506
}
2507

    
2508

    
2509
LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2510
  if (instr->is_function_entry()) {
2511
    LOperand* context = UseFixed(instr->context(), cp);
2512
    return MarkAsCall(new(zone()) LStackCheck(context), instr);
2513
  } else {
2514
    ASSERT(instr->is_backwards_branch());
2515
    LOperand* context = UseAny(instr->context());
2516
    return AssignEnvironment(
2517
        AssignPointerMap(new(zone()) LStackCheck(context)));
2518
  }
2519
}
2520

    
2521

    
2522
LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2523
  HEnvironment* outer = current_block_->last_environment();
2524
  HConstant* undefined = graph()->GetConstantUndefined();
2525
  HEnvironment* inner = outer->CopyForInlining(instr->closure(),
2526
                                               instr->arguments_count(),
2527
                                               instr->function(),
2528
                                               undefined,
2529
                                               instr->inlining_kind(),
2530
                                               instr->undefined_receiver());
2531
  // Only replay binding of arguments object if it wasn't removed from graph.
2532
  if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
2533
    inner->Bind(instr->arguments_var(), instr->arguments_object());
2534
  }
2535
  inner->set_entry(instr);
2536
  current_block_->UpdateEnvironment(inner);
2537
  chunk_->AddInlinedClosure(instr->closure());
2538
  return NULL;
2539
}
2540

    
2541

    
2542
LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2543
  LInstruction* pop = NULL;
2544

    
2545
  HEnvironment* env = current_block_->last_environment();
2546

    
2547
  if (env->entry()->arguments_pushed()) {
2548
    int argument_count = env->arguments_environment()->parameter_count();
2549
    pop = new(zone()) LDrop(argument_count);
2550
    ASSERT(instr->argument_delta() == -argument_count);
2551
  }
2552

    
2553
  HEnvironment* outer = current_block_->last_environment()->
2554
      DiscardInlined(false);
2555
  current_block_->UpdateEnvironment(outer);
2556

    
2557
  return pop;
2558
}
2559

    
2560

    
2561
LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
2562
  LOperand* context = UseFixed(instr->context(), cp);
2563
  LOperand* object = UseFixed(instr->enumerable(), a0);
2564
  LForInPrepareMap* result = new(zone()) LForInPrepareMap(context, object);
2565
  return MarkAsCall(DefineFixed(result, v0), instr, CAN_DEOPTIMIZE_EAGERLY);
2566
}
2567

    
2568

    
2569
LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
2570
  LOperand* map = UseRegister(instr->map());
2571
  return AssignEnvironment(DefineAsRegister(new(zone()) LForInCacheArray(map)));
2572
}
2573

    
2574

    
2575
LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
2576
  LOperand* value = UseRegisterAtStart(instr->value());
2577
  LOperand* map = UseRegisterAtStart(instr->map());
2578
  return AssignEnvironment(new(zone()) LCheckMapValue(value, map));
2579
}
2580

    
2581

    
2582
LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
2583
  LOperand* object = UseRegister(instr->object());
2584
  LOperand* index = UseRegister(instr->index());
2585
  return DefineAsRegister(new(zone()) LLoadFieldByIndex(object, index));
2586
}
2587

    
2588

    
2589
} }  // namespace v8::internal