Commit 13f0ef5b authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] Only emit StackCheck if function might call

For functions without any calls, there is no value in executing a stack
check. The current frame is materialized at that point anyway.
Note that for loops, we still emit additional stack checks in the loop
header.

For unity, the reduction in code size is moderate (0.53%), as only 4000
of the 34000 functions are leaf functions (no calls). However, we also
save some compile time and gain performance, so this is still worth
doing it.

Drive-by: Fix the effect chain generated in {StackCheck()}.

R=mstarzinger@chromium.org, ahaas@chromium.org

Change-Id: Ia6ec58d0ea46de02634c923cdf8e6e08d8902c59
Reviewed-on: https://chromium-review.googlesource.com/533333Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46013}
parent 71582719
...@@ -295,6 +295,7 @@ void WasmGraphBuilder::StackCheck(wasm::WasmCodePosition position, ...@@ -295,6 +295,7 @@ void WasmGraphBuilder::StackCheck(wasm::WasmCodePosition position,
jsgraph()->ExternalConstant( jsgraph()->ExternalConstant(
ExternalReference::address_of_stack_limit(jsgraph()->isolate())), ExternalReference::address_of_stack_limit(jsgraph()->isolate())),
jsgraph()->IntPtrConstant(0), *effect, *control); jsgraph()->IntPtrConstant(0), *effect, *control);
*effect = limit;
Node* pointer = graph()->NewNode(jsgraph()->machine()->LoadStackPointer()); Node* pointer = graph()->NewNode(jsgraph()->machine()->LoadStackPointer());
Node* check = Node* check =
...@@ -302,7 +303,6 @@ void WasmGraphBuilder::StackCheck(wasm::WasmCodePosition position, ...@@ -302,7 +303,6 @@ void WasmGraphBuilder::StackCheck(wasm::WasmCodePosition position,
Diamond stack_check(graph(), jsgraph()->common(), check, BranchHint::kTrue); Diamond stack_check(graph(), jsgraph()->common(), check, BranchHint::kTrue);
stack_check.Chain(*control); stack_check.Chain(*control);
Node* effect_true = *effect;
Handle<Code> code = jsgraph()->isolate()->builtins()->WasmStackGuard(); Handle<Code> code = jsgraph()->isolate()->builtins()->WasmStackGuard();
CallInterfaceDescriptor idesc = CallInterfaceDescriptor idesc =
...@@ -318,13 +318,34 @@ void WasmGraphBuilder::StackCheck(wasm::WasmCodePosition position, ...@@ -318,13 +318,34 @@ void WasmGraphBuilder::StackCheck(wasm::WasmCodePosition position,
SetSourcePosition(call, position); SetSourcePosition(call, position);
Node* ephi = graph()->NewNode(jsgraph()->common()->EffectPhi(2), effect_true, Node* ephi = graph()->NewNode(jsgraph()->common()->EffectPhi(2), *effect,
call, stack_check.merge); call, stack_check.merge);
*control = stack_check.merge; *control = stack_check.merge;
*effect = ephi; *effect = ephi;
} }
void WasmGraphBuilder::PatchInStackCheckIfNeeded() {
if (!needs_stack_check_) return;
Node* start = graph()->start();
// Place a stack check which uses a dummy node as control and effect.
Node* dummy = graph()->NewNode(jsgraph()->common()->Dead());
Node* control = dummy;
Node* effect = dummy;
// The function-prologue stack check is associated with position 0, which
// is never a position of any instruction in the function.
StackCheck(0, &effect, &control);
// In testing, no steck checks were emitted. Nothing to rewire then.
if (effect == dummy) return;
// Now patch all control uses of {start} to use {control} and all effect uses
// to use {effect} instead. Then rewire the dummy node to use start instead.
NodeProperties::ReplaceUses(start, start, effect, control);
NodeProperties::ReplaceUses(dummy, nullptr, start, start);
}
Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, Node* right, Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, Node* right,
wasm::WasmCodePosition position) { wasm::WasmCodePosition position) {
const Operator* op; const Operator* op;
...@@ -1709,6 +1730,7 @@ Node* WasmGraphBuilder::BuildFloatToIntConversionInstruction( ...@@ -1709,6 +1730,7 @@ Node* WasmGraphBuilder::BuildFloatToIntConversionInstruction(
} }
Node* WasmGraphBuilder::GrowMemory(Node* input) { Node* WasmGraphBuilder::GrowMemory(Node* input) {
SetNeedsStackCheck();
Diamond check_input_range( Diamond check_input_range(
graph(), jsgraph()->common(), graph(), jsgraph()->common(),
graph()->NewNode(jsgraph()->machine()->Uint32LessThanOrEqual(), input, graph()->NewNode(jsgraph()->machine()->Uint32LessThanOrEqual(), input,
...@@ -1734,6 +1756,7 @@ Node* WasmGraphBuilder::GrowMemory(Node* input) { ...@@ -1734,6 +1756,7 @@ Node* WasmGraphBuilder::GrowMemory(Node* input) {
} }
Node* WasmGraphBuilder::Throw(Node* input) { Node* WasmGraphBuilder::Throw(Node* input) {
SetNeedsStackCheck();
MachineOperatorBuilder* machine = jsgraph()->machine(); MachineOperatorBuilder* machine = jsgraph()->machine();
// Pass the thrown value as two SMIs: // Pass the thrown value as two SMIs:
...@@ -1757,6 +1780,7 @@ Node* WasmGraphBuilder::Throw(Node* input) { ...@@ -1757,6 +1780,7 @@ Node* WasmGraphBuilder::Throw(Node* input) {
} }
Node* WasmGraphBuilder::Catch(Node* input, wasm::WasmCodePosition position) { Node* WasmGraphBuilder::Catch(Node* input, wasm::WasmCodePosition position) {
SetNeedsStackCheck();
CommonOperatorBuilder* common = jsgraph()->common(); CommonOperatorBuilder* common = jsgraph()->common();
Node* parameters[] = {input}; // caught value Node* parameters[] = {input}; // caught value
...@@ -2154,6 +2178,7 @@ Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) { ...@@ -2154,6 +2178,7 @@ Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) {
Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args, Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args,
Node*** rets, Node*** rets,
wasm::WasmCodePosition position) { wasm::WasmCodePosition position) {
SetNeedsStackCheck();
const size_t params = sig->parameter_count(); const size_t params = sig->parameter_count();
const size_t extra = 2; // effect and control inputs. const size_t extra = 2; // effect and control inputs.
const size_t count = 1 + params + extra; const size_t count = 1 + params + extra;
...@@ -2907,6 +2932,7 @@ Node* WasmGraphBuilder::MemBuffer(uint32_t offset) { ...@@ -2907,6 +2932,7 @@ Node* WasmGraphBuilder::MemBuffer(uint32_t offset) {
Node* WasmGraphBuilder::CurrentMemoryPages() { Node* WasmGraphBuilder::CurrentMemoryPages() {
// CurrentMemoryPages can not be called from asm.js. // CurrentMemoryPages can not be called from asm.js.
DCHECK_EQ(wasm::kWasmOrigin, module_->module->get_origin()); DCHECK_EQ(wasm::kWasmOrigin, module_->module->get_origin());
SetNeedsStackCheck();
Node* call = Node* call =
BuildCallToRuntime(Runtime::kWasmMemorySize, jsgraph(), centry_stub_node_, BuildCallToRuntime(Runtime::kWasmMemorySize, jsgraph(), centry_stub_node_,
nullptr, 0, effect_, control_); nullptr, 0, effect_, control_);
......
...@@ -164,6 +164,8 @@ class WasmGraphBuilder { ...@@ -164,6 +164,8 @@ class WasmGraphBuilder {
void StackCheck(wasm::WasmCodePosition position, Node** effect = nullptr, void StackCheck(wasm::WasmCodePosition position, Node** effect = nullptr,
Node** control = nullptr); Node** control = nullptr);
void PatchInStackCheckIfNeeded();
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
// Operations that read and/or write {control} and {effect}. // Operations that read and/or write {control} and {effect}.
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
...@@ -279,6 +281,7 @@ class WasmGraphBuilder { ...@@ -279,6 +281,7 @@ class WasmGraphBuilder {
size_t cur_bufsize_; size_t cur_bufsize_;
Node* def_buffer_[kDefaultBufferSize]; Node* def_buffer_[kDefaultBufferSize];
bool has_simd_ = false; bool has_simd_ = false;
bool needs_stack_check_ = false;
wasm::FunctionSig* sig_; wasm::FunctionSig* sig_;
SetOncePointer<const Operator> allocate_heap_number_operator_; SetOncePointer<const Operator> allocate_heap_number_operator_;
...@@ -404,7 +407,10 @@ class WasmGraphBuilder { ...@@ -404,7 +407,10 @@ class WasmGraphBuilder {
int AddParameterNodes(Node** args, int pos, int param_count, int AddParameterNodes(Node** args, int pos, int param_count,
wasm::FunctionSig* sig); wasm::FunctionSig* sig);
void SetNeedsStackCheck() { needs_stack_check_ = true; }
}; };
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -617,6 +617,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -617,6 +617,7 @@ class WasmFullDecoder : public WasmDecoder {
WasmDecoder::DecodeLocals(this, sig_, local_types_); WasmDecoder::DecodeLocals(this, sig_, local_types_);
InitSsaEnv(); InitSsaEnv();
DecodeFunctionBody(); DecodeFunctionBody();
FinishFunction();
if (failed()) return TraceFailed(); if (failed()) return TraceFailed();
...@@ -715,11 +716,6 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -715,11 +716,6 @@ class WasmFullDecoder : public WasmDecoder {
ssa_env->control = start; ssa_env->control = start;
ssa_env->effect = start; ssa_env->effect = start;
SetEnv("initial", ssa_env); SetEnv("initial", ssa_env);
if (builder_) {
// The function-prologue stack check is associated with position 0, which
// is never a position of any instruction in the function.
builder_->StackCheck(0);
}
} }
TFNode* DefaultValue(ValueType type) { TFNode* DefaultValue(ValueType type) {
...@@ -1418,6 +1414,10 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1418,6 +1414,10 @@ class WasmFullDecoder : public WasmDecoder {
if (pc_ > end_ && ok()) error("Beyond end of code"); if (pc_ > end_ && ok()) error("Beyond end of code");
} }
void FinishFunction() {
if (builder_) builder_->PatchInStackCheckIfNeeded();
}
void EndControl() { void EndControl() {
ssa_env_->Kill(SsaEnv::kControlEnd); ssa_env_->Kill(SsaEnv::kControlEnd);
if (!control_.empty()) { if (!control_.empty()) {
......
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