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

History | View | Annotate | Download (88.3 KB)

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

    
28
#include "v8.h"
29

    
30
#include "lithium-allocator-inl.h"
31
#include "arm/lithium-arm.h"
32
#include "arm/lithium-codegen-arm.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 "shl-t";
161
    case Token::SAR: return "sar-t";
162
    case Token::SHR: return "shr-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
void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
187
  stream->Add("if ");
188
  left()->PrintTo(stream);
189
  stream->Add(" %s ", Token::String(op()));
190
  right()->PrintTo(stream);
191
  stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
192
}
193

    
194

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

    
201

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

    
208

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

    
215

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

    
222

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

    
230

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

    
237

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

    
244

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

    
254

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

    
263

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

    
271

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

    
278

    
279
void LCallConstantFunction::PrintDataTo(StringStream* stream) {
280
  stream->Add("#%d / ", arity());
281
}
282

    
283

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

    
289

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

    
296

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

    
303

    
304
void LCallKeyed::PrintDataTo(StringStream* stream) {
305
  stream->Add("[r2] #%d / ", arity());
306
}
307

    
308

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

    
314

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

    
320

    
321
void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
322
  stream->Add("#%d / ", arity());
323
}
324

    
325

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

    
332

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

    
341

    
342
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
343
  arguments()->PrintTo(stream);
344
  stream->Add(" length ");
345
  length()->PrintTo(stream);
346
  stream->Add(" index ");
347
  index()->PrintTo(stream);
348
}
349

    
350

    
351
void LStoreNamedField::PrintDataTo(StringStream* stream) {
352
  object()->PrintTo(stream);
353
  hydrogen()->access().PrintTo(stream);
354
  stream->Add(" <- ");
355
  value()->PrintTo(stream);
356
}
357

    
358

    
359
void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
360
  object()->PrintTo(stream);
361
  stream->Add(".");
362
  stream->Add(*String::cast(*name())->ToCString());
363
  stream->Add(" <- ");
364
  value()->PrintTo(stream);
365
}
366

    
367

    
368
void LLoadKeyed::PrintDataTo(StringStream* stream) {
369
  elements()->PrintTo(stream);
370
  stream->Add("[");
371
  key()->PrintTo(stream);
372
  if (hydrogen()->IsDehoisted()) {
373
    stream->Add(" + %d]", additional_index());
374
  } else {
375
    stream->Add("]");
376
  }
377
}
378

    
379

    
380
void LStoreKeyed::PrintDataTo(StringStream* stream) {
381
  elements()->PrintTo(stream);
382
  stream->Add("[");
383
  key()->PrintTo(stream);
384
  if (hydrogen()->IsDehoisted()) {
385
    stream->Add(" + %d] <-", additional_index());
386
  } else {
387
    stream->Add("] <- ");
388
  }
389

    
390
  if (value() == NULL) {
391
    ASSERT(hydrogen()->IsConstantHoleStore() &&
392
           hydrogen()->value()->representation().IsDouble());
393
    stream->Add("<the hole(nan)>");
394
  } else {
395
    value()->PrintTo(stream);
396
  }
397
}
398

    
399

    
400
void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
401
  object()->PrintTo(stream);
402
  stream->Add("[");
403
  key()->PrintTo(stream);
404
  stream->Add("] <- ");
405
  value()->PrintTo(stream);
406
}
407

    
408

    
409
void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
410
  object()->PrintTo(stream);
411
  stream->Add(" %p -> %p", *original_map(), *transitioned_map());
412
}
413

    
414

    
415
int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
416
  // Skip a slot if for a double-width slot.
417
  if (kind == DOUBLE_REGISTERS) spill_slot_count_++;
418
  return spill_slot_count_++;
419
}
420

    
421

    
422
LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind)  {
423
  int index = GetNextSpillIndex(kind);
424
  if (kind == DOUBLE_REGISTERS) {
425
    return LDoubleStackSlot::Create(index, zone());
426
  } else {
427
    ASSERT(kind == GENERAL_REGISTERS);
428
    return LStackSlot::Create(index, zone());
429
  }
430
}
431

    
432

    
433
LPlatformChunk* LChunkBuilder::Build() {
434
  ASSERT(is_unused());
435
  chunk_ = new(zone()) LPlatformChunk(info(), graph());
436
  LPhase phase("L_Building chunk", chunk_);
437
  status_ = BUILDING;
438

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

    
447
  const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
448
  for (int i = 0; i < blocks->length(); i++) {
449
    HBasicBlock* next = NULL;
450
    if (i < blocks->length() - 1) next = blocks->at(i + 1);
451
    DoBasicBlock(blocks->at(i), next);
452
    if (is_aborted()) return NULL;
453
  }
454
  status_ = DONE;
455
  return chunk_;
456
}
457

    
458

    
459
void LChunkBuilder::Abort(BailoutReason reason) {
460
  info()->set_bailout_reason(reason);
461
  status_ = ABORTED;
462
}
463

    
464

    
465
LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
466
  return new(zone()) LUnallocated(LUnallocated::FIXED_REGISTER,
467
                                  Register::ToAllocationIndex(reg));
468
}
469

    
470

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

    
476

    
477
LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
478
  return Use(value, ToUnallocated(fixed_register));
479
}
480

    
481

    
482
LOperand* LChunkBuilder::UseFixedDouble(HValue* value, DoubleRegister reg) {
483
  return Use(value, ToUnallocated(reg));
484
}
485

    
486

    
487
LOperand* LChunkBuilder::UseRegister(HValue* value) {
488
  return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
489
}
490

    
491

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

    
498

    
499
LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
500
  return Use(value, new(zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
501
}
502

    
503

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

    
508

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

    
514

    
515
LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
516
  return value->IsConstant()
517
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
518
      : Use(value);
519
}
520

    
521

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

    
528

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

    
535

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

    
542

    
543
LOperand* LChunkBuilder::UseConstant(HValue* value) {
544
  return chunk_->DefineConstantOperand(HConstant::cast(value));
545
}
546

    
547

    
548
LOperand* LChunkBuilder::UseAny(HValue* value) {
549
  return value->IsConstant()
550
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
551
      :  Use(value, new(zone()) LUnallocated(LUnallocated::ANY));
552
}
553

    
554

    
555
LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
556
  if (value->EmitAtUses()) {
557
    HInstruction* instr = HInstruction::cast(value);
558
    VisitInstruction(instr);
559
  }
560
  operand->set_virtual_register(value->id());
561
  return operand;
562
}
563

    
564

    
565
template<int I, int T>
566
LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
567
                                    LUnallocated* result) {
568
  result->set_virtual_register(current_instruction_->id());
569
  instr->set_result(result);
570
  return instr;
571
}
572

    
573

    
574
template<int I, int T>
575
LInstruction* LChunkBuilder::DefineAsRegister(
576
    LTemplateInstruction<1, I, T>* instr) {
577
  return Define(instr,
578
                new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
579
}
580

    
581

    
582
template<int I, int T>
583
LInstruction* LChunkBuilder::DefineAsSpilled(
584
    LTemplateInstruction<1, I, T>* instr, int index) {
585
  return Define(instr,
586
                new(zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
587
}
588

    
589

    
590
template<int I, int T>
591
LInstruction* LChunkBuilder::DefineSameAsFirst(
592
    LTemplateInstruction<1, I, T>* instr) {
593
  return Define(instr,
594
                new(zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
595
}
596

    
597

    
598
template<int I, int T>
599
LInstruction* LChunkBuilder::DefineFixed(
600
    LTemplateInstruction<1, I, T>* instr, Register reg) {
601
  return Define(instr, ToUnallocated(reg));
602
}
603

    
604

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

    
611

    
612
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
613
  HEnvironment* hydrogen_env = current_block_->last_environment();
614
  int argument_index_accumulator = 0;
615
  ZoneList<HValue*> objects_to_materialize(0, zone());
616
  instr->set_environment(CreateEnvironment(hydrogen_env,
617
                                           &argument_index_accumulator,
618
                                           &objects_to_materialize));
619
  return instr;
620
}
621

    
622

    
623
LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
624
                                        HInstruction* hinstr,
625
                                        CanDeoptimize can_deoptimize) {
626
  info()->MarkAsNonDeferredCalling();
627
#ifdef DEBUG
628
  instr->VerifyCall();
629
#endif
630
  instr->MarkAsCall();
631
  instr = AssignPointerMap(instr);
632

    
633
  if (hinstr->HasObservableSideEffects()) {
634
    ASSERT(hinstr->next()->IsSimulate());
635
    HSimulate* sim = HSimulate::cast(hinstr->next());
636
    ASSERT(instruction_pending_deoptimization_environment_ == NULL);
637
    ASSERT(pending_deoptimization_ast_id_.IsNone());
638
    instruction_pending_deoptimization_environment_ = instr;
639
    pending_deoptimization_ast_id_ = sim->ast_id();
640
  }
641

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

    
653
  return instr;
654
}
655

    
656

    
657
LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
658
  ASSERT(!instr->HasPointerMap());
659
  instr->set_pointer_map(new(zone()) LPointerMap(zone()));
660
  return instr;
661
}
662

    
663

    
664
LUnallocated* LChunkBuilder::TempRegister() {
665
  LUnallocated* operand =
666
      new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
667
  int vreg = allocator_->GetVirtualRegister();
668
  if (!allocator_->AllocationOk()) {
669
    Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
670
    vreg = 0;
671
  }
672
  operand->set_virtual_register(vreg);
673
  return operand;
674
}
675

    
676

    
677
LOperand* LChunkBuilder::FixedTemp(Register reg) {
678
  LUnallocated* operand = ToUnallocated(reg);
679
  ASSERT(operand->HasFixedPolicy());
680
  return operand;
681
}
682

    
683

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

    
690

    
691
LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
692
  return new(zone()) LLabel(instr->block());
693
}
694

    
695

    
696
LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
697
  return DefineAsRegister(new(zone()) LDummyUse(UseAny(instr->value())));
698
}
699

    
700

    
701
LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
702
  UNREACHABLE();
703
  return NULL;
704
}
705

    
706

    
707
LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
708
  return AssignEnvironment(new(zone()) LDeoptimize);
709
}
710

    
711

    
712
LInstruction* LChunkBuilder::DoShift(Token::Value op,
713
                                     HBitwiseBinaryOperation* instr) {
714
  if (instr->representation().IsSmiOrInteger32()) {
715
    ASSERT(instr->left()->representation().Equals(instr->representation()));
716
    ASSERT(instr->right()->representation().Equals(instr->representation()));
717
    LOperand* left = UseRegisterAtStart(instr->left());
718

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

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

    
746
    LInstruction* result =
747
        DefineAsRegister(new(zone()) LShiftI(op, left, right, does_deopt));
748
    return does_deopt ? AssignEnvironment(result) : result;
749
  } else {
750
    return DoArithmeticT(op, instr);
751
  }
752
}
753

    
754

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

    
776

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

    
791

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

    
858

    
859
void LChunkBuilder::VisitInstruction(HInstruction* current) {
860
  HInstruction* old_current = current_instruction_;
861
  current_instruction_ = current;
862
  if (current->has_position()) position_ = current->position();
863

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

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

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

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

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

    
928

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

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

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

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

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

    
1009
  return result;
1010
}
1011

    
1012

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

    
1017

    
1018
LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
1019
  LInstruction* goto_instr = CheckElideControlInstruction(instr);
1020
  if (goto_instr != NULL) return goto_instr;
1021

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

    
1037

    
1038
LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
1039
  return new(zone()) LDebugBreak();
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* instr) {
1052
  info()->MarkAsRequiresFrame();
1053
  LOperand* value = UseRegister(instr->value());
1054
  return DefineAsRegister(new(zone()) LArgumentsLength(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(), r0),
1068
                              UseFixed(instr->right(), r1));
1069
  return MarkAsCall(DefineFixed(result, r0), 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(), r0),
1079
          FixedTemp(r4));
1080
  return MarkAsCall(DefineFixed(result, r0), 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(), r1);
1094
  LOperand* receiver = UseFixed(instr->receiver(), r0);
1095
  LOperand* length = UseFixed(instr->length(), r2);
1096
  LOperand* elements = UseFixed(instr->elements(), r3);
1097
  LApplyArguments* result = new(zone()) LApplyArguments(function,
1098
                                                receiver,
1099
                                                length,
1100
                                                elements);
1101
  return MarkAsCall(DefineFixed(result, r0), 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, r0), instr);
1173
}
1174

    
1175

    
1176
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
1177
  LOperand* context = UseFixed(instr->context(), cp);
1178
  LOperand* function = UseFixed(instr->function(), r1);
1179
  LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
1180
  return MarkAsCall(DefineFixed(result, r0), 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::DoMathFloor(HUnaryMathOperation* instr) {
1204
  LOperand* input = UseRegister(instr->value());
1205
  LMathFloor* result = new(zone()) LMathFloor(input);
1206
  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1207
}
1208

    
1209

    
1210
LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
1211
  LOperand* input = UseRegister(instr->value());
1212
  LOperand* temp = FixedTemp(d3);
1213
  LMathRound* result = new(zone()) LMathRound(input, temp);
1214
  return AssignEnvironment(DefineAsRegister(result));
1215
}
1216

    
1217

    
1218
LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
1219
  Representation r = instr->value()->representation();
1220
  LOperand* context = (r.IsDouble() || r.IsSmiOrInteger32())
1221
      ? NULL
1222
      : UseFixed(instr->context(), cp);
1223
  LOperand* input = UseRegister(instr->value());
1224
  LMathAbs* result = new(zone()) LMathAbs(context, input);
1225
  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1226
}
1227

    
1228

    
1229
LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
1230
  LOperand* input = UseFixedDouble(instr->value(), d2);
1231
  LMathLog* result = new(zone()) LMathLog(input);
1232
  return MarkAsCall(DefineFixedDouble(result, d2), instr);
1233
}
1234

    
1235

    
1236
LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
1237
  LOperand* input = UseFixedDouble(instr->value(), d2);
1238
  LMathSin* result = new(zone()) LMathSin(input);
1239
  return MarkAsCall(DefineFixedDouble(result, d2), instr);
1240
}
1241

    
1242

    
1243
LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
1244
  LOperand* input = UseFixedDouble(instr->value(), d2);
1245
  LMathCos* result = new(zone()) LMathCos(input);
1246
  return MarkAsCall(DefineFixedDouble(result, d2), instr);
1247
}
1248

    
1249

    
1250
LInstruction* LChunkBuilder::DoMathTan(HUnaryMathOperation* instr) {
1251
  LOperand* input = UseFixedDouble(instr->value(), d2);
1252
  LMathTan* result = new(zone()) LMathTan(input);
1253
  return MarkAsCall(DefineFixedDouble(result, d2), instr);
1254
}
1255

    
1256

    
1257
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
1258
  ASSERT(instr->representation().IsDouble());
1259
  ASSERT(instr->value()->representation().IsDouble());
1260
  LOperand* input = UseRegister(instr->value());
1261
  LOperand* temp1 = TempRegister();
1262
  LOperand* temp2 = TempRegister();
1263
  LOperand* double_temp = FixedTemp(d3);  // Chosen by fair dice roll.
1264
  LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2);
1265
  return DefineAsRegister(result);
1266
}
1267

    
1268

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

    
1275

    
1276
LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
1277
  LOperand* input = UseFixedDouble(instr->value(), d2);
1278
  LOperand* temp = FixedTemp(d3);
1279
  LMathPowHalf* result = new(zone()) LMathPowHalf(input, temp);
1280
  return DefineFixedDouble(result, d2);
1281
}
1282

    
1283

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

    
1292

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

    
1298

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

    
1304

    
1305
LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
1306
  return MarkAsCall(DefineFixed(new(zone()) LCallKnownGlobal, r0), instr);
1307
}
1308

    
1309

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

    
1317

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

    
1325

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

    
1333

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

    
1339

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

    
1344

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

    
1349

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

    
1354

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

    
1359

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

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

    
1374

    
1375
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1376
  if (instr->representation().IsSmiOrInteger32()) {
1377
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1378
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1379
    if (instr->HasPowerOf2Divisor()) {
1380
      ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
1381
      LOperand* value = UseRegisterAtStart(instr->left());
1382
      LDivI* div = new(zone()) LDivI(value, UseConstant(instr->right()), NULL);
1383
      return AssignEnvironment(DefineAsRegister(div));
1384
    }
1385
    LOperand* dividend = UseRegister(instr->left());
1386
    LOperand* divisor = UseRegister(instr->right());
1387
    LOperand* temp = CpuFeatures::IsSupported(SUDIV) ? NULL : FixedTemp(d4);
1388
    LDivI* div = new(zone()) LDivI(dividend, divisor, temp);
1389
    return AssignEnvironment(DefineAsRegister(div));
1390
  } else if (instr->representation().IsDouble()) {
1391
    return DoArithmeticD(Token::DIV, instr);
1392
  } else {
1393
    return DoArithmeticT(Token::DIV, instr);
1394
  }
1395
}
1396

    
1397

    
1398
bool LChunkBuilder::HasMagicNumberForDivisor(int32_t divisor) {
1399
  uint32_t divisor_abs = abs(divisor);
1400
  // Dividing by 0, 1, and powers of 2 is easy.
1401
  // Note that IsPowerOf2(0) returns true;
1402
  ASSERT(IsPowerOf2(0) == true);
1403
  if (IsPowerOf2(divisor_abs)) return true;
1404

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

    
1421
  return false;
1422
}
1423

    
1424

    
1425
HValue* LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(HValue* divisor) {
1426
  if (CpuFeatures::IsSupported(SUDIV)) {
1427
    // A value with an integer representation does not need to be transformed.
1428
    if (divisor->representation().IsInteger32()) {
1429
      return divisor;
1430
    // A change from an integer32 can be replaced by the integer32 value.
1431
    } else if (divisor->IsChange() &&
1432
               HChange::cast(divisor)->from().IsInteger32()) {
1433
      return HChange::cast(divisor)->value();
1434
    }
1435
  }
1436

    
1437
  if (divisor->IsConstant() && HConstant::cast(divisor)->HasInteger32Value()) {
1438
    HConstant* constant_val = HConstant::cast(divisor);
1439
    int32_t int32_val = constant_val->Integer32Value();
1440
    if (LChunkBuilder::HasMagicNumberForDivisor(int32_val) ||
1441
        CpuFeatures::IsSupported(SUDIV)) {
1442
      return constant_val->CopyToRepresentation(Representation::Integer32(),
1443
                                                divisor->block()->zone());
1444
    }
1445
  }
1446

    
1447
  return NULL;
1448
}
1449

    
1450

    
1451
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
1452
  HValue* right = instr->right();
1453
  LOperand* dividend = UseRegister(instr->left());
1454
  LOperand* divisor = CpuFeatures::IsSupported(SUDIV)
1455
      ? UseRegister(right)
1456
      : UseOrConstant(right);
1457
  LOperand* remainder = TempRegister();
1458
  ASSERT(CpuFeatures::IsSupported(SUDIV) ||
1459
         (right->IsConstant() &&
1460
          HConstant::cast(right)->HasInteger32Value() &&
1461
          HasMagicNumberForDivisor(HConstant::cast(right)->Integer32Value())));
1462
  return AssignEnvironment(DefineAsRegister(
1463
          new(zone()) LMathFloorOfDiv(dividend, divisor, remainder)));
1464
}
1465

    
1466

    
1467
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1468
  HValue* left = instr->left();
1469
  HValue* right = instr->right();
1470
  if (instr->representation().IsSmiOrInteger32()) {
1471
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1472
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1473
    if (instr->HasPowerOf2Divisor()) {
1474
      ASSERT(!right->CanBeZero());
1475
      LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
1476
                                     UseOrConstant(right));
1477
      LInstruction* result = DefineAsRegister(mod);
1478
      return (left->CanBeNegative() &&
1479
              instr->CheckFlag(HValue::kBailoutOnMinusZero))
1480
          ? AssignEnvironment(result)
1481
          : result;
1482
    } else if (instr->fixed_right_arg().has_value) {
1483
      LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
1484
                                     UseRegisterAtStart(right));
1485
      return AssignEnvironment(DefineAsRegister(mod));
1486
    } else if (CpuFeatures::IsSupported(SUDIV)) {
1487
      LModI* mod = new(zone()) LModI(UseRegister(left),
1488
                                     UseRegister(right));
1489
      LInstruction* result = DefineAsRegister(mod);
1490
      return (right->CanBeZero() ||
1491
              (left->RangeCanInclude(kMinInt) &&
1492
               right->RangeCanInclude(-1) &&
1493
               instr->CheckFlag(HValue::kBailoutOnMinusZero)) ||
1494
              (left->CanBeNegative() &&
1495
               instr->CanBeZero() &&
1496
               instr->CheckFlag(HValue::kBailoutOnMinusZero)))
1497
          ? AssignEnvironment(result)
1498
          : result;
1499
    } else {
1500
      LModI* mod = new(zone()) LModI(UseRegister(left),
1501
                                     UseRegister(right),
1502
                                     FixedTemp(d10),
1503
                                     FixedTemp(d11));
1504
      LInstruction* result = DefineAsRegister(mod);
1505
      return (right->CanBeZero() ||
1506
              (left->CanBeNegative() &&
1507
               instr->CanBeZero() &&
1508
               instr->CheckFlag(HValue::kBailoutOnMinusZero)))
1509
          ? AssignEnvironment(result)
1510
          : result;
1511
    }
1512
  } else if (instr->representation().IsDouble()) {
1513
    return DoArithmeticD(Token::MOD, instr);
1514
  } else {
1515
    return DoArithmeticT(Token::MOD, instr);
1516
  }
1517
}
1518

    
1519

    
1520
LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1521
  if (instr->representation().IsSmiOrInteger32()) {
1522
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1523
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1524
    HValue* left = instr->BetterLeftOperand();
1525
    HValue* right = instr->BetterRightOperand();
1526
    LOperand* left_op;
1527
    LOperand* right_op;
1528
    bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
1529
    bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero);
1530

    
1531
    if (right->IsConstant()) {
1532
      HConstant* constant = HConstant::cast(right);
1533
      int32_t constant_value = constant->Integer32Value();
1534
      // Constants -1, 0 and 1 can be optimized if the result can overflow.
1535
      // For other constants, it can be optimized only without overflow.
1536
      if (!can_overflow || ((constant_value >= -1) && (constant_value <= 1))) {
1537
        left_op = UseRegisterAtStart(left);
1538
        right_op = UseConstant(right);
1539
      } else {
1540
        if (bailout_on_minus_zero) {
1541
          left_op = UseRegister(left);
1542
        } else {
1543
          left_op = UseRegisterAtStart(left);
1544
        }
1545
        right_op = UseRegister(right);
1546
      }
1547
    } else {
1548
      if (bailout_on_minus_zero) {
1549
        left_op = UseRegister(left);
1550
      } else {
1551
        left_op = UseRegisterAtStart(left);
1552
      }
1553
      right_op = UseRegister(right);
1554
    }
1555
    LMulI* mul = new(zone()) LMulI(left_op, right_op);
1556
    if (can_overflow || bailout_on_minus_zero) {
1557
      AssignEnvironment(mul);
1558
    }
1559
    return DefineAsRegister(mul);
1560

    
1561
  } else if (instr->representation().IsDouble()) {
1562
    if (instr->UseCount() == 1 && (instr->uses().value()->IsAdd() ||
1563
                                   instr->uses().value()->IsSub())) {
1564
      HBinaryOperation* use = HBinaryOperation::cast(instr->uses().value());
1565

    
1566
      if (use->IsAdd() && instr == use->left()) {
1567
        // This mul is the lhs of an add. The add and mul will be folded into a
1568
        // multiply-add in DoAdd.
1569
        return NULL;
1570
      }
1571
      if (instr == use->right() && use->IsAdd() && !use->left()->IsMul()) {
1572
        // This mul is the rhs of an add, where the lhs is not another mul.
1573
        // The add and mul will be folded into a multiply-add in DoAdd.
1574
        return NULL;
1575
      }
1576
      if (instr == use->right() && use->IsSub()) {
1577
        // This mul is the rhs of a sub. The sub and mul will be folded into a
1578
        // multiply-sub in DoSub.
1579
        return NULL;
1580
      }
1581
    }
1582

    
1583
    return DoArithmeticD(Token::MUL, instr);
1584
  } else {
1585
    return DoArithmeticT(Token::MUL, instr);
1586
  }
1587
}
1588

    
1589

    
1590
LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1591
  if (instr->representation().IsSmiOrInteger32()) {
1592
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1593
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1594

    
1595
    if (instr->left()->IsConstant()) {
1596
      // If lhs is constant, do reverse subtraction instead.
1597
      return DoRSub(instr);
1598
    }
1599

    
1600
    LOperand* left = UseRegisterAtStart(instr->left());
1601
    LOperand* right = UseOrConstantAtStart(instr->right());
1602
    LSubI* sub = new(zone()) LSubI(left, right);
1603
    LInstruction* result = DefineAsRegister(sub);
1604
    if (instr->CheckFlag(HValue::kCanOverflow)) {
1605
      result = AssignEnvironment(result);
1606
    }
1607
    return result;
1608
  } else if (instr->representation().IsDouble()) {
1609
    if (instr->right()->IsMul()) {
1610
      return DoMultiplySub(instr->left(), HMul::cast(instr->right()));
1611
    }
1612

    
1613
    return DoArithmeticD(Token::SUB, instr);
1614
  } else {
1615
    return DoArithmeticT(Token::SUB, instr);
1616
  }
1617
}
1618

    
1619

    
1620
LInstruction* LChunkBuilder::DoRSub(HSub* instr) {
1621
  ASSERT(instr->representation().IsSmiOrInteger32());
1622
  ASSERT(instr->left()->representation().Equals(instr->representation()));
1623
  ASSERT(instr->right()->representation().Equals(instr->representation()));
1624

    
1625
  // Note: The lhs of the subtraction becomes the rhs of the
1626
  // reverse-subtraction.
1627
  LOperand* left = UseRegisterAtStart(instr->right());
1628
  LOperand* right = UseOrConstantAtStart(instr->left());
1629
  LRSubI* rsb = new(zone()) LRSubI(left, right);
1630
  LInstruction* result = DefineAsRegister(rsb);
1631
  if (instr->CheckFlag(HValue::kCanOverflow)) {
1632
    result = AssignEnvironment(result);
1633
  }
1634
  return result;
1635
}
1636

    
1637

    
1638
LInstruction* LChunkBuilder::DoMultiplyAdd(HMul* mul, HValue* addend) {
1639
  LOperand* multiplier_op = UseRegisterAtStart(mul->left());
1640
  LOperand* multiplicand_op = UseRegisterAtStart(mul->right());
1641
  LOperand* addend_op = UseRegisterAtStart(addend);
1642
  return DefineSameAsFirst(new(zone()) LMultiplyAddD(addend_op, multiplier_op,
1643
                                                     multiplicand_op));
1644
}
1645

    
1646

    
1647
LInstruction* LChunkBuilder::DoMultiplySub(HValue* minuend, HMul* mul) {
1648
  LOperand* minuend_op = UseRegisterAtStart(minuend);
1649
  LOperand* multiplier_op = UseRegisterAtStart(mul->left());
1650
  LOperand* multiplicand_op = UseRegisterAtStart(mul->right());
1651

    
1652
  return DefineSameAsFirst(new(zone()) LMultiplySubD(minuend_op,
1653
                                                     multiplier_op,
1654
                                                     multiplicand_op));
1655
}
1656

    
1657

    
1658
LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1659
  if (instr->representation().IsSmiOrInteger32()) {
1660
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1661
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1662
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1663
    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1664
    LAddI* add = new(zone()) LAddI(left, right);
1665
    LInstruction* result = DefineAsRegister(add);
1666
    if (instr->CheckFlag(HValue::kCanOverflow)) {
1667
      result = AssignEnvironment(result);
1668
    }
1669
    return result;
1670
  } else if (instr->representation().IsDouble()) {
1671
    if (instr->left()->IsMul()) {
1672
      return DoMultiplyAdd(HMul::cast(instr->left()), instr->right());
1673
    }
1674

    
1675
    if (instr->right()->IsMul()) {
1676
      ASSERT(!instr->left()->IsMul());
1677
      return DoMultiplyAdd(HMul::cast(instr->right()), instr->left());
1678
    }
1679

    
1680
    return DoArithmeticD(Token::ADD, instr);
1681
  } else {
1682
    return DoArithmeticT(Token::ADD, instr);
1683
  }
1684
}
1685

    
1686

    
1687
LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
1688
  LOperand* left = NULL;
1689
  LOperand* right = NULL;
1690
  if (instr->representation().IsSmiOrInteger32()) {
1691
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1692
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1693
    left = UseRegisterAtStart(instr->BetterLeftOperand());
1694
    right = UseOrConstantAtStart(instr->BetterRightOperand());
1695
  } else {
1696
    ASSERT(instr->representation().IsDouble());
1697
    ASSERT(instr->left()->representation().IsDouble());
1698
    ASSERT(instr->right()->representation().IsDouble());
1699
    left = UseRegisterAtStart(instr->left());
1700
    right = UseRegisterAtStart(instr->right());
1701
  }
1702
  return DefineAsRegister(new(zone()) LMathMinMax(left, right));
1703
}
1704

    
1705

    
1706
LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1707
  ASSERT(instr->representation().IsDouble());
1708
  // We call a C function for double power. It can't trigger a GC.
1709
  // We need to use fixed result register for the call.
1710
  Representation exponent_type = instr->right()->representation();
1711
  ASSERT(instr->left()->representation().IsDouble());
1712
  LOperand* left = UseFixedDouble(instr->left(), d1);
1713
  LOperand* right = exponent_type.IsDouble() ?
1714
      UseFixedDouble(instr->right(), d2) :
1715
      UseFixed(instr->right(), r2);
1716
  LPower* result = new(zone()) LPower(left, right);
1717
  return MarkAsCall(DefineFixedDouble(result, d3),
1718
                    instr,
1719
                    CAN_DEOPTIMIZE_EAGERLY);
1720
}
1721

    
1722

    
1723
LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
1724
  ASSERT(instr->representation().IsDouble());
1725
  ASSERT(instr->global_object()->representation().IsTagged());
1726
  LOperand* global_object = UseTempRegister(instr->global_object());
1727
  LOperand* scratch = TempRegister();
1728
  LOperand* scratch2 = TempRegister();
1729
  LOperand* scratch3 = TempRegister();
1730
  LRandom* result = new(zone()) LRandom(
1731
      global_object, scratch, scratch2, scratch3);
1732
  return DefineFixedDouble(result, d7);
1733
}
1734

    
1735

    
1736
LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1737
  ASSERT(instr->left()->representation().IsTagged());
1738
  ASSERT(instr->right()->representation().IsTagged());
1739
  LOperand* context = UseFixed(instr->context(), cp);
1740
  LOperand* left = UseFixed(instr->left(), r1);
1741
  LOperand* right = UseFixed(instr->right(), r0);
1742
  LCmpT* result = new(zone()) LCmpT(context, left, right);
1743
  return MarkAsCall(DefineFixed(result, r0), instr);
1744
}
1745

    
1746

    
1747
LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
1748
    HCompareNumericAndBranch* instr) {
1749
  Representation r = instr->representation();
1750
  if (r.IsSmiOrInteger32()) {
1751
    ASSERT(instr->left()->representation().Equals(r));
1752
    ASSERT(instr->right()->representation().Equals(r));
1753
    LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1754
    LOperand* right = UseRegisterOrConstantAtStart(instr->right());
1755
    return new(zone()) LCompareNumericAndBranch(left, right);
1756
  } else {
1757
    ASSERT(r.IsDouble());
1758
    ASSERT(instr->left()->representation().IsDouble());
1759
    ASSERT(instr->right()->representation().IsDouble());
1760
    LOperand* left = UseRegisterAtStart(instr->left());
1761
    LOperand* right = UseRegisterAtStart(instr->right());
1762
    return new(zone()) LCompareNumericAndBranch(left, right);
1763
  }
1764
}
1765

    
1766

    
1767
LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
1768
    HCompareObjectEqAndBranch* instr) {
1769
  LInstruction* goto_instr = CheckElideControlInstruction(instr);
1770
  if (goto_instr != NULL) return goto_instr;
1771
  LOperand* left = UseRegisterAtStart(instr->left());
1772
  LOperand* right = UseRegisterAtStart(instr->right());
1773
  return new(zone()) LCmpObjectEqAndBranch(left, right);
1774
}
1775

    
1776

    
1777
LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
1778
    HCompareHoleAndBranch* instr) {
1779
  LOperand* value = UseRegisterAtStart(instr->value());
1780
  return new(zone()) LCmpHoleAndBranch(value);
1781
}
1782

    
1783

    
1784
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
1785
  ASSERT(instr->value()->representation().IsTagged());
1786
  LOperand* value = UseRegisterAtStart(instr->value());
1787
  LOperand* temp = TempRegister();
1788
  return new(zone()) LIsObjectAndBranch(value, temp);
1789
}
1790

    
1791

    
1792
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1793
  ASSERT(instr->value()->representation().IsTagged());
1794
  LOperand* value = UseRegisterAtStart(instr->value());
1795
  LOperand* temp = TempRegister();
1796
  return new(zone()) LIsStringAndBranch(value, temp);
1797
}
1798

    
1799

    
1800
LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1801
  ASSERT(instr->value()->representation().IsTagged());
1802
  return new(zone()) LIsSmiAndBranch(Use(instr->value()));
1803
}
1804

    
1805

    
1806
LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1807
    HIsUndetectableAndBranch* instr) {
1808
  ASSERT(instr->value()->representation().IsTagged());
1809
  LOperand* value = UseRegisterAtStart(instr->value());
1810
  return new(zone()) LIsUndetectableAndBranch(value, TempRegister());
1811
}
1812

    
1813

    
1814
LInstruction* LChunkBuilder::DoStringCompareAndBranch(
1815
    HStringCompareAndBranch* instr) {
1816
  ASSERT(instr->left()->representation().IsTagged());
1817
  ASSERT(instr->right()->representation().IsTagged());
1818
  LOperand* context = UseFixed(instr->context(), cp);
1819
  LOperand* left = UseFixed(instr->left(), r1);
1820
  LOperand* right = UseFixed(instr->right(), r0);
1821
  LStringCompareAndBranch* result =
1822
      new(zone()) LStringCompareAndBranch(context, left, right);
1823
  return MarkAsCall(result, instr);
1824
}
1825

    
1826

    
1827
LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1828
    HHasInstanceTypeAndBranch* instr) {
1829
  ASSERT(instr->value()->representation().IsTagged());
1830
  LOperand* value = UseRegisterAtStart(instr->value());
1831
  return new(zone()) LHasInstanceTypeAndBranch(value);
1832
}
1833

    
1834

    
1835
LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
1836
    HGetCachedArrayIndex* instr)  {
1837
  ASSERT(instr->value()->representation().IsTagged());
1838
  LOperand* value = UseRegisterAtStart(instr->value());
1839

    
1840
  return DefineAsRegister(new(zone()) LGetCachedArrayIndex(value));
1841
}
1842

    
1843

    
1844
LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
1845
    HHasCachedArrayIndexAndBranch* instr) {
1846
  ASSERT(instr->value()->representation().IsTagged());
1847
  return new(zone()) LHasCachedArrayIndexAndBranch(
1848
      UseRegisterAtStart(instr->value()));
1849
}
1850

    
1851

    
1852
LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1853
    HClassOfTestAndBranch* instr) {
1854
  ASSERT(instr->value()->representation().IsTagged());
1855
  LOperand* value = UseRegister(instr->value());
1856
  return new(zone()) LClassOfTestAndBranch(value, TempRegister());
1857
}
1858

    
1859

    
1860
LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) {
1861
  LOperand* map = UseRegisterAtStart(instr->value());
1862
  return DefineAsRegister(new(zone()) LMapEnumLength(map));
1863
}
1864

    
1865

    
1866
LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
1867
  LOperand* object = UseRegisterAtStart(instr->value());
1868
  return DefineAsRegister(new(zone()) LElementsKind(object));
1869
}
1870

    
1871

    
1872
LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
1873
  LOperand* object = UseRegister(instr->value());
1874
  LValueOf* result = new(zone()) LValueOf(object, TempRegister());
1875
  return DefineAsRegister(result);
1876
}
1877

    
1878

    
1879
LInstruction* LChunkBuilder::DoDateField(HDateField* instr) {
1880
  LOperand* object = UseFixed(instr->value(), r0);
1881
  LDateField* result =
1882
      new(zone()) LDateField(object, FixedTemp(r1), instr->index());
1883
  return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY);
1884
}
1885

    
1886

    
1887
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
1888
  LOperand* string = UseRegister(instr->string());
1889
  LOperand* index = UseRegisterOrConstant(instr->index());
1890
  LOperand* value = UseRegister(instr->value());
1891
  return new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
1892
}
1893

    
1894

    
1895
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1896
  LOperand* value = UseRegisterOrConstantAtStart(instr->index());
1897
  LOperand* length = UseRegister(instr->length());
1898
  return AssignEnvironment(new(zone()) LBoundsCheck(value, length));
1899
}
1900

    
1901

    
1902
LInstruction* LChunkBuilder::DoBoundsCheckBaseIndexInformation(
1903
    HBoundsCheckBaseIndexInformation* instr) {
1904
  UNREACHABLE();
1905
  return NULL;
1906
}
1907

    
1908

    
1909
LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1910
  // The control instruction marking the end of a block that completed
1911
  // abruptly (e.g., threw an exception).  There is nothing specific to do.
1912
  return NULL;
1913
}
1914

    
1915

    
1916
LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
1917
  LOperand* context = UseFixed(instr->context(), cp);
1918
  LOperand* value = UseFixed(instr->value(), r0);
1919
  return MarkAsCall(new(zone()) LThrow(context, value), instr);
1920
}
1921

    
1922

    
1923
LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) {
1924
  return NULL;
1925
}
1926

    
1927

    
1928
LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
1929
  // All HForceRepresentation instructions should be eliminated in the
1930
  // representation change phase of Hydrogen.
1931
  UNREACHABLE();
1932
  return NULL;
1933
}
1934

    
1935

    
1936
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1937
  Representation from = instr->from();
1938
  Representation to = instr->to();
1939
  if (from.IsSmi()) {
1940
    if (to.IsTagged()) {
1941
      LOperand* value = UseRegister(instr->value());
1942
      return DefineSameAsFirst(new(zone()) LDummyUse(value));
1943
    }
1944
    from = Representation::Tagged();
1945
  }
1946
  if (from.IsTagged()) {
1947
    if (to.IsDouble()) {
1948
      LOperand* value = UseRegister(instr->value());
1949
      LNumberUntagD* res = new(zone()) LNumberUntagD(value);
1950
      return AssignEnvironment(DefineAsRegister(res));
1951
    } else if (to.IsSmi()) {
1952
      HValue* val = instr->value();
1953
      LOperand* value = UseRegister(val);
1954
      if (val->type().IsSmi()) {
1955
        return DefineSameAsFirst(new(zone()) LDummyUse(value));
1956
      }
1957
      return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
1958
    } else {
1959
      ASSERT(to.IsInteger32());
1960
      LOperand* value = NULL;
1961
      LInstruction* res = NULL;
1962
      HValue* val = instr->value();
1963
      if (val->type().IsSmi() || val->representation().IsSmi()) {
1964
        value = UseRegisterAtStart(val);
1965
        res = DefineAsRegister(new(zone()) LSmiUntag(value, false));
1966
      } else {
1967
        value = UseRegister(val);
1968
        LOperand* temp1 = TempRegister();
1969
        LOperand* temp2 = FixedTemp(d11);
1970
        res = DefineSameAsFirst(new(zone()) LTaggedToI(value,
1971
                                                       temp1,
1972
                                                       temp2));
1973
        res = AssignEnvironment(res);
1974
      }
1975
      return res;
1976
    }
1977
  } else if (from.IsDouble()) {
1978
    if (to.IsTagged()) {
1979
      info()->MarkAsDeferredCalling();
1980
      LOperand* value = UseRegister(instr->value());
1981
      LOperand* temp1 = TempRegister();
1982
      LOperand* temp2 = TempRegister();
1983

    
1984
      // Make sure that the temp and result_temp registers are
1985
      // different.
1986
      LUnallocated* result_temp = TempRegister();
1987
      LNumberTagD* result = new(zone()) LNumberTagD(value, temp1, temp2);
1988
      Define(result, result_temp);
1989
      return AssignPointerMap(result);
1990
    } else if (to.IsSmi()) {
1991
      LOperand* value = UseRegister(instr->value());
1992
      return AssignEnvironment(
1993
          DefineAsRegister(new(zone()) LDoubleToSmi(value)));
1994
    } else {
1995
      ASSERT(to.IsInteger32());
1996
      LOperand* value = UseRegister(instr->value());
1997
      LDoubleToI* res = new(zone()) LDoubleToI(value);
1998
      return AssignEnvironment(DefineAsRegister(res));
1999
    }
2000
  } else if (from.IsInteger32()) {
2001
    info()->MarkAsDeferredCalling();
2002
    if (to.IsTagged()) {
2003
      HValue* val = instr->value();
2004
      LOperand* value = UseRegisterAtStart(val);
2005
      if (val->CheckFlag(HInstruction::kUint32)) {
2006
        LNumberTagU* result = new(zone()) LNumberTagU(value);
2007
        return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
2008
      } else if (val->HasRange() && val->range()->IsInSmiRange()) {
2009
        return DefineAsRegister(new(zone()) LSmiTag(value));
2010
      } else {
2011
        LNumberTagI* result = new(zone()) LNumberTagI(value);
2012
        return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
2013
      }
2014
    } else if (to.IsSmi()) {
2015
      HValue* val = instr->value();
2016
      LOperand* value = UseRegister(val);
2017
      LInstruction* result = val->CheckFlag(HInstruction::kUint32)
2018
          ? DefineSameAsFirst(new(zone()) LUint32ToSmi(value))
2019
          : DefineSameAsFirst(new(zone()) LInteger32ToSmi(value));
2020
      if (val->HasRange() && val->range()->IsInSmiRange()) {
2021
        return result;
2022
      }
2023
      return AssignEnvironment(result);
2024
    } else {
2025
      ASSERT(to.IsDouble());
2026
      if (instr->value()->CheckFlag(HInstruction::kUint32)) {
2027
        return DefineAsRegister(
2028
            new(zone()) LUint32ToDouble(UseRegister(instr->value())));
2029
      } else {
2030
        return DefineAsRegister(
2031
            new(zone()) LInteger32ToDouble(Use(instr->value())));
2032
      }
2033
    }
2034
  }
2035
  UNREACHABLE();
2036
  return NULL;
2037
}
2038

    
2039

    
2040
LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
2041
  LOperand* value = UseRegisterAtStart(instr->value());
2042
  return AssignEnvironment(new(zone()) LCheckNonSmi(value));
2043
}
2044

    
2045

    
2046
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
2047
  LOperand* value = UseRegisterAtStart(instr->value());
2048
  return AssignEnvironment(new(zone()) LCheckSmi(value));
2049
}
2050

    
2051

    
2052
LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
2053
  LOperand* value = UseRegisterAtStart(instr->value());
2054
  LInstruction* result = new(zone()) LCheckInstanceType(value);
2055
  return AssignEnvironment(result);
2056
}
2057

    
2058

    
2059
LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
2060
  LOperand* value = UseRegisterAtStart(instr->value());
2061
  return AssignEnvironment(new(zone()) LCheckValue(value));
2062
}
2063

    
2064

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

    
2079

    
2080
LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
2081
  HValue* value = instr->value();
2082
  Representation input_rep = value->representation();
2083
  LOperand* reg = UseRegister(value);
2084
  if (input_rep.IsDouble()) {
2085
    return DefineAsRegister(new(zone()) LClampDToUint8(reg));
2086
  } else if (input_rep.IsInteger32()) {
2087
    return DefineAsRegister(new(zone()) LClampIToUint8(reg));
2088
  } else {
2089
    ASSERT(input_rep.IsSmiOrTagged());
2090
    // Register allocator doesn't (yet) support allocation of double
2091
    // temps. Reserve d1 explicitly.
2092
    LClampTToUint8* result = new(zone()) LClampTToUint8(reg, FixedTemp(d11));
2093
    return AssignEnvironment(DefineAsRegister(result));
2094
  }
2095
}
2096

    
2097

    
2098
LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
2099
  LOperand* context = info()->IsStub()
2100
      ? UseFixed(instr->context(), cp)
2101
      : NULL;
2102
  LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
2103
  return new(zone()) LReturn(UseFixed(instr->value(), r0), context,
2104
                             parameter_count);
2105
}
2106

    
2107

    
2108
LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
2109
  Representation r = instr->representation();
2110
  if (r.IsSmi()) {
2111
    return DefineAsRegister(new(zone()) LConstantS);
2112
  } else if (r.IsInteger32()) {
2113
    return DefineAsRegister(new(zone()) LConstantI);
2114
  } else if (r.IsDouble()) {
2115
    return DefineAsRegister(new(zone()) LConstantD);
2116
  } else if (r.IsExternal()) {
2117
    return DefineAsRegister(new(zone()) LConstantE);
2118
  } else if (r.IsTagged()) {
2119
    return DefineAsRegister(new(zone()) LConstantT);
2120
  } else {
2121
    UNREACHABLE();
2122
    return NULL;
2123
  }
2124
}
2125

    
2126

    
2127
LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
2128
  LLoadGlobalCell* result = new(zone()) LLoadGlobalCell;
2129
  return instr->RequiresHoleCheck()
2130
      ? AssignEnvironment(DefineAsRegister(result))
2131
      : DefineAsRegister(result);
2132
}
2133

    
2134

    
2135
LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
2136
  LOperand* context = UseFixed(instr->context(), cp);
2137
  LOperand* global_object = UseFixed(instr->global_object(), r0);
2138
  LLoadGlobalGeneric* result =
2139
      new(zone()) LLoadGlobalGeneric(context, global_object);
2140
  return MarkAsCall(DefineFixed(result, r0), instr);
2141
}
2142

    
2143

    
2144
LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
2145
  LOperand* value = UseRegister(instr->value());
2146
  // Use a temp to check the value in the cell in the case where we perform
2147
  // a hole check.
2148
  return instr->RequiresHoleCheck()
2149
      ? AssignEnvironment(new(zone()) LStoreGlobalCell(value, TempRegister()))
2150
      : new(zone()) LStoreGlobalCell(value, NULL);
2151
}
2152

    
2153

    
2154
LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
2155
  LOperand* context = UseFixed(instr->context(), cp);
2156
  LOperand* global_object = UseFixed(instr->global_object(), r1);
2157
  LOperand* value = UseFixed(instr->value(), r0);
2158
  LStoreGlobalGeneric* result =
2159
      new(zone()) LStoreGlobalGeneric(context, global_object, value);
2160
  return MarkAsCall(result, instr);
2161
}
2162

    
2163

    
2164
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
2165
  LOperand* context = UseRegisterAtStart(instr->value());
2166
  LInstruction* result =
2167
      DefineAsRegister(new(zone()) LLoadContextSlot(context));
2168
  return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
2169
}
2170

    
2171

    
2172
LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
2173
  LOperand* context;
2174
  LOperand* value;
2175
  if (instr->NeedsWriteBarrier()) {
2176
    context = UseTempRegister(instr->context());
2177
    value = UseTempRegister(instr->value());
2178
  } else {
2179
    context = UseRegister(instr->context());
2180
    value = UseRegister(instr->value());
2181
  }
2182
  LInstruction* result = new(zone()) LStoreContextSlot(context, value);
2183
  return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
2184
}
2185

    
2186

    
2187
LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
2188
  LOperand* obj = UseRegisterAtStart(instr->object());
2189
  return DefineAsRegister(new(zone()) LLoadNamedField(obj));
2190
}
2191

    
2192

    
2193
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
2194
  LOperand* context = UseFixed(instr->context(), cp);
2195
  LOperand* object = UseFixed(instr->object(), r0);
2196
  LInstruction* result =
2197
      DefineFixed(new(zone()) LLoadNamedGeneric(context, object), r0);
2198
  return MarkAsCall(result, instr);
2199
}
2200

    
2201

    
2202
LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
2203
    HLoadFunctionPrototype* instr) {
2204
  return AssignEnvironment(DefineAsRegister(
2205
      new(zone()) LLoadFunctionPrototype(UseRegister(instr->function()))));
2206
}
2207

    
2208

    
2209
LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
2210
  return DefineAsRegister(new(zone()) LLoadRoot);
2211
}
2212

    
2213

    
2214
LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
2215
    HLoadExternalArrayPointer* instr) {
2216
  LOperand* input = UseRegisterAtStart(instr->value());
2217
  return DefineAsRegister(new(zone()) LLoadExternalArrayPointer(input));
2218
}
2219

    
2220

    
2221
LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
2222
  ASSERT(instr->key()->representation().IsSmiOrInteger32());
2223
  ElementsKind elements_kind = instr->elements_kind();
2224
  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2225
  LLoadKeyed* result = NULL;
2226

    
2227
  if (!instr->is_external()) {
2228
    LOperand* obj = NULL;
2229
    if (instr->representation().IsDouble()) {
2230
      obj = UseRegister(instr->elements());
2231
    } else {
2232
      ASSERT(instr->representation().IsSmiOrTagged());
2233
      obj = UseRegisterAtStart(instr->elements());
2234
    }
2235
    result = new(zone()) LLoadKeyed(obj, key);
2236
  } else {
2237
    ASSERT(
2238
        (instr->representation().IsInteger32() &&
2239
         (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
2240
         (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
2241
        (instr->representation().IsDouble() &&
2242
         ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
2243
          (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
2244
    LOperand* external_pointer = UseRegister(instr->elements());
2245
    result = new(zone()) LLoadKeyed(external_pointer, key);
2246
  }
2247

    
2248
  DefineAsRegister(result);
2249
  // An unsigned int array load might overflow and cause a deopt, make sure it
2250
  // has an environment.
2251
  bool can_deoptimize = instr->RequiresHoleCheck() ||
2252
      (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS);
2253
  return can_deoptimize ? AssignEnvironment(result) : result;
2254
}
2255

    
2256

    
2257
LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
2258
  LOperand* context = UseFixed(instr->context(), cp);
2259
  LOperand* object = UseFixed(instr->object(), r1);
2260
  LOperand* key = UseFixed(instr->key(), r0);
2261

    
2262
  LInstruction* result =
2263
      DefineFixed(new(zone()) LLoadKeyedGeneric(context, object, key), r0);
2264
  return MarkAsCall(result, instr);
2265
}
2266

    
2267

    
2268
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
2269
  if (!instr->is_external()) {
2270
    ASSERT(instr->elements()->representation().IsTagged());
2271
    bool needs_write_barrier = instr->NeedsWriteBarrier();
2272
    LOperand* object = NULL;
2273
    LOperand* key = NULL;
2274
    LOperand* val = NULL;
2275

    
2276
    if (instr->value()->representation().IsDouble()) {
2277
      object = UseRegisterAtStart(instr->elements());
2278
      val = UseRegister(instr->value());
2279
      key = UseRegisterOrConstantAtStart(instr->key());
2280
    } else {
2281
      ASSERT(instr->value()->representation().IsSmiOrTagged());
2282
      if (needs_write_barrier) {
2283
        object = UseTempRegister(instr->elements());
2284
        val = UseTempRegister(instr->value());
2285
        key = UseTempRegister(instr->key());
2286
      } else {
2287
        object = UseRegisterAtStart(instr->elements());
2288
        val = UseRegisterAtStart(instr->value());
2289
        key = UseRegisterOrConstantAtStart(instr->key());
2290
      }
2291
    }
2292

    
2293
    return new(zone()) LStoreKeyed(object, key, val);
2294
  }
2295

    
2296
  ASSERT(
2297
      (instr->value()->representation().IsInteger32() &&
2298
       (instr->elements_kind() != EXTERNAL_FLOAT_ELEMENTS) &&
2299
       (instr->elements_kind() != EXTERNAL_DOUBLE_ELEMENTS)) ||
2300
      (instr->value()->representation().IsDouble() &&
2301
       ((instr->elements_kind() == EXTERNAL_FLOAT_ELEMENTS) ||
2302
        (instr->elements_kind() == EXTERNAL_DOUBLE_ELEMENTS))));
2303
  ASSERT(instr->elements()->representation().IsExternal());
2304
  LOperand* val = UseRegister(instr->value());
2305
  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2306
  LOperand* external_pointer = UseRegister(instr->elements());
2307
  return new(zone()) LStoreKeyed(external_pointer, key, val);
2308
}
2309

    
2310

    
2311
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
2312
  LOperand* context = UseFixed(instr->context(), cp);
2313
  LOperand* obj = UseFixed(instr->object(), r2);
2314
  LOperand* key = UseFixed(instr->key(), r1);
2315
  LOperand* val = UseFixed(instr->value(), r0);
2316

    
2317
  ASSERT(instr->object()->representation().IsTagged());
2318
  ASSERT(instr->key()->representation().IsTagged());
2319
  ASSERT(instr->value()->representation().IsTagged());
2320

    
2321
  return MarkAsCall(
2322
      new(zone()) LStoreKeyedGeneric(context, obj, key, val), instr);
2323
}
2324

    
2325

    
2326
LInstruction* LChunkBuilder::DoTransitionElementsKind(
2327
    HTransitionElementsKind* instr) {
2328
  LOperand* object = UseRegister(instr->object());
2329
  if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
2330
    LOperand* new_map_reg = TempRegister();
2331
    LTransitionElementsKind* result =
2332
        new(zone()) LTransitionElementsKind(object, NULL, new_map_reg);
2333
    return result;
2334
  } else {
2335
    LOperand* context = UseFixed(instr->context(), cp);
2336
    LTransitionElementsKind* result =
2337
        new(zone()) LTransitionElementsKind(object, context, NULL);
2338
    return AssignPointerMap(result);
2339
  }
2340
}
2341

    
2342

    
2343
LInstruction* LChunkBuilder::DoTrapAllocationMemento(
2344
    HTrapAllocationMemento* instr) {
2345
  LOperand* object = UseRegister(instr->object());
2346
  LOperand* temp = TempRegister();
2347
  LTrapAllocationMemento* result =
2348
      new(zone()) LTrapAllocationMemento(object, temp);
2349
  return AssignEnvironment(result);
2350
}
2351

    
2352

    
2353
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2354
  bool is_in_object = instr->access().IsInobject();
2355
  bool needs_write_barrier = instr->NeedsWriteBarrier();
2356
  bool needs_write_barrier_for_map = instr->has_transition() &&
2357
      instr->NeedsWriteBarrierForMap();
2358

    
2359
  LOperand* obj;
2360
  if (needs_write_barrier) {
2361
    obj = is_in_object
2362
        ? UseRegister(instr->object())
2363
        : UseTempRegister(instr->object());
2364
  } else {
2365
    obj = needs_write_barrier_for_map
2366
        ? UseRegister(instr->object())
2367
        : UseRegisterAtStart(instr->object());
2368
  }
2369

    
2370
  LOperand* val;
2371
  if (needs_write_barrier ||
2372
      (FLAG_track_fields && instr->field_representation().IsSmi())) {
2373
    val = UseTempRegister(instr->value());
2374
  } else if (FLAG_track_double_fields &&
2375
             instr->field_representation().IsDouble()) {
2376
    val = UseRegisterAtStart(instr->value());
2377
  } else {
2378
    val = UseRegister(instr->value());
2379
  }
2380

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

    
2384
  LStoreNamedField* result = new(zone()) LStoreNamedField(obj, val, temp);
2385
  if (FLAG_track_heap_object_fields &&
2386
      instr->field_representation().IsHeapObject()) {
2387
    if (!instr->value()->type().IsHeapObject()) {
2388
      return AssignEnvironment(result);
2389
    }
2390
  }
2391
  return result;
2392
}
2393

    
2394

    
2395
LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
2396
  LOperand* context = UseFixed(instr->context(), cp);
2397
  LOperand* obj = UseFixed(instr->object(), r1);
2398
  LOperand* val = UseFixed(instr->value(), r0);
2399

    
2400
  LInstruction* result = new(zone()) LStoreNamedGeneric(context, obj, val);
2401
  return MarkAsCall(result, instr);
2402
}
2403

    
2404

    
2405
LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2406
  LOperand* context = UseFixed(instr->context(), cp);
2407
  LOperand* left = UseRegisterAtStart(instr->left());
2408
  LOperand* right = UseRegisterAtStart(instr->right());
2409
  return MarkAsCall(
2410
      DefineFixed(new(zone()) LStringAdd(context, left, right), r0),
2411
      instr);
2412
}
2413

    
2414

    
2415
LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2416
  LOperand* string = UseTempRegister(instr->string());
2417
  LOperand* index = UseTempRegister(instr->index());
2418
  LOperand* context = UseAny(instr->context());
2419
  LStringCharCodeAt* result =
2420
      new(zone()) LStringCharCodeAt(context, string, index);
2421
  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
2422
}
2423

    
2424

    
2425
LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
2426
  LOperand* char_code = UseRegister(instr->value());
2427
  LOperand* context = UseAny(instr->context());
2428
  LStringCharFromCode* result =
2429
      new(zone()) LStringCharFromCode(context, char_code);
2430
  return AssignPointerMap(DefineAsRegister(result));
2431
}
2432

    
2433

    
2434
LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
2435
  info()->MarkAsDeferredCalling();
2436
  LOperand* context = UseAny(instr->context());
2437
  LOperand* size = instr->size()->IsConstant()
2438
      ? UseConstant(instr->size())
2439
      : UseTempRegister(instr->size());
2440
  LOperand* temp1 = TempRegister();
2441
  LOperand* temp2 = TempRegister();
2442
  LAllocate* result = new(zone()) LAllocate(context, size, temp1, temp2);
2443
  return AssignPointerMap(DefineAsRegister(result));
2444
}
2445

    
2446

    
2447
LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
2448
  LOperand* context = UseFixed(instr->context(), cp);
2449
  return MarkAsCall(
2450
      DefineFixed(new(zone()) LRegExpLiteral(context), r0), instr);
2451
}
2452

    
2453

    
2454
LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
2455
  LOperand* context = UseFixed(instr->context(), cp);
2456
  return MarkAsCall(
2457
      DefineFixed(new(zone()) LFunctionLiteral(context), r0), instr);
2458
}
2459

    
2460

    
2461
LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2462
  ASSERT(argument_count_ == 0);
2463
  allocator_->MarkAsOsrEntry();
2464
  current_block_->last_environment()->set_ast_id(instr->ast_id());
2465
  return AssignEnvironment(new(zone()) LOsrEntry);
2466
}
2467

    
2468

    
2469
LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2470
  LParameter* result = new(zone()) LParameter;
2471
  if (instr->kind() == HParameter::STACK_PARAMETER) {
2472
    int spill_index = chunk()->GetParameterStackSlot(instr->index());
2473
    return DefineAsSpilled(result, spill_index);
2474
  } else {
2475
    ASSERT(info()->IsStub());
2476
    CodeStubInterfaceDescriptor* descriptor =
2477
        info()->code_stub()->GetInterfaceDescriptor(info()->isolate());
2478
    int index = static_cast<int>(instr->index());
2479
    Register reg = DESCRIPTOR_GET_PARAMETER_REGISTER(descriptor, index);
2480
    return DefineFixed(result, reg);
2481
  }
2482
}
2483

    
2484

    
2485
LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2486
  // Use an index that corresponds to the location in the unoptimized frame,
2487
  // which the optimized frame will subsume.
2488
  int env_index = instr->index();
2489
  int spill_index = 0;
2490
  if (instr->environment()->is_parameter_index(env_index)) {
2491
    spill_index = chunk()->GetParameterStackSlot(env_index);
2492
  } else {
2493
    spill_index = env_index - instr->environment()->first_local_index();
2494
    if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
2495
      Abort(kTooManySpillSlotsNeededForOSR);
2496
      spill_index = 0;
2497
    }
2498
  }
2499
  return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
2500
}
2501

    
2502

    
2503
LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
2504
  LOperand* context = UseFixed(instr->context(), cp);
2505
  return MarkAsCall(DefineFixed(new(zone()) LCallStub(context), r0), instr);
2506
}
2507

    
2508

    
2509
LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2510
  // There are no real uses of the arguments object.
2511
  // arguments.length and element access are supported directly on
2512
  // stack arguments, and any real arguments object use causes a bailout.
2513
  // So this value is never used.
2514
  return NULL;
2515
}
2516

    
2517

    
2518
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
2519
  instr->ReplayEnvironment(current_block_->last_environment());
2520

    
2521
  // There are no real uses of a captured object.
2522
  return NULL;
2523
}
2524

    
2525

    
2526
LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2527
  info()->MarkAsRequiresFrame();
2528
  LOperand* args = UseRegister(instr->arguments());
2529
  LOperand* length;
2530
  LOperand* index;
2531
  if (instr->length()->IsConstant() && instr->index()->IsConstant()) {
2532
    length = UseRegisterOrConstant(instr->length());
2533
    index = UseOrConstant(instr->index());
2534
  } else {
2535
    length = UseTempRegister(instr->length());
2536
    index = UseRegisterAtStart(instr->index());
2537
  }
2538
  return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
2539
}
2540

    
2541

    
2542
LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
2543
  LOperand* object = UseFixed(instr->value(), r0);
2544
  LToFastProperties* result = new(zone()) LToFastProperties(object);
2545
  return MarkAsCall(DefineFixed(result, r0), instr);
2546
}
2547

    
2548

    
2549
LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2550
  LOperand* context = UseFixed(instr->context(), cp);
2551
  LTypeof* result = new(zone()) LTypeof(context, UseFixed(instr->value(), r0));
2552
  return MarkAsCall(DefineFixed(result, r0), instr);
2553
}
2554

    
2555

    
2556
LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2557
  return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value()));
2558
}
2559

    
2560

    
2561
LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
2562
    HIsConstructCallAndBranch* instr) {
2563
  return new(zone()) LIsConstructCallAndBranch(TempRegister());
2564
}
2565

    
2566

    
2567
LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2568
  instr->ReplayEnvironment(current_block_->last_environment());
2569

    
2570
  // If there is an instruction pending deoptimization environment create a
2571
  // lazy bailout instruction to capture the environment.
2572
  if (pending_deoptimization_ast_id_ == instr->ast_id()) {
2573
    LInstruction* result = new(zone()) LLazyBailout;
2574
    result = AssignEnvironment(result);
2575
    // Store the lazy deopt environment with the instruction if needed. Right
2576
    // now it is only used for LInstanceOfKnownGlobal.
2577
    instruction_pending_deoptimization_environment_->
2578
        SetDeferredLazyDeoptimizationEnvironment(result->environment());
2579
    instruction_pending_deoptimization_environment_ = NULL;
2580
    pending_deoptimization_ast_id_ = BailoutId::None();
2581
    return result;
2582
  }
2583

    
2584
  return NULL;
2585
}
2586

    
2587

    
2588
LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2589
  if (instr->is_function_entry()) {
2590
    LOperand* context = UseFixed(instr->context(), cp);
2591
    return MarkAsCall(new(zone()) LStackCheck(context), instr);
2592
  } else {
2593
    ASSERT(instr->is_backwards_branch());
2594
    LOperand* context = UseAny(instr->context());
2595
    return AssignEnvironment(
2596
        AssignPointerMap(new(zone()) LStackCheck(context)));
2597
  }
2598
}
2599

    
2600

    
2601
LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2602
  HEnvironment* outer = current_block_->last_environment();
2603
  HConstant* undefined = graph()->GetConstantUndefined();
2604
  HEnvironment* inner = outer->CopyForInlining(instr->closure(),
2605
                                               instr->arguments_count(),
2606
                                               instr->function(),
2607
                                               undefined,
2608
                                               instr->inlining_kind(),
2609
                                               instr->undefined_receiver());
2610
  // Only replay binding of arguments object if it wasn't removed from graph.
2611
  if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
2612
    inner->Bind(instr->arguments_var(), instr->arguments_object());
2613
  }
2614
  inner->set_entry(instr);
2615
  current_block_->UpdateEnvironment(inner);
2616
  chunk_->AddInlinedClosure(instr->closure());
2617
  return NULL;
2618
}
2619

    
2620

    
2621
LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2622
  LInstruction* pop = NULL;
2623

    
2624
  HEnvironment* env = current_block_->last_environment();
2625

    
2626
  if (env->entry()->arguments_pushed()) {
2627
    int argument_count = env->arguments_environment()->parameter_count();
2628
    pop = new(zone()) LDrop(argument_count);
2629
    ASSERT(instr->argument_delta() == -argument_count);
2630
  }
2631

    
2632
  HEnvironment* outer = current_block_->last_environment()->
2633
      DiscardInlined(false);
2634
  current_block_->UpdateEnvironment(outer);
2635

    
2636
  return pop;
2637
}
2638

    
2639

    
2640
LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
2641
  LOperand* context = UseFixed(instr->context(), cp);
2642
  LOperand* object = UseFixed(instr->enumerable(), r0);
2643
  LForInPrepareMap* result = new(zone()) LForInPrepareMap(context, object);
2644
  return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY);
2645
}
2646

    
2647

    
2648
LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
2649
  LOperand* map = UseRegister(instr->map());
2650
  return AssignEnvironment(DefineAsRegister(new(zone()) LForInCacheArray(map)));
2651
}
2652

    
2653

    
2654
LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
2655
  LOperand* value = UseRegisterAtStart(instr->value());
2656
  LOperand* map = UseRegisterAtStart(instr->map());
2657
  return AssignEnvironment(new(zone()) LCheckMapValue(value, map));
2658
}
2659

    
2660

    
2661
LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
2662
  LOperand* object = UseRegister(instr->object());
2663
  LOperand* index = UseRegister(instr->index());
2664
  return DefineAsRegister(new(zone()) LLoadFieldByIndex(object, index));
2665
}
2666

    
2667

    
2668
} }  // namespace v8::internal