Implement inlined stack-check guards in TurboFan.
authormstarzinger@chromium.org <mstarzinger@chromium.org>
Wed, 1 Oct 2014 14:03:02 +0000 (14:03 +0000)
committermstarzinger@chromium.org <mstarzinger@chromium.org>
Wed, 1 Oct 2014 14:03:02 +0000 (14:03 +0000)
R=bmeurer@chromium.org
TEST=cctest/test-run-stackcheck/TerminateAtMethodEntry

Review URL: https://codereview.chromium.org/621833003

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24367 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

16 files changed:
src/compiler/arm/code-generator-arm.cc
src/compiler/arm/instruction-selector-arm.cc
src/compiler/arm64/code-generator-arm64.cc
src/compiler/ast-graph-builder.cc
src/compiler/ast-graph-builder.h
src/compiler/ia32/code-generator-ia32.cc
src/compiler/instruction-codes.h
src/compiler/instruction-selector.cc
src/compiler/machine-operator.cc
src/compiler/machine-operator.h
src/compiler/opcodes.h
src/compiler/simplified-lowering.cc
src/compiler/x64/code-generator-x64.cc
test/cctest/cctest.gyp
test/cctest/compiler/test-run-stackcheck.cc [new file with mode: 0644]
test/unittests/compiler/machine-operator-unittest.cc

index fabcfdcdc5f769ad7eafa59e07f6b6c0a289f2bd..f278326cf7bbd52648a850aba271c11361b4e5cc 100644 (file)
@@ -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());
index e83d1e54afda27035f8590d2e63f5f1b8da4d471..c3efad52fd9679236c1b31c58dcf90e27f269792 100644 (file)
@@ -73,6 +73,7 @@ class ArmOperandGenerator : public OperandGenerator {
       case kArchJmp:
       case kArchNop:
       case kArchRet:
+      case kArchStackPointer:
       case kArchTruncateDoubleToI:
       case kArmMul:
       case kArmMla:
index a56de204b7163776172db42b9b1ace442001c59a..c041e15366db11a50b7b98b98fc4aeed27795f66 100644 (file)
@@ -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;
index 3ac4b4639f4305f53e4e56748cdedf302bd02d43..fa987796a21133f68cca057c71cafd664ed9ebd9 100644 (file)
@@ -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())) {
index feded98b4e9b0f20a0b87bdc08b3bb0703848d64..967b24bda13d32f33101068e2a2429fdd775b89c 100644 (file)
@@ -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)
index 4bb75006640969a48f5fab52f9856e5290848b6e..2b51b6fb92dc8cb8960b3c6f81fd7e360dc1c27c 100644 (file)
@@ -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;
index 0abed6c32181217e7d636d6dcee67b040297fce2..fd7c53078f9bb2bed8f836cc916ebb6a6063cab0 100644 (file)
@@ -33,6 +33,7 @@ namespace compiler {
   V(ArchJmp)                \
   V(ArchNop)                \
   V(ArchRet)                \
+  V(ArchStackPointer)       \
   V(ArchTruncateDoubleToI)  \
   TARGET_ARCH_OPCODE_LIST(V)
 
index d0be3fecd113852c39879086d76a2fcbe78c48ab..09a8e018eb20a309e93bce003b0cd8ddfaf5a2d6 100644 (file)
@@ -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.
index 35e0e5419a2d7840458407e0ea187d204ed3694c..e88c792ec1d0b4934633c264b77943367486f8b9 100644 (file)
@@ -119,7 +119,8 @@ struct StaticParameterTraits<LoadRepresentation> {
   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) \
index 622f863929ab01eb4ff2485d45129d17a6456246..ad54f98fa9acf7cb24d994f5542608d321794abd 100644 (file)
@@ -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; }
index c1de6899239a9f2e950ef887f6182a08b6403953..ced9847dd01bb4ed362f750f7d2931d986b9cd5e 100644 (file)
   V(Float64Sqrt)              \
   V(Float64Equal)             \
   V(Float64LessThan)          \
-  V(Float64LessThanOrEqual)
+  V(Float64LessThanOrEqual)   \
+  V(LoadStackPointer)
 
 #define VALUE_OP_LIST(V) \
   COMMON_OP_LIST(V)      \
index 75fff31c7b58cc445827cad446bd689f9df0f727..c64c00979d6a1fd524146fd127ef63d75b1dfc43 100644 (file)
@@ -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<LoadRepresentation>(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<StoreRepresentation>(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;
index 2c8783322ef2dbc7e2f60d7d576db378cb8c09b2..37aca107a2320a224fb3c0f55f7fd78e35858080 100644 (file)
@@ -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;
index eecadd62be27b52323c23b99d44a6cb58d3f1889..fdcffba974d98f0061028b7df33830ae34aa3f1e 100644 (file)
@@ -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 (file)
index 0000000..8c1664b
--- /dev/null
@@ -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());
+}
index a417a4b9ed3242f64a2bfe539d6d84915089c5f2..0f63e3c393e62c37d2690eb291aedb1c4c4d8dd1 100644 (file)
@@ -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
 };