Commit df5a509a authored by Eric Holk's avatar Eric Holk Committed by Commit Bot

[wasm] use ccall to set/clear thread in wasm flag

CCalls have significantly less overhead than runtime calls which will improve
runtime performance on programs that make lots of transitions between JS and
Wasm.

Bug: v8:5277
Change-Id: If09dea97f24eb43753847e2b894ebc1ba5168c23
Reviewed-on: https://chromium-review.googlesource.com/688481
Commit-Queue: Eric Holk <eholk@chromium.org>
Reviewed-by: 's avatarMircea Trofin <mtrofin@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48297}
parent 6f4a86c1
...@@ -1015,6 +1015,18 @@ ExternalReference ExternalReference::wasm_float64_pow(Isolate* isolate) { ...@@ -1015,6 +1015,18 @@ ExternalReference ExternalReference::wasm_float64_pow(Isolate* isolate) {
Redirect(isolate, FUNCTION_ADDR(wasm::float64_pow_wrapper))); Redirect(isolate, FUNCTION_ADDR(wasm::float64_pow_wrapper)));
} }
ExternalReference ExternalReference::wasm_set_thread_in_wasm_flag(
Isolate* isolate) {
return ExternalReference(
Redirect(isolate, FUNCTION_ADDR(wasm::set_thread_in_wasm_flag)));
}
ExternalReference ExternalReference::wasm_clear_thread_in_wasm_flag(
Isolate* isolate) {
return ExternalReference(
Redirect(isolate, FUNCTION_ADDR(wasm::clear_thread_in_wasm_flag)));
}
static void f64_mod_wrapper(double* param0, double* param1) { static void f64_mod_wrapper(double* param0, double* param1) {
WriteDoubleValue(param0, WriteDoubleValue(param0,
modulo(ReadDoubleValue(param0), ReadDoubleValue(param1))); modulo(ReadDoubleValue(param0), ReadDoubleValue(param1)));
......
...@@ -871,6 +871,8 @@ class ExternalReference BASE_EMBEDDED { ...@@ -871,6 +871,8 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference wasm_word32_popcnt(Isolate* isolate); static ExternalReference wasm_word32_popcnt(Isolate* isolate);
static ExternalReference wasm_word64_popcnt(Isolate* isolate); static ExternalReference wasm_word64_popcnt(Isolate* isolate);
static ExternalReference wasm_float64_pow(Isolate* isolate); static ExternalReference wasm_float64_pow(Isolate* isolate);
static ExternalReference wasm_set_thread_in_wasm_flag(Isolate* isolate);
static ExternalReference wasm_clear_thread_in_wasm_flag(Isolate* isolate);
static ExternalReference f64_acos_wrapper_function(Isolate* isolate); static ExternalReference f64_acos_wrapper_function(Isolate* isolate);
static ExternalReference f64_asin_wrapper_function(Isolate* isolate); static ExternalReference f64_asin_wrapper_function(Isolate* isolate);
......
...@@ -2302,13 +2302,30 @@ Node* WasmGraphBuilder::BuildDiv64Call(Node* left, Node* right, ...@@ -2302,13 +2302,30 @@ Node* WasmGraphBuilder::BuildDiv64Call(Node* left, Node* right,
return load; return load;
} }
Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) { Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node* const* args) {
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;
// Reallocate the buffer to make space for extra inputs. // Reallocate the buffer to make space for extra inputs.
args = Realloc(args, 1 + params, count); Node** new_args = Realloc(args, 1 + params, count);
return BuildCCallWithBuffer(sig, new_args, count);
}
// Builds a CCall using the caller-provided buffer rather than calling Buffer()
// and copying. The args array contains the function to call and any
// parameters. There should be space for two more arguments at the end, which
// BuildCCallWithBuffer will fill with the effect and control nodes.
//
// TODO(eholk): Refactor this as a variadic template that knows the right number
// of arguments.
Node* WasmGraphBuilder::BuildCCallWithBuffer(MachineSignature* sig, Node** args,
size_t args_len) {
const size_t params = sig->parameter_count();
const size_t extra = 2; // effect and control inputs.
const size_t count = 1 + params + extra;
DCHECK_LE(count, args_len);
// Add effect and control inputs. // Add effect and control inputs.
args[params + 1] = *effect_; args[params + 1] = *effect_;
...@@ -2773,8 +2790,9 @@ Node* WasmGraphBuilder::BuildHeapNumberValueIndexConstant() { ...@@ -2773,8 +2790,9 @@ Node* WasmGraphBuilder::BuildHeapNumberValueIndexConstant() {
void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code, void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code,
Address wasm_context_address) { Address wasm_context_address) {
int wasm_count = static_cast<int>(sig_->parameter_count()); const int wasm_count = static_cast<int>(sig_->parameter_count());
int count = wasm_count + 4; // wasm_code, wasm_context, effect, and control. const int count =
wasm_count + 4; // wasm_code, wasm_context, effect, and control.
Node** args = Buffer(count); Node** args = Buffer(count);
// Build the start and the JS parameter nodes. // Build the start and the JS parameter nodes.
...@@ -3269,36 +3287,22 @@ void WasmGraphBuilder::EnsureFunctionTableNodes() { ...@@ -3269,36 +3287,22 @@ void WasmGraphBuilder::EnsureFunctionTableNodes() {
Node* WasmGraphBuilder::BuildModifyThreadInWasmFlag(bool new_value) { Node* WasmGraphBuilder::BuildModifyThreadInWasmFlag(bool new_value) {
// TODO(eholk): generate code to modify the thread-local storage directly, // TODO(eholk): generate code to modify the thread-local storage directly,
// rather than calling the runtime. // rather than calling the runtime.
//
// Note that the runtime functions also toggle the wasm_execution_time
// counters. Make sure this behavior is preserved if we avoid the runtime
// call.
if (!trap_handler::UseTrapHandler()) { if (!trap_handler::UseTrapHandler()) {
return *control_; return *control_;
} }
const Runtime::FunctionId f = // Using two functions instead of taking the new value as a parameter saves
new_value ? Runtime::kSetThreadInWasm : Runtime::kClearThreadInWasm; // one instruction on each call to set up the parameter.
const Runtime::Function* fun = Runtime::FunctionForId(f); ExternalReference ref =
DCHECK_EQ(0, fun->nargs); new_value ? ExternalReference::wasm_set_thread_in_wasm_flag(
const CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor( jsgraph()->isolate())
jsgraph()->zone(), f, fun->nargs, Operator::kNoProperties, : ExternalReference::wasm_clear_thread_in_wasm_flag(
CallDescriptor::kNoFlags); jsgraph()->isolate());
// CEntryStubConstant nodes have to be created and cached in the main MachineSignature::Builder sig_builder(jsgraph()->zone(), 0, 0);
// thread. At the moment this is only done for CEntryStubConstant(1). Node* args[] = {graph()->NewNode(jsgraph()->common()->ExternalConstant(ref)),
DCHECK_EQ(1, fun->result_size); nullptr, // Extra space for CCall effect and control inputs
Node* inputs[] = {centry_stub_node_, nullptr};
jsgraph()->ExternalConstant( return BuildCCallWithBuffer(sig_builder.Build(), args, arraysize(args));
ExternalReference(f, jsgraph()->isolate())), // ref
jsgraph()->Int32Constant(fun->nargs), // arity
jsgraph()->NoContextConstant(),
*effect_,
*control_};
Node* node = jsgraph()->graph()->NewNode(jsgraph()->common()->Call(desc),
arraysize(inputs), inputs);
*effect_ = node;
return node;
} }
// Only call this function for code which is not reused across instantiations, // Only call this function for code which is not reused across instantiations,
...@@ -3307,10 +3311,6 @@ Node* WasmGraphBuilder::BuildCallToRuntimeWithContext(Runtime::FunctionId f, ...@@ -3307,10 +3311,6 @@ Node* WasmGraphBuilder::BuildCallToRuntimeWithContext(Runtime::FunctionId f,
Node* js_context, Node* js_context,
Node** parameters, Node** parameters,
int parameter_count) { int parameter_count) {
// Setting and clearing the thread-in-wasm flag should not be done as a normal
// runtime call.
DCHECK_NE(f, Runtime::kSetThreadInWasm);
DCHECK_NE(f, Runtime::kClearThreadInWasm);
// We're leaving Wasm code, so clear the flag. // We're leaving Wasm code, so clear the flag.
*control_ = BuildModifyThreadInWasmFlag(false); *control_ = BuildModifyThreadInWasmFlag(false);
// Since the thread-in-wasm flag is clear, it is as if we are calling from JS. // Since the thread-in-wasm flag is clear, it is as if we are calling from JS.
......
...@@ -405,7 +405,9 @@ class WasmGraphBuilder { ...@@ -405,7 +405,9 @@ class WasmGraphBuilder {
Node* MaskShiftCount32(Node* node); Node* MaskShiftCount32(Node* node);
Node* MaskShiftCount64(Node* node); Node* MaskShiftCount64(Node* node);
Node* BuildCCall(MachineSignature* sig, Node** args); Node* BuildCCall(MachineSignature* sig, Node* const* args);
Node* BuildCCallWithBuffer(MachineSignature* sig, Node** args,
size_t args_len);
Node* BuildWasmCall(wasm::FunctionSig* sig, Node** args, Node*** rets, Node* BuildWasmCall(wasm::FunctionSig* sig, Node** args, Node*** rets,
wasm::WasmCodePosition position); wasm::WasmCodePosition position);
...@@ -504,7 +506,7 @@ class WasmGraphBuilder { ...@@ -504,7 +506,7 @@ class WasmGraphBuilder {
void BuildEncodeException32BitValue(uint32_t* index, Node* value); void BuildEncodeException32BitValue(uint32_t* index, Node* value);
Node* BuildDecodeException32BitValue(Node* const* values, uint32_t* index); Node* BuildDecodeException32BitValue(Node* const* values, uint32_t* index);
Node** Realloc(Node** buffer, size_t old_count, size_t new_count) { Node** Realloc(Node* const* buffer, size_t old_count, size_t new_count) {
Node** buf = Buffer(new_count); Node** buf = Buffer(new_count);
if (buf != buffer) memcpy(buf, buffer, old_count * sizeof(Node*)); if (buf != buffer) memcpy(buf, buffer, old_count * sizeof(Node*));
return buf; return buf;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "src/assembler.h" #include "src/assembler.h"
#include "src/counters.h" #include "src/counters.h"
#include "src/ic/stub-cache.h" #include "src/ic/stub-cache.h"
#include "src/trap-handler/trap-handler.h"
#if defined(DEBUG) && defined(V8_OS_LINUX) && !defined(V8_OS_ANDROID) #if defined(DEBUG) && defined(V8_OS_LINUX) && !defined(V8_OS_ANDROID)
#define SYMBOLIZE_FUNCTION #define SYMBOLIZE_FUNCTION
...@@ -215,6 +216,15 @@ void ExternalReferenceTable::AddReferences(Isolate* isolate) { ...@@ -215,6 +216,15 @@ void ExternalReferenceTable::AddReferences(Isolate* isolate) {
"wasm::word32_popcnt"); "wasm::word32_popcnt");
Add(ExternalReference::wasm_word64_popcnt(isolate).address(), Add(ExternalReference::wasm_word64_popcnt(isolate).address(),
"wasm::word64_popcnt"); "wasm::word64_popcnt");
// If the trap handler is not supported, the optimizer will remove these
// runtime functions. In this case, the arm simulator will break if we add
// them to the external reference table.
if (V8_TRAP_HANDLER_SUPPORTED) {
Add(ExternalReference::wasm_set_thread_in_wasm_flag(isolate).address(),
"wasm::set_thread_in_wasm_flag");
Add(ExternalReference::wasm_clear_thread_in_wasm_flag(isolate).address(),
"wasm::clear_thread_in_wasm_flag");
}
Add(ExternalReference::f64_acos_wrapper_function(isolate).address(), Add(ExternalReference::f64_acos_wrapper_function(isolate).address(),
"f64_acos_wrapper"); "f64_acos_wrapper");
Add(ExternalReference::f64_asin_wrapper_function(isolate).address(), Add(ExternalReference::f64_asin_wrapper_function(isolate).address(),
......
...@@ -1005,6 +1005,9 @@ class Isolate { ...@@ -1005,6 +1005,9 @@ class Isolate {
} }
bool serializer_enabled() const { return serializer_enabled_; } bool serializer_enabled() const { return serializer_enabled_; }
void set_serializer_enabled_for_test(bool serializer_enabled) {
serializer_enabled_ = serializer_enabled;
}
bool snapshot_available() const { bool snapshot_available() const {
return snapshot_blob_ != NULL && snapshot_blob_->raw_size != 0; return snapshot_blob_ != NULL && snapshot_blob_->raw_size != 0;
} }
......
...@@ -252,16 +252,6 @@ RUNTIME_FUNCTION(Runtime_WasmExceptionSetElement) { ...@@ -252,16 +252,6 @@ RUNTIME_FUNCTION(Runtime_WasmExceptionSetElement) {
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
RUNTIME_FUNCTION(Runtime_SetThreadInWasm) {
trap_handler::SetThreadInWasm();
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_ClearThreadInWasm) {
trap_handler::ClearThreadInWasm();
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) { RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
DCHECK_EQ(3, args.length()); DCHECK_EQ(3, args.length());
HandleScope scope(isolate); HandleScope scope(isolate);
......
...@@ -653,8 +653,6 @@ namespace internal { ...@@ -653,8 +653,6 @@ namespace internal {
F(WasmExceptionGetElement, 1, 1) \ F(WasmExceptionGetElement, 1, 1) \
F(WasmRunInterpreter, 3, 1) \ F(WasmRunInterpreter, 3, 1) \
F(WasmStackGuard, 0, 1) \ F(WasmStackGuard, 0, 1) \
F(SetThreadInWasm, 0, 1) \
F(ClearThreadInWasm, 0, 1) \
F(WasmCompileLazy, 0, 1) F(WasmCompileLazy, 0, 1)
#define FOR_EACH_INTRINSIC_RETURN_PAIR(F) \ #define FOR_EACH_INTRINSIC_RETURN_PAIR(F) \
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "include/v8config.h" #include "include/v8config.h"
#include "src/base/bits.h" #include "src/base/bits.h"
#include "src/trap-handler/trap-handler.h"
#include "src/utils.h" #include "src/utils.h"
#include "src/wasm/wasm-external-refs.h" #include "src/wasm/wasm-external-refs.h"
...@@ -223,6 +224,10 @@ void float64_pow_wrapper(double* param0, double* param1) { ...@@ -223,6 +224,10 @@ void float64_pow_wrapper(double* param0, double* param1) {
WriteDoubleValue(param0, Pow(x, y)); WriteDoubleValue(param0, Pow(x, y));
} }
void set_thread_in_wasm_flag() { trap_handler::SetThreadInWasm(); }
void clear_thread_in_wasm_flag() { trap_handler::ClearThreadInWasm(); }
static WasmTrapCallbackForTesting wasm_trap_callback_for_testing = nullptr; static WasmTrapCallbackForTesting wasm_trap_callback_for_testing = nullptr;
void set_trap_callback_for_testing(WasmTrapCallbackForTesting callback) { void set_trap_callback_for_testing(WasmTrapCallbackForTesting callback) {
......
...@@ -61,6 +61,9 @@ uint32_t word64_popcnt_wrapper(uint64_t* input); ...@@ -61,6 +61,9 @@ uint32_t word64_popcnt_wrapper(uint64_t* input);
void float64_pow_wrapper(double* param0, double* param1); void float64_pow_wrapper(double* param0, double* param1);
void set_thread_in_wasm_flag();
void clear_thread_in_wasm_flag();
typedef void (*WasmTrapCallbackForTesting)(); typedef void (*WasmTrapCallbackForTesting)();
void set_trap_callback_for_testing(WasmTrapCallbackForTesting callback); void set_trap_callback_for_testing(WasmTrapCallbackForTesting callback);
......
...@@ -320,6 +320,10 @@ class WasmSerializationTest { ...@@ -320,6 +320,10 @@ class WasmSerializationTest {
WasmSerializationTest::BuildWireBytes(zone(), &buffer); WasmSerializationTest::BuildWireBytes(zone(), &buffer);
Isolate* serialization_isolate = CcTest::InitIsolateOnce(); Isolate* serialization_isolate = CcTest::InitIsolateOnce();
// Isolates do not have serialization enabled by default. We must enable it
// here or else the assembler will not mark external references so that the
// serializer can handle them correctly.
serialization_isolate->set_serializer_enabled_for_test(true);
ErrorThrower thrower(serialization_isolate, ""); ErrorThrower thrower(serialization_isolate, "");
uint8_t* bytes = nullptr; uint8_t* bytes = nullptr;
size_t bytes_size = 0; size_t bytes_size = 0;
......
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