| 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;
|
|
|