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) {
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) {
WriteDoubleValue(param0,
modulo(ReadDoubleValue(param0), ReadDoubleValue(param1)));
......
......@@ -871,6 +871,8 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference wasm_word32_popcnt(Isolate* isolate);
static ExternalReference wasm_word64_popcnt(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_asin_wrapper_function(Isolate* isolate);
......
......@@ -2302,13 +2302,30 @@ Node* WasmGraphBuilder::BuildDiv64Call(Node* left, Node* right,
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 extra = 2; // effect and control inputs.
const size_t count = 1 + params + extra;
// 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.
args[params + 1] = *effect_;
......@@ -2773,8 +2790,9 @@ Node* WasmGraphBuilder::BuildHeapNumberValueIndexConstant() {
void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code,
Address wasm_context_address) {
int wasm_count = static_cast<int>(sig_->parameter_count());
int count = wasm_count + 4; // wasm_code, wasm_context, effect, and control.
const int wasm_count = static_cast<int>(sig_->parameter_count());
const int count =
wasm_count + 4; // wasm_code, wasm_context, effect, and control.
Node** args = Buffer(count);
// Build the start and the JS parameter nodes.
......@@ -3269,36 +3287,22 @@ void WasmGraphBuilder::EnsureFunctionTableNodes() {
Node* WasmGraphBuilder::BuildModifyThreadInWasmFlag(bool new_value) {
// TODO(eholk): generate code to modify the thread-local storage directly,
// 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()) {
return *control_;
}
const Runtime::FunctionId f =
new_value ? Runtime::kSetThreadInWasm : Runtime::kClearThreadInWasm;
const Runtime::Function* fun = Runtime::FunctionForId(f);
DCHECK_EQ(0, fun->nargs);
const CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
jsgraph()->zone(), f, fun->nargs, Operator::kNoProperties,
CallDescriptor::kNoFlags);
// CEntryStubConstant nodes have to be created and cached in the main
// thread. At the moment this is only done for CEntryStubConstant(1).
DCHECK_EQ(1, fun->result_size);
Node* inputs[] = {centry_stub_node_,
jsgraph()->ExternalConstant(
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;
// Using two functions instead of taking the new value as a parameter saves
// one instruction on each call to set up the parameter.
ExternalReference ref =
new_value ? ExternalReference::wasm_set_thread_in_wasm_flag(
jsgraph()->isolate())
: ExternalReference::wasm_clear_thread_in_wasm_flag(
jsgraph()->isolate());
MachineSignature::Builder sig_builder(jsgraph()->zone(), 0, 0);
Node* args[] = {graph()->NewNode(jsgraph()->common()->ExternalConstant(ref)),
nullptr, // Extra space for CCall effect and control inputs
nullptr};
return BuildCCallWithBuffer(sig_builder.Build(), args, arraysize(args));
}
// Only call this function for code which is not reused across instantiations,
......@@ -3307,10 +3311,6 @@ Node* WasmGraphBuilder::BuildCallToRuntimeWithContext(Runtime::FunctionId f,
Node* js_context,
Node** parameters,
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.
*control_ = BuildModifyThreadInWasmFlag(false);
// Since the thread-in-wasm flag is clear, it is as if we are calling from JS.
......
......@@ -405,7 +405,9 @@ class WasmGraphBuilder {
Node* MaskShiftCount32(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,
wasm::WasmCodePosition position);
......@@ -504,7 +506,7 @@ class WasmGraphBuilder {
void BuildEncodeException32BitValue(uint32_t* index, Node* value);
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);
if (buf != buffer) memcpy(buf, buffer, old_count * sizeof(Node*));
return buf;
......
......@@ -8,6 +8,7 @@
#include "src/assembler.h"
#include "src/counters.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)
#define SYMBOLIZE_FUNCTION
......@@ -215,6 +216,15 @@ void ExternalReferenceTable::AddReferences(Isolate* isolate) {
"wasm::word32_popcnt");
Add(ExternalReference::wasm_word64_popcnt(isolate).address(),
"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(),
"f64_acos_wrapper");
Add(ExternalReference::f64_asin_wrapper_function(isolate).address(),
......
......@@ -1005,6 +1005,9 @@ class Isolate {
}
bool serializer_enabled() const { return serializer_enabled_; }
void set_serializer_enabled_for_test(bool serializer_enabled) {
serializer_enabled_ = serializer_enabled;
}
bool snapshot_available() const {
return snapshot_blob_ != NULL && snapshot_blob_->raw_size != 0;
}
......
......@@ -252,16 +252,6 @@ RUNTIME_FUNCTION(Runtime_WasmExceptionSetElement) {
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) {
DCHECK_EQ(3, args.length());
HandleScope scope(isolate);
......
......@@ -653,8 +653,6 @@ namespace internal {
F(WasmExceptionGetElement, 1, 1) \
F(WasmRunInterpreter, 3, 1) \
F(WasmStackGuard, 0, 1) \
F(SetThreadInWasm, 0, 1) \
F(ClearThreadInWasm, 0, 1) \
F(WasmCompileLazy, 0, 1)
#define FOR_EACH_INTRINSIC_RETURN_PAIR(F) \
......
......@@ -10,6 +10,7 @@
#include "include/v8config.h"
#include "src/base/bits.h"
#include "src/trap-handler/trap-handler.h"
#include "src/utils.h"
#include "src/wasm/wasm-external-refs.h"
......@@ -223,6 +224,10 @@ void float64_pow_wrapper(double* param0, double* param1) {
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;
void set_trap_callback_for_testing(WasmTrapCallbackForTesting callback) {
......
......@@ -61,6 +61,9 @@ uint32_t word64_popcnt_wrapper(uint64_t* input);
void float64_pow_wrapper(double* param0, double* param1);
void set_thread_in_wasm_flag();
void clear_thread_in_wasm_flag();
typedef void (*WasmTrapCallbackForTesting)();
void set_trap_callback_for_testing(WasmTrapCallbackForTesting callback);
......
......@@ -320,6 +320,10 @@ class WasmSerializationTest {
WasmSerializationTest::BuildWireBytes(zone(), &buffer);
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, "");
uint8_t* bytes = nullptr;
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