Commit 3c4a32dc authored by Benedikt Meurer's avatar Benedikt Meurer

[turbofan] Introduce JSStackCheck operator.

The key idea here is that the stack check should be explicit, such that
we can eliminate unnecessary stack checks after graph building and
potentially inlining.

R=mstarzinger@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#27056}
parent a5fa093d
......@@ -508,7 +508,7 @@ void AstGraphBuilder::CreateGraphBody() {
VisitDeclarations(scope->declarations());
// Build a stack-check before the body.
Node* node = BuildStackCheck();
Node* node = NewNode(javascript()->StackCheck());
PrepareFrameState(node, BailoutId::FunctionEntry());
// Visit statements in the function body.
......@@ -2965,21 +2965,6 @@ Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) {
}
Node* AstGraphBuilder::BuildStackCheck() {
IfBuilder stack_check(this);
Node* limit = BuildLoadExternal(
ExternalReference::address_of_stack_limit(isolate()), kMachPtr);
Node* stack = NewNode(jsgraph()->machine()->LoadStackPointer());
Node* tag = NewNode(jsgraph()->machine()->UintLessThan(), limit, stack);
stack_check.If(tag, BranchHint::kTrue);
stack_check.Then();
stack_check.Else();
Node* guard = NewNode(javascript()->CallRuntime(Runtime::kStackGuard, 0));
stack_check.End();
return guard;
}
bool AstGraphBuilder::CheckOsrEntry(IterationStatement* stmt) {
if (info()->osr_ast_id() == stmt->OsrEntryId()) {
info()->set_osr_expr_stack_height(std::max(
......
......@@ -260,9 +260,6 @@ class AstGraphBuilder : public AstVisitor {
// Builders for binary operations.
Node* BuildBinaryOp(Node* left, Node* right, Token::Value op);
// Builder for stack-check guards.
Node* BuildStackCheck();
// Check if the given statement is an OSR entry.
// If so, record the stack height into the compilation and return {true}.
bool CheckOsrEntry(IterationStatement* stmt);
......
......@@ -480,6 +480,40 @@ void JSGenericLowering::LowerJSCallRuntime(Node* node) {
ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
}
void JSGenericLowering::LowerJSStackCheck(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* limit = graph()->NewNode(
machine()->Load(kMachPtr),
jsgraph()->ExternalConstant(
ExternalReference::address_of_stack_limit(isolate())),
jsgraph()->IntPtrConstant(0), effect, control);
Node* pointer = graph()->NewNode(machine()->LoadStackPointer());
Node* check = graph()->NewNode(machine()->UintLessThan(), limit, pointer);
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* etrue = effect;
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
NodeProperties::ReplaceControlInput(node, if_false);
Node* efalse = node;
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
// Relax controls of {node}, i.e. make it free floating.
NodeProperties::ReplaceWithValue(node, node, ephi, merge);
NodeProperties::ReplaceEffectInput(ephi, efalse, 1);
// Turn the stack check into a runtime call.
ReplaceWithRuntimeCall(node, Runtime::kStackGuard);
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -240,6 +240,7 @@ const StoreNamedParameters& StoreNamedParametersOf(const Operator* op) {
V(TypeOf, Operator::kPure, 1, 1) \
V(InstanceOf, Operator::kNoProperties, 2, 1) \
V(Debugger, Operator::kNoProperties, 0, 0) \
V(StackCheck, Operator::kNoProperties, 0, 0) \
V(CreateFunctionContext, Operator::kNoProperties, 1, 1) \
V(CreateWithContext, Operator::kNoProperties, 2, 1) \
V(CreateBlockContext, Operator::kNoProperties, 2, 1) \
......
......@@ -254,6 +254,8 @@ class JSOperatorBuilder FINAL : public ZoneObject {
const Operator* InstanceOf();
const Operator* Debugger();
const Operator* StackCheck();
// TODO(titzer): nail down the static parts of each of these context flavors.
const Operator* CreateFunctionContext();
const Operator* CreateCatchContext(const Unique<String>& name);
......
......@@ -131,7 +131,8 @@
V(JSCallFunction) \
V(JSCallRuntime) \
V(JSYield) \
V(JSDebugger)
V(JSDebugger) \
V(JSStackCheck)
#define JS_OP_LIST(V) \
JS_SIMPLE_BINOP_LIST(V) \
......@@ -304,7 +305,7 @@ class IrOpcode {
// Returns true if opcode for JavaScript operator.
static bool IsJsOpcode(Value value) {
return kJSEqual <= value && value <= kJSDebugger;
return kJSEqual <= value && value <= kJSStackCheck;
}
// Returns true if opcode for constant operator.
......
......@@ -72,6 +72,9 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
case IrOpcode::kJSToNumber:
case IrOpcode::kJSToName:
// Misc operations
case IrOpcode::kJSStackCheck:
// Properties
case IrOpcode::kJSLoadNamed:
case IrOpcode::kJSLoadProperty:
......
......@@ -1519,6 +1519,12 @@ Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) {
Bounds Typer::Visitor::TypeJSDebugger(Node* node) {
UNREACHABLE();
return Bounds();
}
Bounds Typer::Visitor::TypeJSStackCheck(Node* node) {
return Bounds::Unbounded(zone());
}
......
......@@ -550,6 +550,11 @@ void Verifier::Visitor::Check(Node* node) {
CheckUpperIs(node, Type::Any());
break;
case IrOpcode::kJSStackCheck:
// Type is empty.
CheckNotTyped(node);
break;
// Simplified operators
// -------------------------------
case IrOpcode::kAnyToBoolean:
......
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