lithium.cc 22.6 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5 6
#include "src/lithium.h"

7
#include "src/scopes.h"
8 9

#if V8_TARGET_ARCH_IA32
10 11
#include "src/ia32/lithium-ia32.h"  // NOLINT
#include "src/ia32/lithium-codegen-ia32.h"  // NOLINT
12
#elif V8_TARGET_ARCH_X64
13 14
#include "src/x64/lithium-x64.h"  // NOLINT
#include "src/x64/lithium-codegen-x64.h"  // NOLINT
15
#elif V8_TARGET_ARCH_ARM
16 17
#include "src/arm/lithium-arm.h"  // NOLINT
#include "src/arm/lithium-codegen-arm.h"  // NOLINT
18 19 20
#elif V8_TARGET_ARCH_PPC
#include "src/ppc/lithium-ppc.h"          // NOLINT
#include "src/ppc/lithium-codegen-ppc.h"  // NOLINT
21
#elif V8_TARGET_ARCH_MIPS
22 23
#include "src/mips/lithium-mips.h"  // NOLINT
#include "src/mips/lithium-codegen-mips.h"  // NOLINT
24
#elif V8_TARGET_ARCH_ARM64
25 26
#include "src/arm64/lithium-arm64.h"  // NOLINT
#include "src/arm64/lithium-codegen-arm64.h"  // NOLINT
27 28 29
#elif V8_TARGET_ARCH_MIPS64
#include "src/mips64/lithium-mips64.h"  // NOLINT
#include "src/mips64/lithium-codegen-mips64.h"  // NOLINT
danno@chromium.org's avatar
danno@chromium.org committed
30
#elif V8_TARGET_ARCH_X87
31 32
#include "src/x87/lithium-x87.h"  // NOLINT
#include "src/x87/lithium-codegen-x87.h"  // NOLINT
33 34 35
#else
#error "Unknown architecture."
#endif
36 37 38 39

namespace v8 {
namespace internal {

40 41 42 43 44

void LOperand::PrintTo(StringStream* stream) {
  LUnallocated* unalloc = NULL;
  switch (kind()) {
    case INVALID:
45
      stream->Add("(0)");
46 47 48 49
      break;
    case UNALLOCATED:
      unalloc = LUnallocated::cast(this);
      stream->Add("v%d", unalloc->virtual_register());
50 51 52 53 54
      if (unalloc->basic_policy() == LUnallocated::FIXED_SLOT) {
        stream->Add("(=%dS)", unalloc->fixed_slot_index());
        break;
      }
      switch (unalloc->extended_policy()) {
55 56 57
        case LUnallocated::NONE:
          break;
        case LUnallocated::FIXED_REGISTER: {
58
          int reg_index = unalloc->fixed_register_index();
59 60
          if (reg_index < 0 ||
              reg_index >= Register::kMaxNumAllocatableRegisters) {
61 62 63
            stream->Add("(=invalid_reg#%d)", reg_index);
          } else {
            const char* register_name =
64
                Register::AllocationIndexToString(reg_index);
65 66
            stream->Add("(=%s)", register_name);
          }
67 68 69
          break;
        }
        case LUnallocated::FIXED_DOUBLE_REGISTER: {
70
          int reg_index = unalloc->fixed_register_index();
71 72
          if (reg_index < 0 ||
              reg_index >= DoubleRegister::kMaxNumAllocatableRegisters) {
73 74 75
            stream->Add("(=invalid_double_reg#%d)", reg_index);
          } else {
            const char* double_register_name =
76
                DoubleRegister::AllocationIndexToString(reg_index);
77 78
            stream->Add("(=%s)", double_register_name);
          }
79 80 81 82 83
          break;
        }
        case LUnallocated::MUST_HAVE_REGISTER:
          stream->Add("(R)");
          break;
84 85 86
        case LUnallocated::MUST_HAVE_DOUBLE_REGISTER:
          stream->Add("(D)");
          break;
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
        case LUnallocated::WRITABLE_REGISTER:
          stream->Add("(WR)");
          break;
        case LUnallocated::SAME_AS_FIRST_INPUT:
          stream->Add("(1)");
          break;
        case LUnallocated::ANY:
          stream->Add("(-)");
          break;
      }
      break;
    case CONSTANT_OPERAND:
      stream->Add("[constant:%d]", index());
      break;
    case STACK_SLOT:
      stream->Add("[stack:%d]", index());
      break;
    case DOUBLE_STACK_SLOT:
      stream->Add("[double_stack:%d]", index());
      break;
107 108
    case REGISTER: {
      int reg_index = index();
109
      if (reg_index < 0 || reg_index >= Register::kMaxNumAllocatableRegisters) {
110 111
        stream->Add("(=invalid_reg#%d|R)", reg_index);
      } else {
112
        stream->Add("[%s|R]", Register::AllocationIndexToString(reg_index));
113
      }
114
      break;
115 116 117
    }
    case DOUBLE_REGISTER: {
      int reg_index = index();
118 119
      if (reg_index < 0 ||
          reg_index >= DoubleRegister::kMaxNumAllocatableRegisters) {
120 121
        stream->Add("(=invalid_double_reg#%d|R)", reg_index);
      } else {
122 123
        stream->Add("[%s|R]",
                    DoubleRegister::AllocationIndexToString(reg_index));
124
      }
125
      break;
126
    }
127 128 129
  }
}

130 131 132 133 134 135 136 137 138 139 140 141

template<LOperand::Kind kOperandKind, int kNumCachedOperands>
LSubKindOperand<kOperandKind, kNumCachedOperands>*
LSubKindOperand<kOperandKind, kNumCachedOperands>::cache = NULL;


template<LOperand::Kind kOperandKind, int kNumCachedOperands>
void LSubKindOperand<kOperandKind, kNumCachedOperands>::SetUpCache() {
  if (cache) return;
  cache = new LSubKindOperand[kNumCachedOperands];
  for (int i = 0; i < kNumCachedOperands; i++) {
    cache[i].ConvertTo(kOperandKind, i);
142
  }
143 144 145 146 147 148
}


template<LOperand::Kind kOperandKind, int kNumCachedOperands>
void LSubKindOperand<kOperandKind, kNumCachedOperands>::TearDownCache() {
  delete[] cache;
149
  cache = NULL;
150
}
151 152 153


void LOperand::SetUpCaches() {
154
#define LITHIUM_OPERAND_SETUP(name, type, number) L##name::SetUpCache();
155 156 157 158 159 160
  LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_SETUP)
#undef LITHIUM_OPERAND_SETUP
}


void LOperand::TearDownCaches() {
161
#define LITHIUM_OPERAND_TEARDOWN(name, type, number) L##name::TearDownCache();
162 163
  LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_TEARDOWN)
#undef LITHIUM_OPERAND_TEARDOWN
164
}
165

166

167 168 169 170 171 172 173 174 175
bool LParallelMove::IsRedundant() const {
  for (int i = 0; i < move_operands_.length(); ++i) {
    if (!move_operands_[i].IsRedundant()) return false;
  }
  return true;
}


void LParallelMove::PrintDataTo(StringStream* stream) const {
176 177
  bool first = true;
  for (int i = 0; i < move_operands_.length(); ++i) {
178
    if (!move_operands_[i].IsEliminated()) {
179 180 181 182 183 184
      LOperand* source = move_operands_[i].source();
      LOperand* destination = move_operands_[i].destination();
      if (!first) stream->Add(" ");
      first = false;
      if (source->Equals(destination)) {
        destination->PrintTo(stream);
185
      } else {
186
        destination->PrintTo(stream);
187
        stream->Add(" = ");
188
        source->PrintTo(stream);
189
      }
190
      stream->Add(";");
191 192 193 194 195
    }
  }
}


196
void LEnvironment::PrintTo(StringStream* stream) {
197
  stream->Add("[id=%d|", ast_id().ToInt());
198 199 200
  if (deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
    stream->Add("deopt_id=%d|", deoptimization_index());
  }
201 202
  stream->Add("parameters=%d|", parameter_count());
  stream->Add("arguments_stack_height=%d|", arguments_stack_height());
203 204 205 206 207 208 209 210 211 212 213 214
  for (int i = 0; i < values_.length(); ++i) {
    if (i != 0) stream->Add(";");
    if (values_[i] == NULL) {
      stream->Add("[hole]");
    } else {
      values_[i]->PrintTo(stream);
    }
  }
  stream->Add("]");
}


215
void LPointerMap::RecordPointer(LOperand* op, Zone* zone) {
216 217
  // Do not record arguments as pointers.
  if (op->IsStackSlot() && op->index() < 0) return;
218
  DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
219
  pointer_operands_.Add(op, zone);
220 221 222
}


223 224 225
void LPointerMap::RemovePointer(LOperand* op) {
  // Do not record arguments as pointers.
  if (op->IsStackSlot() && op->index() < 0) return;
226
  DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
227 228 229 230 231 232 233 234 235
  for (int i = 0; i < pointer_operands_.length(); ++i) {
    if (pointer_operands_[i]->Equals(op)) {
      pointer_operands_.Remove(i);
      --i;
    }
  }
}


236
void LPointerMap::RecordUntagged(LOperand* op, Zone* zone) {
237 238
  // Do not record arguments as pointers.
  if (op->IsStackSlot() && op->index() < 0) return;
239
  DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
240
  untagged_operands_.Add(op, zone);
241 242 243
}


244 245 246 247 248 249
void LPointerMap::PrintTo(StringStream* stream) {
  stream->Add("{");
  for (int i = 0; i < pointer_operands_.length(); ++i) {
    if (i != 0) stream->Add(";");
    pointer_operands_[i]->PrintTo(stream);
  }
250
  stream->Add("}");
251 252 253
}


254 255 256 257
int StackSlotOffset(int index) {
  if (index >= 0) {
    // Local or spill slot. Skip the frame pointer, function, and
    // context in the fixed part of the frame.
258 259
    return -(index + 1) * kPointerSize -
        StandardFrameConstants::kFixedFrameSizeFromFp;
260 261
  } else {
    // Incoming parameter. Skip the return address.
262
    return -(index + 1) * kPointerSize + kFPOnStackSize + kPCOnStackSize;
263 264 265 266
  }
}


267 268 269 270
LChunk::LChunk(CompilationInfo* info, HGraph* graph)
    : spill_slot_count_(0),
      info_(info),
      graph_(graph),
271 272
      instructions_(32, info->zone()),
      pointer_maps_(8, info->zone()),
273
      inlined_functions_(1, info->zone()),
274 275
      deprecation_dependencies_(32, info->zone()),
      stability_dependencies_(8, info->zone()) {}
276 277


278
LLabel* LChunk::GetLabel(int block_id) const {
279 280 281 282 283 284
  HBasicBlock* block = graph_->blocks()->at(block_id);
  int first_instruction = block->first_instruction_index();
  return LLabel::cast(instructions_[first_instruction]);
}


285
int LChunk::LookupDestination(int block_id) const {
286 287 288 289 290 291 292
  LLabel* cur = GetLabel(block_id);
  while (cur->replacement() != NULL) {
    cur = cur->replacement();
  }
  return cur->block_id();
}

293
Label* LChunk::GetAssemblyLabel(int block_id) const {
294
  LLabel* label = GetLabel(block_id);
295
  DCHECK(!label->HasReplacement());
296 297 298
  return label->label();
}

299

300
void LChunk::MarkEmptyBlocks() {
301
  LPhase phase("L_Mark empty blocks", this);
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
  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);
      if (label->IsRedundant() &&
          !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()));
        }
      }
    }
  }
}


335
void LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
336
  LInstructionGap* gap = new (zone()) LInstructionGap(block);
337
  gap->set_hydrogen_value(instr->hydrogen_value());
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
  int index = -1;
  if (instr->IsControl()) {
    instructions_.Add(gap, zone());
    index = instructions_.length();
    instructions_.Add(instr, zone());
  } else {
    index = instructions_.length();
    instructions_.Add(instr, zone());
    instructions_.Add(gap, zone());
  }
  if (instr->HasPointerMap()) {
    pointer_maps_.Add(instr->pointer_map(), zone());
    instr->pointer_map()->set_lithium_position(index);
  }
}


355
LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) {
356 357 358 359
  return LConstantOperand::Create(constant->id(), zone());
}


360
int LChunk::GetParameterStackSlot(int index) const {
361 362 363 364
  // 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.
365 366
  int result = index - info()->num_parameters() - 1;

367
  DCHECK(result < 0);
368 369 370 371 372
  return result;
}


// A parameter relative to ebp in the arguments stub.
373
int LChunk::ParameterAt(int index) {
374
  DCHECK(-1 <= index);  // -1 is the receiver.
375 376 377 378 379
  return (1 + info()->scope()->num_parameters() - index) *
      kPointerSize;
}


380
LGap* LChunk::GetGapAt(int index) const {
381 382 383 384
  return LGap::cast(instructions_[index]);
}


385
bool LChunk::IsGapAt(int index) const {
386 387 388 389
  return instructions_[index]->IsGap();
}


390
int LChunk::NearestGapPos(int index) const {
391 392 393 394 395
  while (!IsGapAt(index)) index--;
  return index;
}


396
void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
397 398 399 400 401
  GetGapAt(index)->GetOrCreateParallelMove(
      LGap::START, zone())->AddMove(from, to, zone());
}


402
HConstant* LChunk::LookupConstant(LConstantOperand* operand) const {
403
  return HConstant::cast(graph_->LookupValue(operand->index()));
404 405 406
}


407
Representation LChunk::LookupLiteralRepresentation(
408 409 410 411 412
    LConstantOperand* operand) const {
  return graph_->LookupValue(operand->index())->representation();
}


413
static void AddWeakObjectToCodeDependency(Isolate* isolate,
414
                                          Handle<HeapObject> object,
415
                                          Handle<Code> code) {
416
  Handle<WeakCell> cell = Code::WeakCellFor(code);
417 418
  Heap* heap = isolate->heap();
  Handle<DependentCode> dep(heap->LookupWeakObjectToCodeDependency(object));
419
  dep = DependentCode::InsertWeakCode(dep, DependentCode::kWeakCodeGroup, cell);
420 421 422 423 424 425 426
  heap->AddWeakObjectToCodeDependency(object, dep);
}


void LChunk::RegisterWeakObjectsInOptimizedCode(Handle<Code> code) const {
  DCHECK(code->is_optimized_code());
  ZoneList<Handle<Map> > maps(1, zone());
427
  ZoneList<Handle<HeapObject> > objects(1, zone());
428 429 430 431 432 433
  int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
                  RelocInfo::ModeMask(RelocInfo::CELL);
  for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) {
    RelocInfo::Mode mode = it.rinfo()->rmode();
    if (mode == RelocInfo::CELL &&
        code->IsWeakObjectInOptimizedCode(it.rinfo()->target_cell())) {
434
      objects.Add(Handle<HeapObject>(it.rinfo()->target_cell()), zone());
435 436 437 438 439
    } else if (mode == RelocInfo::EMBEDDED_OBJECT &&
               code->IsWeakObjectInOptimizedCode(it.rinfo()->target_object())) {
      if (it.rinfo()->target_object()->IsMap()) {
        Handle<Map> map(Map::cast(it.rinfo()->target_object()));
        maps.Add(map, zone());
440 441 442
      } else {
        Handle<HeapObject> object(
            HeapObject::cast(it.rinfo()->target_object()));
443 444 445 446 447
        objects.Add(object, zone());
      }
    }
  }
  for (int i = 0; i < maps.length(); i++) {
448 449 450 451
    if (maps.at(i)->dependent_code()->number_of_entries(
            DependentCode::kWeakCodeGroup) == 0) {
      isolate()->heap()->AddRetainedMap(maps.at(i));
    }
452 453 454 455 456 457 458 459 460
    Map::AddDependentCode(maps.at(i), DependentCode::kWeakCodeGroup, code);
  }
  for (int i = 0; i < objects.length(); i++) {
    AddWeakObjectToCodeDependency(isolate(), objects.at(i), code);
  }
  code->set_can_have_weak_objects(true);
}


461
void LChunk::CommitDependencies(Handle<Code> code) const {
462 463 464
  if (!code->is_optimized_code()) return;
  HandleScope scope(isolate());

465
  for (Handle<Map> map : deprecation_dependencies_) {
466 467
    DCHECK(!map->is_deprecated());
    DCHECK(map->CanBeDeprecated());
468 469 470
    Map::AddDependentCode(map, DependentCode::kTransitionGroup, code);
  }

471
  for (Handle<Map> map : stability_dependencies_) {
472 473
    DCHECK(map->is_stable());
    DCHECK(map->CanTransition());
474 475 476
    Map::AddDependentCode(map, DependentCode::kPrototypeCheckGroup, code);
  }

477
  info_->dependencies()->Commit(code);
478
  RegisterWeakObjectsInOptimizedCode(code);
479 480 481
}


482
LChunk* LChunk::NewChunk(HGraph* graph) {
483 484
  DisallowHandleAllocation no_handles;
  DisallowHeapAllocation no_gc;
485
  graph->DisallowAddingNewValues();
486
  int values = graph->GetMaximumValueID();
487
  CompilationInfo* info = graph->info();
488
  if (values > LUnallocated::kMaxVirtualRegisters) {
489
    info->AbortOptimization(kNotEnoughVirtualRegistersForValues);
490 491 492
    return NULL;
  }
  LAllocator allocator(values, graph);
493
  LChunkBuilder builder(info, graph, &allocator);
494
  LChunk* chunk = builder.Build();
495 496 497
  if (chunk == NULL) return NULL;

  if (!allocator.Allocate(chunk)) {
498
    info->AbortOptimization(kNotEnoughVirtualRegistersRegalloc);
499 500 501
    return NULL;
  }

502 503 504
  chunk->set_allocated_double_registers(
      allocator.assigned_double_registers());

505 506 507 508
  return chunk;
}


509
Handle<Code> LChunk::Codegen() {
510
  MacroAssembler assembler(info()->isolate(), NULL, 0);
511 512 513
  LOG_CODE_EVENT(info()->isolate(),
                 CodeStartLinePosInfoRecordEvent(
                     assembler.positions_recorder()));
514 515
  // Code serializer only takes unoptimized code.
  DCHECK(!info()->will_serialize());
516 517 518 519 520
  LCodeGen generator(this, &assembler, info());

  MarkEmptyBlocks();

  if (generator.GenerateCode()) {
521
    generator.CheckEnvironmentUsage();
522
    CodeGenerator::MakeCodePrologue(info(), "optimized");
523
    Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&assembler, info());
524
    generator.FinishCode(code);
525
    CommitDependencies(code);
526
    code->set_is_crankshafted(true);
527 528 529 530
    void* jit_handler_data =
        assembler.positions_recorder()->DetachJITHandlerData();
    LOG_CODE_EVENT(info()->isolate(),
                   CodeEndLinePosInfoRecordEvent(*code, jit_handler_data));
531

532
    CodeGenerator::PrintCode(code, info());
533
    DCHECK(!(info()->isolate()->serializer_enabled() &&
534 535
             info()->GetMustNotHaveEagerFrame() &&
             generator.NeedsEagerFrame()));
536 537
    return code;
  }
538
  assembler.AbortedCodeGeneration();
539 540 541 542
  return Handle<Code>::null();
}


543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
void LChunk::set_allocated_double_registers(BitVector* allocated_registers) {
  allocated_double_registers_ = allocated_registers;
  BitVector* doubles = allocated_double_registers();
  BitVector::Iterator iterator(doubles);
  while (!iterator.Done()) {
    if (info()->saves_caller_doubles()) {
      if (kDoubleSize == kPointerSize * 2) {
        spill_slot_count_ += 2;
      } else {
        spill_slot_count_++;
      }
    }
    iterator.Advance();
  }
}


560 561 562 563 564 565 566 567 568 569 570 571
void LChunkBuilderBase::Abort(BailoutReason reason) {
  info()->AbortOptimization(reason);
  status_ = ABORTED;
}


void LChunkBuilderBase::Retry(BailoutReason reason) {
  info()->RetryOptimization(reason);
  status_ = ABORTED;
}


572
LEnvironment* LChunkBuilderBase::CreateEnvironment(
573
    HEnvironment* hydrogen_env, int* argument_index_accumulator,
574 575 576
    ZoneList<HValue*>* objects_to_materialize) {
  if (hydrogen_env == NULL) return NULL;

577 578 579
  LEnvironment* outer =
      CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator,
                        objects_to_materialize);
580
  BailoutId ast_id = hydrogen_env->ast_id();
581
  DCHECK(!ast_id.IsNone() ||
582
         hydrogen_env->frame_type() != JS_FUNCTION);
583 584 585 586 587 588

  int omitted_count = (hydrogen_env->frame_type() == JS_FUNCTION)
                          ? 0
                          : hydrogen_env->specials_count();

  int value_count = hydrogen_env->length() - omitted_count;
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
  LEnvironment* result =
      new(zone()) LEnvironment(hydrogen_env->closure(),
                               hydrogen_env->frame_type(),
                               ast_id,
                               hydrogen_env->parameter_count(),
                               argument_count_,
                               value_count,
                               outer,
                               hydrogen_env->entry(),
                               zone());
  int argument_index = *argument_index_accumulator;

  // Store the environment description into the environment
  // (with holes for nested objects)
  for (int i = 0; i < hydrogen_env->length(); ++i) {
604 605 606 607
    if (hydrogen_env->is_special_index(i) &&
        hydrogen_env->frame_type() != JS_FUNCTION) {
      continue;
    }
608 609
    LOperand* op;
    HValue* value = hydrogen_env->values()->at(i);
610
    CHECK(!value->IsPushArguments());  // Do not deopt outgoing arguments
611 612 613 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 645
    if (value->IsArgumentsObject() || value->IsCapturedObject()) {
      op = LEnvironment::materialization_marker();
    } else {
      op = UseAny(value);
    }
    result->AddValue(op,
                     value->representation(),
                     value->CheckFlag(HInstruction::kUint32));
  }

  // Recursively store the nested objects into the environment
  for (int i = 0; i < hydrogen_env->length(); ++i) {
    if (hydrogen_env->is_special_index(i)) continue;

    HValue* value = hydrogen_env->values()->at(i);
    if (value->IsArgumentsObject() || value->IsCapturedObject()) {
      AddObjectToMaterialize(value, objects_to_materialize, result);
    }
  }

  if (hydrogen_env->frame_type() == JS_FUNCTION) {
    *argument_index_accumulator = argument_index;
  }

  return result;
}


// Add an object to the supplied environment and object materialization list.
//
// Notes:
//
// We are building three lists here:
//
// 1. In the result->object_mapping_ list (added to by the
jarin@chromium.org's avatar
jarin@chromium.org committed
646 647 648 649
//    LEnvironment::Add*Object methods), we store the lengths (number
//    of fields) of the captured objects in depth-first traversal order, or
//    in case of duplicated objects, we store the index to the duplicate object
//    (with a tag to differentiate between captured and duplicated objects).
650 651
//
// 2. The object fields are stored in the result->values_ list
jarin@chromium.org's avatar
jarin@chromium.org committed
652 653 654 655
//    (added to by the LEnvironment.AddValue method) sequentially as lists
//    of fields with holes for nested objects (the holes will be expanded
//    later by LCodegen::AddToTranslation according to the
//    LEnvironment.object_mapping_ list).
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
//
// 3. The auxiliary objects_to_materialize array stores the hydrogen values
//    in the same order as result->object_mapping_ list. This is used
//    to detect duplicate values and calculate the corresponding object index.
void LChunkBuilderBase::AddObjectToMaterialize(HValue* value,
    ZoneList<HValue*>* objects_to_materialize, LEnvironment* result) {
  int object_index = objects_to_materialize->length();
  // Store the hydrogen value into the de-duplication array
  objects_to_materialize->Add(value, zone());
  // Find out whether we are storing a duplicated value
  int previously_materialized_object = -1;
  for (int prev = 0; prev < object_index; ++prev) {
    if (objects_to_materialize->at(prev) == value) {
      previously_materialized_object = prev;
      break;
    }
  }
  // Store the captured object length (or duplicated object index)
  // into the environment. For duplicated objects, we stop here.
  int length = value->OperandCount();
  bool is_arguments = value->IsArgumentsObject();
  if (previously_materialized_object >= 0) {
    result->AddDuplicateObject(previously_materialized_object);
    return;
  } else {
    result->AddNewObject(is_arguments ? length - 1 : length, is_arguments);
  }
  // Store the captured object's fields into the environment
  for (int i = is_arguments ? 1 : 0; i < length; ++i) {
    LOperand* op;
    HValue* arg_value = value->OperandAt(i);
    if (arg_value->IsArgumentsObject() || arg_value->IsCapturedObject()) {
      // Insert a hole for nested objects
      op = LEnvironment::materialization_marker();
    } else {
691
      DCHECK(!arg_value->IsPushArguments());
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
      // For ordinary values, tell the register allocator we need the value
      // to be alive here
      op = UseAny(arg_value);
    }
    result->AddValue(op,
                     arg_value->representation(),
                     arg_value->CheckFlag(HInstruction::kUint32));
  }
  // Recursively store all the nested captured objects into the environment
  for (int i = is_arguments ? 1 : 0; i < length; ++i) {
    HValue* arg_value = value->OperandAt(i);
    if (arg_value->IsArgumentsObject() || arg_value->IsCapturedObject()) {
      AddObjectToMaterialize(arg_value, objects_to_materialize, result);
    }
  }
}


710 711 712 713 714 715 716
LPhase::~LPhase() {
  if (ShouldProduceTraceOutput()) {
    isolate()->GetHTracer()->TraceLithium(name(), chunk_);
  }
}


717 718
}  // namespace internal
}  // namespace v8