Commit b6bfe7b9 authored by clemensh's avatar clemensh Committed by Commit bot

[wasm] Introduce WasmStackGuard builtin

Instead of placing a runtime call to StackGuard in the compiled wasm
code, we just call the builtin, which is cheaper. By passing Smi::kZero
as context, we save even more code space and avoid embedding the
context in the code.
The WasmStackGuard builtin then calls the new WasmStackGuard runtime
function, which gets the context from the instance attached to the
calling wasm code, and then does the usual StackGuard logic.

For the unity benchmark in asm-wasm mode, generated code size reduces
from 63.0 to 61.6 MB (-2.1%).

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

Review-Url: https://codereview.chromium.org/2691993004
Cr-Commit-Position: refs/heads/master@{#43277}
parent a8e3925e
...@@ -407,7 +407,6 @@ config("toolchain") { ...@@ -407,7 +407,6 @@ config("toolchain") {
# TODO(hans): Remove once http://crbug.com/428099 is resolved. # TODO(hans): Remove once http://crbug.com/428099 is resolved.
"-Winconsistent-missing-override", "-Winconsistent-missing-override",
] ]
#if (v8_current_cpu == "x64" || v8_current_cpu == "arm64" || #if (v8_current_cpu == "x64" || v8_current_cpu == "arm64" ||
# v8_current_cpu == "mips64el") { # v8_current_cpu == "mips64el") {
# cflags += [ "-Wshorten-64-to-32" ] # cflags += [ "-Wshorten-64-to-32" ]
...@@ -1010,6 +1009,7 @@ v8_source_set("v8_base") { ...@@ -1010,6 +1009,7 @@ v8_source_set("v8_base") {
"src/builtins/builtins-symbol.cc", "src/builtins/builtins-symbol.cc",
"src/builtins/builtins-typedarray.cc", "src/builtins/builtins-typedarray.cc",
"src/builtins/builtins-utils.h", "src/builtins/builtins-utils.h",
"src/builtins/builtins-wasm.cc",
"src/builtins/builtins.cc", "src/builtins/builtins.cc",
"src/builtins/builtins.h", "src/builtins/builtins.h",
"src/cached-powers.cc", "src/cached-powers.cc",
......
// Copyright 2017 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/builtins/builtins-utils.h"
#include "src/code-stub-assembler.h"
namespace v8 {
namespace internal {
typedef compiler::Node Node;
TF_BUILTIN(WasmStackGuard, CodeStubAssembler) {
Node* context = SmiConstant(Smi::kZero);
TailCallRuntime(Runtime::kWasmStackGuard, context);
}
} // namespace internal
} // namespace v8
...@@ -816,7 +816,10 @@ class Isolate; ...@@ -816,7 +816,10 @@ class Isolate;
/* ES6 #sec-%typedarray%.prototype.values */ \ /* ES6 #sec-%typedarray%.prototype.values */ \
TFJ(TypedArrayPrototypeValues, 0) \ TFJ(TypedArrayPrototypeValues, 0) \
/* ES6 #sec-%typedarray%.prototype.copywithin */ \ /* ES6 #sec-%typedarray%.prototype.copywithin */ \
CPP(TypedArrayPrototypeCopyWithin) CPP(TypedArrayPrototypeCopyWithin) \
\
/* Wasm */ \
TFS(WasmStackGuard, BUILTIN, kNoExtraICState, WasmStackGuard, 1)
#define IGNORE_BUILTIN(...) #define IGNORE_BUILTIN(...)
......
...@@ -474,40 +474,44 @@ Node* WasmGraphBuilder::Int64Constant(int64_t value) { ...@@ -474,40 +474,44 @@ Node* WasmGraphBuilder::Int64Constant(int64_t value) {
void WasmGraphBuilder::StackCheck(wasm::WasmCodePosition position, void WasmGraphBuilder::StackCheck(wasm::WasmCodePosition position,
Node** effect, Node** control) { Node** effect, Node** control) {
if (FLAG_wasm_no_stack_checks) return; if (FLAG_wasm_no_stack_checks) return;
if (effect == nullptr) {
effect = effect_;
}
if (control == nullptr) {
control = control_;
}
// We do not generate stack checks for cctests. // We do not generate stack checks for cctests.
if (module_ && !module_->instance->context.is_null()) { if (!module_ || module_->instance->context.is_null()) return;
Node* limit = graph()->NewNode( if (effect == nullptr) effect = effect_;
jsgraph()->machine()->Load(MachineType::Pointer()), if (control == nullptr) control = control_;
jsgraph()->ExternalConstant(
ExternalReference::address_of_stack_limit(jsgraph()->isolate())), Node* limit = graph()->NewNode(
jsgraph()->IntPtrConstant(0), *effect, *control); jsgraph()->machine()->Load(MachineType::Pointer()),
Node* pointer = graph()->NewNode(jsgraph()->machine()->LoadStackPointer()); jsgraph()->ExternalConstant(
ExternalReference::address_of_stack_limit(jsgraph()->isolate())),
Node* check = jsgraph()->IntPtrConstant(0), *effect, *control);
graph()->NewNode(jsgraph()->machine()->UintLessThan(), limit, pointer); Node* pointer = graph()->NewNode(jsgraph()->machine()->LoadStackPointer());
Diamond stack_check(graph(), jsgraph()->common(), check, BranchHint::kTrue); Node* check =
stack_check.Chain(*control); graph()->NewNode(jsgraph()->machine()->UintLessThan(), limit, pointer);
Node* effect_true = *effect;
Diamond stack_check(graph(), jsgraph()->common(), check, BranchHint::kTrue);
// Generate a call to the runtime if there is a stack check failure. stack_check.Chain(*control);
Node* call = BuildCallToRuntime(Runtime::kStackGuard, jsgraph(), Node* effect_true = *effect;
module_->instance->context, nullptr, 0,
effect, stack_check.if_false); Handle<Code> code = jsgraph()->isolate()->builtins()->WasmStackGuard();
SetSourcePosition(call, position); CallInterfaceDescriptor idesc =
WasmStackGuardDescriptor(jsgraph()->isolate());
Node* ephi = graph()->NewNode(jsgraph()->common()->EffectPhi(2), CallDescriptor* desc = Linkage::GetStubCallDescriptor(
effect_true, call, stack_check.merge); jsgraph()->isolate(), jsgraph()->zone(), idesc, 0,
CallDescriptor::kNoFlags, Operator::kNoProperties);
*control = stack_check.merge; Node* stub_code = jsgraph()->HeapConstant(code);
*effect = ephi;
} Node* context = jsgraph()->SmiConstant(0);
Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), stub_code,
context, *effect, stack_check.if_false);
SetSourcePosition(call, position);
Node* ephi = graph()->NewNode(jsgraph()->common()->EffectPhi(2), effect_true,
call, stack_check.merge);
*control = stack_check.merge;
*effect = ephi;
} }
Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, Node* right, Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, Node* right,
...@@ -3004,7 +3008,7 @@ void WasmGraphBuilder::BuildWasmInterpreterEntry( ...@@ -3004,7 +3008,7 @@ void WasmGraphBuilder::BuildWasmInterpreterEntry(
arg_buffer, // argument buffer arg_buffer, // argument buffer
}; };
BuildCallToRuntime(Runtime::kWasmRunInterpreter, jsgraph(), BuildCallToRuntime(Runtime::kWasmRunInterpreter, jsgraph(),
jsgraph()->isolate()->native_context(), parameters, instance->compiled_module()->native_context(), parameters,
arraysize(parameters), effect_, *control_); arraysize(parameters), effect_, *control_);
// Read back the return value. // Read back the return value.
......
...@@ -95,7 +95,8 @@ class PlatformInterfaceDescriptor; ...@@ -95,7 +95,8 @@ class PlatformInterfaceDescriptor;
V(InterpreterCEntry) \ V(InterpreterCEntry) \
V(ResumeGenerator) \ V(ResumeGenerator) \
V(FrameDropperTrampoline) \ V(FrameDropperTrampoline) \
V(PromiseHandleReject) V(PromiseHandleReject) \
V(WasmStackGuard)
class V8_EXPORT_PRIVATE CallInterfaceDescriptorData { class V8_EXPORT_PRIVATE CallInterfaceDescriptorData {
public: public:
...@@ -952,6 +953,12 @@ class PromiseHandleRejectDescriptor final : public CallInterfaceDescriptor { ...@@ -952,6 +953,12 @@ class PromiseHandleRejectDescriptor final : public CallInterfaceDescriptor {
CallInterfaceDescriptor, kParameterCount) CallInterfaceDescriptor, kParameterCount)
}; };
class WasmStackGuardDescriptor final : public CallInterfaceDescriptor {
public:
DECLARE_DEFAULT_DESCRIPTOR(WasmStackGuardDescriptor, CallInterfaceDescriptor,
0)
};
#undef DECLARE_DESCRIPTOR_WITH_BASE #undef DECLARE_DESCRIPTOR_WITH_BASE
#undef DECLARE_DESCRIPTOR #undef DECLARE_DESCRIPTOR
#undef DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE #undef DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE
......
...@@ -21,7 +21,7 @@ namespace v8 { ...@@ -21,7 +21,7 @@ namespace v8 {
namespace internal { namespace internal {
namespace { namespace {
Handle<WasmInstanceObject> GetWasmInstanceOnStackTop(Isolate* isolate) { WasmInstanceObject* GetWasmInstanceOnStackTop(Isolate* isolate) {
DisallowHeapAllocation no_allocation; DisallowHeapAllocation no_allocation;
const Address entry = Isolate::c_entry_fp(isolate->thread_local_top()); const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
Address pc = Address pc =
...@@ -30,7 +30,12 @@ Handle<WasmInstanceObject> GetWasmInstanceOnStackTop(Isolate* isolate) { ...@@ -30,7 +30,12 @@ Handle<WasmInstanceObject> GetWasmInstanceOnStackTop(Isolate* isolate) {
DCHECK_EQ(Code::WASM_FUNCTION, code->kind()); DCHECK_EQ(Code::WASM_FUNCTION, code->kind());
WasmInstanceObject* owning_instance = wasm::GetOwningWasmInstance(code); WasmInstanceObject* owning_instance = wasm::GetOwningWasmInstance(code);
CHECK_NOT_NULL(owning_instance); CHECK_NOT_NULL(owning_instance);
return handle(owning_instance, isolate); return owning_instance;
}
Context* GetWasmContextOnStackTop(Isolate* isolate) {
return GetWasmInstanceOnStackTop(isolate)
->compiled_module()
->ptr_to_native_context();
} }
} // namespace } // namespace
...@@ -38,7 +43,8 @@ RUNTIME_FUNCTION(Runtime_WasmMemorySize) { ...@@ -38,7 +43,8 @@ RUNTIME_FUNCTION(Runtime_WasmMemorySize) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(0, args.length()); DCHECK_EQ(0, args.length());
Handle<WasmInstanceObject> instance = GetWasmInstanceOnStackTop(isolate); Handle<WasmInstanceObject> instance(GetWasmInstanceOnStackTop(isolate),
isolate);
return *isolate->factory()->NewNumberFromInt( return *isolate->factory()->NewNumberFromInt(
wasm::GetInstanceMemorySize(isolate, instance)); wasm::GetInstanceMemorySize(isolate, instance));
} }
...@@ -47,7 +53,8 @@ RUNTIME_FUNCTION(Runtime_WasmGrowMemory) { ...@@ -47,7 +53,8 @@ RUNTIME_FUNCTION(Runtime_WasmGrowMemory) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(1, args.length()); DCHECK_EQ(1, args.length());
CONVERT_UINT32_ARG_CHECKED(delta_pages, 0); CONVERT_UINT32_ARG_CHECKED(delta_pages, 0);
Handle<WasmInstanceObject> instance = GetWasmInstanceOnStackTop(isolate); Handle<WasmInstanceObject> instance(GetWasmInstanceOnStackTop(isolate),
isolate);
return *isolate->factory()->NewNumberFromInt( return *isolate->factory()->NewNumberFromInt(
wasm::GrowMemory(isolate, instance, delta_pages)); wasm::GrowMemory(isolate, instance, delta_pages));
} }
...@@ -56,13 +63,7 @@ Object* ThrowRuntimeError(Isolate* isolate, int message_id, int byte_offset, ...@@ -56,13 +63,7 @@ Object* ThrowRuntimeError(Isolate* isolate, int message_id, int byte_offset,
bool patch_source_position) { bool patch_source_position) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_NULL(isolate->context()); DCHECK_NULL(isolate->context());
StackFrameIterator it(isolate); isolate->set_context(GetWasmContextOnStackTop(isolate));
it.Advance();
CHECK(it.frame()->is_wasm_compiled());
isolate->set_context(*WasmCompiledFrame::cast(it.frame())
->wasm_instance()
->compiled_module()
->native_context());
Handle<Object> error_obj = isolate->factory()->NewWasmRuntimeError( Handle<Object> error_obj = isolate->factory()->NewWasmRuntimeError(
static_cast<MessageTemplate::Template>(message_id)); static_cast<MessageTemplate::Template>(message_id));
...@@ -161,7 +162,7 @@ RUNTIME_FUNCTION(Runtime_WasmGetCaughtExceptionValue) { ...@@ -161,7 +162,7 @@ RUNTIME_FUNCTION(Runtime_WasmGetCaughtExceptionValue) {
} }
RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) { RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
DCHECK(args.length() == 3); DCHECK_EQ(3, args.length());
HandleScope scope(isolate); HandleScope scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(JSObject, instance_obj, 0); CONVERT_ARG_HANDLE_CHECKED(JSObject, instance_obj, 0);
CONVERT_NUMBER_CHECKED(int32_t, func_index, Int32, args[1]); CONVERT_NUMBER_CHECKED(int32_t, func_index, Int32, args[1]);
...@@ -177,13 +178,27 @@ RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) { ...@@ -177,13 +178,27 @@ RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
CHECK(arg_buffer_obj->IsSmi()); CHECK(arg_buffer_obj->IsSmi());
uint8_t* arg_buffer = reinterpret_cast<uint8_t*>(*arg_buffer_obj); uint8_t* arg_buffer = reinterpret_cast<uint8_t*>(*arg_buffer_obj);
// Set the current isolate's context, saving the previous one. DCHECK_EQ(isolate->context(),
SaveContext save(isolate); instance->compiled_module()->ptr_to_native_context());
isolate->set_context(*instance->compiled_module()->native_context());
instance->debug_info()->RunInterpreter(func_index, arg_buffer); instance->debug_info()->RunInterpreter(func_index, arg_buffer);
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
RUNTIME_FUNCTION(Runtime_WasmStackGuard) {
SealHandleScope shs(isolate);
DCHECK_EQ(0, args.length());
// Set the current isolate's context.
DCHECK_NULL(isolate->context());
isolate->set_context(GetWasmContextOnStackTop(isolate));
// Check if this is a real stack overflow.
StackLimitCheck check(isolate);
if (check.JsHasOverflowed()) return isolate->StackOverflow();
return isolate->stack_guard()->HandleInterrupts();
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -643,7 +643,8 @@ namespace internal { ...@@ -643,7 +643,8 @@ namespace internal {
F(ThrowWasmTrapFloatUnrepresentable, 0, 1) \ F(ThrowWasmTrapFloatUnrepresentable, 0, 1) \
F(ThrowWasmTrapFuncInvalid, 0, 1) \ F(ThrowWasmTrapFuncInvalid, 0, 1) \
F(ThrowWasmTrapFuncSigMismatch, 0, 1) \ F(ThrowWasmTrapFuncSigMismatch, 0, 1) \
F(WasmRunInterpreter, 3, 1) F(WasmRunInterpreter, 3, 1) \
F(WasmStackGuard, 0, 1)
#define FOR_EACH_INTRINSIC_RETURN_PAIR(F) \ #define FOR_EACH_INTRINSIC_RETURN_PAIR(F) \
F(LoadLookupSlotForCall, 1, 2) F(LoadLookupSlotForCall, 1, 2)
......
...@@ -516,6 +516,7 @@ ...@@ -516,6 +516,7 @@
'builtins/builtins-symbol.cc', 'builtins/builtins-symbol.cc',
'builtins/builtins-typedarray.cc', 'builtins/builtins-typedarray.cc',
'builtins/builtins-utils.h', 'builtins/builtins-utils.h',
'builtins/builtins-wasm.cc',
'builtins/builtins.cc', 'builtins/builtins.cc',
'builtins/builtins.h', 'builtins/builtins.h',
'cached-powers.cc', 'cached-powers.cc',
......
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