Index: src/x64/codegen-x64.cc |
=================================================================== |
--- src/x64/codegen-x64.cc (revision 5077) |
+++ src/x64/codegen-x64.cc (working copy) |
@@ -139,7 +139,7 @@ |
} |
-// ----------------------------------------------------------------------------- |
+// ------------------------------------------------------------------------- |
// CodeGenerator implementation. |
CodeGenerator::CodeGenerator(MacroAssembler* masm) |
@@ -155,6 +155,12 @@ |
} |
+// Calling conventions: |
+// rbp: caller's frame pointer |
+// rsp: stack pointer |
+// rdi: called JS function |
+// rsi: callee's context |
+ |
void CodeGenerator::Generate(CompilationInfo* info) { |
// Record the position for debugging purposes. |
CodeForFunctionPosition(info->function()); |
@@ -171,7 +177,7 @@ |
// Adjust for function-level loop nesting. |
ASSERT_EQ(0, loop_nesting_); |
- loop_nesting_ += info->loop_nesting(); |
+ loop_nesting_ = info->loop_nesting(); |
JumpTarget::set_compiling_deferred_code(false); |
@@ -432,7 +438,7 @@ |
default: |
UNREACHABLE(); |
- return Operand(rsp, 0); |
+ return Operand(rax); |
} |
} |
@@ -469,14 +475,14 @@ |
// frame. If the expression is boolean-valued it may be compiled (or |
// partially compiled) into control flow to the control destination. |
// If force_control is true, control flow is forced. |
-void CodeGenerator::LoadCondition(Expression* x, |
+void CodeGenerator::LoadCondition(Expression* expr, |
ControlDestination* dest, |
bool force_control) { |
ASSERT(!in_spilled_code()); |
int original_height = frame_->height(); |
{ CodeGenState new_state(this, dest); |
- Visit(x); |
+ Visit(expr); |
// If we hit a stack overflow, we may not have actually visited |
// the expression. In that case, we ensure that we have a |
@@ -496,7 +502,6 @@ |
if (force_control && !dest->is_used()) { |
// Convert the TOS value into flow to the control destination. |
- // TODO(X64): Make control flow to control destinations work. |
ToBoolean(dest); |
} |
@@ -506,7 +511,6 @@ |
void CodeGenerator::LoadAndSpill(Expression* expression) { |
- // TODO(x64): No architecture specific code. Move to shared location. |
ASSERT(in_spilled_code()); |
set_in_spilled_code(false); |
Load(expression); |
@@ -652,7 +656,6 @@ |
frame_->Push(&result); |
} |
- |
Variable* arguments = scope()->arguments()->var(); |
Variable* shadow = scope()->arguments_shadow()->var(); |
ASSERT(arguments != NULL && arguments->slot() != NULL); |
@@ -663,11 +666,11 @@ |
// We have to skip storing into the arguments slot if it has |
// already been written to. This can happen if the a function |
// has a local variable named 'arguments'. |
- LoadFromSlot(scope()->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); |
+ LoadFromSlot(arguments->slot(), NOT_INSIDE_TYPEOF); |
Result probe = frame_->Pop(); |
if (probe.is_constant()) { |
- // We have to skip updating the arguments object if it has been |
- // assigned a proper value. |
+ // We have to skip updating the arguments object if it has |
+ // been assigned a proper value. |
skip_arguments = !probe.handle()->IsTheHole(); |
} else { |
__ CompareRoot(probe.reg(), Heap::kTheHoleValueRootIndex); |
@@ -686,9 +689,6 @@ |
//------------------------------------------------------------------------------ |
// CodeGenerator implementation of variables, lookups, and stores. |
-//------------------------------------------------------------------------------ |
-// CodeGenerator implementation of variables, lookups, and stores. |
- |
Reference::Reference(CodeGenerator* cgen, |
Expression* expression, |
bool persist_after_get) |
@@ -845,8 +845,8 @@ |
const char* GenericBinaryOpStub::GetName() { |
if (name_ != NULL) return name_; |
- const int len = 100; |
- name_ = Bootstrapper::AllocateAutoDeletedArray(len); |
+ const int kMaxNameLength = 100; |
+ name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength); |
if (name_ == NULL) return "OOM"; |
const char* op_name = Token::Name(op_); |
const char* overwrite_name; |
@@ -857,7 +857,7 @@ |
default: overwrite_name = "UnknownOverwrite"; break; |
} |
- OS::SNPrintF(Vector<char>(name_, len), |
+ OS::SNPrintF(Vector<char>(name_, kMaxNameLength), |
"GenericBinaryOpStub_%s_%s%s_%s%s_%s_%s", |
op_name, |
overwrite_name, |
@@ -1138,7 +1138,7 @@ |
if (answer >= Smi::kMinValue && answer <= Smi::kMaxValue) { |
// If the product is zero and the non-zero factor is negative, |
// the spec requires us to return floating point negative zero. |
- if (answer != 0 || (left + right) >= 0) { |
+ if (answer != 0 || (left >= 0 && right >= 0)) { |
answer_object = Smi::FromInt(static_cast<int>(answer)); |
} |
} |
@@ -1645,7 +1645,6 @@ |
}; |
- |
void DeferredInlineSmiSub::Generate() { |
GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, NO_SMI_CODE_IN_STUB); |
igostub.GenerateCall(masm_, dst_, value_); |
@@ -1710,6 +1709,7 @@ |
} else { |
operand->ToRegister(); |
frame_->Spill(operand->reg()); |
+ answer = *operand; |
DeferredCode* deferred = new DeferredInlineSmiSub(operand->reg(), |
smi_value, |
overwrite_mode); |
@@ -1721,7 +1721,7 @@ |
smi_value, |
deferred->entry_label()); |
deferred->BindExit(); |
- answer = *operand; |
+ operand->Unuse(); |
} |
break; |
} |
@@ -1932,6 +1932,7 @@ |
return answer; |
} |
+ |
static bool CouldBeNaN(const Result& result) { |
if (result.type_info().IsSmi()) return false; |
if (result.type_info().IsInteger32()) return false; |
@@ -2179,7 +2180,8 @@ |
} |
} else { |
// Neither side is a constant Smi, constant 1-char string, or constant null. |
- // If either side is a non-smi constant, skip the smi check. |
+ // If either side is a non-smi constant, or known to be a heap number, |
+ // skip the smi check. |
bool known_non_smi = |
(left_side.is_constant() && !left_side.handle()->IsSmi()) || |
(right_side.is_constant() && !right_side.handle()->IsSmi()) || |
@@ -2205,6 +2207,7 @@ |
bool inline_number_compare = |
loop_nesting() > 0 && cc != equal && !is_loop_condition; |
+ // Left and right needed in registers for the following code. |
left_side.ToRegister(); |
right_side.ToRegister(); |
@@ -2222,6 +2225,8 @@ |
GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); |
} |
+ // End of in-line compare, call out to the compare stub. Don't include |
+ // number comparison in the stub if it was inlined. |
CompareStub stub(cc, strict, nan_info, !inline_number_compare); |
Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
__ testq(answer.reg(), answer.reg()); // Sets both zero and sign flag. |
@@ -2252,6 +2257,8 @@ |
GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); |
} |
+ // End of in-line compare, call out to the compare stub. Don't include |
+ // number comparison in the stub if it was inlined. |
CompareStub stub(cc, strict, nan_info, !inline_number_compare); |
Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
__ testq(answer.reg(), answer.reg()); // Sets both zero and sign flags. |
@@ -2704,7 +2711,6 @@ |
void CodeGenerator::VisitAndSpill(Statement* statement) { |
- // TODO(X64): No architecture specific code. Move to shared location. |
ASSERT(in_spilled_code()); |
set_in_spilled_code(false); |
Visit(statement); |
@@ -2716,6 +2722,9 @@ |
void CodeGenerator::VisitStatementsAndSpill(ZoneList<Statement*>* statements) { |
+#ifdef DEBUG |
+ int original_height = frame_->height(); |
+#endif |
ASSERT(in_spilled_code()); |
set_in_spilled_code(false); |
VisitStatements(statements); |
@@ -2723,14 +2732,20 @@ |
frame_->SpillAll(); |
} |
set_in_spilled_code(true); |
+ |
+ ASSERT(!has_valid_frame() || frame_->height() == original_height); |
} |
void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { |
+#ifdef DEBUG |
+ int original_height = frame_->height(); |
+#endif |
ASSERT(!in_spilled_code()); |
for (int i = 0; has_valid_frame() && i < statements->length(); i++) { |
Visit(statements->at(i)); |
} |
+ ASSERT(!has_valid_frame() || frame_->height() == original_height); |
} |
@@ -2966,6 +2981,7 @@ |
CodeForStatementPosition(node); |
Load(node->expression()); |
Result return_value = frame_->Pop(); |
+ masm()->WriteRecordedPositions(); |
if (function_return_is_shadowed_) { |
function_return_.Jump(&return_value); |
} else { |
@@ -3003,6 +3019,8 @@ |
// receiver. |
frame_->Exit(); |
masm_->ret((scope()->num_parameters() + 1) * kPointerSize); |
+ DeleteFrame(); |
+ |
#ifdef ENABLE_DEBUGGER_SUPPORT |
// Add padding that will be overwritten by a debugger breakpoint. |
// frame_->Exit() generates "movq rsp, rbp; pop rbp; ret k" |
@@ -3016,7 +3034,6 @@ |
ASSERT_EQ(Assembler::kJSReturnSequenceLength, |
masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); |
#endif |
- DeleteFrame(); |
} |
@@ -3055,8 +3072,6 @@ |
void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
- // TODO(X64): This code is completely generic and should be moved somewhere |
- // where it can be shared between architectures. |
ASSERT(!in_spilled_code()); |
Comment cmnt(masm_, "[ SwitchStatement"); |
CodeForStatementPosition(node); |
@@ -3348,8 +3363,8 @@ |
LoadCondition(node->cond(), &dest, true); |
} |
} else { |
- // If we have chosen not to recompile the test at the |
- // bottom, jump back to the one at the top. |
+ // If we have chosen not to recompile the test at the bottom, |
+ // jump back to the one at the top. |
if (has_valid_frame()) { |
node->continue_target()->Jump(); |
} |
@@ -3911,6 +3926,7 @@ |
node->break_target()->Unuse(); |
} |
+ |
void CodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) { |
ASSERT(!in_spilled_code()); |
VirtualFrame::SpilledScope spilled_scope; |