Commit 1f617767 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] For wasm-interpret-all: Iterate code only once for patching

Before, we were redirecting each function to the interpreter by iterating all
code and patching all call sites using this one function. The runtime was
hence quadratic if all functions were redirected to the interpreter as
done by the --wasm-interpret-all flag.
This CL fixes this to only iterate the code once and redirecting an
arbitrary number of function.

R=ahaas@chromium.org, titzer@chromium.org
BUG=v8:5822

Change-Id: Ia4f2e94a2468f9bef3035b599e1f8a18acf309da
Reviewed-on: https://chromium-review.googlesource.com/455785
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#43946}
parent e678c8c7
......@@ -8,6 +8,7 @@
#include "src/debug/debug.h"
#include "src/factory.h"
#include "src/frames-inl.h"
#include "src/identity-map.h"
#include "src/isolate.h"
#include "src/wasm/module-decoder.h"
#include "src/wasm/wasm-interpreter.h"
......@@ -391,26 +392,28 @@ Handle<FixedArray> GetOrCreateInterpretedFunctions(
return new_arr;
}
void RedirectCallsitesInCode(Code* code, Code* old_target, Code* new_target) {
using CodeRelocationMap = IdentityMap<Handle<Code>, FreeStoreAllocationPolicy>;
void RedirectCallsitesInCode(Code* code, CodeRelocationMap& map) {
DisallowHeapAllocation no_gc;
for (RelocIterator it(code, RelocInfo::kCodeTargetMask); !it.done();
it.next()) {
DCHECK(RelocInfo::IsCodeTarget(it.rinfo()->rmode()));
Code* target = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
if (target != old_target) continue;
Handle<Code>* new_target = map.Find(target);
if (!new_target) continue;
it.rinfo()->set_target_address(code->GetIsolate(),
new_target->instruction_start());
(*new_target)->instruction_start());
}
}
void RedirectCallsitesInInstance(Isolate* isolate, WasmInstanceObject* instance,
Code* old_target, Code* new_target) {
CodeRelocationMap& map) {
DisallowHeapAllocation no_gc;
// Redirect all calls in wasm functions.
FixedArray* code_table = instance->compiled_module()->ptr_to_code_table();
for (int i = 0, e = GetNumFunctions(instance); i < e; ++i) {
RedirectCallsitesInCode(Code::cast(code_table->get(i)), old_target,
new_target);
RedirectCallsitesInCode(Code::cast(code_table->get(i)), map);
}
// Redirect all calls in exported functions.
......@@ -420,7 +423,7 @@ void RedirectCallsitesInInstance(Isolate* isolate, WasmInstanceObject* instance,
WeakCell* weak_function = WeakCell::cast(weak_exported_functions->get(i));
if (weak_function->cleared()) continue;
Code* code = JSFunction::cast(weak_function->value())->code();
RedirectCallsitesInCode(code, old_target, new_target);
RedirectCallsitesInCode(code, map);
}
}
......@@ -460,34 +463,38 @@ void WasmDebugInfo::SetBreakpoint(Handle<WasmDebugInfo> debug_info,
int func_index, int offset) {
Isolate* isolate = debug_info->GetIsolate();
InterpreterHandle* handle = GetOrCreateInterpreterHandle(isolate, debug_info);
RedirectToInterpreter(debug_info, func_index);
RedirectToInterpreter(debug_info, Vector<int>(&func_index, 1));
const WasmFunction* func = &handle->module()->functions[func_index];
handle->interpreter()->SetBreakpoint(func, offset, true);
}
void WasmDebugInfo::RedirectToInterpreter(Handle<WasmDebugInfo> debug_info,
int func_index) {
Vector<int> func_indexes) {
Isolate* isolate = debug_info->GetIsolate();
DCHECK_LE(0, func_index);
DCHECK_GT(debug_info->wasm_instance()->module()->functions.size(),
func_index);
Handle<FixedArray> interpreted_functions =
GetOrCreateInterpretedFunctions(isolate, debug_info);
if (!interpreted_functions->get(func_index)->IsUndefined(isolate)) return;
// Ensure that the interpreter is instantiated.
GetOrCreateInterpreterHandle(isolate, debug_info);
Handle<FixedArray> interpreted_functions =
GetOrCreateInterpretedFunctions(isolate, debug_info);
Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
Handle<Code> new_code = compiler::CompileWasmInterpreterEntry(
isolate, func_index,
instance->compiled_module()->module()->functions[func_index].sig,
instance);
Handle<FixedArray> code_table = instance->compiled_module()->code_table();
Handle<Code> old_code(Code::cast(code_table->get(func_index)), isolate);
interpreted_functions->set(func_index, *new_code);
RedirectCallsitesInInstance(isolate, *instance, *old_code, *new_code);
CodeRelocationMap code_to_relocate(isolate->heap());
for (int func_index : func_indexes) {
DCHECK_LE(0, func_index);
DCHECK_GT(debug_info->wasm_instance()->module()->functions.size(),
func_index);
if (!interpreted_functions->get(func_index)->IsUndefined(isolate)) continue;
Handle<Code> new_code = compiler::CompileWasmInterpreterEntry(
isolate, func_index,
instance->compiled_module()->module()->functions[func_index].sig,
instance);
Code* old_code = Code::cast(code_table->get(func_index));
interpreted_functions->set(func_index, *new_code);
DCHECK_NULL(code_to_relocate.Find(old_code));
code_to_relocate.Set(old_code, new_code);
}
RedirectCallsitesInInstance(isolate, *instance, code_to_relocate);
}
void WasmDebugInfo::PrepareStep(StepAction step_action) {
......
......@@ -1471,11 +1471,15 @@ class InstantiationHelper {
if (FLAG_wasm_interpret_all) {
Handle<WasmDebugInfo> debug_info =
WasmInstanceObject::GetOrCreateDebugInfo(instance);
std::vector<int> func_indexes;
for (int func_index = num_imported_functions,
num_wasm_functions = static_cast<int>(module_->functions.size());
func_index < num_wasm_functions; ++func_index) {
WasmDebugInfo::RedirectToInterpreter(debug_info, func_index);
func_indexes.push_back(func_index);
}
WasmDebugInfo::RedirectToInterpreter(
debug_info, Vector<int>(func_indexes.data(),
static_cast<int>(func_indexes.size())));
}
//--------------------------------------------------------------------------
......
......@@ -467,9 +467,10 @@ class WasmDebugInfo : public FixedArray {
// interpreter and will always pause at the given offset.
static void SetBreakpoint(Handle<WasmDebugInfo>, int func_index, int offset);
// Make a function always execute in the interpreter without setting a
// Make a set of functions always execute in the interpreter without setting
// breakpoints.
static void RedirectToInterpreter(Handle<WasmDebugInfo>, int func_index);
static void RedirectToInterpreter(Handle<WasmDebugInfo>,
Vector<int> func_indexes);
void PrepareStep(StepAction);
......
......@@ -46,8 +46,9 @@ class ArgPassingHelper {
std::vector<uint8_t> outer_code{bytes_outer_function};
runner.Build(outer_code.data(), outer_code.data() + outer_code.size());
int funcs_to_redict[] = {static_cast<int>(inner_compiler.function_index())};
WasmDebugInfo::RedirectToInterpreter(debug_info_,
inner_compiler.function_index());
ArrayVector(funcs_to_redict));
main_fun_wrapper_ = runner.module().WrapCode(runner.function_index());
}
......
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