Commit ba023c54 authored by lrn@chromium.org's avatar lrn@chromium.org

X64 Crankshaft: Ported lots of boilerplate code.

Small tweaks to make X64 compliant.
A few UNIMPLEMENTED left, but most empty functions call Abort to bail out.

Review URL: http://codereview.chromium.org/6201006

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6297 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 0b047d79
......@@ -42,7 +42,6 @@ namespace internal {
class LDeferredCode;
class SafepointGenerator;
class LCodeGen BASE_EMBEDDED {
public:
LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info)
......
......@@ -186,6 +186,20 @@ void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
CPU::FlushICache(pc_, instruction_count);
}
// -----------------------------------------------------------------------------
// Register constants.
const int Register::registerCodeByAllocationIndex[kNumAllocatableRegisters] = {
// rax, rbx, rdx, rcx, rdi, r8, r9, r11, r14, r12
0, 3, 2, 1, 7, 8, 9, 11, 14, 12
};
const int Register::allocationIndexByRegisterCode[kNumRegisters] = {
0, 3, 2, 1, -1, -1, -1, 4, 5, 6, -1, 7, 9, -1, 8, -1
};
// -----------------------------------------------------------------------------
// Implementation of Operand
......
......@@ -98,6 +98,16 @@ struct Register {
static const int kNumRegisters = 16;
static const int kNumAllocatableRegisters = 10;
static int ToAllocationIndex(Register reg) {
return allocationIndexByRegisterCode[reg.code()];
}
static Register FromAllocationIndex(int index) {
ASSERT(index >= 0 && index < kNumAllocatableRegisters);
Register result = { registerCodeByAllocationIndex[index] };
return result;
}
static const char* AllocationIndexToString(int index) {
ASSERT(index >= 0 && index < kNumAllocatableRegisters);
const char* const names[] = {
......@@ -143,6 +153,9 @@ struct Register {
// Unfortunately we can't make this private in a struct when initializing
// by assignment.
int code_;
private:
static const int registerCodeByAllocationIndex[kNumAllocatableRegisters];
static const int allocationIndexByRegisterCode[kNumRegisters];
};
const Register rax = { 0 };
......@@ -173,6 +186,12 @@ struct XMMRegister {
return reg.code() - 1;
}
static XMMRegister FromAllocationIndex(int index) {
ASSERT(0 <= index && index < kNumAllocatableRegisters);
XMMRegister result = { index + 1 };
return result;
}
static const char* AllocationIndexToString(int index) {
ASSERT(index >= 0 && index < kNumAllocatableRegisters);
const char* const names[] = {
......
......@@ -35,6 +35,148 @@ namespace internal {
#define __ masm()->
bool LCodeGen::GenerateCode() {
HPhase phase("Code generation", chunk());
ASSERT(is_unused());
status_ = GENERATING;
return GeneratePrologue() &&
GenerateBody() &&
GenerateDeferredCode() &&
GenerateSafepointTable();
}
void LCodeGen::FinishCode(Handle<Code> code) {
ASSERT(is_done());
code->set_stack_slots(StackSlotCount());
code->set_safepoint_table_start(safepoints_.GetCodeOffset());
PopulateDeoptimizationData(code);
}
void LCodeGen::Abort(const char* format, ...) {
if (FLAG_trace_bailout) {
SmartPointer<char> debug_name = graph()->debug_name()->ToCString();
PrintF("Aborting LCodeGen in @\"%s\": ", *debug_name);
va_list arguments;
va_start(arguments, format);
OS::VPrint(format, arguments);
va_end(arguments);
PrintF("\n");
}
status_ = ABORTED;
}
void LCodeGen::Comment(const char* format, ...) {
Abort("Unimplemented: %s", "Comment");
}
bool LCodeGen::GeneratePrologue() {
Abort("Unimplemented: %s", "GeneratePrologue");
return !is_aborted();
}
bool LCodeGen::GenerateBody() {
ASSERT(is_generating());
bool emit_instructions = true;
for (current_instruction_ = 0;
!is_aborted() && current_instruction_ < instructions_->length();
current_instruction_++) {
LInstruction* instr = instructions_->at(current_instruction_);
if (instr->IsLabel()) {
LLabel* label = LLabel::cast(instr);
emit_instructions = !label->HasReplacement();
}
if (emit_instructions) {
Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
instr->CompileToNative(this);
}
}
return !is_aborted();
}
LInstruction* LCodeGen::GetNextInstruction() {
if (current_instruction_ < instructions_->length() - 1) {
return instructions_->at(current_instruction_ + 1);
} else {
return NULL;
}
}
bool LCodeGen::GenerateDeferredCode() {
ASSERT(is_generating());
for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
LDeferredCode* code = deferred_[i];
__ bind(code->entry());
code->Generate();
__ jmp(code->exit());
}
// Deferred code is the last part of the instruction sequence. Mark
// the generated code as done unless we bailed out.
if (!is_aborted()) status_ = DONE;
return !is_aborted();
}
bool LCodeGen::GenerateSafepointTable() {
Abort("Unimplemented: %s", "GeneratePrologue");
return !is_aborted();
}
Register LCodeGen::ToRegister(int index) const {
return Register::FromAllocationIndex(index);
}
XMMRegister LCodeGen::ToDoubleRegister(int index) const {
return XMMRegister::FromAllocationIndex(index);
}
Register LCodeGen::ToRegister(LOperand* op) const {
ASSERT(op->IsRegister());
return ToRegister(op->index());
}
XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
ASSERT(op->IsDoubleRegister());
return ToDoubleRegister(op->index());
}
int LCodeGen::ToInteger32(LConstantOperand* op) const {
Handle<Object> value = chunk_->LookupLiteral(op);
ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) ==
value->Number());
return static_cast<int32_t>(value->Number());
}
Operand LCodeGen::ToOperand(LOperand* op) const {
// Does not handle registers. In X64 assembler, plain registers are not
// representable as an Operand.
ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
int index = op->index();
if (index >= 0) {
// Local or spill slot. Skip the frame pointer, function, and
// context in the fixed part of the frame.
return Operand(rbp, -(index + 3) * kPointerSize);
} else {
// Incoming parameter. Skip the return address.
return Operand(rbp, -(index - 1) * kPointerSize);
}
}
void LCodeGen::WriteTranslation(LEnvironment* environment,
Translation* translation) {
......@@ -75,6 +217,886 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
}
void LCodeGen::AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged) {
if (op == NULL) {
// TODO(twuerthinger): Introduce marker operands to indicate that this value
// is not present and must be reconstructed from the deoptimizer. Currently
// this is only used for the arguments object.
translation->StoreArgumentsObject();
} else if (op->IsStackSlot()) {
if (is_tagged) {
translation->StoreStackSlot(op->index());
} else {
translation->StoreInt32StackSlot(op->index());
}
} else if (op->IsDoubleStackSlot()) {
translation->StoreDoubleStackSlot(op->index());
} else if (op->IsArgument()) {
ASSERT(is_tagged);
int src_index = StackSlotCount() + op->index();
translation->StoreStackSlot(src_index);
} else if (op->IsRegister()) {
Register reg = ToRegister(op);
if (is_tagged) {
translation->StoreRegister(reg);
} else {
translation->StoreInt32Register(reg);
}
} else if (op->IsDoubleRegister()) {
XMMRegister reg = ToDoubleRegister(op);
translation->StoreDoubleRegister(reg);
} else if (op->IsConstantOperand()) {
Handle<Object> literal = chunk()->LookupLiteral(LConstantOperand::cast(op));
int src_index = DefineDeoptimizationLiteral(literal);
translation->StoreLiteral(src_index);
} else {
UNREACHABLE();
}
}
void LCodeGen::CallCode(Handle<Code> code,
RelocInfo::Mode mode,
LInstruction* instr) {
Abort("Unimplemented: %s", "CallCode");
}
void LCodeGen::CallRuntime(Runtime::Function* function,
int num_arguments,
LInstruction* instr) {
Abort("Unimplemented: %s", "CallRuntime");
}
void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr) {
// Create the environment to bailout to. If the call has side effects
// execution has to continue after the call otherwise execution can continue
// from a previous bailout point repeating the call.
LEnvironment* deoptimization_environment;
if (instr->HasDeoptimizationEnvironment()) {
deoptimization_environment = instr->deoptimization_environment();
} else {
deoptimization_environment = instr->environment();
}
RegisterEnvironmentForDeoptimization(deoptimization_environment);
RecordSafepoint(instr->pointer_map(),
deoptimization_environment->deoptimization_index());
}
void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
Abort("Unimplemented: %s", "RegisterEnvironmentForDeoptimization");
}
void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
Abort("Unimplemented: %s", "Deoptimiz");
}
void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
int length = deoptimizations_.length();
if (length == 0) return;
ASSERT(FLAG_deopt);
Handle<DeoptimizationInputData> data =
Factory::NewDeoptimizationInputData(length, TENURED);
data->SetTranslationByteArray(*translations_.CreateByteArray());
data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
Handle<FixedArray> literals =
Factory::NewFixedArray(deoptimization_literals_.length(), TENURED);
for (int i = 0; i < deoptimization_literals_.length(); i++) {
literals->set(i, *deoptimization_literals_[i]);
}
data->SetLiteralArray(*literals);
data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id()));
data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
// Populate the deoptimization entries.
for (int i = 0; i < length; i++) {
LEnvironment* env = deoptimizations_[i];
data->SetAstId(i, Smi::FromInt(env->ast_id()));
data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
data->SetArgumentsStackHeight(i,
Smi::FromInt(env->arguments_stack_height()));
}
code->set_deoptimization_data(*data);
}
int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
int result = deoptimization_literals_.length();
for (int i = 0; i < deoptimization_literals_.length(); ++i) {
if (deoptimization_literals_[i].is_identical_to(literal)) return i;
}
deoptimization_literals_.Add(literal);
return result;
}
void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
ASSERT(deoptimization_literals_.length() == 0);
const ZoneList<Handle<JSFunction> >* inlined_closures =
chunk()->inlined_closures();
for (int i = 0, length = inlined_closures->length();
i < length;
i++) {
DefineDeoptimizationLiteral(inlined_closures->at(i));
}
inlined_function_count_ = deoptimization_literals_.length();
}
void LCodeGen::RecordSafepoint(LPointerMap* pointers,
int deoptimization_index) {
const ZoneList<LOperand*>* operands = pointers->operands();
Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
deoptimization_index);
for (int i = 0; i < operands->length(); i++) {
LOperand* pointer = operands->at(i);
if (pointer->IsStackSlot()) {
safepoint.DefinePointerSlot(pointer->index());
}
}
}
void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments,
int deoptimization_index) {
const ZoneList<LOperand*>* operands = pointers->operands();
Safepoint safepoint =
safepoints_.DefineSafepointWithRegisters(
masm(), arguments, deoptimization_index);
for (int i = 0; i < operands->length(); i++) {
LOperand* pointer = operands->at(i);
if (pointer->IsStackSlot()) {
safepoint.DefinePointerSlot(pointer->index());
} else if (pointer->IsRegister()) {
safepoint.DefinePointerRegister(ToRegister(pointer));
}
}
// Register rsi always contains a pointer to the context.
safepoint.DefinePointerRegister(rsi);
}
void LCodeGen::RecordPosition(int position) {
if (!FLAG_debug_info || position == RelocInfo::kNoPosition) return;
masm()->positions_recorder()->RecordPosition(position);
}
void LCodeGen::DoLabel(LLabel* label) {
if (label->is_loop_header()) {
Comment(";;; B%d - LOOP entry", label->block_id());
} else {
Comment(";;; B%d", label->block_id());
}
__ bind(label->label());
current_block_ = label->block_id();
LCodeGen::DoGap(label);
}
void LCodeGen::DoParallelMove(LParallelMove* move) {
Abort("Unimplemented: %s", "DoParallelMove");
}
void LCodeGen::DoGap(LGap* gap) {
for (int i = LGap::FIRST_INNER_POSITION;
i <= LGap::LAST_INNER_POSITION;
i++) {
LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
LParallelMove* move = gap->GetParallelMove(inner_pos);
if (move != NULL) DoParallelMove(move);
}
LInstruction* next = GetNextInstruction();
if (next != NULL && next->IsLazyBailout()) {
int pc = masm()->pc_offset();
safepoints_.SetPcAfterGap(pc);
}
}
void LCodeGen::DoParameter(LParameter* instr) {
// Nothing to do.
}
void LCodeGen::DoCallStub(LCallStub* instr) {
Abort("Unimplemented: %s", "DoCallStub");
}
void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
// Nothing to do.
}
void LCodeGen::DoModI(LModI* instr) {
Abort("Unimplemented: %s", "DoModI");
}
void LCodeGen::DoDivI(LDivI* instr) {
Abort("Unimplemented: %s", "DoDivI");}
void LCodeGen::DoMulI(LMulI* instr) {
Abort("Unimplemented: %s", "DoMultI");}
void LCodeGen::DoBitI(LBitI* instr) {
Abort("Unimplemented: %s", "DoBitI");}
void LCodeGen::DoShiftI(LShiftI* instr) {
Abort("Unimplemented: %s", "DoShiftI");
}
void LCodeGen::DoSubI(LSubI* instr) {
Abort("Unimplemented: %s", "DoSubI");
}
void LCodeGen::DoConstantI(LConstantI* instr) {
Abort("Unimplemented: %s", "DoConstantI");
}
void LCodeGen::DoConstantD(LConstantD* instr) {
Abort("Unimplemented: %s", "DoConstantI");
}
void LCodeGen::DoConstantT(LConstantT* instr) {
Abort("Unimplemented: %s", "DoConstantT");
}
void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
Abort("Unimplemented: %s", "DoJSArrayLength");
}
void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
Abort("Unimplemented: %s", "DoFixedArrayLength");
}
void LCodeGen::DoValueOf(LValueOf* instr) {
Abort("Unimplemented: %s", "DoValueOf");
}
void LCodeGen::DoBitNotI(LBitNotI* instr) {
Abort("Unimplemented: %s", "DoBitNotI");
}
void LCodeGen::DoThrow(LThrow* instr) {
Abort("Unimplemented: %s", "DoThrow");
}
void LCodeGen::DoAddI(LAddI* instr) {
Abort("Unimplemented: %s", "DoAddI");
}
void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
Abort("Unimplemented: %s", "DoArithmeticD");
}
void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
Abort("Unimplemented: %s", "DoArithmeticT");
}
int LCodeGen::GetNextEmittedBlock(int block) {
for (int i = block + 1; i < graph()->blocks()->length(); ++i) {
LLabel* label = chunk_->GetLabel(i);
if (!label->HasReplacement()) return i;
}
return -1;
}
void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
Abort("Unimplemented: %s", "EmitBranch");
}
void LCodeGen::DoBranch(LBranch* instr) {
Abort("Unimplemented: %s", "DoBranch");
}
void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) {
Abort("Unimplemented: %s", "EmitGoto");
}
void LCodeGen::DoDeferredStackCheck(LGoto* instr) {
Abort("Unimplemented: %s", "DoDeferredStackCheck");
}
void LCodeGen::DoGoto(LGoto* instr) {
Abort("Unimplemented: %s", "DoGoto");
}
Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
Condition cond = no_condition;
switch (op) {
case Token::EQ:
case Token::EQ_STRICT:
cond = equal;
break;
case Token::LT:
cond = is_unsigned ? below : less;
break;
case Token::GT:
cond = is_unsigned ? above : greater;
break;
case Token::LTE:
cond = is_unsigned ? below_equal : less_equal;
break;
case Token::GTE:
cond = is_unsigned ? above_equal : greater_equal;
break;
case Token::IN:
case Token::INSTANCEOF:
default:
UNREACHABLE();
}
return cond;
}
void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) {
Abort("Unimplemented: %s", "EmitCmpI");
}
void LCodeGen::DoCmpID(LCmpID* instr) {
Abort("Unimplemented: %s", "DoCmpID");
}
void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
Abort("Unimplemented: %s", "DoCmpIDAndBranch");
}
void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) {
Abort("Unimplemented: %s", "DoCmpJSObjectEq");
}
void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) {
Abort("Unimplemented: %s", "DoCmpJSObjectAndBranch");
}
void LCodeGen::DoIsNull(LIsNull* instr) {
Abort("Unimplemented: %s", "DoIsNull");
}
void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
Abort("Unimplemented: %s", "DoIsNullAndBranch");
}
Condition LCodeGen::EmitIsObject(Register input,
Register temp1,
Register temp2,
Label* is_not_object,
Label* is_object) {
Abort("Unimplemented: %s", "EmitIsObject");
return below_equal;
}
void LCodeGen::DoIsObject(LIsObject* instr) {
Abort("Unimplemented: %s", "DoIsObject");
}
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
Abort("Unimplemented: %s", "DoIsObjectAndBranch");
}
void LCodeGen::DoIsSmi(LIsSmi* instr) {
Abort("Unimplemented: %s", "DoIsSmi");
}
void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
Abort("Unimplemented: %s", "DoIsSmiAndBranch");
}
InstanceType LHasInstanceType::TestType() {
InstanceType from = hydrogen()->from();
InstanceType to = hydrogen()->to();
if (from == FIRST_TYPE) return to;
ASSERT(from == to || to == LAST_TYPE);
return from;
}
Condition LHasInstanceType::BranchCondition() {
InstanceType from = hydrogen()->from();
InstanceType to = hydrogen()->to();
if (from == to) return equal;
if (to == LAST_TYPE) return above_equal;
if (from == FIRST_TYPE) return below_equal;
UNREACHABLE();
return equal;
}
void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) {
Abort("Unimplemented: %s", "DoHasInstanceType");
}
void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
Abort("Unimplemented: %s", "DoHasInstanceTypeAndBranch");
}
void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
Abort("Unimplemented: %s", "DoHasCachedArrayIndex");
}
void LCodeGen::DoHasCachedArrayIndexAndBranch(
LHasCachedArrayIndexAndBranch* instr) {
Abort("Unimplemented: %s", "DoHasCachedArrayIndexAndBranch");
}
// Branches to a label or falls through with the answer in the z flag. Trashes
// the temp registers, but not the input. Only input and temp2 may alias.
void LCodeGen::EmitClassOfTest(Label* is_true,
Label* is_false,
Handle<String>class_name,
Register input,
Register temp,
Register temp2) {
Abort("Unimplemented: %s", "EmitClassOfTest");
}
void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
Abort("Unimplemented: %s", "DoClassOfTest");
}
void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
Abort("Unimplemented: %s", "DoClassOfTestAndBranch");
}
void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
Abort("Unimplemented: %s", "DoCmpMapAndBranch");
}
void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
Abort("Unimplemented: %s", "DoInstanceOf");
}
void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) {
Abort("Unimplemented: %s", "DoInstanceOfAndBranch");
}
void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
Abort("Unimplemented: %s", "DoInstanceOfKnowGLobal");
}
void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check) {
Abort("Unimplemented: %s", "DoDeferredLInstanceOfKnownGlobakl");
}
void LCodeGen::DoCmpT(LCmpT* instr) {
Abort("Unimplemented: %s", "DoCmpT");
}
void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) {
Abort("Unimplemented: %s", "DoCmpTAndBranch");
}
void LCodeGen::DoReturn(LReturn* instr) {
Abort("Unimplemented: %s", "DoReturn");
}
void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) {
Abort("Unimplemented: %s", "DoLoadGlobal");
}
void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) {
Abort("Unimplemented: %s", "DoStoreGlobal");
}
void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
Abort("Unimplemented: %s", "DoLoadNamedField");
}
void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
Abort("Unimplemented: %s", "DoLoadNamedGeneric");
}
void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
Abort("Unimplemented: %s", "DoLoadFunctionPrototype");
}
void LCodeGen::DoLoadElements(LLoadElements* instr) {
Abort("Unimplemented: %s", "DoLoadElements");
}
void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
Abort("Unimplemented: %s", "DoAccessArgumentsAt");
}
void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
Abort("Unimplemented: %s", "DoLoadKeyedFastElement");
}
void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
Abort("Unimplemented: %s", "DoLoadKeyedGeneric");
}
void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
Abort("Unimplemented: %s", "DoArgumentsElements");
}
void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
Abort("Unimplemented: %s", "DoArgumentsLength");
}
void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
Abort("Unimplemented: %s", "DoApplyArguments");
}
void LCodeGen::DoPushArgument(LPushArgument* instr) {
Abort("Unimplemented: %s", "DoPushArgument");
}
void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
Abort("Unimplemented: %s", "DoGlobalObject");
}
void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
Abort("Unimplemented: %s", "DoGlobalReceiver");
}
void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr) {
Abort("Unimplemented: %s", "CallKnownFunction");
}
void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
Abort("Unimplemented: %s", "DoCallConstantFunction");
}
void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
Abort("Unimplemented: %s", "DoDeferredMathAbsTaggedHeapNumber");
}
void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
Abort("Unimplemented: %s", "DoMathAbs");
}
void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
Abort("Unimplemented: %s", "DoMathFloor");
}
void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
Abort("Unimplemented: %s", "DoMathRound");
}
void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
Abort("Unimplemented: %s", "DoMathSqrt");
}
void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
Abort("Unimplemented: %s", "DoMathPowHalf");
}
void LCodeGen::DoPower(LPower* instr) {
Abort("Unimplemented: %s", "DoPower");
}
void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
Abort("Unimplemented: %s", "DoMathLog");
}
void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
Abort("Unimplemented: %s", "DoMathCos");
}
void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
Abort("Unimplemented: %s", "DoMathSin");
}
void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
Abort("Unimplemented: %s", "DoUnaryMathOperation");
}
void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
Abort("Unimplemented: %s", "DoCallKeyed");
}
void LCodeGen::DoCallNamed(LCallNamed* instr) {
Abort("Unimplemented: %s", "DoCallNamed");
}
void LCodeGen::DoCallFunction(LCallFunction* instr) {
Abort("Unimplemented: %s", "DoCallFunction");
}
void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
Abort("Unimplemented: %s", "DoCallGlobal");
}
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
Abort("Unimplemented: %s", "DoCallKnownGlobal");
}
void LCodeGen::DoCallNew(LCallNew* instr) {
Abort("Unimplemented: %s", "DoCallNew");
}
void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
Abort("Unimplemented: %s", "DoCallRuntime");
}
void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
Abort("Unimplemented: %s", "DoStoreNamedField");
}
void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
Abort("Unimplemented: %s", "DoStoreNamedGeneric");
}
void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
Abort("Unimplemented: %s", "DoBoundsCheck");
}
void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
Abort("Unimplemented: %s", "DoStoreKeyedFastElement");
}
void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
Abort("Unimplemented: %s", "DoStoreKeyedGeneric");
}
void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
Abort("Unimplemented: %s", "DoInteger32ToDouble");
}
void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
Abort("Unimplemented: %s", "DoNumberTagI");
}
void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
Abort("Unimplemented: %s", "DoDeferredNumberTagI");
}
void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
Abort("Unimplemented: %s", "DoNumberTagD");
}
void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
Abort("Unimplemented: %s", "DoDeferredNumberTagD");
}
void LCodeGen::DoSmiTag(LSmiTag* instr) {
Abort("Unimplemented: %s", "DoSmiTag");
}
void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
Abort("Unimplemented: %s", "DoSmiUntag");
}
void LCodeGen::EmitNumberUntagD(Register input_reg,
XMMRegister result_reg,
LEnvironment* env) {
Abort("Unimplemented: %s", "EmitNumberUntagD");
}
void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
Abort("Unimplemented: %s", "DoDeferredTaggedToI");
}
void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
Abort("Unimplemented: %s", "DoTaggedToI");
}
void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
Abort("Unimplemented: %s", "DoNumberUntagD");
}
void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
Abort("Unimplemented: %s", "DoDoubleToI");
}
void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
Abort("Unimplemented: %s", "DoCheckSmi");
}
void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
Abort("Unimplemented: %s", "DoCheckInstanceType");
}
void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
Abort("Unimplemented: %s", "DoCheckFunction");
}
void LCodeGen::DoCheckMap(LCheckMap* instr) {
Abort("Unimplemented: %s", "DoCheckMap");
}
void LCodeGen::LoadPrototype(Register result, Handle<JSObject> prototype) {
Abort("Unimplemented: %s", "LoadPrototype");
}
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
Abort("Unimplemented: %s", "DoCheckPrototypeMaps");
}
void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
Abort("Unimplemented: %s", "DoArrayLiteral");
}
void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
Abort("Unimplemented: %s", "DoObjectLiteral");
}
void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
Abort("Unimplemented: %s", "DoRegExpLiteral");
}
void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
Abort("Unimplemented: %s", "DoFunctionLiteral");
}
void LCodeGen::DoTypeof(LTypeof* instr) {
Abort("Unimplemented: %s", "DoTypeof");
}
void LCodeGen::DoTypeofIs(LTypeofIs* instr) {
Abort("Unimplemented: %s", "DoTypeofIs");
}
void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
Abort("Unimplemented: %s", "DoTypeofIsAndBranch");
}
Condition LCodeGen::EmitTypeofIs(Label* true_label,
Label* false_label,
Register input,
Handle<String> type_name) {
Abort("Unimplemented: %s", "EmitTypeofIs");
return no_condition;
}
void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
// No code for lazy bailout instruction. Used to capture environment after a
// call for populating the safepoint data with deoptimization data.
......@@ -86,11 +1108,20 @@ void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
}
void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
UNIMPLEMENTED();
void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
Abort("Unimplemented: %s", "DoDeleteProperty");
}
void LCodeGen::DoStackCheck(LStackCheck* instr) {
Abort("Unimplemented: %s", "DoStackCheck");
}
void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
Abort("Unimplemented: %s", "DoOsrEntry");
}
#undef __
} } // namespace v8::internal
......@@ -30,6 +30,7 @@
#include "x64/lithium-x64.h"
#include "checks.h"
#include "deoptimizer.h"
#include "safepoint-table.h"
#include "scopes.h"
......@@ -63,15 +64,20 @@ class LCodeGen BASE_EMBEDDED {
// Try to generate code for the entire chunk, but it may fail if the
// chunk contains constructs we cannot handle. Returns true if the
// code generation attempt succeeded.
bool GenerateCode() {
UNIMPLEMENTED();
return false;
}
bool GenerateCode();
// Finish the code by setting stack height, safepoint, and bailout
// information on it.
void FinishCode(Handle<Code> code) { UNIMPLEMENTED(); }
void FinishCode(Handle<Code> code);
// Deferred code support.
void DoDeferredNumberTagD(LNumberTagD* instr);
void DoDeferredNumberTagI(LNumberTagI* instr);
void DoDeferredTaggedToI(LTaggedToI* instr);
void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
void DoDeferredStackCheck(LGoto* instr);
void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check);
// Parallel move support.
void DoParallelMove(LParallelMove* move);
......@@ -102,55 +108,37 @@ class LCodeGen BASE_EMBEDDED {
HGraph* graph() const { return chunk_->graph(); }
MacroAssembler* masm() const { return masm_; }
int GetNextEmittedBlock(int block) {
UNIMPLEMENTED();
return 0;
}
LInstruction* GetNextInstruction() {
UNIMPLEMENTED();
return NULL;
}
int GetNextEmittedBlock(int block);
LInstruction* GetNextInstruction();
void EmitClassOfTest(Label* if_true,
Label* if_false,
Handle<String> class_name,
Register input,
Register temporary,
Register temporary2) { UNIMPLEMENTED(); }
Register temporary2);
int StackSlotCount() const { return chunk()->spill_slot_count(); }
int ParameterCount() const { return scope()->num_parameters(); }
void Abort(const char* format, ...) { UNIMPLEMENTED(); }
void Comment(const char* format, ...) { UNIMPLEMENTED(); }
void Abort(const char* format, ...);
void Comment(const char* format, ...);
void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code); }
// Code generation passes. Returns true if code generation should
// continue.
bool GeneratePrologue() {
UNIMPLEMENTED();
return true;
}
bool GenerateBody() {
UNIMPLEMENTED();
return true;
}
bool GenerateDeferredCode() {
UNIMPLEMENTED();
return true;
}
bool GenerateSafepointTable() {
UNIMPLEMENTED();
return true;
}
bool GeneratePrologue();
bool GenerateBody();
bool GenerateDeferredCode();
bool GenerateSafepointTable();
void CallCode(Handle<Code> code,
RelocInfo::Mode mode,
LInstruction* instr) { UNIMPLEMENTED(); }
LInstruction* instr);
void CallRuntime(Runtime::Function* function,
int num_arguments,
LInstruction* instr) { UNIMPLEMENTED(); }
LInstruction* instr);
void CallRuntime(Runtime::FunctionId id,
int num_arguments,
LInstruction* instr) {
......@@ -158,19 +146,70 @@ class LCodeGen BASE_EMBEDDED {
CallRuntime(function, num_arguments, instr);
}
void DeoptimizeIf(Condition cc, LEnvironment* environment) {
UNIMPLEMENTED();
}
// Generate a direct call to a known function. Expects the function
// to be in edi.
void CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr);
void LoadPrototype(Register result, Handle<JSObject> prototype);
void RegisterLazyDeoptimization(LInstruction* instr);
void RegisterEnvironmentForDeoptimization(LEnvironment* environment);
void DeoptimizeIf(Condition cc, LEnvironment* environment);
void AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged) { UNIMPLEMENTED(); }
int DefineDeoptimizationLiteral(Handle<Object> literal) {
UNIMPLEMENTED();
return 0;
}
void PopulateDeoptimizationLiteralsWithInlinedFunctions() { UNIMPLEMENTED(); }
bool is_tagged);
void PopulateDeoptimizationData(Handle<Code> code);
int DefineDeoptimizationLiteral(Handle<Object> literal);
void PopulateDeoptimizationLiteralsWithInlinedFunctions();
Register ToRegister(int index) const;
XMMRegister ToDoubleRegister(int index) const;
Register ToRegister(LOperand* op) const;
XMMRegister ToDoubleRegister(LOperand* op) const;
int ToInteger32(LConstantOperand* op) const;
Operand ToOperand(LOperand* op) const;
// Specific math operations - used from DoUnaryMathOperation.
void DoMathAbs(LUnaryMathOperation* instr);
void DoMathFloor(LUnaryMathOperation* instr);
void DoMathRound(LUnaryMathOperation* instr);
void DoMathSqrt(LUnaryMathOperation* instr);
void DoMathPowHalf(LUnaryMathOperation* instr);
void DoMathLog(LUnaryMathOperation* instr);
void DoMathCos(LUnaryMathOperation* instr);
void DoMathSin(LUnaryMathOperation* instr);
// Support for recording safepoint and position information.
void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
void RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments,
int deoptimization_index);
void RecordPosition(int position);
static Condition TokenToCondition(Token::Value op, bool is_unsigned);
void EmitGoto(int block, LDeferredCode* deferred_stack_check = NULL);
void EmitBranch(int left_block, int right_block, Condition cc);
void EmitCmpI(LOperand* left, LOperand* right);
void EmitNumberUntagD(Register input, XMMRegister result, LEnvironment* env);
// Emits optimized code for typeof x == "y". Modifies input register.
// Returns the condition on which a final split to
// true and false label should be made, to optimize fallthrough.
Condition EmitTypeofIs(Label* true_label, Label* false_label,
Register input, Handle<String> type_name);
// Emits optimized code for %_IsObject(x). Preserves input register.
// Returns the condition on which a final split to
// true and false label should be made, to optimize fallthrough.
Condition EmitIsObject(Register input,
Register temp1,
Register temp2,
Label* is_not_object,
Label* is_object);
LChunk* const chunk_;
MacroAssembler* const masm_;
......@@ -192,6 +231,9 @@ class LCodeGen BASE_EMBEDDED {
// itself is emitted at the end of the generated code.
SafepointTableBuilder safepoints_;
// Compiler from a set of parallel moves to a sequential list of moves.
LGapResolver resolver_;
friend class LDeferredCode;
friend class LEnvironment;
friend class SafepointGenerator;
......
......@@ -31,6 +31,13 @@
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;
......@@ -57,28 +64,40 @@ void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index,
}
void LOsrEntry::CompileToNative(LCodeGen* generator) {
UNIMPLEMENTED();
// Implement in lithium-codegen-x64.cc.
}
void LInstruction::PrintTo(StringStream* stream) {
stream->Add("%s ", this->Mnemonic());
if (HasResult()) {
LTemplateInstruction<1>::cast(this)->result()->PrintTo(stream);
stream->Add(" ");
PrintOutputOperandTo(stream);
}
PrintDataTo(stream);
if (HasEnvironment()) {
stream->Add(" ");
// environment()->PrintTo(stream);
environment()->PrintTo(stream);
}
if (HasPointerMap()) {
stream->Add(" ");
// pointer_map()->PrintTo(stream);
pointer_map()->PrintTo(stream);
}
}
template<int R, int I, int T>
void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) {
for (int i = 0; i < I; i++) {
stream->Add(i == 0 ? "= " : " ");
inputs_.at(i)->PrintTo(stream);
}
}
template<int R, int I, int T>
void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) {
if (this->HasResult()) {
this->result()->PrintTo(stream);
stream->Add(" ");
}
}
......@@ -114,11 +133,316 @@ void LGap::PrintDataTo(StringStream* stream) {
}
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";
default:
UNREACHABLE();
return NULL;
}
}
void LGoto::PrintDataTo(StringStream* stream) {
stream->Add("B%d", block_id());
}
void LBranch::PrintDataTo(StringStream* stream) {
stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
input()->PrintTo(stream);
}
void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if ");
left()->PrintTo(stream);
stream->Add(" %s ", Token::String(op()));
right()->PrintTo(stream);
stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
}
void LIsNullAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if ");
input()->PrintTo(stream);
stream->Add(is_strict() ? " === null" : " == null");
stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
}
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_object(");
input()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_smi(");
input()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if has_instance_type(");
input()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if has_cached_array_index(");
input()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if class_of_test(");
input()->PrintTo(stream);
stream->Add(", \"%o\") then B%d else B%d",
*hydrogen()->class_name(),
true_block_id(),
false_block_id());
}
void LTypeofIs::PrintDataTo(StringStream* stream) {
input()->PrintTo(stream);
stream->Add(" == \"%s\"", *hydrogen()->type_literal()->ToCString());
}
void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if typeof ");
input()->PrintTo(stream);
stream->Add(" == \"%s\" then B%d else B%d",
*hydrogen()->type_literal()->ToCString(),
true_block_id(), false_block_id());
}
void LCallConstantFunction::PrintDataTo(StringStream* stream) {
stream->Add("#%d / ", arity());
}
void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
stream->Add("/%s ", hydrogen()->OpName());
input()->PrintTo(stream);
}
void LCallKeyed::PrintDataTo(StringStream* stream) {
stream->Add("[ecx] #%d / ", arity());
}
void LCallNamed::PrintDataTo(StringStream* stream) {
SmartPointer<char> name_string = name()->ToCString();
stream->Add("%s #%d / ", *name_string, arity());
}
void LCallGlobal::PrintDataTo(StringStream* stream) {
SmartPointer<char> name_string = name()->ToCString();
stream->Add("%s #%d / ", *name_string, arity());
}
void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
stream->Add("#%d / ", arity());
}
void LCallNew::PrintDataTo(StringStream* stream) {
stream->Add("= ");
input()->PrintTo(stream);
stream->Add(" #%d / ", arity());
}
void LClassOfTest::PrintDataTo(StringStream* stream) {
stream->Add("= class_of_test(");
input()->PrintTo(stream);
stream->Add(", \"%o\")", *hydrogen()->class_name());
}
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
arguments()->PrintTo(stream);
stream->Add(" length ");
length()->PrintTo(stream);
stream->Add(" index ");
index()->PrintTo(stream);
}
int LChunk::GetNextSpillIndex(bool is_double) {
// Need to consider what index means: Is it 32 bit or 64 bit index?
UNIMPLEMENTED();
return 0;
}
LOperand* LChunk::GetNextSpillSlot(bool is_double) {
UNIMPLEMENTED();
return NULL;
}
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);
if (!goto_instr->include_stack_check() &&
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()));
}
}
}
}
}
void LStoreNamed::PrintDataTo(StringStream* stream) {
object()->PrintTo(stream);
stream->Add(".");
stream->Add(*String::cast(*name())->ToCString());
stream->Add(" <- ");
value()->PrintTo(stream);
}
void LStoreKeyed::PrintDataTo(StringStream* stream) {
object()->PrintTo(stream);
stream->Add("[");
key()->PrintTo(stream);
stream->Add("] <- ");
value()->PrintTo(stream);
}
int LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
LGap* gap = new LGap(block);
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);
}
return 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.
int result = index - graph()->info()->scope()->num_parameters() - 1;
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.
return (1 + graph()->info()->scope()->num_parameters() - index) *
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());
chunk_ = new LChunk(graph());
......@@ -150,10 +474,843 @@ void LChunkBuilder::Abort(const char* format, ...) {
}
LRegister* LChunkBuilder::ToOperand(Register reg) {
return LRegister::Create(Register::ToAllocationIndex(reg));
}
LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
return new LUnallocated(LUnallocated::FIXED_REGISTER,
Register::ToAllocationIndex(reg));
}
LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
return new LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
XMMRegister::ToAllocationIndex(reg));
}
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) {
return Use(value, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
}
LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
return Use(value,
new LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
LUnallocated::USED_AT_START));
}
LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
return Use(value, new LUnallocated(LUnallocated::WRITABLE_REGISTER));
}
LOperand* LChunkBuilder::Use(HValue* value) {
return Use(value, new LUnallocated(LUnallocated::NONE));
}
LOperand* LChunkBuilder::UseAtStart(HValue* value) {
return Use(value, new LUnallocated(LUnallocated::NONE,
LUnallocated::USED_AT_START));
}
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);
}
LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
if (value->EmitAtUses()) {
HInstruction* instr = HInstruction::cast(value);
VisitInstruction(instr);
}
allocator_->RecordUse(value, operand);
return operand;
}
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) {
return Define(instr, new LUnallocated(LUnallocated::NONE));
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineAsRegister(
LTemplateInstruction<1, I, T>* instr) {
return Define(instr, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineAsSpilled(
LTemplateInstruction<1, I, T>* instr,
int index) {
return Define(instr, new LUnallocated(LUnallocated::FIXED_SLOT, index));
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineSameAsFirst(
LTemplateInstruction<1, I, T>* instr) {
return Define(instr, new LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineFixed(LTemplateInstruction<1, I, T>* instr,
Register reg) {
return Define(instr, ToUnallocated(reg));
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineFixedDouble(
LTemplateInstruction<1, I, T>* instr,
XMMRegister reg) {
return Define(instr, ToUnallocated(reg));
}
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment();
instr->set_environment(CreateEnvironment(hydrogen_env));
return instr;
}
LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
LInstruction* instr, int ast_id) {
ASSERT(instructions_pending_deoptimization_environment_ == NULL);
ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
instructions_pending_deoptimization_environment_ = instr;
pending_deoptimization_ast_id_ = ast_id;
return instr;
}
void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
instructions_pending_deoptimization_environment_ = NULL;
pending_deoptimization_ast_id_ = AstNode::kNoNumber;
}
LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
HInstruction* hinstr,
CanDeoptimize can_deoptimize) {
allocator_->MarkAsCall();
instr = AssignPointerMap(instr);
if (hinstr->HasSideEffects()) {
ASSERT(hinstr->next()->IsSimulate());
HSimulate* sim = HSimulate::cast(hinstr->next());
instr = SetInstructionPendingDeoptimizationEnvironment(
instr, sim->ast_id());
}
// 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 =
(can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) || !hinstr->HasSideEffects();
if (needs_environment && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr);
}
return instr;
}
LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) {
allocator_->MarkAsSaveDoubles();
return instr;
}
LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
ASSERT(!instr->HasPointerMap());
instr->set_pointer_map(new LPointerMap(position_));
return instr;
}
LUnallocated* LChunkBuilder::TempRegister() {
LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
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) {
return new LLabel(instr->block());
}
LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
return AssignEnvironment(new LDeoptimize);
}
LInstruction* LChunkBuilder::DoBit(Token::Value op,
HBitwiseBinaryOperation* instr) {
Abort("Unimplemented: %s", "DoBit");
return NULL;
}
LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
HArithmeticBinaryOperation* instr) {
Abort("Unimplemented: %s", "DoArithmeticD");
return NULL;
}
LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
HArithmeticBinaryOperation* instr) {
Abort("Unimplemented: %s", "DoArithmeticT");
return NULL;
}
void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
ASSERT(is_building());
Abort("Lithium not implemented on x64.");
Abort("Unimplemented: %s", "DoBasicBlock");
}
void LChunkBuilder::VisitInstruction(HInstruction* current) {
HInstruction* old_current = current_instruction_;
current_instruction_ = current;
allocator_->BeginInstruction();
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);
}
if (current->IsBranch()) {
instr->set_hydrogen_value(HBranch::cast(current)->value());
} else {
instr->set_hydrogen_value(current);
}
int index = chunk_->AddInstruction(instr, current_block_);
allocator_->SummarizeInstruction(index);
} else {
// This instruction should be omitted.
allocator_->OmitInstruction();
}
current_instruction_ = old_current;
}
LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
if (hydrogen_env == NULL) return NULL;
LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
int ast_id = hydrogen_env->ast_id();
ASSERT(ast_id != AstNode::kNoNumber);
int value_count = hydrogen_env->length();
LEnvironment* result = new LEnvironment(hydrogen_env->closure(),
ast_id,
hydrogen_env->parameter_count(),
argument_count_,
value_count,
outer);
int argument_index = 0;
for (int i = 0; i < value_count; ++i) {
HValue* value = hydrogen_env->values()->at(i);
LOperand* op = NULL;
if (value->IsArgumentsObject()) {
op = NULL;
} else if (value->IsPushArgument()) {
op = new LArgument(argument_index++);
} else {
op = UseOrConstant(value);
if (op->IsUnallocated()) {
LUnallocated* unalloc = LUnallocated::cast(op);
unalloc->set_policy(LUnallocated::ANY);
}
}
result->AddValue(op, value->representation());
}
return result;
}
LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
Abort("Unimplemented: %s", "DoGoto");
return NULL;
}
LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
Abort("Unimplemented: %s", "DoBranch");
return NULL;
}
LInstruction* LChunkBuilder::DoCompareMapAndBranch(
HCompareMapAndBranch* instr) {
Abort("Unimplemented: %s", "DoCompareMapAndBranch");
return NULL;
}
LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
Abort("Unimplemented: %s", "DoArgumentsLength");
return NULL;
}
LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
Abort("Unimplemented: %s", "DoArgumentsElements");
return NULL;
}
LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
Abort("Unimplemented: %s", "DoInstanceOf");
return NULL;
}
LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
HInstanceOfKnownGlobal* instr) {
Abort("Unimplemented: %s", "DoInstanceOfKnownGlobal");
return NULL;
}
LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
Abort("Unimplemented: %s", "DoApplyArguments");
return NULL;
}
LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
Abort("Unimplemented: %s", "DoPushArgument");
return NULL;
}
LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
Abort("Unimplemented: %s", "DoGlobalObject");
return NULL;
}
LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
Abort("Unimplemented: %s", "DoGlobalReceiver");
return NULL;
}
LInstruction* LChunkBuilder::DoCallConstantFunction(
HCallConstantFunction* instr) {
Abort("Unimplemented: %s", "DoCallConstantFunction");
return NULL;
}
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
Abort("Unimplemented: %s", "DoUnaryMathOperation");
return NULL;
}
LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
Abort("Unimplemented: %s", "DoCallKeyed");
return NULL;
}
LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
Abort("Unimplemented: %s", "DoCallNamed");
return NULL;
}
LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
Abort("Unimplemented: %s", "DoCallGlobal");
return NULL;
}
LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
Abort("Unimplemented: %s", "DoCallKnownGlobal");
return NULL;
}
LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
Abort("Unimplemented: %s", "DoCallNew");
return NULL;
}
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
Abort("Unimplemented: %s", "DoCallFunction");
return NULL;
}
LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
Abort("Unimplemented: %s", "DoCallRuntime");
return NULL;
}
LInstruction* LChunkBuilder::DoShr(HShr* instr) {
Abort("Unimplemented: %s", "DoShr");
return NULL;
}
LInstruction* LChunkBuilder::DoSar(HSar* instr) {
Abort("Unimplemented: %s", "DoSar");
return NULL;
}
LInstruction* LChunkBuilder::DoShl(HShl* instr) {
Abort("Unimplemented: %s", "DoShl");
return NULL;
}
LInstruction* LChunkBuilder::DoBitAnd(HBitAnd* instr) {
Abort("Unimplemented: %s", "DoBitAnd");
return NULL;
}
LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
Abort("Unimplemented: %s", "DoBitNot");
return NULL;
}
LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) {
Abort("Unimplemented: %s", "DoBitOr");
return NULL;
}
LInstruction* LChunkBuilder::DoBitXor(HBitXor* instr) {
Abort("Unimplemented: %s", "DoBitXor");
return NULL;
}
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
Abort("Unimplemented: %s", "DoDiv");
return NULL;
}
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
Abort("Unimplemented: %s", "DoMod");
return NULL;
}
LInstruction* LChunkBuilder::DoMul(HMul* instr) {
Abort("Unimplemented: %s", "DoMul");
return NULL;
}
LInstruction* LChunkBuilder::DoSub(HSub* instr) {
Abort("Unimplemented: %s", "DoSub");
return NULL;
}
LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
Abort("Unimplemented: %s", "DoAdd");
return NULL;
}
LInstruction* LChunkBuilder::DoPower(HPower* instr) {
Abort("Unimplemented: %s", "DoPower");
return NULL;
}
LInstruction* LChunkBuilder::DoCompare(HCompare* instr) {
Abort("Unimplemented: %s", "DoCompare");
return NULL;
}
LInstruction* LChunkBuilder::DoCompareJSObjectEq(
HCompareJSObjectEq* instr) {
Abort("Unimplemented: %s", "DoCompareJSObjectEq");
return NULL;
}
LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
Abort("Unimplemented: %s", "DoIsNull");
return NULL;
}
LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) {
Abort("Unimplemented: %s", "DoIsObject");
return NULL;
}
LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) {
Abort("Unimplemented: %s", "DoIsSmi");
return NULL;
}
LInstruction* LChunkBuilder::DoHasInstanceType(HHasInstanceType* instr) {
Abort("Unimplemented: %s", "DoHasInstanceType");
return NULL;
}
LInstruction* LChunkBuilder::DoHasCachedArrayIndex(
HHasCachedArrayIndex* instr) {
Abort("Unimplemented: %s", "DoHasCachedArrayIndex");
return NULL;
}
LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) {
Abort("Unimplemented: %s", "DoClassOfTest");
return NULL;
}
LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
Abort("Unimplemented: %s", "DoJSArrayLength");
return NULL;
}
LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
Abort("Unimplemented: %s", "DoFixedArrayLength");
return NULL;
}
LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
Abort("Unimplemented: %s", "DoValueOf");
return NULL;
}
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
Abort("Unimplemented: %s", "DoBoundsCheck");
return NULL;
}
LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
Abort("Unimplemented: %s", "DoThrow");
return NULL;
}
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
Abort("Unimplemented: %s", "DoChange");
return NULL;
}
LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
Abort("Unimplemented: %s", "DoCheckNonSmi");
return NULL;
}
LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
Abort("Unimplemented: %s", "DoCheckInstanceType");
return NULL;
}
LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
Abort("Unimplemented: %s", "DoCheckPrototypeMaps");
return NULL;
}
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
Abort("Unimplemented: %s", "DoCheckSmi");
return NULL;
}
LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
Abort("Unimplemented: %s", "DoCheckFunction");
return NULL;
}
LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
Abort("Unimplemented: %s", "DoCheckMap");
return NULL;
}
LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
Abort("Unimplemented: %s", "DoReturn");
return NULL;
}
LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
Abort("Unimplemented: %s", "DoConstant");
return NULL;
}
LInstruction* LChunkBuilder::DoLoadGlobal(HLoadGlobal* instr) {
Abort("Unimplemented: %s", "DoLoadGlobal");
return NULL;
}
LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) {
Abort("Unimplemented: %s", "DoStoreGlobal");
return NULL;
}
LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
Abort("Unimplemented: %s", "DoLoadNamedField");
return NULL;
}
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
Abort("Unimplemented: %s", "DoLoadNamedGeneric");
return NULL;
}
LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
HLoadFunctionPrototype* instr) {
Abort("Unimplemented: %s", "DoLoadFunctionPrototype");
return NULL;
}
LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
Abort("Unimplemented: %s", "DoLoadElements");
return NULL;
}
LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
HLoadKeyedFastElement* instr) {
Abort("Unimplemented: %s", "DoLoadKeyedFastElement");
return NULL;
}
LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
Abort("Unimplemented: %s", "DoLoadKeyedGeneric");
return NULL;
}
LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
HStoreKeyedFastElement* instr) {
Abort("Unimplemented: %s", "DoStoreKeyedFastElement");
return NULL;
}
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
Abort("Unimplemented: %s", "DoStoreKeyedGeneric");
return NULL;
}
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
Abort("Unimplemented: %s", "DoStoreNamedField");
return NULL;
}
LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
Abort("Unimplemented: %s", "DoStoreNamedGeneric");
return NULL;
}
LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
Abort("Unimplemented: %s", "DoArrayLiteral");
return NULL;
}
LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
Abort("Unimplemented: %s", "DoObjectLiteral");
return NULL;
}
LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
Abort("Unimplemented: %s", "DoRegExpLiteral");
return NULL;
}
LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
Abort("Unimplemented: %s", "DoFunctionLiteral");
return NULL;
}
LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) {
Abort("Unimplemented: %s", "DoDeleteProperty");
return NULL;
}
LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
Abort("Unimplemented: %s", "DoOsrEntry");
return NULL;
}
LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
Abort("Unimplemented: %s", "DoParameter");
return NULL;
}
LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
Abort("Unimplemented: %s", "DoUnknownOSRValue");
return NULL;
}
LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
Abort("Unimplemented: %s", "DoCallStub");
return NULL;
}
LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
Abort("Unimplemented: %s", "DoArgumentsObject");
return NULL;
}
LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
Abort("Unimplemented: %s", "DoAccessArgumentsAt");
return NULL;
}
LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
Abort("Unimplemented: %s", "DoTypeof");
return NULL;
}
LInstruction* LChunkBuilder::DoTypeofIs(HTypeofIs* instr) {
Abort("Unimplemented: %s", "DoTypeofIs");
return NULL;
}
LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
Abort("Unimplemented: %s", "DoSimulate");
return NULL;
}
LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
Abort("Unimplemented: %s", "DoStackCheck");
return NULL;
}
LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
Abort("Unimplemented: %s", "DoEnterInlined");
return NULL;
}
LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
Abort("Unimplemented: %s", "DoLeaveInlined");
return NULL;
}
} } // namespace v8::internal
......@@ -43,23 +43,225 @@ class LCodeGen;
// Type hierarchy:
//
// LInstruction
// LAccessArgumentsAt
// LArgumentsElements
// LArgumentsLength
// LBinaryOperation
// LAddI
// LApplyArguments
// LArithmeticD
// LArithmeticT
// LBitI
// LBoundsCheck
// LCmpID
// LCmpIDAndBranch
// LCmpJSObjectEq
// LCmpJSObjectEqAndBranch
// LCmpT
// LDivI
// LInstanceOf
// LInstanceOfAndBranch
// LInstanceOfKnownGlobal
// LLoadKeyedFastElement
// LLoadKeyedGeneric
// LModI
// LMulI
// LPower
// LShiftI
// LSubI
// LCallConstantFunction
// LCallFunction
// LCallGlobal
// LCallKeyed
// LCallKnownGlobal
// LCallNamed
// LCallRuntime
// LCallStub
// LCheckPrototypeMaps
// LConstant
// LConstantD
// LConstantI
// LConstantT
// LDeoptimize
// LFunctionLiteral
// LGap
// LLabel
// LGlobalObject
// LGlobalReceiver
// LGoto
// LLazyBailout
// LLoadGlobal
// LMaterializedLiteral
// LArrayLiteral
// LObjectLiteral
// LRegExpLiteral
// LOsrEntry
// LParameter
// LRegExpConstructResult
// LStackCheck
// LStoreKeyed
// LStoreKeyedFastElement
// LStoreKeyedGeneric
// LStoreNamed
// LStoreNamedField
// LStoreNamedGeneric
// LUnaryOperation
// LBitNotI
// LBranch
// LCallNew
// LCheckFunction
// LCheckInstanceType
// LCheckMap
// LCheckSmi
// LClassOfTest
// LClassOfTestAndBranch
// LDeleteProperty
// LDoubleToI
// LFixedArrayLength
// LHasCachedArrayIndex
// LHasCachedArrayIndexAndBranch
// LHasInstanceType
// LHasInstanceTypeAndBranch
// LInteger32ToDouble
// LIsNull
// LIsNullAndBranch
// LIsObject
// LIsObjectAndBranch
// LIsSmi
// LIsSmiAndBranch
// LJSArrayLength
// LLoadNamedField
// LLoadNamedGeneric
// LLoadFunctionPrototype
// LNumberTagD
// LNumberTagI
// LPushArgument
// LReturn
// LSmiTag
// LStoreGlobal
// LTaggedToI
// LThrow
// LTypeof
// LTypeofIs
// LTypeofIsAndBranch
// LUnaryMathOperation
// LValueOf
// LUnknownOSRValue
#define LITHIUM_ALL_INSTRUCTION_LIST(V) \
V(BinaryOperation) \
V(Constant) \
V(Call) \
V(MaterializedLiteral) \
V(StoreKeyed) \
V(StoreNamed) \
V(UnaryOperation) \
LITHIUM_CONCRETE_INSTRUCTION_LIST(V)
#define LITHIUM_CONCRETE_INSTRUCTION_LIST(V) \
V(AccessArgumentsAt) \
V(AddI) \
V(ApplyArguments) \
V(ArgumentsElements) \
V(ArgumentsLength) \
V(ArithmeticD) \
V(ArithmeticT) \
V(ArrayLiteral) \
V(BitI) \
V(BitNotI) \
V(BoundsCheck) \
V(Branch) \
V(CallConstantFunction) \
V(CallFunction) \
V(CallGlobal) \
V(CallKeyed) \
V(CallKnownGlobal) \
V(CallNamed) \
V(CallNew) \
V(CallRuntime) \
V(CallStub) \
V(CheckFunction) \
V(CheckInstanceType) \
V(CheckMap) \
V(CheckPrototypeMaps) \
V(CheckSmi) \
V(CmpID) \
V(CmpIDAndBranch) \
V(CmpJSObjectEq) \
V(CmpJSObjectEqAndBranch) \
V(CmpMapAndBranch) \
V(CmpT) \
V(CmpTAndBranch) \
V(ConstantD) \
V(ConstantI) \
V(ConstantT) \
V(DeleteProperty) \
V(Deoptimize) \
V(DivI) \
V(DoubleToI) \
V(FunctionLiteral) \
V(Gap) \
V(GlobalObject) \
V(GlobalReceiver) \
V(Goto) \
V(FixedArrayLength) \
V(InstanceOf) \
V(InstanceOfAndBranch) \
V(InstanceOfKnownGlobal) \
V(Integer32ToDouble) \
V(IsNull) \
V(IsNullAndBranch) \
V(IsObject) \
V(IsObjectAndBranch) \
V(IsSmi) \
V(IsSmiAndBranch) \
V(JSArrayLength) \
V(HasInstanceType) \
V(HasInstanceTypeAndBranch) \
V(HasCachedArrayIndex) \
V(HasCachedArrayIndexAndBranch) \
V(ClassOfTest) \
V(ClassOfTestAndBranch) \
V(Label) \
V(LazyBailout) \
V(OsrEntry)
V(LoadElements) \
V(LoadGlobal) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadNamedField) \
V(LoadNamedGeneric) \
V(LoadFunctionPrototype) \
V(ModI) \
V(MulI) \
V(NumberTagD) \
V(NumberTagI) \
V(NumberUntagD) \
V(ObjectLiteral) \
V(OsrEntry) \
V(Parameter) \
V(Power) \
V(PushArgument) \
V(RegExpLiteral) \
V(Return) \
V(ShiftI) \
V(SmiTag) \
V(SmiUntag) \
V(StackCheck) \
V(StoreGlobal) \
V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
V(SubI) \
V(TaggedToI) \
V(Throw) \
V(Typeof) \
V(TypeofIs) \
V(TypeofIsAndBranch) \
V(UnaryMathOperation) \
V(UnknownOSRValue) \
V(ValueOf)
#define DECLARE_INSTRUCTION(type) \
......@@ -91,7 +293,8 @@ class LInstruction: public ZoneObject {
virtual void CompileToNative(LCodeGen* generator) = 0;
virtual const char* Mnemonic() const = 0;
virtual void PrintTo(StringStream* stream);
virtual void PrintDataTo(StringStream* stream) { }
virtual void PrintDataTo(StringStream* stream) = 0;
virtual void PrintOutputOperandTo(StringStream* stream) = 0;
// Declare virtual type testers.
#define DECLARE_DO(type) virtual bool Is##type() const { return false; }
......@@ -130,32 +333,61 @@ class LInstruction: public ZoneObject {
};
template <int Result>
class LTemplateInstruction: public LInstruction { };
template<typename T, int N>
class OperandContainer {
public:
OperandContainer() {
for (int i = 0; i < N; i++) elems_[i] = NULL;
}
int length() const { return N; }
T at(int i) const { return elems_[i]; }
void set_at(int i, T value) { elems_[i] = value; }
private:
T elems_[N];
};
template<>
class LTemplateInstruction<0>: public LInstruction {
virtual bool HasResult() const { return false; }
template<typename T>
class OperandContainer<T, 0> {
public:
int length() const { return 0; }
T at(int i) const {
UNREACHABLE();
return NULL;
}
void set_at(int i, T value) {
UNREACHABLE();
}
};
template<>
class LTemplateInstruction<1>: public LInstruction {
template<int R, int I, int T>
class LTemplateInstruction: public LInstruction {
public:
static LTemplateInstruction<1>* cast(LInstruction* instr) {
ASSERT(instr->HasResult());
return reinterpret_cast<LTemplateInstruction<1>*>(instr);
}
void set_result(LOperand* operand) { result_.set(operand); }
LOperand* result() const { return result_.get(); }
virtual bool HasResult() const { return result_.is_set(); }
// Allow 0 or 1 output operands.
STATIC_ASSERT(R == 0 || R == 1);
virtual bool HasResult() const { return R != 0; }
void set_result(LOperand* operand) { outputs_.set_at(0, operand); }
LOperand* result() const { return outputs_.at(0); }
int InputCount() const { return inputs_.length(); }
LOperand* InputAt(int i) const { return inputs_.at(i); }
void SetInputAt(int i, LOperand* operand) { inputs_.set_at(i, operand); }
int TempCount() const { return temps_.length(); }
LOperand* TempAt(int i) const { return temps_.at(i); }
virtual void PrintDataTo(StringStream* stream);
virtual void PrintOutputOperandTo(StringStream* stream);
private:
SetOncePointer<LOperand> result_;
OperandContainer<LOperand*, R> outputs_;
OperandContainer<LOperand*, I> inputs_;
OperandContainer<LOperand*, T> temps_;
};
class LGap: public LTemplateInstruction<0> {
class LGap: public LTemplateInstruction<0, 0, 0> {
public:
explicit LGap(HBasicBlock* block)
: block_(block) {
......@@ -196,7 +428,7 @@ class LGap: public LTemplateInstruction<0> {
};
class LGoto: public LTemplateInstruction<0> {
class LGoto: public LTemplateInstruction<0, 0, 0> {
public:
LGoto(int block_id, bool include_stack_check = false)
: block_id_(block_id), include_stack_check_(include_stack_check) { }
......@@ -214,7 +446,7 @@ class LGoto: public LTemplateInstruction<0> {
};
class LLazyBailout: public LTemplateInstruction<0> {
class LLazyBailout: public LTemplateInstruction<0, 0, 0> {
public:
LLazyBailout() : gap_instructions_size_(0) { }
......@@ -230,7 +462,7 @@ class LLazyBailout: public LTemplateInstruction<0> {
};
class LDeoptimize: public LTemplateInstruction<0> {
class LDeoptimize: public LTemplateInstruction<0, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize")
};
......@@ -258,144 +490,1532 @@ class LLabel: public LGap {
};
class LOsrEntry: public LTemplateInstruction<0> {
class LParameter: public LTemplateInstruction<1, 0, 0> {
public:
LOsrEntry();
DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry")
DECLARE_CONCRETE_INSTRUCTION(Parameter, "parameter")
};
LOperand** SpilledRegisterArray() { return register_spills_; }
LOperand** SpilledDoubleRegisterArray() { return double_register_spills_; }
void MarkSpilledRegister(int allocation_index, LOperand* spill_operand);
void MarkSpilledDoubleRegister(int allocation_index,
LOperand* spill_operand);
class LCallStub: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(CallStub, "call-stub")
DECLARE_HYDROGEN_ACCESSOR(CallStub)
private:
// Arrays of spill slot operands for registers with an assigned spill
// slot, i.e., that must also be restored to the spill slot on OSR entry.
// NULL if the register has no assigned spill slot. Indexed by allocation
// index.
LOperand* register_spills_[Register::kNumAllocatableRegisters];
LOperand* double_register_spills_[DoubleRegister::kNumAllocatableRegisters];
TranscendentalCache::Type transcendental_type() {
return hydrogen()->transcendental_type();
}
};
class LChunkBuilder;
class LChunk: public ZoneObject {
class LUnknownOSRValue: public LTemplateInstruction<1, 0, 0> {
public:
explicit LChunk(HGraph* graph)
: spill_slot_count_(0),
graph_(graph),
instructions_(32),
pointer_maps_(8),
inlined_closures_(1) { }
DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue, "unknown-osr-value")
};
int spill_slot_count() const { return spill_slot_count_; }
HGraph* graph() const { return graph_; }
const ZoneList<LInstruction*>* instructions() const { return &instructions_; }
const ZoneList<LPointerMap*>* pointer_maps() const { return &pointer_maps_; }
const ZoneList<Handle<JSFunction> >* inlined_closures() const {
return &inlined_closures_;
}
LOperand* GetNextSpillSlot(bool double_slot) {
UNIMPLEMENTED();
return NULL;
template<int R>
class LUnaryOperation: public LTemplateInstruction<R, 1, 0> {
public:
explicit LUnaryOperation<R>(LOperand* input) {
this->SetInputAt(0, input);
}
LConstantOperand* DefineConstantOperand(HConstant* constant) {
UNIMPLEMENTED();
return NULL;
}
LOperand* input() const { return this->InputAt(0); }
DECLARE_INSTRUCTION(UnaryOperation)
};
LLabel* GetLabel(int block_id) const {
UNIMPLEMENTED();
return NULL;
}
int GetParameterStackSlot(int index) const {
UNIMPLEMENTED();
return 0;
template<int R>
class LBinaryOperation: public LTemplateInstruction<R, 2, 0> {
public:
LBinaryOperation(LOperand* left, LOperand* right) {
this->SetInputAt(0, left);
this->SetInputAt(1, right);
}
void AddGapMove(int index, LOperand* from, LOperand* to) { UNIMPLEMENTED(); }
DECLARE_INSTRUCTION(BinaryOperation)
LGap* GetGapAt(int index) const {
UNIMPLEMENTED();
return NULL;
LOperand* left() const { return this->InputAt(0); }
LOperand* right() const { return this->InputAt(1); }
};
class LApplyArguments: public LTemplateInstruction<1, 4, 0> {
public:
LApplyArguments(LOperand* function,
LOperand* receiver,
LOperand* length,
LOperand* elements) {
this->SetInputAt(0, function);
this->SetInputAt(1, receiver);
this->SetInputAt(2, length);
this->SetInputAt(3, elements);
}
bool IsGapAt(int index) const {
UNIMPLEMENTED();
return false;
DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply-arguments")
LOperand* function() const { return InputAt(0); }
LOperand* receiver() const { return InputAt(1); }
LOperand* length() const { return InputAt(2); }
LOperand* elements() const { return InputAt(3); }
};
class LAccessArgumentsAt: public LTemplateInstruction<1, 3, 0> {
public:
LAccessArgumentsAt(LOperand* arguments, LOperand* length, LOperand* index) {
this->SetInputAt(0, arguments);
this->SetInputAt(1, length);
this->SetInputAt(2, index);
}
int NearestGapPos(int index) const {
UNIMPLEMENTED();
return 0;
DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt, "access-arguments-at")
LOperand* arguments() const { return this->InputAt(0); }
LOperand* length() const { return this->InputAt(1); }
LOperand* index() const { return this->InputAt(2); }
virtual void PrintDataTo(StringStream* stream);
};
class LArgumentsLength: public LUnaryOperation<1> {
public:
explicit LArgumentsLength(LOperand* elements)
: LUnaryOperation<1>(elements) {}
DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength, "arguments-length")
};
class LArgumentsElements: public LTemplateInstruction<1, 0, 0> {
public:
LArgumentsElements() { }
DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements")
};
class LModI: public LBinaryOperation<1> {
public:
LModI(LOperand* left, LOperand* right) : LBinaryOperation<1>(left, right) { }
DECLARE_CONCRETE_INSTRUCTION(ModI, "mod-i")
DECLARE_HYDROGEN_ACCESSOR(Mod)
};
class LDivI: public LBinaryOperation<1> {
public:
LDivI(LOperand* left, LOperand* right)
: LBinaryOperation<1>(left, right) { }
DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
DECLARE_HYDROGEN_ACCESSOR(Div)
};
class LMulI: public LBinaryOperation<1> {
public:
LMulI(LOperand* left, LOperand* right, LOperand* temp)
: LBinaryOperation<1>(left, right), temp_(temp) { }
DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-i")
DECLARE_HYDROGEN_ACCESSOR(Mul)
LOperand* temp() const { return temp_; }
private:
LOperand* temp_;
};
class LCmpID: public LBinaryOperation<1> {
public:
LCmpID(LOperand* left, LOperand* right)
: LBinaryOperation<1>(left, right) { }
Token::Value op() const { return hydrogen()->token(); }
bool is_double() const {
return hydrogen()->GetInputRepresentation().IsDouble();
}
void MarkEmptyBlocks() { UNIMPLEMENTED(); }
DECLARE_CONCRETE_INSTRUCTION(CmpID, "cmp-id")
DECLARE_HYDROGEN_ACCESSOR(Compare)
};
class LCmpIDAndBranch: public LCmpID {
public:
LCmpIDAndBranch(LOperand* left,
LOperand* right,
int true_block_id,
int false_block_id)
: LCmpID(left, right),
true_block_id_(true_block_id),
false_block_id_(false_block_id) { }
DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch")
virtual void PrintDataTo(StringStream* stream);
virtual bool IsControl() const { return true; }
#ifdef DEBUG
void Verify() { }
#endif
int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; }
private:
int spill_slot_count_;
HGraph* const graph_;
ZoneList<LInstruction*> instructions_;
ZoneList<LPointerMap*> pointer_maps_;
ZoneList<Handle<JSFunction> > inlined_closures_;
int true_block_id_;
int false_block_id_;
};
class LChunkBuilder BASE_EMBEDDED {
class LUnaryMathOperation: public LUnaryOperation<1> {
public:
LChunkBuilder(HGraph* graph, LAllocator* allocator)
: chunk_(NULL),
graph_(graph),
status_(UNUSED),
current_instruction_(NULL),
current_block_(NULL),
next_block_(NULL),
argument_count_(0),
allocator_(allocator),
position_(RelocInfo::kNoPosition),
instructions_pending_deoptimization_environment_(NULL),
pending_deoptimization_ast_id_(AstNode::kNoNumber) { }
explicit LUnaryMathOperation(LOperand* value)
: LUnaryOperation<1>(value) { }
// Build the sequence for the graph.
LChunk* Build();
DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary-math-operation")
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
// Declare methods that deal with the individual node types.
#define DECLARE_DO(type) LInstruction* Do##type(H##type* node) { \
UNIMPLEMENTED(); \
return NULL; \
}
HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
#undef DECLARE_DO
virtual void PrintDataTo(StringStream* stream);
BuiltinFunctionId op() const { return hydrogen()->op(); }
};
class LCmpJSObjectEq: public LBinaryOperation<1> {
public:
LCmpJSObjectEq(LOperand* left, LOperand* right)
: LBinaryOperation<1>(left, right) {}
DECLARE_CONCRETE_INSTRUCTION(CmpJSObjectEq, "cmp-jsobject-eq")
};
class LCmpJSObjectEqAndBranch: public LCmpJSObjectEq {
public:
LCmpJSObjectEqAndBranch(LOperand* left,
LOperand* right,
int true_block_id,
int false_block_id)
: LCmpJSObjectEq(left, right),
true_block_id_(true_block_id),
false_block_id_(false_block_id) { }
DECLARE_CONCRETE_INSTRUCTION(CmpJSObjectEqAndBranch,
"cmp-jsobject-eq-and-branch")
int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; }
private:
enum Status {
UNUSED,
BUILDING,
DONE,
ABORTED
};
int true_block_id_;
int false_block_id_;
};
LChunk* chunk() const { return chunk_; }
HGraph* graph() const { return graph_; }
bool is_unused() const { return status_ == UNUSED; }
bool is_building() const { return status_ == BUILDING; }
bool is_done() const { return status_ == DONE; }
bool is_aborted() const { return status_ == ABORTED; }
class LIsNull: public LUnaryOperation<1> {
public:
explicit LIsNull(LOperand* value) : LUnaryOperation<1>(value) { }
void Abort(const char* format, ...);
DECLARE_CONCRETE_INSTRUCTION(IsNull, "is-null")
DECLARE_HYDROGEN_ACCESSOR(IsNull)
bool is_strict() const { return hydrogen()->is_strict(); }
};
class LIsNullAndBranch: public LIsNull {
public:
LIsNullAndBranch(LOperand* value,
LOperand* temp,
int true_block_id,
int false_block_id)
: LIsNull(value),
temp_(temp),
true_block_id_(true_block_id),
false_block_id_(false_block_id) { }
DECLARE_CONCRETE_INSTRUCTION(IsNullAndBranch, "is-null-and-branch")
virtual void PrintDataTo(StringStream* stream);
virtual bool IsControl() const { return true; }
int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; }
LOperand* temp() const { return temp_; }
private:
LOperand* temp_;
int true_block_id_;
int false_block_id_;
};
class LIsObject: public LUnaryOperation<1> {
public:
LIsObject(LOperand* value, LOperand* temp)
: LUnaryOperation<1>(value), temp_(temp) {}
DECLARE_CONCRETE_INSTRUCTION(IsObject, "is-object")
LOperand* temp() const { return temp_; }
private:
LOperand* temp_;
};
class LIsObjectAndBranch: public LIsObject {
public:
LIsObjectAndBranch(LOperand* value,
LOperand* temp,
LOperand* temp2,
int true_block_id,
int false_block_id)
: LIsObject(value, temp),
temp2_(temp2),
true_block_id_(true_block_id),
false_block_id_(false_block_id) { }
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
virtual void PrintDataTo(StringStream* stream);
virtual bool IsControl() const { return true; }
int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; }
LOperand* temp2() const { return temp2_; }
private:
LOperand* temp2_;
int true_block_id_;
int false_block_id_;
};
class LIsSmi: public LUnaryOperation<1> {
public:
explicit LIsSmi(LOperand* value) : LUnaryOperation<1>(value) {}
DECLARE_CONCRETE_INSTRUCTION(IsSmi, "is-smi")
DECLARE_HYDROGEN_ACCESSOR(IsSmi)
};
class LIsSmiAndBranch: public LIsSmi {
public:
LIsSmiAndBranch(LOperand* value,
int true_block_id,
int false_block_id)
: LIsSmi(value),
true_block_id_(true_block_id),
false_block_id_(false_block_id) { }
DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch")
virtual void PrintDataTo(StringStream* stream);
virtual bool IsControl() const { return true; }
int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; }
private:
int true_block_id_;
int false_block_id_;
};
class LHasInstanceType: public LUnaryOperation<1> {
public:
explicit LHasInstanceType(LOperand* value)
: LUnaryOperation<1>(value) { }
DECLARE_CONCRETE_INSTRUCTION(HasInstanceType, "has-instance-type")
DECLARE_HYDROGEN_ACCESSOR(HasInstanceType)
InstanceType TestType(); // The type to test against when generating code.
Condition BranchCondition(); // The branch condition for 'true'.
};
class LHasInstanceTypeAndBranch: public LHasInstanceType {
public:
LHasInstanceTypeAndBranch(LOperand* value,
LOperand* temporary,
int true_block_id,
int false_block_id)
: LHasInstanceType(value),
temp_(temporary),
true_block_id_(true_block_id),
false_block_id_(false_block_id) { }
DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch,
"has-instance-type-and-branch")
virtual void PrintDataTo(StringStream* stream);
virtual bool IsControl() const { return true; }
int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; }
LOperand* temp() { return temp_; }
private:
LOperand* temp_;
int true_block_id_;
int false_block_id_;
};
class LHasCachedArrayIndex: public LUnaryOperation<1> {
public:
explicit LHasCachedArrayIndex(LOperand* value) : LUnaryOperation<1>(value) {}
DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndex, "has-cached-array-index")
DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndex)
};
class LHasCachedArrayIndexAndBranch: public LHasCachedArrayIndex {
public:
LHasCachedArrayIndexAndBranch(LOperand* value,
int true_block_id,
int false_block_id)
: LHasCachedArrayIndex(value),
true_block_id_(true_block_id),
false_block_id_(false_block_id) { }
DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch,
"has-cached-array-index-and-branch")
virtual void PrintDataTo(StringStream* stream);
virtual bool IsControl() const { return true; }
int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; }
private:
int true_block_id_;
int false_block_id_;
};
class LClassOfTest: public LUnaryOperation<1> {
public:
LClassOfTest(LOperand* value, LOperand* temp)
: LUnaryOperation<1>(value), temporary_(temp) {}
DECLARE_CONCRETE_INSTRUCTION(ClassOfTest, "class-of-test")
DECLARE_HYDROGEN_ACCESSOR(ClassOfTest)
virtual void PrintDataTo(StringStream* stream);
LOperand* temporary() { return temporary_; }
private:
LOperand* temporary_;
};
class LClassOfTestAndBranch: public LClassOfTest {
public:
LClassOfTestAndBranch(LOperand* value,
LOperand* temporary,
LOperand* temporary2,
int true_block_id,
int false_block_id)
: LClassOfTest(value, temporary),
temporary2_(temporary2),
true_block_id_(true_block_id),
false_block_id_(false_block_id) { }
DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch,
"class-of-test-and-branch")
virtual void PrintDataTo(StringStream* stream);
virtual bool IsControl() const { return true; }
int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; }
LOperand* temporary2() { return temporary2_; }
private:
LOperand* temporary2_;
int true_block_id_;
int false_block_id_;
};
class LCmpT: public LBinaryOperation<1> {
public:
LCmpT(LOperand* left, LOperand* right) : LBinaryOperation<1>(left, right) {}
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
DECLARE_HYDROGEN_ACCESSOR(Compare)
Token::Value op() const { return hydrogen()->token(); }
};
class LCmpTAndBranch: public LCmpT {
public:
LCmpTAndBranch(LOperand* left,
LOperand* right,
int true_block_id,
int false_block_id)
: LCmpT(left, right),
true_block_id_(true_block_id),
false_block_id_(false_block_id) { }
DECLARE_CONCRETE_INSTRUCTION(CmpTAndBranch, "cmp-t-and-branch")
int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; }
private:
int true_block_id_;
int false_block_id_;
};
class LInstanceOf: public LBinaryOperation<1> {
public:
LInstanceOf(LOperand* left, LOperand* right)
: LBinaryOperation<1>(left, right) { }
DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance-of")
};
class LInstanceOfAndBranch: public LInstanceOf {
public:
LInstanceOfAndBranch(LOperand* left,
LOperand* right,
int true_block_id,
int false_block_id)
: LInstanceOf(left, right),
true_block_id_(true_block_id),
false_block_id_(false_block_id) { }
DECLARE_CONCRETE_INSTRUCTION(InstanceOfAndBranch, "instance-of-and-branch")
int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; }
private:
int true_block_id_;
int false_block_id_;
};
class LInstanceOfKnownGlobal: public LUnaryOperation<1> {
public:
LInstanceOfKnownGlobal(LOperand* left, LOperand* temp)
: LUnaryOperation<1>(left), temp_(temp) { }
DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal,
"instance-of-known-global")
DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal)
Handle<JSFunction> function() const { return hydrogen()->function(); }
LOperand* temp() const { return temp_; }
private:
LOperand* temp_;
};
class LBoundsCheck: public LBinaryOperation<0> {
public:
LBoundsCheck(LOperand* index, LOperand* length)
: LBinaryOperation<0>(index, length) { }
LOperand* index() const { return left(); }
LOperand* length() const { return right(); }
DECLARE_CONCRETE_INSTRUCTION(BoundsCheck, "bounds-check")
};
class LBitI: public LBinaryOperation<1> {
public:
LBitI(Token::Value op, LOperand* left, LOperand* right)
: LBinaryOperation<1>(left, right), op_(op) { }
Token::Value op() const { return op_; }
DECLARE_CONCRETE_INSTRUCTION(BitI, "bit-i")
private:
Token::Value op_;
};
class LShiftI: public LBinaryOperation<1> {
public:
LShiftI(Token::Value op, LOperand* left, LOperand* right, bool can_deopt)
: LBinaryOperation<1>(left, right), op_(op), can_deopt_(can_deopt) { }
Token::Value op() const { return op_; }
bool can_deopt() const { return can_deopt_; }
DECLARE_CONCRETE_INSTRUCTION(ShiftI, "shift-i")
private:
Token::Value op_;
bool can_deopt_;
};
class LSubI: public LBinaryOperation<1> {
public:
LSubI(LOperand* left, LOperand* right)
: LBinaryOperation<1>(left, right) { }
DECLARE_CONCRETE_INSTRUCTION(SubI, "sub-i")
DECLARE_HYDROGEN_ACCESSOR(Sub)
};
class LConstant: public LTemplateInstruction<1, 0, 0> {
DECLARE_INSTRUCTION(Constant)
};
class LConstantI: public LConstant {
public:
explicit LConstantI(int32_t value) : value_(value) { }
int32_t value() const { return value_; }
DECLARE_CONCRETE_INSTRUCTION(ConstantI, "constant-i")
private:
int32_t value_;
};
class LConstantD: public LConstant {
public:
explicit LConstantD(double value) : value_(value) { }
double value() const { return value_; }
DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d")
private:
double value_;
};
class LConstantT: public LConstant {
public:
explicit LConstantT(Handle<Object> value) : value_(value) { }
Handle<Object> value() const { return value_; }
DECLARE_CONCRETE_INSTRUCTION(ConstantT, "constant-t")
private:
Handle<Object> value_;
};
class LBranch: public LUnaryOperation<0> {
public:
LBranch(LOperand* input, int true_block_id, int false_block_id)
: LUnaryOperation<0>(input),
true_block_id_(true_block_id),
false_block_id_(false_block_id) { }
DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
DECLARE_HYDROGEN_ACCESSOR(Value)
virtual void PrintDataTo(StringStream* stream);
virtual bool IsControl() const { return true; }
int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; }
private:
int true_block_id_;
int false_block_id_;
};
class LCmpMapAndBranch: public LUnaryOperation<0> {
public:
explicit LCmpMapAndBranch(LOperand* value) : LUnaryOperation<0>(value) { }
DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareMapAndBranch)
virtual bool IsControl() const { return true; }
Handle<Map> map() const { return hydrogen()->map(); }
int true_block_id() const {
return hydrogen()->true_destination()->block_id();
}
int false_block_id() const {
return hydrogen()->false_destination()->block_id();
}
};
class LJSArrayLength: public LUnaryOperation<1> {
public:
explicit LJSArrayLength(LOperand* input) : LUnaryOperation<1>(input) { }
DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length")
DECLARE_HYDROGEN_ACCESSOR(JSArrayLength)
};
class LFixedArrayLength: public LUnaryOperation<1> {
public:
explicit LFixedArrayLength(LOperand* input) : LUnaryOperation<1>(input) { }
DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length")
DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength)
};
class LValueOf: public LUnaryOperation<1> {
public:
LValueOf(LOperand* input, LOperand* temporary)
: LUnaryOperation<1>(input), temporary_(temporary) { }
LOperand* temporary() const { return temporary_; }
DECLARE_CONCRETE_INSTRUCTION(ValueOf, "value-of")
DECLARE_HYDROGEN_ACCESSOR(ValueOf)
private:
LOperand* temporary_;
};
class LThrow: public LUnaryOperation<1> {
public:
explicit LThrow(LOperand* value) : LUnaryOperation<1>(value) { }
DECLARE_CONCRETE_INSTRUCTION(Throw, "throw")
};
class LBitNotI: public LUnaryOperation<1> {
public:
explicit LBitNotI(LOperand* input) : LUnaryOperation<1>(input) { }
DECLARE_CONCRETE_INSTRUCTION(BitNotI, "bit-not-i")
};
class LAddI: public LBinaryOperation<1> {
public:
LAddI(LOperand* left, LOperand* right)
: LBinaryOperation<1>(left, right) { }
DECLARE_CONCRETE_INSTRUCTION(AddI, "add-i")
DECLARE_HYDROGEN_ACCESSOR(Add)
};
class LPower: public LBinaryOperation<1> {
public:
LPower(LOperand* left, LOperand* right)
: LBinaryOperation<1>(left, right) { }
DECLARE_CONCRETE_INSTRUCTION(Power, "power")
DECLARE_HYDROGEN_ACCESSOR(Power)
};
class LArithmeticD: public LBinaryOperation<1> {
public:
LArithmeticD(Token::Value op, LOperand* left, LOperand* right)
: LBinaryOperation<1>(left, right), op_(op) { }
Token::Value op() const { return op_; }
virtual void CompileToNative(LCodeGen* generator);
virtual const char* Mnemonic() const;
private:
Token::Value op_;
};
class LArithmeticT: public LBinaryOperation<1> {
public:
LArithmeticT(Token::Value op, LOperand* left, LOperand* right)
: LBinaryOperation<1>(left, right), op_(op) { }
virtual void CompileToNative(LCodeGen* generator);
virtual const char* Mnemonic() const;
Token::Value op() const { return op_; }
private:
Token::Value op_;
};
class LReturn: public LUnaryOperation<0> {
public:
explicit LReturn(LOperand* use) : LUnaryOperation<0>(use) { }
DECLARE_CONCRETE_INSTRUCTION(Return, "return")
};
class LLoadNamedField: public LUnaryOperation<1> {
public:
explicit LLoadNamedField(LOperand* object) : LUnaryOperation<1>(object) { }
DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field")
DECLARE_HYDROGEN_ACCESSOR(LoadNamedField)
};
class LLoadNamedGeneric: public LUnaryOperation<1> {
public:
explicit LLoadNamedGeneric(LOperand* object) : LUnaryOperation<1>(object) { }
DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load-named-generic")
DECLARE_HYDROGEN_ACCESSOR(LoadNamedGeneric)
LOperand* object() const { return input(); }
Handle<Object> name() const { return hydrogen()->name(); }
};
class LLoadFunctionPrototype: public LUnaryOperation<1> {
public:
LLoadFunctionPrototype(LOperand* function, LOperand* temporary)
: LUnaryOperation<1>(function), temporary_(temporary) { }
DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load-function-prototype")
DECLARE_HYDROGEN_ACCESSOR(LoadFunctionPrototype)
LOperand* function() const { return input(); }
LOperand* temporary() const { return temporary_; }
private:
LOperand* temporary_;
};
class LLoadElements: public LUnaryOperation<1> {
public:
explicit LLoadElements(LOperand* obj) : LUnaryOperation<1>(obj) { }
DECLARE_CONCRETE_INSTRUCTION(LoadElements, "load-elements")
};
class LLoadKeyedFastElement: public LBinaryOperation<1> {
public:
LLoadKeyedFastElement(LOperand* elements, LOperand* key)
: LBinaryOperation<1>(elements, key) { }
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement, "load-keyed-fast-element")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastElement)
LOperand* elements() const { return left(); }
LOperand* key() const { return right(); }
};
class LLoadKeyedGeneric: public LBinaryOperation<1> {
public:
LLoadKeyedGeneric(LOperand* obj, LOperand* key)
: LBinaryOperation<1>(obj, key) { }
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic")
LOperand* object() const { return left(); }
LOperand* key() const { return right(); }
};
class LLoadGlobal: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(LoadGlobal, "load-global")
DECLARE_HYDROGEN_ACCESSOR(LoadGlobal)
};
class LStoreGlobal: public LUnaryOperation<0> {
public:
explicit LStoreGlobal(LOperand* value) : LUnaryOperation<0>(value) {}
DECLARE_CONCRETE_INSTRUCTION(StoreGlobal, "store-global")
DECLARE_HYDROGEN_ACCESSOR(StoreGlobal)
};
class LPushArgument: public LUnaryOperation<0> {
public:
explicit LPushArgument(LOperand* argument) : LUnaryOperation<0>(argument) {}
DECLARE_CONCRETE_INSTRUCTION(PushArgument, "push-argument")
};
class LGlobalObject: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object")
};
class LGlobalReceiver: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global-receiver")
};
class LCallConstantFunction: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(CallConstantFunction, "call-constant-function")
DECLARE_HYDROGEN_ACCESSOR(CallConstantFunction)
virtual void PrintDataTo(StringStream* stream);
Handle<JSFunction> function() { return hydrogen()->function(); }
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallKeyed: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call-keyed")
DECLARE_HYDROGEN_ACCESSOR(CallKeyed)
virtual void PrintDataTo(StringStream* stream);
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallNamed: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(CallNamed, "call-named")
DECLARE_HYDROGEN_ACCESSOR(CallNamed)
virtual void PrintDataTo(StringStream* stream);
Handle<String> name() const { return hydrogen()->name(); }
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallFunction: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function")
DECLARE_HYDROGEN_ACCESSOR(CallFunction)
int arity() const { return hydrogen()->argument_count() - 2; }
};
class LCallGlobal: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(CallGlobal, "call-global")
DECLARE_HYDROGEN_ACCESSOR(CallGlobal)
virtual void PrintDataTo(StringStream* stream);
Handle<String> name() const {return hydrogen()->name(); }
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallKnownGlobal: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(CallKnownGlobal, "call-known-global")
DECLARE_HYDROGEN_ACCESSOR(CallKnownGlobal)
virtual void PrintDataTo(StringStream* stream);
Handle<JSFunction> target() const { return hydrogen()->target(); }
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallNew: public LUnaryOperation<1> {
public:
explicit LCallNew(LOperand* constructor) : LUnaryOperation<1>(constructor) { }
DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
DECLARE_HYDROGEN_ACCESSOR(CallNew)
virtual void PrintDataTo(StringStream* stream);
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallRuntime: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
Runtime::Function* function() const { return hydrogen()->function(); }
int arity() const { return hydrogen()->argument_count(); }
};
class LInteger32ToDouble: public LUnaryOperation<1> {
public:
explicit LInteger32ToDouble(LOperand* use) : LUnaryOperation<1>(use) { }
DECLARE_CONCRETE_INSTRUCTION(Integer32ToDouble, "int32-to-double")
};
class LNumberTagI: public LUnaryOperation<1> {
public:
explicit LNumberTagI(LOperand* use) : LUnaryOperation<1>(use) { }
DECLARE_CONCRETE_INSTRUCTION(NumberTagI, "number-tag-i")
};
class LNumberTagD: public LUnaryOperation<1> {
public:
explicit LNumberTagD(LOperand* value, LOperand* temp)
: LUnaryOperation<1>(value), temp_(temp) { }
DECLARE_CONCRETE_INSTRUCTION(NumberTagD, "number-tag-d")
LOperand* temp() const { return temp_; }
private:
LOperand* temp_;
};
// Sometimes truncating conversion from a tagged value to an int32.
class LDoubleToI: public LUnaryOperation<1> {
public:
LDoubleToI(LOperand* value, LOperand* temporary)
: LUnaryOperation<1>(value), temporary_(temporary) { }
DECLARE_CONCRETE_INSTRUCTION(DoubleToI, "double-to-i")
DECLARE_HYDROGEN_ACCESSOR(Change)
bool truncating() { return hydrogen()->CanTruncateToInt32(); }
LOperand* temporary() const { return temporary_; }
private:
LOperand* temporary_;
};
// Truncating conversion from a tagged value to an int32.
class LTaggedToI: public LUnaryOperation<1> {
public:
LTaggedToI(LOperand* value, LOperand* temp)
: LUnaryOperation<1>(value), temp_(temp) { }
DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i")
DECLARE_HYDROGEN_ACCESSOR(Change)
bool truncating() { return hydrogen()->CanTruncateToInt32(); }
LOperand* temp() const { return temp_; }
private:
LOperand* temp_;
};
class LSmiTag: public LUnaryOperation<1> {
public:
explicit LSmiTag(LOperand* use) : LUnaryOperation<1>(use) { }
DECLARE_CONCRETE_INSTRUCTION(SmiTag, "smi-tag")
};
class LNumberUntagD: public LUnaryOperation<1> {
public:
explicit LNumberUntagD(LOperand* value) : LUnaryOperation<1>(value) { }
DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
};
class LSmiUntag: public LUnaryOperation<1> {
public:
LSmiUntag(LOperand* use, bool needs_check)
: LUnaryOperation<1>(use), needs_check_(needs_check) { }
DECLARE_CONCRETE_INSTRUCTION(SmiUntag, "smi-untag")
bool needs_check() const { return needs_check_; }
private:
bool needs_check_;
};
class LStoreNamed: public LTemplateInstruction<0, 2, 0> {
public:
LStoreNamed(LOperand* obj, LOperand* val) {
this->SetInputAt(0, obj);
this->SetInputAt(1, val);
}
DECLARE_INSTRUCTION(StoreNamed)
DECLARE_HYDROGEN_ACCESSOR(StoreNamed)
virtual void PrintDataTo(StringStream* stream);
LOperand* object() const { return this->InputAt(0); }
LOperand* value() const { return this->InputAt(1); }
Handle<Object> name() const { return hydrogen()->name(); }
};
class LStoreNamedField: public LStoreNamed {
public:
LStoreNamedField(LOperand* obj, LOperand* val, LOperand* temp)
: LStoreNamed(obj, val), temp_(temp) { }
DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field")
DECLARE_HYDROGEN_ACCESSOR(StoreNamedField)
bool is_in_object() { return hydrogen()->is_in_object(); }
int offset() { return hydrogen()->offset(); }
bool needs_write_barrier() { return hydrogen()->NeedsWriteBarrier(); }
Handle<Map> transition() const { return hydrogen()->transition(); }
LOperand* temp() { return temp_; }
private:
LOperand* temp_;
};
class LStoreNamedGeneric: public LStoreNamed {
public:
LStoreNamedGeneric(LOperand* obj, LOperand* val)
: LStoreNamed(obj, val) { }
DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic")
DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric)
};
class LStoreKeyed: public LTemplateInstruction<0, 3, 0> {
public:
LStoreKeyed(LOperand* obj, LOperand* key, LOperand* val) {
this->SetInputAt(0, obj);
this->SetInputAt(1, key);
this->SetInputAt(2, val);
}
DECLARE_INSTRUCTION(StoreKeyed)
virtual void PrintDataTo(StringStream* stream);
LOperand* object() const { return this->InputAt(0); }
LOperand* key() const { return this->InputAt(1); }
LOperand* value() const { return this->InputAt(2); }
};
class LStoreKeyedFastElement: public LStoreKeyed {
public:
LStoreKeyedFastElement(LOperand* obj, LOperand* key, LOperand* val)
: LStoreKeyed(obj, key, val) {}
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement,
"store-keyed-fast-element")
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastElement)
};
class LStoreKeyedGeneric: public LStoreKeyed {
public:
LStoreKeyedGeneric(LOperand* obj, LOperand* key, LOperand* val)
: LStoreKeyed(obj, key, val) { }
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic")
};
class LCheckFunction: public LUnaryOperation<0> {
public:
explicit LCheckFunction(LOperand* use) : LUnaryOperation<0>(use) { }
DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function")
DECLARE_HYDROGEN_ACCESSOR(CheckFunction)
};
class LCheckInstanceType: public LUnaryOperation<0> {
public:
LCheckInstanceType(LOperand* use, LOperand* temp)
: LUnaryOperation<0>(use), temp_(temp) { }
DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType, "check-instance-type")
DECLARE_HYDROGEN_ACCESSOR(CheckInstanceType)
LOperand* temp() const { return temp_; }
private:
LOperand* temp_;
};
class LCheckMap: public LUnaryOperation<0> {
public:
explicit LCheckMap(LOperand* use) : LUnaryOperation<0>(use) { }
DECLARE_CONCRETE_INSTRUCTION(CheckMap, "check-map")
DECLARE_HYDROGEN_ACCESSOR(CheckMap)
};
class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 0> {
public:
explicit LCheckPrototypeMaps(LOperand* temp) : temp_(temp) { }
DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps")
DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps)
Handle<JSObject> prototype() const { return hydrogen()->prototype(); }
Handle<JSObject> holder() const { return hydrogen()->holder(); }
LOperand* temp() const { return temp_; }
private:
LOperand* temp_;
};
class LCheckSmi: public LUnaryOperation<0> {
public:
LCheckSmi(LOperand* use, Condition condition)
: LUnaryOperation<0>(use), condition_(condition) { }
Condition condition() const { return condition_; }
virtual void CompileToNative(LCodeGen* generator);
virtual const char* Mnemonic() const {
return (condition_ == zero) ? "check-non-smi" : "check-smi";
}
private:
Condition condition_;
};
class LMaterializedLiteral: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_INSTRUCTION(MaterializedLiteral)
};
class LArrayLiteral: public LMaterializedLiteral {
public:
DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral, "array-literal")
DECLARE_HYDROGEN_ACCESSOR(ArrayLiteral)
};
class LObjectLiteral: public LMaterializedLiteral {
public:
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral, "object-literal")
DECLARE_HYDROGEN_ACCESSOR(ObjectLiteral)
};
class LRegExpLiteral: public LMaterializedLiteral {
public:
DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral, "regexp-literal")
DECLARE_HYDROGEN_ACCESSOR(RegExpLiteral)
};
class LFunctionLiteral: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral, "function-literal")
DECLARE_HYDROGEN_ACCESSOR(FunctionLiteral)
Handle<SharedFunctionInfo> shared_info() { return hydrogen()->shared_info(); }
};
class LTypeof: public LUnaryOperation<1> {
public:
explicit LTypeof(LOperand* input) : LUnaryOperation<1>(input) { }
DECLARE_CONCRETE_INSTRUCTION(Typeof, "typeof")
};
class LTypeofIs: public LUnaryOperation<1> {
public:
explicit LTypeofIs(LOperand* input) : LUnaryOperation<1>(input) { }
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(TypeofIs, "typeof-is")
DECLARE_HYDROGEN_ACCESSOR(TypeofIs)
Handle<String> type_literal() { return hydrogen()->type_literal(); }
};
class LTypeofIsAndBranch: public LTypeofIs {
public:
LTypeofIsAndBranch(LOperand* value,
int true_block_id,
int false_block_id)
: LTypeofIs(value),
true_block_id_(true_block_id),
false_block_id_(false_block_id) { }
DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch")
virtual void PrintDataTo(StringStream* stream);
virtual bool IsControl() const { return true; }
int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; }
private:
int true_block_id_;
int false_block_id_;
};
class LDeleteProperty: public LBinaryOperation<1> {
public:
LDeleteProperty(LOperand* obj, LOperand* key)
: LBinaryOperation<1>(obj, key) { }
DECLARE_CONCRETE_INSTRUCTION(DeleteProperty, "delete-property")
LOperand* object() const { return left(); }
LOperand* key() const { return right(); }
};
class LOsrEntry: public LTemplateInstruction<0, 0, 0> {
public:
LOsrEntry();
DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry")
LOperand** SpilledRegisterArray() { return register_spills_; }
LOperand** SpilledDoubleRegisterArray() { return double_register_spills_; }
void MarkSpilledRegister(int allocation_index, LOperand* spill_operand);
void MarkSpilledDoubleRegister(int allocation_index,
LOperand* spill_operand);
private:
// Arrays of spill slot operands for registers with an assigned spill
// slot, i.e., that must also be restored to the spill slot on OSR entry.
// NULL if the register has no assigned spill slot. Indexed by allocation
// index.
LOperand* register_spills_[Register::kNumAllocatableRegisters];
LOperand* double_register_spills_[DoubleRegister::kNumAllocatableRegisters];
};
class LStackCheck: public LTemplateInstruction<0, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(StackCheck, "stack-check")
};
class LChunkBuilder;
class LChunk: public ZoneObject {
public:
explicit LChunk(HGraph* graph)
: spill_slot_count_(0),
graph_(graph),
instructions_(32),
pointer_maps_(8),
inlined_closures_(1) { }
int AddInstruction(LInstruction* instruction, HBasicBlock* block);
LConstantOperand* DefineConstantOperand(HConstant* constant);
Handle<Object> LookupLiteral(LConstantOperand* operand) const;
Representation LookupLiteralRepresentation(LConstantOperand* operand) const;
int GetNextSpillIndex(bool is_double);
LOperand* GetNextSpillSlot(bool is_double);
int ParameterAt(int index);
int GetParameterStackSlot(int index) const;
int spill_slot_count() const { return spill_slot_count_; }
HGraph* graph() const { return graph_; }
const ZoneList<LInstruction*>* instructions() const { return &instructions_; }
void AddGapMove(int index, LOperand* from, LOperand* to);
LGap* GetGapAt(int index) const;
bool IsGapAt(int index) const;
int NearestGapPos(int index) const;
void MarkEmptyBlocks();
const ZoneList<LPointerMap*>* pointer_maps() const { return &pointer_maps_; }
LLabel* GetLabel(int block_id) const {
HBasicBlock* block = graph_->blocks()->at(block_id);
int first_instruction = block->first_instruction_index();
return LLabel::cast(instructions_[first_instruction]);
}
int LookupDestination(int block_id) const {
LLabel* cur = GetLabel(block_id);
while (cur->replacement() != NULL) {
cur = cur->replacement();
}
return cur->block_id();
}
Label* GetAssemblyLabel(int block_id) const {
LLabel* label = GetLabel(block_id);
ASSERT(!label->HasReplacement());
return label->label();
}
const ZoneList<Handle<JSFunction> >* inlined_closures() const {
return &inlined_closures_;
}
void AddInlinedClosure(Handle<JSFunction> closure) {
inlined_closures_.Add(closure);
}
private:
int spill_slot_count_;
HGraph* const graph_;
ZoneList<LInstruction*> instructions_;
ZoneList<LPointerMap*> pointer_maps_;
ZoneList<Handle<JSFunction> > inlined_closures_;
};
class LChunkBuilder BASE_EMBEDDED {
public:
LChunkBuilder(HGraph* graph, LAllocator* allocator)
: chunk_(NULL),
graph_(graph),
status_(UNUSED),
current_instruction_(NULL),
current_block_(NULL),
next_block_(NULL),
argument_count_(0),
allocator_(allocator),
position_(RelocInfo::kNoPosition),
instructions_pending_deoptimization_environment_(NULL),
pending_deoptimization_ast_id_(AstNode::kNoNumber) { }
// Build the sequence for the graph.
LChunk* Build();
// Declare methods that deal with the individual node types.
#define DECLARE_DO(type) LInstruction* Do##type(H##type* node);
HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
#undef DECLARE_DO
private:
enum Status {
UNUSED,
BUILDING,
DONE,
ABORTED
};
LChunk* chunk() const { return chunk_; }
HGraph* graph() const { return graph_; }
bool is_unused() const { return status_ == UNUSED; }
bool is_building() const { return status_ == BUILDING; }
bool is_done() const { return status_ == DONE; }
bool is_aborted() const { return status_ == ABORTED; }
void Abort(const char* format, ...);
// Methods for getting operands for Use / Define / Temp.
LRegister* ToOperand(Register reg);
LUnallocated* ToUnallocated(Register reg);
LUnallocated* ToUnallocated(XMMRegister reg);
// Methods for setting up define-use relationships.
LOperand* Use(HValue* value, LUnallocated* operand);
LOperand* UseFixed(HValue* value, Register fixed_register);
LOperand* UseFixedDouble(HValue* value, XMMRegister fixed_register);
// A value that is guaranteed to be allocated to a register.
// Operand created by UseRegister is guaranteed to be live until the end of
// instruction. This means that register allocator will not reuse it's
// register for any other operand inside instruction.
// Operand created by UseRegisterAtStart is guaranteed to be live only at
// instruction start. Register allocator is free to assign the same register
// to some other operand used inside instruction (i.e. temporary or
// output).
LOperand* UseRegister(HValue* value);
LOperand* UseRegisterAtStart(HValue* value);
// A value in a register that may be trashed.
LOperand* UseTempRegister(HValue* value);
LOperand* Use(HValue* value);
LOperand* UseAtStart(HValue* value);
LOperand* UseOrConstant(HValue* value);
LOperand* UseOrConstantAtStart(HValue* value);
LOperand* UseRegisterOrConstant(HValue* value);
LOperand* UseRegisterOrConstantAtStart(HValue* value);
// Methods for setting up define-use relationships.
// Return the same instruction that they are passed.
template<int I, int T>
LInstruction* Define(LTemplateInstruction<1, I, T>* instr,
LUnallocated* result);
template<int I, int T>
LInstruction* Define(LTemplateInstruction<1, I, T>* instr);
template<int I, int T>
LInstruction* DefineAsRegister(LTemplateInstruction<1, I, T>* instr);
template<int I, int T>
LInstruction* DefineAsSpilled(LTemplateInstruction<1, I, T>* instr,
int index);
template<int I, int T>
LInstruction* DefineSameAsFirst(LTemplateInstruction<1, I, T>* instr);
template<int I, int T>
LInstruction* DefineFixed(LTemplateInstruction<1, I, T>* instr,
Register reg);
template<int I, int T>
LInstruction* DefineFixedDouble(LTemplateInstruction<1, I, T>* instr,
XMMRegister reg);
LInstruction* AssignEnvironment(LInstruction* instr);
LInstruction* AssignPointerMap(LInstruction* instr);
enum CanDeoptimize { CAN_DEOPTIMIZE_EAGERLY, CANNOT_DEOPTIMIZE_EAGERLY };
// By default we assume that instruction sequences generated for calls
// cannot deoptimize eagerly and we do not attach environment to this
// instruction.
LInstruction* MarkAsCall(
LInstruction* instr,
HInstruction* hinstr,
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
LInstruction* MarkAsSaveDoubles(LInstruction* instr);
LInstruction* SetInstructionPendingDeoptimizationEnvironment(
LInstruction* instr, int ast_id);
void ClearInstructionPendingDeoptimizationEnvironment();
LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env);
// Temporary operand that must be in a register.
LUnallocated* TempRegister();
LOperand* FixedTemp(Register reg);
LOperand* FixedTemp(XMMRegister reg);
void VisitInstruction(HInstruction* current);
void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block);
LInstruction* DoBit(Token::Value op, HBitwiseBinaryOperation* instr);
LInstruction* DoShift(Token::Value op, HBitwiseBinaryOperation* instr);
LInstruction* DoArithmeticD(Token::Value op,
HArithmeticBinaryOperation* instr);
LInstruction* DoArithmeticT(Token::Value op,
HArithmeticBinaryOperation* instr);
LChunk* chunk_;
HGraph* const graph_;
......@@ -412,6 +2032,9 @@ class LChunkBuilder BASE_EMBEDDED {
DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
};
#undef DECLARE_HYDROGEN_ACCESSOR
#undef DECLARE_INSTRUCTION
#undef DECLARE_CONCRETE_INSTRUCTION
} } // namespace v8::internal
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment