2012-05-23 14:24:29 +00:00
|
|
|
// Copyright 2012 the V8 project authors. All rights reserved.
|
2011-01-07 11:49:22 +00:00
|
|
|
// 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.
|
|
|
|
|
2011-03-18 20:35:07 +00:00
|
|
|
#include "v8.h"
|
2011-01-07 11:49:22 +00:00
|
|
|
#include "lithium.h"
|
2012-07-11 14:42:17 +00:00
|
|
|
#include "scopes.h"
|
|
|
|
|
|
|
|
#if V8_TARGET_ARCH_IA32
|
|
|
|
#include "ia32/lithium-ia32.h"
|
2012-07-12 15:10:34 +00:00
|
|
|
#include "ia32/lithium-codegen-ia32.h"
|
2012-07-11 14:42:17 +00:00
|
|
|
#elif V8_TARGET_ARCH_X64
|
|
|
|
#include "x64/lithium-x64.h"
|
2012-07-12 15:10:34 +00:00
|
|
|
#include "x64/lithium-codegen-x64.h"
|
2012-07-11 14:42:17 +00:00
|
|
|
#elif V8_TARGET_ARCH_ARM
|
|
|
|
#include "arm/lithium-arm.h"
|
2012-07-12 15:10:34 +00:00
|
|
|
#include "arm/lithium-codegen-arm.h"
|
2012-07-11 14:42:17 +00:00
|
|
|
#elif V8_TARGET_ARCH_MIPS
|
|
|
|
#include "mips/lithium-mips.h"
|
2012-07-12 15:10:34 +00:00
|
|
|
#include "mips/lithium-codegen-mips.h"
|
2012-07-11 14:42:17 +00:00
|
|
|
#else
|
|
|
|
#error "Unknown architecture."
|
|
|
|
#endif
|
2011-01-07 11:49:22 +00:00
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
|
2011-01-19 13:55:56 +00:00
|
|
|
|
|
|
|
void LOperand::PrintTo(StringStream* stream) {
|
|
|
|
LUnallocated* unalloc = NULL;
|
|
|
|
switch (kind()) {
|
|
|
|
case INVALID:
|
2012-01-24 02:13:28 +00:00
|
|
|
stream->Add("(0)");
|
2011-01-19 13:55:56 +00:00
|
|
|
break;
|
|
|
|
case UNALLOCATED:
|
|
|
|
unalloc = LUnallocated::cast(this);
|
|
|
|
stream->Add("v%d", unalloc->virtual_register());
|
2013-05-02 09:51:07 +00:00
|
|
|
if (unalloc->basic_policy() == LUnallocated::FIXED_SLOT) {
|
|
|
|
stream->Add("(=%dS)", unalloc->fixed_slot_index());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch (unalloc->extended_policy()) {
|
2011-01-19 13:55:56 +00:00
|
|
|
case LUnallocated::NONE:
|
|
|
|
break;
|
|
|
|
case LUnallocated::FIXED_REGISTER: {
|
2013-05-02 09:51:07 +00:00
|
|
|
int reg_index = unalloc->fixed_register_index();
|
2011-01-19 13:55:56 +00:00
|
|
|
const char* register_name =
|
2013-05-02 09:51:07 +00:00
|
|
|
Register::AllocationIndexToString(reg_index);
|
2011-01-19 13:55:56 +00:00
|
|
|
stream->Add("(=%s)", register_name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LUnallocated::FIXED_DOUBLE_REGISTER: {
|
2013-05-02 09:51:07 +00:00
|
|
|
int reg_index = unalloc->fixed_register_index();
|
2011-01-19 13:55:56 +00:00
|
|
|
const char* double_register_name =
|
2013-05-02 09:51:07 +00:00
|
|
|
DoubleRegister::AllocationIndexToString(reg_index);
|
2011-01-19 13:55:56 +00:00
|
|
|
stream->Add("(=%s)", double_register_name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LUnallocated::MUST_HAVE_REGISTER:
|
|
|
|
stream->Add("(R)");
|
|
|
|
break;
|
|
|
|
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;
|
|
|
|
case REGISTER:
|
|
|
|
stream->Add("[%s|R]", Register::AllocationIndexToString(index()));
|
|
|
|
break;
|
|
|
|
case DOUBLE_REGISTER:
|
|
|
|
stream->Add("[%s|R]", DoubleRegister::AllocationIndexToString(index()));
|
|
|
|
break;
|
|
|
|
case ARGUMENT:
|
|
|
|
stream->Add("[arg:%d]", index());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-12 13:56:56 +00:00
|
|
|
#define DEFINE_OPERAND_CACHE(name, type) \
|
2012-03-28 13:12:00 +00:00
|
|
|
L##name* L##name::cache = NULL; \
|
|
|
|
\
|
|
|
|
void L##name::SetUpCache() { \
|
2012-03-12 13:56:56 +00:00
|
|
|
if (cache) return; \
|
2012-03-28 13:12:00 +00:00
|
|
|
cache = new L##name[kNumCachedOperands]; \
|
2012-03-12 13:56:56 +00:00
|
|
|
for (int i = 0; i < kNumCachedOperands; i++) { \
|
|
|
|
cache[i].ConvertTo(type, i); \
|
|
|
|
} \
|
|
|
|
} \
|
2012-03-28 13:12:00 +00:00
|
|
|
\
|
|
|
|
void L##name::TearDownCache() { \
|
|
|
|
delete[] cache; \
|
|
|
|
}
|
2012-03-12 13:56:56 +00:00
|
|
|
|
2012-03-28 13:12:00 +00:00
|
|
|
LITHIUM_OPERAND_LIST(DEFINE_OPERAND_CACHE)
|
2012-03-12 13:56:56 +00:00
|
|
|
#undef DEFINE_OPERAND_CACHE
|
|
|
|
|
|
|
|
void LOperand::SetUpCaches() {
|
2012-03-28 13:12:00 +00:00
|
|
|
#define LITHIUM_OPERAND_SETUP(name, type) L##name::SetUpCache();
|
|
|
|
LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_SETUP)
|
|
|
|
#undef LITHIUM_OPERAND_SETUP
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void LOperand::TearDownCaches() {
|
|
|
|
#define LITHIUM_OPERAND_TEARDOWN(name, type) L##name::TearDownCache();
|
|
|
|
LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_TEARDOWN)
|
|
|
|
#undef LITHIUM_OPERAND_TEARDOWN
|
2012-03-12 13:56:56 +00:00
|
|
|
}
|
2011-01-19 13:55:56 +00:00
|
|
|
|
2012-03-28 13:12:00 +00:00
|
|
|
|
2011-01-10 11:31:21 +00:00
|
|
|
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 {
|
2011-01-17 11:25:36 +00:00
|
|
|
bool first = true;
|
|
|
|
for (int i = 0; i < move_operands_.length(); ++i) {
|
2011-01-10 11:31:21 +00:00
|
|
|
if (!move_operands_[i].IsEliminated()) {
|
2011-01-17 11:25:36 +00:00
|
|
|
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);
|
2011-01-10 11:31:21 +00:00
|
|
|
} else {
|
2011-01-17 11:25:36 +00:00
|
|
|
destination->PrintTo(stream);
|
2011-01-10 11:31:21 +00:00
|
|
|
stream->Add(" = ");
|
2011-01-17 11:25:36 +00:00
|
|
|
source->PrintTo(stream);
|
2011-01-10 11:31:21 +00:00
|
|
|
}
|
2011-01-17 11:25:36 +00:00
|
|
|
stream->Add(";");
|
2011-01-10 11:31:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-11 15:51:08 +00:00
|
|
|
void LEnvironment::PrintTo(StringStream* stream) {
|
2012-08-06 14:13:09 +00:00
|
|
|
stream->Add("[id=%d|", ast_id().ToInt());
|
2013-02-11 14:12:13 +00:00
|
|
|
if (deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
|
|
|
|
stream->Add("deopt_id=%d|", deoptimization_index());
|
|
|
|
}
|
2013-04-24 09:31:55 +00:00
|
|
|
stream->Add("parameters=%d|", parameter_count());
|
|
|
|
stream->Add("arguments_stack_height=%d|", arguments_stack_height());
|
2011-01-11 15:51:08 +00:00
|
|
|
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("]");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-11 12:42:31 +00:00
|
|
|
void LPointerMap::RecordPointer(LOperand* op, Zone* zone) {
|
2011-01-11 15:51:08 +00:00
|
|
|
// Do not record arguments as pointers.
|
|
|
|
if (op->IsStackSlot() && op->index() < 0) return;
|
|
|
|
ASSERT(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
|
2012-06-11 12:42:31 +00:00
|
|
|
pointer_operands_.Add(op, zone);
|
2011-01-11 15:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-19 18:36:47 +00:00
|
|
|
void LPointerMap::RemovePointer(LOperand* op) {
|
|
|
|
// Do not record arguments as pointers.
|
|
|
|
if (op->IsStackSlot() && op->index() < 0) return;
|
|
|
|
ASSERT(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
|
|
|
|
for (int i = 0; i < pointer_operands_.length(); ++i) {
|
|
|
|
if (pointer_operands_[i]->Equals(op)) {
|
|
|
|
pointer_operands_.Remove(i);
|
|
|
|
--i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-11 12:42:31 +00:00
|
|
|
void LPointerMap::RecordUntagged(LOperand* op, Zone* zone) {
|
2011-09-19 18:36:47 +00:00
|
|
|
// Do not record arguments as pointers.
|
|
|
|
if (op->IsStackSlot() && op->index() < 0) return;
|
|
|
|
ASSERT(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
|
2012-06-11 12:42:31 +00:00
|
|
|
untagged_operands_.Add(op, zone);
|
2011-09-19 18:36:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-11 15:51:08 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
stream->Add("} @%d", position());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-09 09:35:57 +00:00
|
|
|
int ElementsKindToShiftSize(ElementsKind elements_kind) {
|
2011-06-09 15:19:37 +00:00
|
|
|
switch (elements_kind) {
|
2011-09-09 09:35:57 +00:00
|
|
|
case EXTERNAL_BYTE_ELEMENTS:
|
|
|
|
case EXTERNAL_PIXEL_ELEMENTS:
|
|
|
|
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
|
2011-05-10 15:25:17 +00:00
|
|
|
return 0;
|
2011-09-09 09:35:57 +00:00
|
|
|
case EXTERNAL_SHORT_ELEMENTS:
|
|
|
|
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
|
2011-05-10 15:25:17 +00:00
|
|
|
return 1;
|
2011-09-09 09:35:57 +00:00
|
|
|
case EXTERNAL_INT_ELEMENTS:
|
|
|
|
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
|
|
|
|
case EXTERNAL_FLOAT_ELEMENTS:
|
2011-05-10 15:25:17 +00:00
|
|
|
return 2;
|
2011-09-09 09:35:57 +00:00
|
|
|
case EXTERNAL_DOUBLE_ELEMENTS:
|
|
|
|
case FAST_DOUBLE_ELEMENTS:
|
2012-05-23 14:24:29 +00:00
|
|
|
case FAST_HOLEY_DOUBLE_ELEMENTS:
|
2011-05-10 15:25:17 +00:00
|
|
|
return 3;
|
2012-05-23 14:24:29 +00:00
|
|
|
case FAST_SMI_ELEMENTS:
|
2011-09-09 09:35:57 +00:00
|
|
|
case FAST_ELEMENTS:
|
2012-05-23 14:24:29 +00:00
|
|
|
case FAST_HOLEY_SMI_ELEMENTS:
|
|
|
|
case FAST_HOLEY_ELEMENTS:
|
2011-09-09 09:35:57 +00:00
|
|
|
case DICTIONARY_ELEMENTS:
|
|
|
|
case NON_STRICT_ARGUMENTS_ELEMENTS:
|
2011-06-09 15:19:37 +00:00
|
|
|
return kPointerSizeLog2;
|
2011-05-10 15:25:17 +00:00
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-02-07 13:15:41 +00:00
|
|
|
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.
|
|
|
|
return -(index + 3) * kPointerSize;
|
|
|
|
} else {
|
|
|
|
// Incoming parameter. Skip the return address.
|
2013-07-23 13:46:10 +00:00
|
|
|
return -(index + 1) * kPointerSize + kFPOnStackSize + kPCOnStackSize;
|
2013-02-07 13:15:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-02-04 12:01:59 +00:00
|
|
|
LChunk::LChunk(CompilationInfo* info, HGraph* graph)
|
|
|
|
: spill_slot_count_(0),
|
|
|
|
info_(info),
|
|
|
|
graph_(graph),
|
|
|
|
instructions_(32, graph->zone()),
|
|
|
|
pointer_maps_(8, graph->zone()),
|
|
|
|
inlined_closures_(1, graph->zone()) {
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-12 15:29:14 +00:00
|
|
|
LLabel* LChunk::GetLabel(int block_id) const {
|
2012-07-11 14:42:17 +00:00
|
|
|
HBasicBlock* block = graph_->blocks()->at(block_id);
|
|
|
|
int first_instruction = block->first_instruction_index();
|
|
|
|
return LLabel::cast(instructions_[first_instruction]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-12 15:29:14 +00:00
|
|
|
int LChunk::LookupDestination(int block_id) const {
|
2012-07-11 14:42:17 +00:00
|
|
|
LLabel* cur = GetLabel(block_id);
|
|
|
|
while (cur->replacement() != NULL) {
|
|
|
|
cur = cur->replacement();
|
|
|
|
}
|
|
|
|
return cur->block_id();
|
|
|
|
}
|
|
|
|
|
2012-07-12 15:29:14 +00:00
|
|
|
Label* LChunk::GetAssemblyLabel(int block_id) const {
|
2012-07-11 14:42:17 +00:00
|
|
|
LLabel* label = GetLabel(block_id);
|
|
|
|
ASSERT(!label->HasReplacement());
|
|
|
|
return label->label();
|
|
|
|
}
|
|
|
|
|
2013-07-05 09:52:11 +00:00
|
|
|
|
2012-07-12 15:29:14 +00:00
|
|
|
void LChunk::MarkEmptyBlocks() {
|
2013-06-25 12:22:26 +00:00
|
|
|
LPhase phase("L_Mark empty blocks", this);
|
2012-07-11 14:42:17 +00:00
|
|
|
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()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-12 15:29:14 +00:00
|
|
|
void LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
|
2012-07-11 14:42:17 +00:00
|
|
|
LInstructionGap* gap = new(graph_->zone()) LInstructionGap(block);
|
2013-04-22 09:48:35 +00:00
|
|
|
gap->set_hydrogen_value(instr->hydrogen_value());
|
2012-07-11 14:42:17 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-12 15:29:14 +00:00
|
|
|
LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) {
|
2012-07-11 14:42:17 +00:00
|
|
|
return LConstantOperand::Create(constant->id(), zone());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-12 15:29:14 +00:00
|
|
|
int LChunk::GetParameterStackSlot(int index) const {
|
2012-07-11 14:42:17 +00:00
|
|
|
// 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.
|
|
|
|
int result = index - info()->scope()->num_parameters() - 1;
|
|
|
|
ASSERT(result < 0);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// A parameter relative to ebp in the arguments stub.
|
2012-07-12 15:29:14 +00:00
|
|
|
int LChunk::ParameterAt(int index) {
|
2012-07-11 14:42:17 +00:00
|
|
|
ASSERT(-1 <= index); // -1 is the receiver.
|
|
|
|
return (1 + info()->scope()->num_parameters() - index) *
|
|
|
|
kPointerSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-12 15:29:14 +00:00
|
|
|
LGap* LChunk::GetGapAt(int index) const {
|
2012-07-11 14:42:17 +00:00
|
|
|
return LGap::cast(instructions_[index]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-12 15:29:14 +00:00
|
|
|
bool LChunk::IsGapAt(int index) const {
|
2012-07-11 14:42:17 +00:00
|
|
|
return instructions_[index]->IsGap();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-12 15:29:14 +00:00
|
|
|
int LChunk::NearestGapPos(int index) const {
|
2012-07-11 14:42:17 +00:00
|
|
|
while (!IsGapAt(index)) index--;
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-12 15:29:14 +00:00
|
|
|
void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
|
2012-07-11 14:42:17 +00:00
|
|
|
GetGapAt(index)->GetOrCreateParallelMove(
|
|
|
|
LGap::START, zone())->AddMove(from, to, zone());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-12 15:29:14 +00:00
|
|
|
HConstant* LChunk::LookupConstant(LConstantOperand* operand) const {
|
2012-07-11 16:17:02 +00:00
|
|
|
return HConstant::cast(graph_->LookupValue(operand->index()));
|
2012-07-11 14:42:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-12 15:29:14 +00:00
|
|
|
Representation LChunk::LookupLiteralRepresentation(
|
2012-07-11 14:42:17 +00:00
|
|
|
LConstantOperand* operand) const {
|
|
|
|
return graph_->LookupValue(operand->index())->representation();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-12 15:29:14 +00:00
|
|
|
LChunk* LChunk::NewChunk(HGraph* graph) {
|
2013-06-03 15:32:22 +00:00
|
|
|
DisallowHandleAllocation no_handles;
|
|
|
|
DisallowHeapAllocation no_gc;
|
2012-07-12 15:10:34 +00:00
|
|
|
int values = graph->GetMaximumValueID();
|
2012-08-28 07:18:06 +00:00
|
|
|
CompilationInfo* info = graph->info();
|
2012-07-12 15:10:34 +00:00
|
|
|
if (values > LUnallocated::kMaxVirtualRegisters) {
|
2013-08-02 09:53:11 +00:00
|
|
|
info->set_bailout_reason(kNotEnoughVirtualRegistersForValues);
|
2012-07-12 15:10:34 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
LAllocator allocator(values, graph);
|
2012-08-28 07:18:06 +00:00
|
|
|
LChunkBuilder builder(info, graph, &allocator);
|
2012-07-12 15:29:14 +00:00
|
|
|
LChunk* chunk = builder.Build();
|
2012-07-12 15:10:34 +00:00
|
|
|
if (chunk == NULL) return NULL;
|
|
|
|
|
|
|
|
if (!allocator.Allocate(chunk)) {
|
2013-08-02 09:53:11 +00:00
|
|
|
info->set_bailout_reason(kNotEnoughVirtualRegistersRegalloc);
|
2012-07-12 15:10:34 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-02-04 12:01:59 +00:00
|
|
|
chunk->set_allocated_double_registers(
|
|
|
|
allocator.assigned_double_registers());
|
|
|
|
|
2012-07-12 15:10:34 +00:00
|
|
|
return chunk;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-18 09:50:46 +00:00
|
|
|
Handle<Code> LChunk::Codegen() {
|
2012-07-12 15:10:34 +00:00
|
|
|
MacroAssembler assembler(info()->isolate(), NULL, 0);
|
2013-02-18 18:06:12 +00:00
|
|
|
LOG_CODE_EVENT(info()->isolate(),
|
|
|
|
CodeStartLinePosInfoRecordEvent(
|
|
|
|
assembler.positions_recorder()));
|
2012-07-12 15:10:34 +00:00
|
|
|
LCodeGen generator(this, &assembler, info());
|
|
|
|
|
|
|
|
MarkEmptyBlocks();
|
|
|
|
|
|
|
|
if (generator.GenerateCode()) {
|
2013-05-24 10:57:59 +00:00
|
|
|
CodeGenerator::MakeCodePrologue(info(), "optimized");
|
2013-04-18 09:50:46 +00:00
|
|
|
Code::Flags flags = info()->flags();
|
2012-07-12 15:10:34 +00:00
|
|
|
Handle<Code> code =
|
|
|
|
CodeGenerator::MakeCodeEpilogue(&assembler, flags, info());
|
|
|
|
generator.FinishCode(code);
|
2013-04-18 09:50:46 +00:00
|
|
|
code->set_is_crankshafted(true);
|
2013-08-16 19:52:29 +00:00
|
|
|
void* jit_handler_data =
|
|
|
|
assembler.positions_recorder()->DetachJITHandlerData();
|
|
|
|
LOG_CODE_EVENT(info()->isolate(),
|
|
|
|
CodeEndLinePosInfoRecordEvent(*code, jit_handler_data));
|
2013-02-18 18:06:12 +00:00
|
|
|
|
2012-07-12 15:10:34 +00:00
|
|
|
CodeGenerator::PrintCode(code, info());
|
|
|
|
return code;
|
|
|
|
}
|
|
|
|
return Handle<Code>::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-02-04 12:01:59 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-02 11:43:41 +00:00
|
|
|
LInstruction* LChunkBuilder::CheckElideControlInstruction(
|
|
|
|
HControlInstruction* instr) {
|
|
|
|
HBasicBlock* successor;
|
|
|
|
if (!instr->KnownSuccessorBlock(&successor)) return NULL;
|
|
|
|
return new(zone()) LGoto(successor);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-25 12:22:26 +00:00
|
|
|
LPhase::~LPhase() {
|
|
|
|
if (ShouldProduceTraceOutput()) {
|
|
|
|
isolate()->GetHTracer()->TraceLithium(name(), chunk_);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-07 11:49:22 +00:00
|
|
|
} } // namespace v8::internal
|