diff --git a/src/compiler/arm/code-generator-arm.cc b/src/compiler/arm/code-generator-arm.cc index fabcfdcdc5..f278326cf7 100644 --- a/src/compiler/arm/code-generator-arm.cc +++ b/src/compiler/arm/code-generator-arm.cc @@ -204,6 +204,10 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { AssembleReturn(); DCHECK_EQ(LeaveCC, i.OutputSBit()); break; + case kArchStackPointer: + __ mov(i.OutputRegister(), sp); + DCHECK_EQ(LeaveCC, i.OutputSBit()); + break; case kArchTruncateDoubleToI: __ TruncateDoubleToI(i.OutputRegister(), i.InputFloat64Register(0)); DCHECK_EQ(LeaveCC, i.OutputSBit()); diff --git a/src/compiler/arm/instruction-selector-arm.cc b/src/compiler/arm/instruction-selector-arm.cc index e83d1e54af..c3efad52fd 100644 --- a/src/compiler/arm/instruction-selector-arm.cc +++ b/src/compiler/arm/instruction-selector-arm.cc @@ -73,6 +73,7 @@ class ArmOperandGenerator : public OperandGenerator { case kArchJmp: case kArchNop: case kArchRet: + case kArchStackPointer: case kArchTruncateDoubleToI: case kArmMul: case kArmMla: diff --git a/src/compiler/arm64/code-generator-arm64.cc b/src/compiler/arm64/code-generator-arm64.cc index a56de204b7..c041e15366 100644 --- a/src/compiler/arm64/code-generator-arm64.cc +++ b/src/compiler/arm64/code-generator-arm64.cc @@ -172,6 +172,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { case kArchRet: AssembleReturn(); break; + case kArchStackPointer: + __ mov(i.OutputRegister(), masm()->StackPointer()); + break; case kArchTruncateDoubleToI: __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0)); break; diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index 3ac4b4639f..fa987796a2 100644 --- a/src/compiler/ast-graph-builder.cc +++ b/src/compiler/ast-graph-builder.cc @@ -86,8 +86,8 @@ bool AstGraphBuilder::CreateGraph() { // Visit declarations within the function scope. VisitDeclarations(scope->declarations()); - // TODO(mstarzinger): This should do an inlined stack check. - Node* node = NewNode(javascript()->CallRuntime(Runtime::kStackGuard, 0)); + // Build a stack-check before the body. + Node* node = BuildStackCheck(); PrepareFrameState(node, BailoutId::FunctionEntry()); // Visit statements in the function body. @@ -2059,6 +2059,24 @@ Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) { } +Node* AstGraphBuilder::BuildStackCheck() { + IfBuilder stack_check(this); + Node* limit = + NewNode(jsgraph()->machine()->Load(kMachPtr), + jsgraph()->ExternalConstant( + ExternalReference::address_of_stack_limit(isolate())), + jsgraph()->ZeroConstant()); + Node* stack = NewNode(jsgraph()->machine()->LoadStackPointer()); + Node* tag = NewNode(jsgraph()->machine()->UintLessThan(), limit, stack); + stack_check.If(tag); + stack_check.Then(); + stack_check.Else(); + Node* guard = NewNode(javascript()->CallRuntime(Runtime::kStackGuard, 0)); + stack_check.End(); + return guard; +} + + void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id, OutputFrameStateCombine combine) { if (OperatorProperties::HasFrameStateInput(node->op())) { diff --git a/src/compiler/ast-graph-builder.h b/src/compiler/ast-graph-builder.h index feded98b4e..967b24bda1 100644 --- a/src/compiler/ast-graph-builder.h +++ b/src/compiler/ast-graph-builder.h @@ -105,6 +105,9 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor { // Builders for binary operations. Node* BuildBinaryOp(Node* left, Node* right, Token::Value op); + // Builder for stack-check guards. + Node* BuildStackCheck(); + #define DECLARE_VISIT(type) virtual void Visit##type(type* node); // Visiting functions for AST nodes make this an AstVisitor. AST_NODE_LIST(DECLARE_VISIT) diff --git a/src/compiler/ia32/code-generator-ia32.cc b/src/compiler/ia32/code-generator-ia32.cc index 4bb7500664..2b51b6fb92 100644 --- a/src/compiler/ia32/code-generator-ia32.cc +++ b/src/compiler/ia32/code-generator-ia32.cc @@ -205,6 +205,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { case kArchRet: AssembleReturn(); break; + case kArchStackPointer: + __ mov(i.OutputRegister(), esp); + break; case kArchTruncateDoubleToI: __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0)); break; diff --git a/src/compiler/instruction-codes.h b/src/compiler/instruction-codes.h index 0abed6c321..fd7c53078f 100644 --- a/src/compiler/instruction-codes.h +++ b/src/compiler/instruction-codes.h @@ -33,6 +33,7 @@ namespace compiler { V(ArchJmp) \ V(ArchNop) \ V(ArchRet) \ + V(ArchStackPointer) \ V(ArchTruncateDoubleToI) \ TARGET_ARCH_OPCODE_LIST(V) diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc index d0be3fecd1..09a8e018eb 100644 --- a/src/compiler/instruction-selector.cc +++ b/src/compiler/instruction-selector.cc @@ -612,6 +612,8 @@ void InstructionSelector::VisitNode(Node* node) { return VisitFloat64LessThan(node); case IrOpcode::kFloat64LessThanOrEqual: return VisitFloat64LessThanOrEqual(node); + case IrOpcode::kLoadStackPointer: + return VisitLoadStackPointer(node); default: V8_Fatal(__FILE__, __LINE__, "Unexpected operator #%d:%s @ node #%d", node->opcode(), node->op()->mnemonic(), node->id()); @@ -727,6 +729,12 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { VisitFloat64Compare(node, &cont); } + +void InstructionSelector::VisitLoadStackPointer(Node* node) { + OperandGenerator g(this); + Emit(kArchStackPointer, g.DefineAsRegister(node)); +} + #endif // V8_TURBOFAN_BACKEND // 32 bit targets do not implement the following instructions. diff --git a/src/compiler/machine-operator.cc b/src/compiler/machine-operator.cc index 35e0e5419a..e88c792ec1 100644 --- a/src/compiler/machine-operator.cc +++ b/src/compiler/machine-operator.cc @@ -119,7 +119,8 @@ struct StaticParameterTraits { V(Float64Sqrt, Operator::kNoProperties, 1, 1) \ V(Float64Equal, Operator::kCommutative, 2, 1) \ V(Float64LessThan, Operator::kNoProperties, 2, 1) \ - V(Float64LessThanOrEqual, Operator::kNoProperties, 2, 1) + V(Float64LessThanOrEqual, Operator::kNoProperties, 2, 1) \ + V(LoadStackPointer, Operator::kNoProperties, 0, 1) #define MACHINE_TYPE_LIST(V) \ diff --git a/src/compiler/machine-operator.h b/src/compiler/machine-operator.h index 622f863929..ad54f98fa9 100644 --- a/src/compiler/machine-operator.h +++ b/src/compiler/machine-operator.h @@ -144,6 +144,9 @@ class MachineOperatorBuilder FINAL { // store [base + index], value const Operator* Store(StoreRepresentation rep); + // Access to the machine stack. + const Operator* LoadStackPointer(); + // Target machine word-size assumed by this builder. bool Is32() const { return word() == kRepWord32; } bool Is64() const { return word() == kRepWord64; } diff --git a/src/compiler/opcodes.h b/src/compiler/opcodes.h index c1de689923..ced9847dd0 100644 --- a/src/compiler/opcodes.h +++ b/src/compiler/opcodes.h @@ -221,7 +221,8 @@ V(Float64Sqrt) \ V(Float64Equal) \ V(Float64LessThan) \ - V(Float64LessThanOrEqual) + V(Float64LessThanOrEqual) \ + V(LoadStackPointer) #define VALUE_OP_LIST(V) \ COMMON_OP_LIST(V) \ diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc index 75fff31c7b..c64c00979d 100644 --- a/src/compiler/simplified-lowering.cc +++ b/src/compiler/simplified-lowering.cc @@ -612,7 +612,7 @@ class RepresentationSelector { //------------------------------------------------------------------ case IrOpcode::kLoad: { // TODO(titzer): machine loads/stores need to know BaseTaggedness!? - MachineType tBase = kRepTagged; + MachineTypeUnion tBase = kRepTagged | kMachPtr; LoadRepresentation rep = OpParameter(node); ProcessInput(node, 0, tBase); // pointer or object ProcessInput(node, 1, kMachInt32); // index @@ -622,7 +622,7 @@ class RepresentationSelector { } case IrOpcode::kStore: { // TODO(titzer): machine loads/stores need to know BaseTaggedness!? - MachineType tBase = kRepTagged; + MachineTypeUnion tBase = kRepTagged | kMachPtr; StoreRepresentation rep = OpParameter(node); ProcessInput(node, 0, tBase); // pointer or object ProcessInput(node, 1, kMachInt32); // index @@ -732,6 +732,8 @@ class RepresentationSelector { case IrOpcode::kFloat64LessThan: case IrOpcode::kFloat64LessThanOrEqual: return VisitFloat64Cmp(node); + case IrOpcode::kLoadStackPointer: + return VisitLeaf(node, kMachPtr); default: VisitInputs(node); break; diff --git a/src/compiler/x64/code-generator-x64.cc b/src/compiler/x64/code-generator-x64.cc index 2c8783322e..37aca107a2 100644 --- a/src/compiler/x64/code-generator-x64.cc +++ b/src/compiler/x64/code-generator-x64.cc @@ -233,6 +233,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { case kArchRet: AssembleReturn(); break; + case kArchStackPointer: + __ movq(i.OutputRegister(), rsp); + break; case kArchTruncateDoubleToI: __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0)); break; diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp index eecadd62be..fdcffba974 100644 --- a/test/cctest/cctest.gyp +++ b/test/cctest/cctest.gyp @@ -81,6 +81,7 @@ 'compiler/test-run-jsops.cc', 'compiler/test-run-machops.cc', 'compiler/test-run-properties.cc', + 'compiler/test-run-stackcheck.cc', 'compiler/test-run-variables.cc', 'compiler/test-schedule.cc', 'compiler/test-scheduler.cc', diff --git a/test/cctest/compiler/test-run-stackcheck.cc b/test/cctest/compiler/test-run-stackcheck.cc new file mode 100644 index 0000000000..8c1664bc83 --- /dev/null +++ b/test/cctest/compiler/test-run-stackcheck.cc @@ -0,0 +1,18 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" + +#include "test/cctest/compiler/function-tester.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +TEST(TerminateAtMethodEntry) { + FunctionTester T("(function(a,b) { return 23; })"); + + T.CheckCall(T.Val(23)); + T.isolate->stack_guard()->RequestTerminateExecution(); + T.CheckThrows(T.undefined(), T.undefined()); +} diff --git a/test/unittests/compiler/machine-operator-unittest.cc b/test/unittests/compiler/machine-operator-unittest.cc index a417a4b9ed..0f63e3c393 100644 --- a/test/unittests/compiler/machine-operator-unittest.cc +++ b/test/unittests/compiler/machine-operator-unittest.cc @@ -201,7 +201,7 @@ const PureOperator kPureOperators[] = { PURE(Float64Mul, 2, 1), PURE(Float64Div, 2, 1), PURE(Float64Mod, 2, 1), PURE(Float64Sqrt, 1, 1), PURE(Float64Equal, 2, 1), PURE(Float64LessThan, 2, 1), - PURE(Float64LessThanOrEqual, 2, 1) + PURE(Float64LessThanOrEqual, 2, 1), PURE(LoadStackPointer, 0, 1) #undef PURE };