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

28 29 30 31
#include "v8.h"

#if defined(V8_TARGET_ARCH_IA32)

32
#include "lithium-allocator-inl.h"
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
#include "ia32/lithium-ia32.h"
#include "ia32/lithium-codegen-ia32.h"

namespace v8 {
namespace internal {

#define DEFINE_COMPILE(type)                            \
  void L##type::CompileToNative(LCodeGen* generator) {  \
    generator->Do##type(this);                          \
  }
LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
#undef DEFINE_COMPILE

LOsrEntry::LOsrEntry() {
  for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) {
    register_spills_[i] = NULL;
  }
  for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; ++i) {
    double_register_spills_[i] = NULL;
  }
}


void LOsrEntry::MarkSpilledRegister(int allocation_index,
                                    LOperand* spill_operand) {
  ASSERT(spill_operand->IsStackSlot());
  ASSERT(register_spills_[allocation_index] == NULL);
  register_spills_[allocation_index] = spill_operand;
}


void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index,
                                          LOperand* spill_operand) {
  ASSERT(spill_operand->IsDoubleStackSlot());
  ASSERT(double_register_spills_[allocation_index] == NULL);
  double_register_spills_[allocation_index] = spill_operand;
}


72 73
#ifdef DEBUG
void LInstruction::VerifyCall() {
74 75 76 77
  // Call instructions can use only fixed registers as temporaries and
  // outputs because all registers are blocked by the calling convention.
  // Inputs operands must use a fixed register or use-at-start policy or
  // a non-register policy.
78 79 80
  ASSERT(Output() == NULL ||
         LUnallocated::cast(Output())->HasFixedPolicy() ||
         !LUnallocated::cast(Output())->HasRegisterPolicy());
81 82
  for (UseIterator it(this); !it.Done(); it.Advance()) {
    LUnallocated* operand = LUnallocated::cast(it.Current());
83 84
    ASSERT(operand->HasFixedPolicy() ||
           operand->IsUsedAtStart());
85
  }
86 87
  for (TempIterator it(this); !it.Done(); it.Advance()) {
    LUnallocated* operand = LUnallocated::cast(it.Current());
88
    ASSERT(operand->HasFixedPolicy() ||!operand->HasRegisterPolicy());
89 90 91 92 93
  }
}
#endif


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

  PrintOutputOperandTo(stream);
98

99 100 101 102 103 104 105 106 107 108 109 110 111 112
  PrintDataTo(stream);

  if (HasEnvironment()) {
    stream->Add(" ");
    environment()->PrintTo(stream);
  }

  if (HasPointerMap()) {
    stream->Add(" ");
    pointer_map()->PrintTo(stream);
  }
}


113
void LInstruction::PrintDataTo(StringStream* stream) {
114
  stream->Add("= ");
115
  for (int i = 0; i < InputCount(); i++) {
116
    if (i > 0) stream->Add(" ");
117
    InputAt(i)->PrintTo(stream);
118
  }
119 120 121
}


122 123
void LInstruction::PrintOutputOperandTo(StringStream* stream) {
  if (HasResult()) result()->PrintTo(stream);
124 125 126
}


127
void LLabel::PrintDataTo(StringStream* stream) {
fschneider@chromium.org's avatar
fschneider@chromium.org committed
128
  LGap::PrintDataTo(stream);
129 130 131 132 133 134 135 136 137 138 139 140 141
  LLabel* rep = replacement();
  if (rep != NULL) {
    stream->Add(" Dead block replaced with B%d", rep->block_id());
  }
}


bool LGap::IsRedundant() const {
  for (int i = 0; i < 4; i++) {
    if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
      return false;
    }
  }
fschneider@chromium.org's avatar
fschneider@chromium.org committed
142

143 144 145 146
  return true;
}


147
void LGap::PrintDataTo(StringStream* stream) {
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
  for (int i = 0; i < 4; i++) {
    stream->Add("(");
    if (parallel_moves_[i] != NULL) {
      parallel_moves_[i]->PrintDataTo(stream);
    }
    stream->Add(") ");
  }
}


const char* LArithmeticD::Mnemonic() const {
  switch (op()) {
    case Token::ADD: return "add-d";
    case Token::SUB: return "sub-d";
    case Token::MUL: return "mul-d";
    case Token::DIV: return "div-d";
    case Token::MOD: return "mod-d";
    default:
      UNREACHABLE();
      return NULL;
  }
}


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


192
void LGoto::PrintDataTo(StringStream* stream) {
193 194 195 196
  stream->Add("B%d", block_id());
}


197
void LBranch::PrintDataTo(StringStream* stream) {
198
  stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
199
  InputAt(0)->PrintTo(stream);
200 201 202
}


203
void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
204
  stream->Add("if ");
205
  InputAt(0)->PrintTo(stream);
206
  stream->Add(" %s ", Token::String(op()));
207
  InputAt(1)->PrintTo(stream);
208 209 210 211
  stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
}


212
void LIsNilAndBranch::PrintDataTo(StringStream* stream) {
213
  stream->Add("if ");
214
  InputAt(0)->PrintTo(stream);
215 216
  stream->Add(kind() == kStrictEquality ? " === " : " == ");
  stream->Add(nil() == kNullValue ? "null" : "undefined");
217 218 219 220
  stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
}


221
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
222
  stream->Add("if is_object(");
223
  InputAt(0)->PrintTo(stream);
224 225 226 227
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


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


235 236 237 238 239 240 241
void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
  stream->Add("if is_undetectable(");
  InputAt(0)->PrintTo(stream);
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


242
void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
243
  stream->Add("if has_instance_type(");
244
  InputAt(0)->PrintTo(stream);
245 246 247 248
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


249
void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
250
  stream->Add("if has_cached_array_index(");
251
  InputAt(0)->PrintTo(stream);
252 253 254 255
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


256
void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
257
  stream->Add("if class_of_test(");
258
  InputAt(0)->PrintTo(stream);
259 260 261 262 263 264 265
  stream->Add(", \"%o\") then B%d else B%d",
              *hydrogen()->class_name(),
              true_block_id(),
              false_block_id());
}


266
void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
267
  stream->Add("if typeof ");
268
  InputAt(0)->PrintTo(stream);
269 270 271 272 273 274
  stream->Add(" == \"%s\" then B%d else B%d",
              *hydrogen()->type_literal()->ToCString(),
              true_block_id(), false_block_id());
}


275
void LCallConstantFunction::PrintDataTo(StringStream* stream) {
276 277 278 279
  stream->Add("#%d / ", arity());
}


280
void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
281
  stream->Add("/%s ", hydrogen()->OpName());
282
  InputAt(0)->PrintTo(stream);
283 284 285
}


286
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
287 288 289 290 291 292 293 294 295
  InputAt(0)->PrintTo(stream);
  stream->Add("[%d]", slot_index());
}


void LStoreContextSlot::PrintDataTo(StringStream* stream) {
  InputAt(0)->PrintTo(stream);
  stream->Add("[%d] <- ", slot_index());
  InputAt(1)->PrintTo(stream);
296 297 298
}


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


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


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


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


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


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


337
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
338 339 340 341 342 343 344 345 346 347 348 349
  arguments()->PrintTo(stream);

  stream->Add(" length ");
  length()->PrintTo(stream);

  stream->Add(" index ");
  index()->PrintTo(stream);
}


int LChunk::GetNextSpillIndex(bool is_double) {
  // Skip a slot if for a double-width slot.
350 351 352 353 354
  if (is_double) {
    spill_slot_count_ |= 1;  // Make it odd, so incrementing makes it even.
    spill_slot_count_++;
    num_double_slots_++;
  }
355 356 357 358
  return spill_slot_count_++;
}


359
LOperand* LChunk::GetNextSpillSlot(bool is_double) {
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
  int index = GetNextSpillIndex(is_double);
  if (is_double) {
    return LDoubleStackSlot::Create(index);
  } else {
    return LStackSlot::Create(index);
  }
}


void LChunk::MarkEmptyBlocks() {
  HPhase phase("Mark empty blocks", this);
  for (int i = 0; i < graph()->blocks()->length(); ++i) {
    HBasicBlock* block = graph()->blocks()->at(i);
    int first = block->first_instruction_index();
    int last = block->last_instruction_index();
    LInstruction* first_instr = instructions()->at(first);
    LInstruction* last_instr = instructions()->at(last);

    LLabel* label = LLabel::cast(first_instr);
    if (last_instr->IsGoto()) {
      LGoto* goto_instr = LGoto::cast(last_instr);
381
      if (label->IsRedundant() &&
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
          !label->is_loop_header()) {
        bool can_eliminate = true;
        for (int i = first + 1; i < last && can_eliminate; ++i) {
          LInstruction* cur = instructions()->at(i);
          if (cur->IsGap()) {
            LGap* gap = LGap::cast(cur);
            if (!gap->IsRedundant()) {
              can_eliminate = false;
            }
          } else {
            can_eliminate = false;
          }
        }

        if (can_eliminate) {
          label->set_replacement(GetLabel(goto_instr->block_id()));
        }
      }
    }
  }
}


405
void LStoreNamedField::PrintDataTo(StringStream* stream) {
406 407 408 409 410 411 412 413
  object()->PrintTo(stream);
  stream->Add(".");
  stream->Add(*String::cast(*name())->ToCString());
  stream->Add(" <- ");
  value()->PrintTo(stream);
}


414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
  object()->PrintTo(stream);
  stream->Add(".");
  stream->Add(*String::cast(*name())->ToCString());
  stream->Add(" <- ");
  value()->PrintTo(stream);
}


void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) {
  object()->PrintTo(stream);
  stream->Add("[");
  key()->PrintTo(stream);
  stream->Add("] <- ");
  value()->PrintTo(stream);
}


432 433 434 435 436 437 438 439 440
void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
  elements()->PrintTo(stream);
  stream->Add("[");
  key()->PrintTo(stream);
  stream->Add("] <- ");
  value()->PrintTo(stream);
}


441
void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
442 443 444 445 446 447 448 449
  object()->PrintTo(stream);
  stream->Add("[");
  key()->PrintTo(stream);
  stream->Add("] <- ");
  value()->PrintTo(stream);
}


450 451 452 453 454 455
void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
  object()->PrintTo(stream);
  stream->Add(" %p -> %p", *original_map(), *transitioned_map());
}


456
void LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
457
  LInstructionGap* gap = new(graph_->zone()) LInstructionGap(block);
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
  int index = -1;
  if (instr->IsControl()) {
    instructions_.Add(gap);
    index = instructions_.length();
    instructions_.Add(instr);
  } else {
    index = instructions_.length();
    instructions_.Add(instr);
    instructions_.Add(gap);
  }
  if (instr->HasPointerMap()) {
    pointer_maps_.Add(instr->pointer_map());
    instr->pointer_map()->set_lithium_position(index);
  }
}


LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) {
  return LConstantOperand::Create(constant->id());
}


int LChunk::GetParameterStackSlot(int index) const {
  // The receiver is at index 0, the first parameter at index 1, so we
  // shift all parameter indexes down by the number of parameters, and
  // make sure they end up negative so they are distinguishable from
  // spill slots.
485
  int result = index - info()->scope()->num_parameters() - 1;
486 487 488 489 490 491 492
  ASSERT(result < 0);
  return result;
}

// A parameter relative to ebp in the arguments stub.
int LChunk::ParameterAt(int index) {
  ASSERT(-1 <= index);  // -1 is the receiver.
493
  return (1 + info()->scope()->num_parameters() - index) *
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
      kPointerSize;
}


LGap* LChunk::GetGapAt(int index) const {
  return LGap::cast(instructions_[index]);
}


bool LChunk::IsGapAt(int index) const {
  return instructions_[index]->IsGap();
}


int LChunk::NearestGapPos(int index) const {
  while (!IsGapAt(index)) index--;
  return index;
}


void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
  GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to);
}


Handle<Object> LChunk::LookupLiteral(LConstantOperand* operand) const {
  return HConstant::cast(graph_->LookupValue(operand->index()))->handle();
}


Representation LChunk::LookupLiteralRepresentation(
    LConstantOperand* operand) const {
  return graph_->LookupValue(operand->index())->representation();
}


LChunk* LChunkBuilder::Build() {
  ASSERT(is_unused());
532
  chunk_ = new(zone()) LChunk(info(), graph());
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
  HPhase phase("Building chunk", chunk_);
  status_ = BUILDING;
  const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
  for (int i = 0; i < blocks->length(); i++) {
    HBasicBlock* next = NULL;
    if (i < blocks->length() - 1) next = blocks->at(i + 1);
    DoBasicBlock(blocks->at(i), next);
    if (is_aborted()) return NULL;
  }
  status_ = DONE;
  return chunk_;
}


void LChunkBuilder::Abort(const char* format, ...) {
  if (FLAG_trace_bailout) {
549 550
    SmartArrayPointer<char> name(
        info()->shared_info()->DebugName()->ToCString());
551
    PrintF("Aborting LChunk building in @\"%s\": ", *name);
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
    va_list arguments;
    va_start(arguments, format);
    OS::VPrint(format, arguments);
    va_end(arguments);
    PrintF("\n");
  }
  status_ = ABORTED;
}


LRegister* LChunkBuilder::ToOperand(Register reg) {
  return LRegister::Create(Register::ToAllocationIndex(reg));
}


LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
568 569
  return new(zone()) LUnallocated(LUnallocated::FIXED_REGISTER,
                                  Register::ToAllocationIndex(reg));
570 571 572 573
}


LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
574 575
  return new(zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
                                  XMMRegister::ToAllocationIndex(reg));
576 577 578 579 580 581 582 583 584 585 586 587 588 589
}


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


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


LOperand* LChunkBuilder::UseRegister(HValue* value) {
590
  return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
591 592 593 594 595
}


LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
  return Use(value,
596 597
             new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
                                      LUnallocated::USED_AT_START));
598 599 600 601
}


LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
602
  return Use(value, new(zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
603 604 605 606
}


LOperand* LChunkBuilder::Use(HValue* value) {
607
  return Use(value, new(zone()) LUnallocated(LUnallocated::NONE));
608 609 610 611
}


LOperand* LChunkBuilder::UseAtStart(HValue* value) {
612 613
  return Use(value, new(zone()) LUnallocated(LUnallocated::NONE,
                                             LUnallocated::USED_AT_START));
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
}


LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
  return value->IsConstant()
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
      : Use(value);
}


LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
  return value->IsConstant()
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
      : UseAtStart(value);
}


LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
  return value->IsConstant()
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
      : UseRegister(value);
}


LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
  return value->IsConstant()
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
      : UseRegisterAtStart(value);
}


645 646 647
LOperand* LChunkBuilder::UseAny(HValue* value) {
  return value->IsConstant()
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
648
      :  Use(value, new(zone()) LUnallocated(LUnallocated::ANY));
649 650 651
}


652 653 654 655 656 657 658 659 660 661
LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
  if (value->EmitAtUses()) {
    HInstruction* instr = HInstruction::cast(value);
    VisitInstruction(instr);
  }
  allocator_->RecordUse(value, operand);
  return operand;
}


662 663 664 665 666 667 668 669 670 671 672
template<int I, int T>
LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
                                    LUnallocated* result) {
  allocator_->RecordDefinition(current_instruction_, result);
  instr->set_result(result);
  return instr;
}


template<int I, int T>
LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr) {
673
  return Define(instr, new(zone()) LUnallocated(LUnallocated::NONE));
674 675 676
}


677 678 679
template<int I, int T>
LInstruction* LChunkBuilder::DefineAsRegister(
    LTemplateInstruction<1, I, T>* instr) {
680 681
  return Define(instr,
                new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
682 683 684
}


685 686 687 688
template<int I, int T>
LInstruction* LChunkBuilder::DefineAsSpilled(
    LTemplateInstruction<1, I, T>* instr,
    int index) {
689 690
  return Define(instr,
                new(zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
691 692 693
}


694 695 696
template<int I, int T>
LInstruction* LChunkBuilder::DefineSameAsFirst(
    LTemplateInstruction<1, I, T>* instr) {
697 698
  return Define(instr,
                new(zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
699 700 701
}


702 703
template<int I, int T>
LInstruction* LChunkBuilder::DefineFixed(LTemplateInstruction<1, I, T>* instr,
704
                                         Register reg) {
705 706 707 708
  return Define(instr, ToUnallocated(reg));
}


709 710 711 712
template<int I, int T>
LInstruction* LChunkBuilder::DefineFixedDouble(
    LTemplateInstruction<1, I, T>* instr,
    XMMRegister reg) {
713 714 715 716 717 718
  return Define(instr, ToUnallocated(reg));
}


LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
  HEnvironment* hydrogen_env = current_block_->last_environment();
719 720 721
  int argument_index_accumulator = 0;
  instr->set_environment(CreateEnvironment(hydrogen_env,
                                           &argument_index_accumulator));
722 723 724 725
  return instr;
}


726 727
LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
    LInstruction* instr, int ast_id) {
728
  ASSERT(instruction_pending_deoptimization_environment_ == NULL);
729
  ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
730
  instruction_pending_deoptimization_environment_ = instr;
731 732 733 734 735 736
  pending_deoptimization_ast_id_ = ast_id;
  return instr;
}


void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
737
  instruction_pending_deoptimization_environment_ = NULL;
738 739 740 741
  pending_deoptimization_ast_id_ = AstNode::kNoNumber;
}


742 743 744
LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
                                        HInstruction* hinstr,
                                        CanDeoptimize can_deoptimize) {
745 746 747 748
#ifdef DEBUG
  instr->VerifyCall();
#endif
  instr->MarkAsCall();
749 750
  instr = AssignPointerMap(instr);

751
  if (hinstr->HasObservableSideEffects()) {
752 753
    ASSERT(hinstr->next()->IsSimulate());
    HSimulate* sim = HSimulate::cast(hinstr->next());
754 755
    instr = SetInstructionPendingDeoptimizationEnvironment(
        instr, sim->ast_id());
756 757 758 759 760 761 762
  }

  // If instruction does not have side-effects lazy deoptimization
  // after the call will try to deoptimize to the point before the call.
  // Thus we still need to attach environment to this call even if
  // call sequence can not deoptimize eagerly.
  bool needs_environment =
763 764
      (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
      !hinstr->HasObservableSideEffects();
765 766 767 768 769 770 771 772
  if (needs_environment && !instr->HasEnvironment()) {
    instr = AssignEnvironment(instr);
  }

  return instr;
}


773
LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) {
774
  instr->MarkAsSaveDoubles();
775 776 777 778
  return instr;
}


779 780
LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
  ASSERT(!instr->HasPointerMap());
781
  instr->set_pointer_map(new(zone()) LPointerMap(position_));
782 783 784 785 786
  return instr;
}


LUnallocated* LChunkBuilder::TempRegister() {
787 788
  LUnallocated* operand =
      new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808
  allocator_->RecordTemporary(operand);
  return operand;
}


LOperand* LChunkBuilder::FixedTemp(Register reg) {
  LUnallocated* operand = ToUnallocated(reg);
  allocator_->RecordTemporary(operand);
  return operand;
}


LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) {
  LUnallocated* operand = ToUnallocated(reg);
  allocator_->RecordTemporary(operand);
  return operand;
}


LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
809
  return new(zone()) LLabel(instr->block());
810 811 812
}


813
LInstruction* LChunkBuilder::DoSoftDeoptimize(HSoftDeoptimize* instr) {
814
  return AssignEnvironment(new(zone()) LDeoptimize);
815 816 817
}


818
LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
819
  return AssignEnvironment(new(zone()) LDeoptimize);
820 821 822 823 824
}


LInstruction* LChunkBuilder::DoShift(Token::Value op,
                                     HBitwiseBinaryOperation* instr) {
825 826 827 828
  if (instr->representation().IsTagged()) {
    ASSERT(instr->left()->representation().IsTagged());
    ASSERT(instr->right()->representation().IsTagged());

829
    LOperand* context = UseFixed(instr->context(), esi);
830 831
    LOperand* left = UseFixed(instr->left(), edx);
    LOperand* right = UseFixed(instr->right(), eax);
832
    LArithmeticT* result = new(zone()) LArithmeticT(op, context, left, right);
833 834 835
    return MarkAsCall(DefineFixed(result, eax), instr);
  }

836
  ASSERT(instr->representation().IsInteger32());
837 838 839
  ASSERT(instr->left()->representation().IsInteger32());
  ASSERT(instr->right()->representation().IsInteger32());
  LOperand* left = UseRegisterAtStart(instr->left());
840

841
  HValue* right_value = instr->right();
842 843 844 845 846 847 848 849 850 851
  LOperand* right = NULL;
  int constant_value = 0;
  if (right_value->IsConstant()) {
    HConstant* constant = HConstant::cast(right_value);
    right = chunk_->DefineConstantOperand(constant);
    constant_value = constant->Integer32Value() & 0x1f;
  } else {
    right = UseFixed(right_value, ecx);
  }

852 853 854 855 856 857 858 859
  // Shift operations can only deoptimize if we do a logical shift by 0 and
  // the result cannot be truncated to int32.
  bool may_deopt = (op == Token::SHR && constant_value == 0);
  bool does_deopt = false;
  if (may_deopt) {
    for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
      if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
        does_deopt = true;
860 861 862 863 864
        break;
      }
    }
  }

865
  LInstruction* result =
866
      DefineSameAsFirst(new(zone()) LShiftI(op, left, right, does_deopt));
867
  return does_deopt ? AssignEnvironment(result) : result;
868 869 870 871 872 873 874 875
}


LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
                                           HArithmeticBinaryOperation* instr) {
  ASSERT(instr->representation().IsDouble());
  ASSERT(instr->left()->representation().IsDouble());
  ASSERT(instr->right()->representation().IsDouble());
876 877 878
  ASSERT(op != Token::MOD);
  LOperand* left = UseRegisterAtStart(instr->left());
  LOperand* right = UseRegisterAtStart(instr->right());
879
  LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
880
  return DefineSameAsFirst(result);
881 882 883 884 885 886 887 888 889 890 891 892 893 894
}


LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
                                           HArithmeticBinaryOperation* instr) {
  ASSERT(op == Token::ADD ||
         op == Token::DIV ||
         op == Token::MOD ||
         op == Token::MUL ||
         op == Token::SUB);
  HValue* left = instr->left();
  HValue* right = instr->right();
  ASSERT(left->representation().IsTagged());
  ASSERT(right->representation().IsTagged());
895
  LOperand* context = UseFixed(instr->context(), esi);
896 897
  LOperand* left_operand = UseFixed(left, edx);
  LOperand* right_operand = UseFixed(right, eax);
898
  LArithmeticT* result =
899
      new(zone()) LArithmeticT(op, context, left_operand, right_operand);
900 901 902
  return MarkAsCall(DefineFixed(result, eax), instr);
}

903

904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979
void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
  ASSERT(is_building());
  current_block_ = block;
  next_block_ = next_block;
  if (block->IsStartBlock()) {
    block->UpdateEnvironment(graph_->start_environment());
    argument_count_ = 0;
  } else if (block->predecessors()->length() == 1) {
    // We have a single predecessor => copy environment and outgoing
    // argument count from the predecessor.
    ASSERT(block->phis()->length() == 0);
    HBasicBlock* pred = block->predecessors()->at(0);
    HEnvironment* last_environment = pred->last_environment();
    ASSERT(last_environment != NULL);
    // Only copy the environment, if it is later used again.
    if (pred->end()->SecondSuccessor() == NULL) {
      ASSERT(pred->end()->FirstSuccessor() == block);
    } else {
      if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
          pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
        last_environment = last_environment->Copy();
      }
    }
    block->UpdateEnvironment(last_environment);
    ASSERT(pred->argument_count() >= 0);
    argument_count_ = pred->argument_count();
  } else {
    // We are at a state join => process phis.
    HBasicBlock* pred = block->predecessors()->at(0);
    // No need to copy the environment, it cannot be used later.
    HEnvironment* last_environment = pred->last_environment();
    for (int i = 0; i < block->phis()->length(); ++i) {
      HPhi* phi = block->phis()->at(i);
      last_environment->SetValueAt(phi->merged_index(), phi);
    }
    for (int i = 0; i < block->deleted_phis()->length(); ++i) {
      last_environment->SetValueAt(block->deleted_phis()->at(i),
                                   graph_->GetConstantUndefined());
    }
    block->UpdateEnvironment(last_environment);
    // Pick up the outgoing argument count of one of the predecessors.
    argument_count_ = pred->argument_count();
  }
  HInstruction* current = block->first();
  int start = chunk_->instructions()->length();
  while (current != NULL && !is_aborted()) {
    // Code for constants in registers is generated lazily.
    if (!current->EmitAtUses()) {
      VisitInstruction(current);
    }
    current = current->next();
  }
  int end = chunk_->instructions()->length() - 1;
  if (end >= start) {
    block->set_first_instruction_index(start);
    block->set_last_instruction_index(end);
  }
  block->set_argument_count(argument_count_);
  next_block_ = NULL;
  current_block_ = NULL;
}


void LChunkBuilder::VisitInstruction(HInstruction* current) {
  HInstruction* old_current = current_instruction_;
  current_instruction_ = current;
  if (current->has_position()) position_ = current->position();
  LInstruction* instr = current->CompileToLithium(this);

  if (instr != NULL) {
    if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
      instr = AssignPointerMap(instr);
    }
    if (FLAG_stress_environments && !instr->HasEnvironment()) {
      instr = AssignEnvironment(instr);
    }
980
    instr->set_hydrogen_value(current);
981
    chunk_->AddInstruction(instr, current_block_);
982 983 984 985 986
  }
  current_instruction_ = old_current;
}


987 988 989
LEnvironment* LChunkBuilder::CreateEnvironment(
    HEnvironment* hydrogen_env,
    int* argument_index_accumulator) {
990 991
  if (hydrogen_env == NULL) return NULL;

992 993
  LEnvironment* outer =
      CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator);
994 995
  int ast_id = hydrogen_env->ast_id();
  ASSERT(ast_id != AstNode::kNoNumber);
996
  int value_count = hydrogen_env->length();
997 998 999 1000 1001 1002 1003
  LEnvironment* result =
      new(zone()) LEnvironment(hydrogen_env->closure(),
                               ast_id,
                               hydrogen_env->parameter_count(),
                               argument_count_,
                               value_count,
                               outer);
1004
  for (int i = 0; i < value_count; ++i) {
1005 1006
    if (hydrogen_env->is_special_index(i)) continue;

1007 1008 1009 1010 1011
    HValue* value = hydrogen_env->values()->at(i);
    LOperand* op = NULL;
    if (value->IsArgumentsObject()) {
      op = NULL;
    } else if (value->IsPushArgument()) {
1012
      op = new(zone()) LArgument((*argument_index_accumulator)++);
1013
    } else {
1014
      op = UseAny(value);
1015 1016 1017 1018 1019 1020 1021 1022 1023
    }
    result->AddValue(op, value->representation());
  }

  return result;
}


LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
1024
  return new(zone()) LGoto(instr->FirstSuccessor()->block_id());
1025 1026 1027
}


1028
LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
1029
  HValue* v = instr->value();
1030 1031 1032
  if (v->EmitAtUses()) {
    ASSERT(v->IsConstant());
    ASSERT(!v->representation().IsDouble());
1033 1034 1035
    HBasicBlock* successor = HConstant::cast(v)->ToBoolean()
        ? instr->FirstSuccessor()
        : instr->SecondSuccessor();
1036
    return new(zone()) LGoto(successor->block_id());
1037
  }
1038
  ToBooleanStub::Types expected = instr->expected_input_types();
1039 1040 1041
  // We need a temporary register when we have to access the map *or* we have
  // no type info yet, in which case we handle all cases (including the ones
  // involving maps).
1042 1043
  bool needs_temp = expected.NeedsMap() || expected.IsEmpty();
  LOperand* temp = needs_temp ? TempRegister() : NULL;
1044
  return AssignEnvironment(new(zone()) LBranch(UseRegister(v), temp));
1045 1046 1047
}


1048
LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
1049 1050
  ASSERT(instr->value()->representation().IsTagged());
  LOperand* value = UseRegisterAtStart(instr->value());
1051
  return new(zone()) LCmpMapAndBranch(value);
1052 1053 1054 1055
}


LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
1056
  return DefineAsRegister(new(zone()) LArgumentsLength(Use(length->value())));
1057 1058 1059 1060
}


LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
1061
  return DefineAsRegister(new(zone()) LArgumentsElements);
1062 1063 1064 1065
}


LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
1066 1067 1068
  LOperand* left = UseFixed(instr->left(), InstanceofStub::left());
  LOperand* right = UseFixed(instr->right(), InstanceofStub::right());
  LOperand* context = UseFixed(instr->context(), esi);
1069
  LInstanceOf* result = new(zone()) LInstanceOf(context, left, right);
1070 1071 1072 1073
  return MarkAsCall(DefineFixed(result, eax), instr);
}


1074 1075
LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
    HInstanceOfKnownGlobal* instr) {
1076
  LInstanceOfKnownGlobal* result =
1077
      new(zone()) LInstanceOfKnownGlobal(
1078 1079
          UseFixed(instr->context(), esi),
          UseFixed(instr->left(), InstanceofStub::left()),
1080
          FixedTemp(edi));
1081
  return MarkAsCall(DefineFixed(result, eax), instr);
1082 1083 1084
}


1085 1086 1087
LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
  LOperand* function = UseFixed(instr->function(), edi);
  LOperand* receiver = UseFixed(instr->receiver(), eax);
1088 1089 1090
  LOperand* length = UseFixed(instr->length(), ebx);
  LOperand* elements = UseFixed(instr->elements(), ecx);
  LOperand* temp = FixedTemp(edx);
1091 1092 1093 1094 1095
  LApplyArguments* result = new(zone()) LApplyArguments(function,
                                                        receiver,
                                                        length,
                                                        elements,
                                                        temp);
1096 1097 1098 1099 1100 1101
  return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY);
}


LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
  ++argument_count_;
1102
  LOperand* argument = UseAny(instr->argument());
1103
  return new(zone()) LPushArgument(argument);
1104 1105 1106
}


1107
LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
1108 1109 1110
  return instr->HasNoUses()
      ? NULL
      : DefineAsRegister(new(zone()) LThisFunction);
1111 1112 1113
}


1114
LInstruction* LChunkBuilder::DoContext(HContext* instr) {
1115
  return instr->HasNoUses() ? NULL : DefineAsRegister(new(zone()) LContext);
1116 1117 1118 1119 1120
}


LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
  LOperand* context = UseRegisterAtStart(instr->value());
1121
  return DefineAsRegister(new(zone()) LOuterContext(context));
1122 1123 1124
}


1125
LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
1126
  LOperand* context = UseRegisterAtStart(instr->value());
1127
  return DefineAsRegister(new(zone()) LGlobalObject(context));
1128 1129 1130 1131
}


LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
1132
  LOperand* global_object = UseRegisterAtStart(instr->value());
1133
  return DefineAsRegister(new(zone()) LGlobalReceiver(global_object));
1134 1135 1136 1137 1138 1139
}


LInstruction* LChunkBuilder::DoCallConstantFunction(
    HCallConstantFunction* instr) {
  argument_count_ -= instr->argument_count();
1140
  return MarkAsCall(DefineFixed(new(zone()) LCallConstantFunction, eax), instr);
1141 1142 1143
}


1144 1145 1146 1147
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
  LOperand* context = UseFixed(instr->context(), esi);
  LOperand* function = UseFixed(instr->function(), edi);
  argument_count_ -= instr->argument_count();
1148
  LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
1149 1150 1151 1152
  return MarkAsCall(DefineFixed(result, eax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
}


1153
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1154
  BuiltinFunctionId op = instr->op();
1155 1156 1157
  if (op == kMathLog) {
    ASSERT(instr->representation().IsDouble());
    ASSERT(instr->value()->representation().IsDouble());
1158
    LOperand* context = UseAny(instr->context());  // Not actually used.
1159
    LOperand* input = UseRegisterAtStart(instr->value());
1160 1161
    LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
                                                                  input);
1162 1163
    return DefineSameAsFirst(result);
  } else if (op == kMathSin || op == kMathCos) {
1164
    LOperand* context = UseFixed(instr->context(), esi);
1165
    LOperand* input = UseFixedDouble(instr->value(), xmm1);
1166 1167
    LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
                                                                  input);
1168 1169 1170
    return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
  } else {
    LOperand* input = UseRegisterAtStart(instr->value());
1171
    LOperand* context = UseAny(instr->context());  // Deferred use by MathAbs.
1172 1173
    LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
                                                                  input);
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183
    switch (op) {
      case kMathAbs:
        return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
      case kMathFloor:
        return AssignEnvironment(DefineAsRegister(result));
      case kMathRound:
        return AssignEnvironment(DefineAsRegister(result));
      case kMathSqrt:
        return DefineSameAsFirst(result);
      case kMathPowHalf:
1184
        return DefineSameAsFirst(result);
1185 1186 1187 1188
      default:
        UNREACHABLE();
        return NULL;
    }
1189 1190 1191 1192 1193 1194
  }
}


LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
  ASSERT(instr->key()->representation().IsTagged());
1195
  LOperand* context = UseFixed(instr->context(), esi);
1196
  LOperand* key = UseFixed(instr->key(), ecx);
1197
  argument_count_ -= instr->argument_count();
1198
  LCallKeyed* result = new(zone()) LCallKeyed(context, key);
1199
  return MarkAsCall(DefineFixed(result, eax), instr);
1200 1201 1202 1203
}


LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
1204
  LOperand* context = UseFixed(instr->context(), esi);
1205
  argument_count_ -= instr->argument_count();
1206
  LCallNamed* result = new(zone()) LCallNamed(context);
1207
  return MarkAsCall(DefineFixed(result, eax), instr);
1208 1209 1210 1211
}


LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
1212
  LOperand* context = UseFixed(instr->context(), esi);
1213
  argument_count_ -= instr->argument_count();
1214
  LCallGlobal* result = new(zone()) LCallGlobal(context);
1215
  return MarkAsCall(DefineFixed(result, eax), instr);
1216 1217 1218 1219 1220
}


LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
  argument_count_ -= instr->argument_count();
1221
  return MarkAsCall(DefineFixed(new(zone()) LCallKnownGlobal, eax), instr);
1222 1223 1224 1225
}


LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
1226
  LOperand* context = UseFixed(instr->context(), esi);
1227 1228
  LOperand* constructor = UseFixed(instr->constructor(), edi);
  argument_count_ -= instr->argument_count();
1229
  LCallNew* result = new(zone()) LCallNew(context, constructor);
1230 1231 1232 1233 1234
  return MarkAsCall(DefineFixed(result, eax), instr);
}


LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1235
  LOperand* context = UseFixed(instr->context(), esi);
1236
  LOperand* function = UseFixed(instr->function(), edi);
1237
  argument_count_ -= instr->argument_count();
1238
  LCallFunction* result = new(zone()) LCallFunction(context, function);
1239
  return MarkAsCall(DefineFixed(result, eax), instr);
1240 1241 1242 1243 1244
}


LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
  argument_count_ -= instr->argument_count();
1245
  LOperand* context = UseFixed(instr->context(), esi);
1246
  return MarkAsCall(DefineFixed(new(zone()) LCallRuntime(context), eax), instr);
1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264
}


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


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


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


1265 1266 1267 1268 1269 1270 1271
LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
  if (instr->representation().IsInteger32()) {
    ASSERT(instr->left()->representation().IsInteger32());
    ASSERT(instr->right()->representation().IsInteger32());

    LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
    LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1272
    return DefineSameAsFirst(new(zone()) LBitI(left, right));
1273 1274 1275 1276 1277 1278 1279 1280
  } else {
    ASSERT(instr->representation().IsTagged());
    ASSERT(instr->left()->representation().IsTagged());
    ASSERT(instr->right()->representation().IsTagged());

    LOperand* context = UseFixed(instr->context(), esi);
    LOperand* left = UseFixed(instr->left(), edx);
    LOperand* right = UseFixed(instr->right(), eax);
1281 1282
    LArithmeticT* result =
        new(zone()) LArithmeticT(instr->op(), context, left, right);
1283 1284
    return MarkAsCall(DefineFixed(result, eax), instr);
  }
1285 1286 1287 1288 1289 1290
}


LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
  ASSERT(instr->value()->representation().IsInteger32());
  ASSERT(instr->representation().IsInteger32());
1291
  LOperand* input = UseRegisterAtStart(instr->value());
1292
  LBitNotI* result = new(zone()) LBitNotI(input);
1293
  return DefineSameAsFirst(result);
1294 1295 1296 1297 1298 1299 1300 1301 1302
}


LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
  if (instr->representation().IsDouble()) {
    return DoArithmeticD(Token::DIV, instr);
  } else if (instr->representation().IsInteger32()) {
    // The temporary operand is necessary to ensure that right is not allocated
    // into edx.
1303
    LOperand* temp = FixedTemp(edx);
1304
    LOperand* dividend = UseFixed(instr->left(), eax);
1305
    LOperand* divisor = UseRegister(instr->right());
1306
    LDivI* result = new(zone()) LDivI(dividend, divisor, temp);
1307
    return AssignEnvironment(DefineFixed(result, eax));
1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318
  } else {
    ASSERT(instr->representation().IsTagged());
    return DoArithmeticT(Token::DIV, instr);
  }
}


LInstruction* LChunkBuilder::DoMod(HMod* instr) {
  if (instr->representation().IsInteger32()) {
    ASSERT(instr->left()->representation().IsInteger32());
    ASSERT(instr->right()->representation().IsInteger32());
1319 1320 1321 1322 1323

    LInstruction* result;
    if (instr->HasPowerOf2Divisor()) {
      ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
      LOperand* value = UseRegisterAtStart(instr->left());
1324 1325
      LModI* mod =
          new(zone()) LModI(value, UseOrConstant(instr->right()), NULL);
1326 1327 1328 1329 1330 1331 1332
      result = DefineSameAsFirst(mod);
    } else {
      // The temporary operand is necessary to ensure that right is
      // not allocated into edx.
      LOperand* temp = FixedTemp(edx);
      LOperand* value = UseFixed(instr->left(), eax);
      LOperand* divisor = UseRegister(instr->right());
1333
      LModI* mod = new(zone()) LModI(value, divisor, temp);
1334 1335 1336
      result = DefineFixed(mod, edx);
    }

1337 1338 1339 1340
    return (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
            instr->CheckFlag(HValue::kCanBeDivByZero))
        ? AssignEnvironment(result)
        : result;
1341 1342 1343 1344 1345 1346 1347
  } else if (instr->representation().IsTagged()) {
    return DoArithmeticT(Token::MOD, instr);
  } else {
    ASSERT(instr->representation().IsDouble());
    // We call a C function for double modulo. It can't trigger a GC.
    // We need to use fixed result register for the call.
    // TODO(fschneider): Allow any register as input registers.
1348 1349
    LOperand* left = UseFixedDouble(instr->left(), xmm2);
    LOperand* right = UseFixedDouble(instr->right(), xmm1);
1350
    LArithmeticD* result = new(zone()) LArithmeticD(Token::MOD, left, right);
1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365
    return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
  }
}


LInstruction* LChunkBuilder::DoMul(HMul* instr) {
  if (instr->representation().IsInteger32()) {
    ASSERT(instr->left()->representation().IsInteger32());
    ASSERT(instr->right()->representation().IsInteger32());
    LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
    LOperand* right = UseOrConstant(instr->MostConstantOperand());
    LOperand* temp = NULL;
    if (instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
      temp = TempRegister();
    }
1366
    LMulI* mul = new(zone()) LMulI(left, right, temp);
1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380
    return AssignEnvironment(DefineSameAsFirst(mul));
  } else if (instr->representation().IsDouble()) {
    return DoArithmeticD(Token::MUL, instr);
  } else {
    ASSERT(instr->representation().IsTagged());
    return DoArithmeticT(Token::MUL, instr);
  }
}


LInstruction* LChunkBuilder::DoSub(HSub* instr) {
  if (instr->representation().IsInteger32()) {
    ASSERT(instr->left()->representation().IsInteger32());
    ASSERT(instr->right()->representation().IsInteger32());
1381 1382
    LOperand* left = UseRegisterAtStart(instr->left());
    LOperand* right = UseOrConstantAtStart(instr->right());
1383
    LSubI* sub = new(zone()) LSubI(left, right);
1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403
    LInstruction* result = DefineSameAsFirst(sub);
    if (instr->CheckFlag(HValue::kCanOverflow)) {
      result = AssignEnvironment(result);
    }
    return result;
  } else if (instr->representation().IsDouble()) {
    return DoArithmeticD(Token::SUB, instr);
  } else {
    ASSERT(instr->representation().IsTagged());
    return DoArithmeticT(Token::SUB, instr);
  }
}


LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
  if (instr->representation().IsInteger32()) {
    ASSERT(instr->left()->representation().IsInteger32());
    ASSERT(instr->right()->representation().IsInteger32());
    LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
    LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1404
    LAddI* add = new(zone()) LAddI(left, right);
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418
    LInstruction* result = DefineSameAsFirst(add);
    if (instr->CheckFlag(HValue::kCanOverflow)) {
      result = AssignEnvironment(result);
    }
    return result;
  } else if (instr->representation().IsDouble()) {
    return DoArithmeticD(Token::ADD, instr);
  } else {
    ASSERT(instr->representation().IsTagged());
    return DoArithmeticT(Token::ADD, instr);
  }
}


1419 1420 1421 1422 1423 1424 1425 1426 1427 1428
LInstruction* LChunkBuilder::DoPower(HPower* instr) {
  ASSERT(instr->representation().IsDouble());
  // We call a C function for double power. It can't trigger a GC.
  // We need to use fixed result register for the call.
  Representation exponent_type = instr->right()->representation();
  ASSERT(instr->left()->representation().IsDouble());
  LOperand* left = UseFixedDouble(instr->left(), xmm1);
  LOperand* right = exponent_type.IsDouble() ?
      UseFixedDouble(instr->right(), xmm2) :
      UseFixed(instr->right(), eax);
1429
  LPower* result = new(zone()) LPower(left, right);
1430
  return MarkAsCall(DefineFixedDouble(result, xmm3), instr,
1431 1432 1433 1434
                    CAN_DEOPTIMIZE_EAGERLY);
}


1435 1436 1437
LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
  ASSERT(instr->left()->representation().IsTagged());
  ASSERT(instr->right()->representation().IsTagged());
1438
  LOperand* context = UseFixed(instr->context(), esi);
1439 1440
  LOperand* left = UseFixed(instr->left(), edx);
  LOperand* right = UseFixed(instr->right(), eax);
1441
  LCmpT* result = new(zone()) LCmpT(context, left, right);
1442 1443 1444 1445 1446 1447
  return MarkAsCall(DefineFixed(result, eax), instr);
}


LInstruction* LChunkBuilder::DoCompareIDAndBranch(
    HCompareIDAndBranch* instr) {
1448 1449 1450
  Representation r = instr->GetInputRepresentation();
  if (r.IsInteger32()) {
    ASSERT(instr->left()->representation().IsInteger32());
1451
    ASSERT(instr->right()->representation().IsInteger32());
1452
    LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1453
    LOperand* right = UseOrConstantAtStart(instr->right());
1454
    return new(zone()) LCmpIDAndBranch(left, right);
1455 1456
  } else {
    ASSERT(r.IsDouble());
1457
    ASSERT(instr->left()->representation().IsDouble());
1458
    ASSERT(instr->right()->representation().IsDouble());
1459 1460 1461 1462 1463 1464 1465 1466 1467
    LOperand* left;
    LOperand* right;
    if (instr->left()->IsConstant() && instr->right()->IsConstant()) {
      left = UseRegisterOrConstantAtStart(instr->left());
      right = UseRegisterOrConstantAtStart(instr->right());
    } else {
      left = UseRegisterAtStart(instr->left());
      right = UseRegisterAtStart(instr->right());
    }
1468
    return new(zone()) LCmpIDAndBranch(left, right);
1469 1470 1471 1472
  }
}


1473 1474
LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
    HCompareObjectEqAndBranch* instr) {
1475
  LOperand* left = UseRegisterAtStart(instr->left());
1476
  LOperand* right = UseAtStart(instr->right());
1477
  return new(zone()) LCmpObjectEqAndBranch(left, right);
1478 1479 1480
}


1481 1482
LInstruction* LChunkBuilder::DoCompareConstantEqAndBranch(
  HCompareConstantEqAndBranch* instr) {
1483 1484
  return new(zone()) LCmpConstantEqAndBranch(
      UseRegisterAtStart(instr->value()));
1485 1486 1487
}


1488
LInstruction* LChunkBuilder::DoIsNilAndBranch(HIsNilAndBranch* instr) {
1489
  // We only need a temp register for non-strict compare.
1490
  LOperand* temp = instr->kind() == kStrictEquality ? NULL : TempRegister();
1491
  return new(zone()) LIsNilAndBranch(UseRegisterAtStart(instr->value()), temp);
1492 1493 1494
}


1495
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
1496
  ASSERT(instr->value()->representation().IsTagged());
1497
  LOperand* temp = TempRegister();
1498
  return new(zone()) LIsObjectAndBranch(UseRegister(instr->value()), temp);
1499 1500 1501
}


1502
LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1503
  ASSERT(instr->value()->representation().IsTagged());
1504
  return new(zone()) LIsSmiAndBranch(Use(instr->value()));
1505 1506 1507
}


1508 1509 1510
LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
    HIsUndetectableAndBranch* instr) {
  ASSERT(instr  ->value()->representation().IsTagged());
1511 1512
  return new(zone()) LIsUndetectableAndBranch(
      UseRegisterAtStart(instr->value()), TempRegister());
1513 1514 1515
}


1516 1517
LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
    HHasInstanceTypeAndBranch* instr) {
1518
  ASSERT(instr->value()->representation().IsTagged());
1519 1520 1521
  return new(zone()) LHasInstanceTypeAndBranch(
      UseRegisterAtStart(instr->value()),
      TempRegister());
1522 1523 1524
}


1525 1526
LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
    HGetCachedArrayIndex* instr)  {
1527 1528 1529
  ASSERT(instr->value()->representation().IsTagged());
  LOperand* value = UseRegisterAtStart(instr->value());

1530
  return DefineAsRegister(new(zone()) LGetCachedArrayIndex(value));
1531 1532 1533
}


1534 1535
LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
    HHasCachedArrayIndexAndBranch* instr) {
1536
  ASSERT(instr->value()->representation().IsTagged());
1537
  return new(zone()) LHasCachedArrayIndexAndBranch(
1538
      UseRegisterAtStart(instr->value()));
1539 1540 1541
}


1542 1543
LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
    HClassOfTestAndBranch* instr) {
1544
  ASSERT(instr->value()->representation().IsTagged());
1545
  return new(zone()) LClassOfTestAndBranch(UseTempRegister(instr->value()),
1546 1547
                                   TempRegister(),
                                   TempRegister());
1548 1549 1550
}


1551 1552
LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
  LOperand* array = UseRegisterAtStart(instr->value());
1553
  return DefineAsRegister(new(zone()) LJSArrayLength(array));
1554
}
1555 1556


1557 1558
LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
    HFixedArrayBaseLength* instr) {
1559
  LOperand* array = UseRegisterAtStart(instr->value());
1560
  return DefineAsRegister(new(zone()) LFixedArrayBaseLength(array));
1561 1562 1563
}


1564 1565
LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
  LOperand* object = UseRegisterAtStart(instr->value());
1566
  return DefineAsRegister(new(zone()) LElementsKind(object));
1567 1568 1569
}


1570 1571
LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
  LOperand* object = UseRegister(instr->value());
1572
  LValueOf* result = new(zone()) LValueOf(object, TempRegister());
1573 1574 1575 1576 1577
  return AssignEnvironment(DefineSameAsFirst(result));
}


LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1578
  return AssignEnvironment(new(zone()) LBoundsCheck(
1579 1580
      UseRegisterOrConstantAtStart(instr->index()),
      UseAtStart(instr->length())));
1581 1582 1583
}


1584 1585 1586 1587 1588 1589 1590
LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
  // The control instruction marking the end of a block that completed
  // abruptly (e.g., threw an exception).  There is nothing specific to do.
  return NULL;
}


1591
LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
1592
  LOperand* context = UseFixed(instr->context(), esi);
1593
  LOperand* value = UseFixed(instr->value(), eax);
1594
  return MarkAsCall(new(zone()) LThrow(context, value), instr);
1595 1596 1597
}


1598 1599 1600 1601 1602
LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) {
  return NULL;
}


1603 1604 1605 1606 1607 1608 1609 1610
LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
  // All HForceRepresentation instructions should be eliminated in the
  // representation change phase of Hydrogen.
  UNREACHABLE();
  return NULL;
}


1611 1612 1613 1614 1615 1616
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
  Representation from = instr->from();
  Representation to = instr->to();
  if (from.IsTagged()) {
    if (to.IsDouble()) {
      LOperand* value = UseRegister(instr->value());
1617
      LNumberUntagD* res = new(zone()) LNumberUntagD(value);
1618 1619 1620 1621 1622 1623
      return AssignEnvironment(DefineAsRegister(res));
    } else {
      ASSERT(to.IsInteger32());
      LOperand* value = UseRegister(instr->value());
      bool needs_check = !instr->value()->type().IsSmi();
      if (needs_check) {
1624
        bool truncating = instr->CanTruncateToInt32();
1625
        LOperand* xmm_temp =
1626
            (truncating && CpuFeatures::IsSupported(SSE3))
1627 1628
            ? NULL
            : FixedTemp(xmm1);
1629
        LTaggedToI* res = new(zone()) LTaggedToI(value, xmm_temp);
1630 1631
        return AssignEnvironment(DefineSameAsFirst(res));
      } else {
1632
        return DefineSameAsFirst(new(zone()) LSmiUntag(value, needs_check));
1633 1634 1635 1636 1637 1638 1639 1640 1641
      }
    }
  } else if (from.IsDouble()) {
    if (to.IsTagged()) {
      LOperand* value = UseRegister(instr->value());
      LOperand* temp = TempRegister();

      // Make sure that temp and result_temp are different registers.
      LUnallocated* result_temp = TempRegister();
1642
      LNumberTagD* result = new(zone()) LNumberTagD(value, temp);
1643 1644 1645
      return AssignPointerMap(Define(result, result_temp));
    } else {
      ASSERT(to.IsInteger32());
1646 1647
      bool truncating = instr->CanTruncateToInt32();
      bool needs_temp = truncating && !CpuFeatures::IsSupported(SSE3);
1648 1649 1650
      LOperand* value = needs_temp ?
          UseTempRegister(instr->value()) : UseRegister(instr->value());
      LOperand* temp = needs_temp ? TempRegister() : NULL;
1651 1652
      return AssignEnvironment(
          DefineAsRegister(new(zone()) LDoubleToI(value, temp)));
1653 1654 1655 1656 1657 1658
    }
  } else if (from.IsInteger32()) {
    if (to.IsTagged()) {
      HValue* val = instr->value();
      LOperand* value = UseRegister(val);
      if (val->HasRange() && val->range()->IsInSmiRange()) {
1659
        return DefineSameAsFirst(new(zone()) LSmiTag(value));
1660
      } else {
1661
        LNumberTagI* result = new(zone()) LNumberTagI(value);
1662 1663 1664 1665
        return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
      }
    } else {
      ASSERT(to.IsDouble());
1666 1667
      return DefineAsRegister(
          new(zone()) LInteger32ToDouble(Use(instr->value())));
1668 1669 1670 1671 1672 1673 1674 1675
    }
  }
  UNREACHABLE();
  return NULL;
}


LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
1676
  LOperand* value = UseAtStart(instr->value());
1677
  return AssignEnvironment(new(zone()) LCheckNonSmi(value));
1678 1679 1680 1681 1682 1683
}


LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
  LOperand* value = UseRegisterAtStart(instr->value());
  LOperand* temp = TempRegister();
1684
  LCheckInstanceType* result = new(zone()) LCheckInstanceType(value, temp);
1685 1686 1687 1688 1689 1690
  return AssignEnvironment(result);
}


LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
  LOperand* temp = TempRegister();
1691
  LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp);
1692 1693 1694 1695 1696
  return AssignEnvironment(result);
}


LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1697
  LOperand* value = UseAtStart(instr->value());
1698
  return AssignEnvironment(new(zone()) LCheckSmi(value));
1699 1700 1701 1702
}


LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
1703 1704 1705 1706 1707 1708 1709
  // If the target is in new space, we'll emit a global cell compare and so
  // want the value in a register.  If the target gets promoted before we
  // emit code, we will still get the register but will do an immediate
  // compare instead of the cell compare.  This is safe.
  LOperand* value = Isolate::Current()->heap()->InNewSpace(*instr->target())
      ? UseRegisterAtStart(instr->value())
      : UseAtStart(instr->value());
1710
  return AssignEnvironment(new(zone()) LCheckFunction(value));
1711 1712 1713 1714 1715
}


LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
  LOperand* value = UseRegisterAtStart(instr->value());
1716
  LCheckMap* result = new(zone()) LCheckMap(value);
1717 1718 1719 1720
  return AssignEnvironment(result);
}


1721 1722 1723 1724 1725
LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
  HValue* value = instr->value();
  Representation input_rep = value->representation();
  if (input_rep.IsDouble()) {
    LOperand* reg = UseRegister(value);
1726
    return DefineAsRegister(new(zone()) LClampDToUint8(reg));
1727 1728
  } else if (input_rep.IsInteger32()) {
    LOperand* reg = UseFixed(value, eax);
1729
    return DefineFixed(new(zone()) LClampIToUint8(reg), eax);
1730 1731 1732 1733 1734 1735
  } else {
    ASSERT(input_rep.IsTagged());
    LOperand* reg = UseFixed(value, eax);
    // Register allocator doesn't (yet) support allocation of double
    // temps. Reserve xmm1 explicitly.
    LOperand* temp = FixedTemp(xmm1);
1736
    LClampTToUint8* result = new(zone()) LClampTToUint8(reg, temp);
1737 1738 1739 1740 1741
    return AssignEnvironment(DefineFixed(result, eax));
  }
}


1742 1743 1744
LInstruction* LChunkBuilder::DoToInt32(HToInt32* instr) {
  HValue* value = instr->value();
  Representation input_rep = value->representation();
1745

1746 1747 1748
  LInstruction* result;
  if (input_rep.IsDouble()) {
    LOperand* reg = UseRegister(value);
1749 1750
    LOperand* temp_reg =
        CpuFeatures::IsSupported(SSE3) ? NULL : TempRegister();
1751
    result = DefineAsRegister(new(zone()) LDoubleToI(reg, temp_reg));
1752 1753 1754 1755 1756 1757 1758 1759
  } else if (input_rep.IsInteger32()) {
    // Canonicalization should already have removed the hydrogen instruction in
    // this case, since it is a noop.
    UNREACHABLE();
    return NULL;
  } else {
    ASSERT(input_rep.IsTagged());
    LOperand* reg = UseRegister(value);
1760 1761 1762 1763
    // Register allocator doesn't (yet) support allocation of double
    // temps. Reserve xmm1 explicitly.
    LOperand* xmm_temp =
        CpuFeatures::IsSupported(SSE3) ? NULL : FixedTemp(xmm1);
1764
    result = DefineSameAsFirst(new(zone()) LTaggedToI(reg, xmm_temp));
1765 1766 1767 1768 1769
  }
  return AssignEnvironment(result);
}


1770
LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1771
  return new(zone()) LReturn(UseFixed(instr->value(), eax));
1772 1773 1774 1775 1776 1777
}


LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
  Representation r = instr->representation();
  if (r.IsInteger32()) {
1778
    return DefineAsRegister(new(zone()) LConstantI);
1779
  } else if (r.IsDouble()) {
1780 1781 1782 1783
    double value = instr->DoubleValue();
    LOperand* temp = (BitCast<uint64_t, double>(value) != 0)
        ? TempRegister()
        : NULL;
1784
    return DefineAsRegister(new(zone()) LConstantD(temp));
1785
  } else if (r.IsTagged()) {
1786
    return DefineAsRegister(new(zone()) LConstantT);
1787
  } else {
1788
    UNREACHABLE();
1789 1790 1791 1792 1793
    return NULL;
  }
}


1794
LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
1795
  LLoadGlobalCell* result = new(zone()) LLoadGlobalCell;
1796
  return instr->RequiresHoleCheck()
1797 1798 1799 1800 1801
      ? AssignEnvironment(DefineAsRegister(result))
      : DefineAsRegister(result);
}


1802 1803 1804
LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
  LOperand* context = UseFixed(instr->context(), esi);
  LOperand* global_object = UseFixed(instr->global_object(), eax);
1805 1806
  LLoadGlobalGeneric* result =
      new(zone()) LLoadGlobalGeneric(context, global_object);
1807 1808 1809 1810
  return MarkAsCall(DefineFixed(result, eax), instr);
}


1811 1812
LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
  LStoreGlobalCell* result =
1813
      new(zone()) LStoreGlobalCell(UseTempRegister(instr->value()),
1814 1815
                           TempRegister(),
                           TempRegister());
1816
  return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
1817 1818 1819
}


1820 1821 1822 1823 1824
LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
  LOperand* context = UseFixed(instr->context(), esi);
  LOperand* global_object = UseFixed(instr->global_object(), edx);
  LOperand* value = UseFixed(instr->value(), eax);
  LStoreGlobalGeneric* result =
1825
      new(zone()) LStoreGlobalGeneric(context, global_object, value);
1826 1827 1828 1829
  return MarkAsCall(result, instr);
}


1830
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1831
  LOperand* context = UseRegisterAtStart(instr->value());
1832
  return DefineAsRegister(new(zone()) LLoadContextSlot(context));
1833 1834 1835 1836 1837 1838
}


LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
  LOperand* value;
  LOperand* temp;
1839
  LOperand* context = UseRegister(instr->context());
1840 1841 1842 1843 1844 1845 1846
  if (instr->NeedsWriteBarrier()) {
    value = UseTempRegister(instr->value());
    temp = TempRegister();
  } else {
    value = UseRegister(instr->value());
    temp = NULL;
  }
1847
  return new(zone()) LStoreContextSlot(context, value, temp);
1848 1849 1850
}


1851
LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
1852 1853
  ASSERT(instr->representation().IsTagged());
  LOperand* obj = UseRegisterAtStart(instr->object());
1854
  return DefineAsRegister(new(zone()) LLoadNamedField(obj));
1855 1856 1857
}


1858 1859 1860
LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic(
    HLoadNamedFieldPolymorphic* instr) {
  ASSERT(instr->representation().IsTagged());
1861
  LOperand* context = UseFixed(instr->context(), esi);
1862 1863
  if (instr->need_generic()) {
    LOperand* obj = UseFixed(instr->object(), eax);
1864
    LLoadNamedFieldPolymorphic* result =
1865
        new(zone()) LLoadNamedFieldPolymorphic(context, obj);
1866 1867 1868
    return MarkAsCall(DefineFixed(result, eax), instr);
  } else {
    LOperand* obj = UseRegisterAtStart(instr->object());
1869
    LLoadNamedFieldPolymorphic* result =
1870
        new(zone()) LLoadNamedFieldPolymorphic(context, obj);
1871 1872 1873 1874 1875
    return AssignEnvironment(DefineAsRegister(result));
  }
}


1876
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
1877
  LOperand* context = UseFixed(instr->context(), esi);
1878
  LOperand* object = UseFixed(instr->object(), eax);
1879
  LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric(context, object);
1880
  return MarkAsCall(DefineFixed(result, eax), instr);
1881 1882 1883
}


1884 1885 1886
LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
    HLoadFunctionPrototype* instr) {
  return AssignEnvironment(DefineAsRegister(
1887 1888
      new(zone()) LLoadFunctionPrototype(UseRegister(instr->function()),
                                         TempRegister())));
1889 1890 1891
}


1892 1893
LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
  LOperand* input = UseRegisterAtStart(instr->value());
1894
  return DefineAsRegister(new(zone()) LLoadElements(input));
1895 1896 1897
}


1898 1899
LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
    HLoadExternalArrayPointer* instr) {
1900
  LOperand* input = UseRegisterAtStart(instr->value());
1901
  return DefineAsRegister(new(zone()) LLoadExternalArrayPointer(input));
1902 1903 1904 1905 1906
}


LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
    HLoadKeyedFastElement* instr) {
1907
  ASSERT(instr->representation().IsTagged());
1908
  ASSERT(instr->key()->representation().IsInteger32());
1909
  LOperand* obj = UseRegisterAtStart(instr->object());
1910
  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
1911
  LLoadKeyedFastElement* result = new(zone()) LLoadKeyedFastElement(obj, key);
1912
  return AssignEnvironment(DefineAsRegister(result));
1913 1914 1915
}


1916 1917 1918 1919 1920 1921 1922
LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
    HLoadKeyedFastDoubleElement* instr) {
  ASSERT(instr->representation().IsDouble());
  ASSERT(instr->key()->representation().IsInteger32());
  LOperand* elements = UseRegisterAtStart(instr->elements());
  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
  LLoadKeyedFastDoubleElement* result =
1923
      new(zone()) LLoadKeyedFastDoubleElement(elements, key);
1924 1925 1926 1927
  return AssignEnvironment(DefineAsRegister(result));
}


1928 1929
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
    HLoadKeyedSpecializedArrayElement* instr) {
1930
  ElementsKind elements_kind = instr->elements_kind();
1931
  Representation representation(instr->representation());
1932
  ASSERT(
1933
      (representation.IsInteger32() &&
1934 1935
       (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
       (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
1936
      (representation.IsDouble() &&
1937 1938
       ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
       (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
1939
  ASSERT(instr->key()->representation().IsInteger32());
1940
  LOperand* external_pointer = UseRegister(instr->external_pointer());
1941
  LOperand* key = UseRegisterOrConstant(instr->key());
1942
  LLoadKeyedSpecializedArrayElement* result =
1943
      new(zone()) LLoadKeyedSpecializedArrayElement(external_pointer,
1944 1945 1946 1947
                                            key);
  LInstruction* load_instr = DefineAsRegister(result);
  // An unsigned int array load might overflow and cause a deopt, make sure it
  // has an environment.
1948
  return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS)
1949 1950
      ? AssignEnvironment(load_instr)
      : load_instr;
1951 1952 1953
}


1954
LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
1955
  LOperand* context = UseFixed(instr->context(), esi);
1956 1957 1958
  LOperand* object = UseFixed(instr->object(), edx);
  LOperand* key = UseFixed(instr->key(), eax);

1959 1960
  LLoadKeyedGeneric* result =
      new(zone()) LLoadKeyedGeneric(context, object, key);
1961
  return MarkAsCall(DefineFixed(result, eax), instr);
1962 1963 1964 1965 1966 1967 1968 1969 1970 1971
}


LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
    HStoreKeyedFastElement* instr) {
  bool needs_write_barrier = instr->NeedsWriteBarrier();
  ASSERT(instr->value()->representation().IsTagged());
  ASSERT(instr->object()->representation().IsTagged());
  ASSERT(instr->key()->representation().IsInteger32());

1972
  LOperand* obj = UseRegister(instr->object());
1973 1974 1975 1976 1977 1978 1979
  LOperand* val = needs_write_barrier
      ? UseTempRegister(instr->value())
      : UseRegisterAtStart(instr->value());
  LOperand* key = needs_write_barrier
      ? UseTempRegister(instr->key())
      : UseRegisterOrConstantAtStart(instr->key());

1980
  return AssignEnvironment(new(zone()) LStoreKeyedFastElement(obj, key, val));
1981 1982 1983
}


1984 1985 1986 1987 1988 1989 1990 1991 1992 1993
LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement(
    HStoreKeyedFastDoubleElement* instr) {
  ASSERT(instr->value()->representation().IsDouble());
  ASSERT(instr->elements()->representation().IsTagged());
  ASSERT(instr->key()->representation().IsInteger32());

  LOperand* elements = UseRegisterAtStart(instr->elements());
  LOperand* val = UseTempRegister(instr->value());
  LOperand* key = UseRegisterOrConstantAtStart(instr->key());

1994
  return new(zone()) LStoreKeyedFastDoubleElement(elements, key, val);
1995 1996 1997
}


1998 1999 2000
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
    HStoreKeyedSpecializedArrayElement* instr) {
  Representation representation(instr->value()->representation());
2001
  ElementsKind elements_kind = instr->elements_kind();
2002 2003
    ASSERT(
      (representation.IsInteger32() &&
2004 2005
       (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
       (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
2006
      (representation.IsDouble() &&
2007 2008
       ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
       (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
2009 2010 2011 2012
  ASSERT(instr->external_pointer()->representation().IsExternal());
  ASSERT(instr->key()->representation().IsInteger32());

  LOperand* external_pointer = UseRegister(instr->external_pointer());
2013
  LOperand* key = UseRegisterOrConstant(instr->key());
2014
  LOperand* val = NULL;
2015 2016 2017
  if (elements_kind == EXTERNAL_BYTE_ELEMENTS ||
      elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
      elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
2018 2019 2020 2021 2022 2023
    // We need a byte register in this case for the value.
    val = UseFixed(instr->value(), eax);
  } else {
    val = UseRegister(instr->value());
  }

2024 2025 2026
  return new(zone()) LStoreKeyedSpecializedArrayElement(external_pointer,
                                                        key,
                                                        val);
2027 2028 2029
}


2030
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
2031 2032
  LOperand* context = UseFixed(instr->context(), esi);
  LOperand* object = UseFixed(instr->object(), edx);
2033
  LOperand* key = UseFixed(instr->key(), ecx);
2034
  LOperand* value = UseFixed(instr->value(), eax);
2035 2036 2037 2038 2039

  ASSERT(instr->object()->representation().IsTagged());
  ASSERT(instr->key()->representation().IsTagged());
  ASSERT(instr->value()->representation().IsTagged());

2040
  LStoreKeyedGeneric* result =
2041
      new(zone()) LStoreKeyedGeneric(context, object, key, value);
2042
  return MarkAsCall(result, instr);
2043 2044 2045
}


2046 2047 2048 2049 2050 2051 2052 2053
LInstruction* LChunkBuilder::DoTransitionElementsKind(
    HTransitionElementsKind* instr) {
  if (instr->original_map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
      instr->transitioned_map()->elements_kind() == FAST_ELEMENTS) {
    LOperand* object = UseRegister(instr->object());
    LOperand* new_map_reg = TempRegister();
    LOperand* temp_reg = TempRegister();
    LTransitionElementsKind* result =
2054
        new(zone()) LTransitionElementsKind(object, new_map_reg, temp_reg);
2055 2056 2057 2058 2059 2060
    return DefineSameAsFirst(result);
  } else {
    LOperand* object = UseFixed(instr->object(), eax);
    LOperand* fixed_object_reg = FixedTemp(edx);
    LOperand* new_map_reg = FixedTemp(ebx);
    LTransitionElementsKind* result =
2061 2062 2063
        new(zone()) LTransitionElementsKind(object,
                                            new_map_reg,
                                            fixed_object_reg);
2064 2065 2066 2067 2068
    return MarkAsCall(DefineFixed(result, eax), instr);
  }
}


2069
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2070
  bool needs_write_barrier = instr->NeedsWriteBarrier();
2071

2072 2073 2074 2075 2076 2077 2078 2079
  LOperand* obj;
  if (needs_write_barrier) {
    obj = instr->is_in_object()
        ? UseRegister(instr->object())
        : UseTempRegister(instr->object());
  } else {
    obj = UseRegisterAtStart(instr->object());
  }
2080 2081 2082 2083 2084 2085 2086 2087

  LOperand* val = needs_write_barrier
      ? UseTempRegister(instr->value())
      : UseRegister(instr->value());

  // We only need a scratch register if we have a write barrier or we
  // have a store into the properties array (not in-object-property).
  LOperand* temp = (!instr->is_in_object() || needs_write_barrier)
2088 2089
      ? TempRegister()
      : NULL;
2090

2091
  return new(zone()) LStoreNamedField(obj, val, temp);
2092 2093 2094 2095
}


LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
2096 2097 2098
  LOperand* context = UseFixed(instr->context(), esi);
  LOperand* object = UseFixed(instr->object(), edx);
  LOperand* value = UseFixed(instr->value(), eax);
2099

2100 2101
  LStoreNamedGeneric* result =
      new(zone()) LStoreNamedGeneric(context, object, value);
2102 2103 2104 2105
  return MarkAsCall(result, instr);
}


2106
LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2107
  LOperand* context = UseFixed(instr->context(), esi);
2108 2109
  LOperand* left = UseOrConstantAtStart(instr->left());
  LOperand* right = UseOrConstantAtStart(instr->right());
2110
  LStringAdd* string_add = new(zone()) LStringAdd(context, left, right);
2111
  return MarkAsCall(DefineFixed(string_add, eax), instr);
2112 2113 2114
}


2115
LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2116 2117
  LOperand* string = UseTempRegister(instr->string());
  LOperand* index = UseTempRegister(instr->index());
2118
  LOperand* context = UseAny(instr->context());
2119 2120
  LStringCharCodeAt* result =
      new(zone()) LStringCharCodeAt(context, string, index);
2121
  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
2122 2123 2124
}


2125 2126
LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
  LOperand* char_code = UseRegister(instr->value());
2127
  LOperand* context = UseAny(instr->context());
2128 2129
  LStringCharFromCode* result =
      new(zone()) LStringCharFromCode(context, char_code);
2130 2131 2132 2133
  return AssignPointerMap(DefineAsRegister(result));
}


2134 2135
LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
  LOperand* string = UseRegisterAtStart(instr->value());
2136
  return DefineAsRegister(new(zone()) LStringLength(string));
2137 2138 2139
}


2140
LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
2141
  LOperand* context = UseFixed(instr->context(), esi);
2142 2143
  return MarkAsCall(
      DefineFixed(new(zone()) LArrayLiteral(context), eax), instr);
2144 2145 2146 2147
}


LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
2148
  LOperand* context = UseFixed(instr->context(), esi);
2149 2150
  return MarkAsCall(
      DefineFixed(new(zone()) LObjectLiteral(context), eax), instr);
2151 2152 2153 2154
}


LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
2155
  LOperand* context = UseFixed(instr->context(), esi);
2156 2157
  return MarkAsCall(
      DefineFixed(new(zone()) LRegExpLiteral(context), eax), instr);
2158 2159 2160 2161
}


LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
2162
  LOperand* context = UseFixed(instr->context(), esi);
2163 2164
  return MarkAsCall(
      DefineFixed(new(zone()) LFunctionLiteral(context), eax), instr);
2165 2166 2167 2168
}


LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) {
2169 2170 2171
  LOperand* context = UseFixed(instr->context(), esi);
  LOperand* object = UseAtStart(instr->object());
  LOperand* key = UseOrConstantAtStart(instr->key());
2172
  LDeleteProperty* result = new(zone()) LDeleteProperty(context, object, key);
2173 2174 2175 2176 2177 2178 2179
  return MarkAsCall(DefineFixed(result, eax), instr);
}


LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
  allocator_->MarkAsOsrEntry();
  current_block_->last_environment()->set_ast_id(instr->ast_id());
2180
  return AssignEnvironment(new(zone()) LOsrEntry);
2181 2182 2183 2184 2185
}


LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
  int spill_index = chunk()->GetParameterStackSlot(instr->index());
2186
  return DefineAsSpilled(new(zone()) LParameter, spill_index);
2187 2188 2189 2190 2191
}


LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
  int spill_index = chunk()->GetNextSpillIndex(false);  // Not double-width.
2192 2193
  if (spill_index > LUnallocated::kMaxFixedIndex) {
    Abort("Too many spill slots needed for OSR");
2194
    spill_index = 0;
2195
  }
2196
  return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
2197 2198 2199 2200
}


LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
2201
  LOperand* context = UseFixed(instr->context(), esi);
2202
  argument_count_ -= instr->argument_count();
2203
  LCallStub* result = new(zone()) LCallStub(context);
2204
  return MarkAsCall(DefineFixed(result, eax), instr);
2205 2206 2207 2208
}


LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2209 2210 2211 2212
  // There are no real uses of the arguments object.
  // arguments.length and element access are supported directly on
  // stack arguments, and any real arguments object use causes a bailout.
  // So this value is never used.
2213 2214 2215 2216 2217 2218 2219 2220
  return NULL;
}


LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
  LOperand* arguments = UseRegister(instr->arguments());
  LOperand* length = UseTempRegister(instr->length());
  LOperand* index = Use(instr->index());
2221 2222
  LAccessArgumentsAt* result =
      new(zone()) LAccessArgumentsAt(arguments, length, index);
2223
  return AssignEnvironment(DefineAsRegister(result));
2224 2225 2226
}


2227 2228
LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
  LOperand* object = UseFixed(instr->value(), eax);
2229
  LToFastProperties* result = new(zone()) LToFastProperties(object);
2230 2231 2232 2233
  return MarkAsCall(DefineFixed(result, eax), instr);
}


2234
LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2235 2236
  LOperand* context = UseFixed(instr->context(), esi);
  LOperand* value = UseAtStart(instr->value());
2237
  LTypeof* result = new(zone()) LTypeof(context, value);
2238 2239 2240 2241
  return MarkAsCall(DefineFixed(result, eax), instr);
}


2242
LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2243
  return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value()));
2244 2245
}

2246

2247 2248
LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
    HIsConstructCallAndBranch* instr) {
2249
  return new(zone()) LIsConstructCallAndBranch(TempRegister());
2250 2251 2252
}


2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270
LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
  HEnvironment* env = current_block_->last_environment();
  ASSERT(env != NULL);

  env->set_ast_id(instr->ast_id());

  env->Drop(instr->pop_count());
  for (int i = 0; i < instr->values()->length(); ++i) {
    HValue* value = instr->values()->at(i);
    if (instr->HasAssignedIndexAt(i)) {
      env->Bind(instr->GetAssignedIndexAt(i), value);
    } else {
      env->Push(value);
    }
  }

  // If there is an instruction pending deoptimization environment create a
  // lazy bailout instruction to capture the environment.
2271 2272
  if (pending_deoptimization_ast_id_ != AstNode::kNoNumber) {
    ASSERT(pending_deoptimization_ast_id_ == instr->ast_id());
2273
    LLazyBailout* lazy_bailout = new(zone()) LLazyBailout;
2274
    LInstruction* result = AssignEnvironment(lazy_bailout);
2275
    instruction_pending_deoptimization_environment_->
2276 2277
        set_deoptimization_environment(result->environment());
    ClearInstructionPendingDeoptimizationEnvironment();
2278 2279 2280 2281 2282 2283 2284 2285
    return result;
  }

  return NULL;
}


LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2286
  if (instr->is_function_entry()) {
2287
    LOperand* context = UseFixed(instr->context(), esi);
2288
    return MarkAsCall(new(zone()) LStackCheck(context), instr);
2289 2290
  } else {
    ASSERT(instr->is_backwards_branch());
2291
    LOperand* context = UseAny(instr->context());
2292 2293
    return AssignEnvironment(
        AssignPointerMap(new(zone()) LStackCheck(context)));
2294
  }
2295 2296 2297 2298 2299 2300 2301 2302
}


LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
  HEnvironment* outer = current_block_->last_environment();
  HConstant* undefined = graph()->GetConstantUndefined();
  HEnvironment* inner = outer->CopyForInlining(instr->closure(),
                                               instr->function(),
2303 2304
                                               undefined,
                                               instr->call_kind());
2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317
  current_block_->UpdateEnvironment(inner);
  chunk_->AddInlinedClosure(instr->closure());
  return NULL;
}


LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
  HEnvironment* outer = current_block_->last_environment()->outer();
  current_block_->UpdateEnvironment(outer);
  return NULL;
}


2318
LInstruction* LChunkBuilder::DoIn(HIn* instr) {
2319
  LOperand* context = UseFixed(instr->context(), esi);
2320 2321
  LOperand* key = UseOrConstantAtStart(instr->key());
  LOperand* object = UseOrConstantAtStart(instr->object());
2322
  LIn* result = new(zone()) LIn(context, key, object);
2323 2324 2325 2326
  return MarkAsCall(DefineFixed(result, eax), instr);
}


2327
} }  // namespace v8::internal
2328 2329

#endif  // V8_TARGET_ARCH_IA32