Commit 3b59a3dd authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] Refactor all call targets to be Addresses

With the introduction of a jump table, call targets will not be
{WasmCode} objects any more. Instead, we just call any {Address}.
This CL does not change anything yet, but changes interfaces to accept
an {Address} instead of {WasmCode*}.

R=titzer@chromium.org

Bug: v8:7758
Change-Id: Id299738bb7cc6a1891e4a03d7f67c24cde6d1699
Reviewed-on: https://chromium-review.googlesource.com/1058793
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarBen Titzer <titzer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53191}
parent 37e9017f
......@@ -4298,7 +4298,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
return instance;
}
void BuildJSToWasmWrapper(wasm::WasmCode* wasm_code) {
void BuildJSToWasmWrapper(Address call_target) {
const int wasm_count = static_cast<int>(sig_->parameter_count());
const int count =
wasm_count + 4; // wasm_code, instance_node, effect, and control.
......@@ -4327,10 +4327,8 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
DCHECK_NULL(instance_node_);
instance_node_ = BuildLoadInstanceFromExportedFunction(js_closure);
Address instr_start =
wasm_code == nullptr ? kNullAddress : wasm_code->instruction_start();
Node* wasm_code_node = mcgraph()->RelocatableIntPtrConstant(
instr_start, RelocInfo::JS_TO_WASM_CALL);
call_target, RelocInfo::JS_TO_WASM_CALL);
if (!wasm::IsJSCompatibleSignature(sig_)) {
// Throw a TypeError. Use the js_context of the calling javascript
// function (passed as a parameter), such that the generated code is
......@@ -4691,7 +4689,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
} // namespace
Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::WasmModule* module,
wasm::WasmCode* wasm_code, uint32_t index,
Address call_target, uint32_t index,
wasm::UseTrapHandler use_trap_handler) {
const wasm::WasmFunction* func = &module->functions[index];
......@@ -4714,7 +4712,7 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::WasmModule* module,
WasmWrapperGraphBuilder builder(&zone, &env, &jsgraph, func->sig, nullptr);
builder.set_control_ptr(&control);
builder.set_effect_ptr(&effect);
builder.BuildJSToWasmWrapper(wasm_code);
builder.BuildJSToWasmWrapper(call_target);
//----------------------------------------------------------------------------
// Run the compilation pipeline.
......
......@@ -110,7 +110,7 @@ Handle<Code> CompileWasmToJSWrapper(Isolate*, Handle<JSReceiver> target,
// Wraps a given wasm code object, producing a code object.
V8_EXPORT_PRIVATE Handle<Code> CompileJSToWasmWrapper(Isolate*,
wasm::WasmModule*,
wasm::WasmCode*,
Address call_target,
uint32_t index,
wasm::UseTrapHandler);
......
......@@ -195,7 +195,7 @@ namespace {
class JSToWasmWrapperCache {
public:
Handle<Code> CloneOrCompileJSToWasmWrapper(
Isolate* isolate, wasm::WasmModule* module, wasm::WasmCode* wasm_code,
Isolate* isolate, wasm::WasmModule* module, Address call_target,
uint32_t index, wasm::UseTrapHandler use_trap_handler) {
const wasm::WasmFunction* func = &module->functions[index];
int cached_idx = sig_map_.Find(func->sig);
......@@ -204,13 +204,12 @@ class JSToWasmWrapperCache {
// Now patch the call to wasm code.
RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::JS_TO_WASM_CALL));
DCHECK(!it.done());
it.rinfo()->set_js_to_wasm_address(
wasm_code == nullptr ? kNullAddress : wasm_code->instruction_start());
it.rinfo()->set_js_to_wasm_address(call_target);
return code;
}
Handle<Code> code = compiler::CompileJSToWasmWrapper(
isolate, module, wasm_code, index, use_trap_handler);
isolate, module, call_target, index, use_trap_handler);
uint32_t new_cache_idx = sig_map_.FindOrInsert(func->sig);
DCHECK_EQ(code_cache_.size(), new_cache_idx);
USE(new_cache_idx);
......@@ -369,13 +368,11 @@ class IndirectPatcher {
public:
void Patch(Handle<WasmInstanceObject> caller_instance,
Handle<WasmInstanceObject> target_instance, int func_index,
Address old_target, const WasmCode* new_code) {
Address old_target, Address new_target) {
TRACE_LAZY(
"IndirectPatcher::Patch(caller=%p, target=%p, func_index=%i, "
"old_target=%p, "
"new_code=%p)\n",
*caller_instance, *target_instance, func_index,
reinterpret_cast<void*>(old_target), new_code);
"old_target=%" PRIuPTR ", new_target=%" PRIuPTR ")\n",
*caller_instance, *target_instance, func_index, old_target, new_target);
if (mapping_.size() == 0 || misses_ >= kMaxMisses) {
BuildMapping(caller_instance);
}
......@@ -394,7 +391,7 @@ class IndirectPatcher {
DCHECK_EQ(
func_index,
code_manager->GetCodeFromStartAddress(entry.target())->index());
entry.set_wasm_to_wasm(*target_instance, new_code);
entry.set_wasm_to_wasm(*target_instance, new_target);
patched++;
}
} else {
......@@ -405,7 +402,7 @@ class IndirectPatcher {
DCHECK_EQ(
func_index,
code_manager->GetCodeFromStartAddress(entry.target())->index());
entry.set(entry.sig_id(), *target_instance, new_code);
entry.set(entry.sig_id(), *target_instance, new_target);
patched++;
}
}
......@@ -436,7 +433,7 @@ class IndirectPatcher {
code->index());
if (new_code->kind() != WasmCode::kLazyStub) {
// Patch an imported function entry which is already compiled.
entry.set_wasm_to_wasm(target_instance, new_code);
entry.set_wasm_to_wasm(target_instance, new_code->instruction_start());
} else {
int key = code->index();
int index = -1 - i;
......@@ -458,7 +455,8 @@ class IndirectPatcher {
code->index());
if (new_code->kind() != WasmCode::kLazyStub) {
// Patch an indirect function table entry which is already compiled.
entry.set(entry.sig_id(), target_instance, new_code);
entry.set(entry.sig_id(), target_instance,
new_code->instruction_start());
} else {
int key = code->index();
int index = i;
......@@ -849,7 +847,7 @@ Address CompileLazy(Isolate* isolate,
->raw();
Address old_target = lazy_stub->instruction_start();
patcher->Patch(caller_instance, target_instance, target_func_index,
old_target, result);
old_target, result->instruction_start());
}
return result->instruction_start();
......@@ -1829,21 +1827,19 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
if (module_->start_function_index >= 0) {
int start_index = module_->start_function_index;
Handle<WasmInstanceObject> start_function_instance = instance;
wasm::WasmCode* start_code;
Address start_call_address;
if (static_cast<uint32_t>(start_index) < module_->num_imported_functions) {
ImportedFunctionEntry entry(instance, start_index);
start_function_instance = handle(entry.instance(), isolate_);
start_code =
isolate_->wasm_engine()->code_manager()->GetCodeFromStartAddress(
entry.target());
DCHECK_EQ(start_code->native_module(),
start_function_instance->compiled_module()->GetNativeModule());
start_call_address = entry.target();
} else {
start_code = native_module->GetIndirectlyCallableCode(start_index);
start_call_address = native_module->GetCallTargetForFunction(start_index);
}
FunctionSig* sig = module_->functions[start_index].sig;
Handle<Code> wrapper_code = js_to_wasm_cache_.CloneOrCompileJSToWasmWrapper(
isolate_, module_, start_code, start_index, use_trap_handler());
isolate_, module_, start_call_address, start_index, use_trap_handler());
// TODO(clemensh): Don't generate an exported function for the start
// function. Use CWasmEntry instead.
start_function_ = WasmExportedFunction::New(
isolate_, start_function_instance, MaybeHandle<String>(), start_index,
static_cast<int>(sig->parameter_count()), wrapper_code);
......@@ -2119,10 +2115,12 @@ int InstanceBuilder::ProcessImports(Handle<WasmInstanceObject> instance) {
return -1;
}
// The import reference is the instance object itself.
auto wasm_code = imported_function->GetWasmCode();
ImportedFunctionEntry(instance, func_index)
.set_wasm_to_wasm(*imported_instance, wasm_code);
native_module->set_code(func_index, wasm_code);
.set_wasm_to_wasm(*imported_instance,
imported_function->GetWasmCallTarget());
// TODO(clemensh): Remove this. NativeModule must be instance
// independent.
native_module->set_code(func_index, imported_function->GetWasmCode());
} else {
// The imported function is a callable.
Handle<JSReceiver> js_receiver(JSReceiver::cast(*value), isolate_);
......@@ -2205,13 +2203,13 @@ int InstanceBuilder::ProcessImports(Handle<WasmInstanceObject> instance) {
auto target = Handle<WasmExportedFunction>::cast(val);
Handle<WasmInstanceObject> imported_instance =
handle(target->instance());
const wasm::WasmCode* exported_code = target->GetWasmCode();
Address exported_call_target = target->GetWasmCallTarget();
FunctionSig* sig = imported_instance->module()
->functions[exported_code->index()]
->functions[target->function_index()]
.sig;
IndirectFunctionTableEntry(instance, i)
.set(module_->signature_map.Find(sig), *imported_instance,
exported_code);
exported_call_target);
}
num_imported_tables++;
break;
......@@ -2646,18 +2644,18 @@ void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
// Update the local dispatch table first.
uint32_t sig_id = module_->signature_ids[function->sig_index];
wasm::WasmCode* wasm_code =
native_module->GetIndirectlyCallableCode(func_index);
Address call_target =
native_module->GetCallTargetForFunction(func_index);
if (func_index < module_->num_imported_functions) {
// Imported functions have the target instance put into the IFT.
WasmInstanceObject* target_instance =
ImportedFunctionEntry(instance, func_index).instance();
IndirectFunctionTableEntry(instance, table_index)
.set(sig_id, target_instance, wasm_code);
.set(sig_id, target_instance, call_target);
} else {
IndirectFunctionTableEntry(instance, table_index)
.set(sig_id, *instance, wasm_code);
.set(sig_id, *instance, call_target);
}
if (!table_instance.table_object.is_null()) {
......@@ -2670,7 +2668,7 @@ void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
Handle<Code> wrapper_code =
js_to_wasm_cache_.CloneOrCompileJSToWasmWrapper(
isolate_, module_, wasm_code, func_index,
isolate_, module_, call_target, func_index,
use_trap_handler());
MaybeHandle<String> func_name;
if (module_->is_asm_js()) {
......@@ -2695,7 +2693,7 @@ void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
// UpdateDispatchTables() should update this instance as well.
WasmTableObject::UpdateDispatchTables(
isolate_, table_instance.table_object, table_index, function->sig,
instance, wasm_code);
instance, call_target);
}
}
}
......@@ -3646,13 +3644,12 @@ void CompileJsToWasmWrappers(Isolate* isolate,
module_object->compiled_module()->GetNativeModule();
wasm::UseTrapHandler use_trap_handler =
native_module->use_trap_handler() ? kUseTrapHandler : kNoTrapHandler;
for (auto exp : module_object->shared()->module()->export_table) {
WasmModule* module = native_module->shared_module_data()->module();
for (auto exp : module->export_table) {
if (exp.kind != kExternalFunction) continue;
wasm::WasmCode* wasm_code =
native_module->GetIndirectlyCallableCode(exp.index);
Address call_target = native_module->GetCallTargetForFunction(exp.index);
Handle<Code> wrapper_code = js_to_wasm_cache.CloneOrCompileJSToWasmWrapper(
isolate, module_object->shared()->module(), wasm_code, exp.index,
use_trap_handler);
isolate, module, call_target, exp.index, use_trap_handler);
export_wrappers->set(wrapper_index, *wrapper_code);
RecordStats(*wrapper_code, counters);
++wrapper_index;
......
......@@ -697,16 +697,19 @@ WasmCode* NativeModule::Lookup(Address pc) {
WasmCodeUniquePtrComparator());
if (iter == owned_code_.begin()) return nullptr;
--iter;
WasmCode* candidate = (*iter).get();
WasmCode* candidate = iter->get();
DCHECK_NOT_NULL(candidate);
return candidate->contains(pc) ? candidate : nullptr;
}
WasmCode* NativeModule::GetIndirectlyCallableCode(uint32_t func_index) {
Address NativeModule::GetCallTargetForFunction(uint32_t func_index) {
// TODO(clemensh): Introduce a jump table and return a slot of it here.
WasmCode* wasm_code = code(func_index);
if (!wasm_code || wasm_code->kind() != WasmCode::kLazyStub) {
return wasm_code;
if (!wasm_code) return kNullAddress;
if (wasm_code->kind() != WasmCode::kLazyStub) {
return wasm_code->instruction_start();
}
#if DEBUG
auto num_imported_functions =
shared_module_data()->module()->num_imported_functions;
......@@ -718,7 +721,7 @@ WasmCode* NativeModule::GetIndirectlyCallableCode(uint32_t func_index) {
// If the function wasn't imported, its index should match.
DCHECK_IMPLIES(func_index >= num_imported_functions,
func_index == wasm_code->index());
return wasm_code;
return wasm_code->instruction_start();
}
if (!lazy_compile_stubs_.get()) {
lazy_compile_stubs_ =
......@@ -732,7 +735,7 @@ WasmCode* NativeModule::GetIndirectlyCallableCode(uint32_t func_index) {
lazy_compile_stubs_.get()->at(func_index) = cloned_code;
}
DCHECK_EQ(func_index, cloned_code->index());
return cloned_code;
return cloned_code->instruction_start();
}
WasmCode* NativeModule::CloneCode(const WasmCode* original_code,
......
......@@ -259,15 +259,21 @@ class V8_EXPORT_PRIVATE NativeModule final {
code_table_[index] = wasm_code;
}
bool has_code(uint32_t index) const {
DCHECK_LT(index, function_count());
return code_table_[index] != nullptr;
}
// Register/release the protected instructions in all code objects with the
// global trap handler for this process.
void UnpackAndRegisterProtectedInstructions();
void ReleaseProtectedInstructions();
// Gets code suitable for indirect or import calls for the given function
// index. If the code at the given index is the lazy compile stub, it will
// clone a non-anonymous lazy compile stub for the purpose.
WasmCode* GetIndirectlyCallableCode(uint32_t func_index);
// Returns the instruction start of code suitable for indirect or import calls
// for the given function index. If the code at the given index is the lazy
// compile stub, it will clone a non-anonymous lazy compile stub for the
// purpose. This will soon change to always return a jump table slot.
Address GetCallTargetForFunction(uint32_t index);
bool SetExecutable(bool executable);
......
......@@ -113,10 +113,9 @@ bool CodeSpecialization::ApplyToWholeModule(
switch (mode) {
case RelocInfo::JS_TO_WASM_CALL: {
changed = true;
const WasmCode* new_code =
native_module->GetIndirectlyCallableCode(exp.index);
it.rinfo()->set_js_to_wasm_address(new_code->instruction_start(),
icache_flush_mode);
Address new_target =
native_module->GetCallTargetForFunction(exp.index);
it.rinfo()->set_js_to_wasm_address(new_target, icache_flush_mode);
} break;
default:
UNREACHABLE();
......
......@@ -405,16 +405,16 @@ void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
auto* wasm_function = &other_instance->module()->functions[func_index];
DCHECK_NOT_NULL(wasm_function);
DCHECK_NOT_NULL(wasm_function->sig);
wasm::WasmCode* wasm_code = exported_function->GetWasmCode();
Address call_target = exported_function->GetWasmCallTarget();
UpdateDispatchTables(isolate, table, table_index, wasm_function->sig,
handle(exported_function->instance()), wasm_code);
handle(exported_function->instance()), call_target);
array->set(table_index, *function);
}
void WasmTableObject::UpdateDispatchTables(
Isolate* isolate, Handle<WasmTableObject> table, int table_index,
wasm::FunctionSig* sig, Handle<WasmInstanceObject> from_instance,
wasm::WasmCode* wasm_code) {
Address call_target) {
// We simply need to update the IFTs for each instance that imports
// this table.
Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate);
......@@ -430,7 +430,7 @@ void WasmTableObject::UpdateDispatchTables(
// not found; it will simply never match any check.
auto sig_id = to_instance->module()->signature_map.Find(sig);
IndirectFunctionTableEntry(to_instance, table_index)
.set(sig_id, *from_instance, wasm_code);
.set(sig_id, *from_instance, call_target);
}
}
......@@ -672,13 +672,12 @@ void IndirectFunctionTableEntry::clear() {
}
void IndirectFunctionTableEntry::set(int sig_id, WasmInstanceObject* instance,
const wasm::WasmCode* wasm_code) {
TRACE_IFT("IFT entry %p[%d] = {sig_id=%d, instance=%p, target=%p}\n",
*instance_, index_, sig_id, instance,
wasm_code->instructions().start());
Address call_target) {
TRACE_IFT("IFT entry %p[%d] = {sig_id=%d, instance=%p, target=%" PRIuPTR
"}\n",
*instance_, index_, sig_id, instance, call_target);
instance_->indirect_function_table_sig_ids()[index_] = sig_id;
instance_->indirect_function_table_targets()[index_] =
wasm_code->instruction_start();
instance_->indirect_function_table_targets()[index_] = call_target;
instance_->indirect_function_table_instances()->set(index_, instance);
}
......@@ -707,14 +706,13 @@ void ImportedFunctionEntry::set_wasm_to_js(
}
void ImportedFunctionEntry::set_wasm_to_wasm(WasmInstanceObject* instance,
const wasm::WasmCode* wasm_code) {
TRACE_IFT("Import WASM %p[%d] = {instance=%p, target=%p}\n", *instance_,
index_, instance, wasm_code->instructions().start());
Address call_target) {
TRACE_IFT("Import WASM %p[%d] = {instance=%p, target=%" PRIuPTR "}\n",
*instance_, index_, instance, call_target);
instance_->imported_function_instances()->set(index_, instance);
instance_->imported_function_callables()->set(
index_, instance_->GetHeap()->undefined_value());
instance_->imported_function_targets()[index_] =
wasm_code->instruction_start();
instance_->imported_function_targets()[index_] = call_target;
}
WasmInstanceObject* ImportedFunctionEntry::instance() {
......@@ -947,15 +945,19 @@ Handle<WasmExportedFunction> WasmExportedFunction::New(
}
wasm::WasmCode* WasmExportedFunction::GetWasmCode() {
Address target = GetWasmCallTarget();
wasm::WasmCode* wasm_code =
GetIsolate()->wasm_engine()->code_manager()->LookupCode(target);
return wasm_code;
}
Address WasmExportedFunction::GetWasmCallTarget() {
DisallowHeapAllocation no_gc;
Handle<Code> export_wrapper_code = handle(this->code());
DCHECK_EQ(export_wrapper_code->kind(), Code::JS_TO_WASM_FUNCTION);
DCHECK_EQ(code()->kind(), Code::JS_TO_WASM_FUNCTION);
int mask = RelocInfo::ModeMask(RelocInfo::JS_TO_WASM_CALL);
RelocIterator it(*export_wrapper_code, mask);
RelocIterator it(code(), mask);
DCHECK(!it.done());
wasm::WasmCode* target =
GetIsolate()->wasm_engine()->code_manager()->LookupCode(
it.rinfo()->js_to_wasm_address());
Address target = it.rinfo()->js_to_wasm_address();
#ifdef DEBUG
// There should only be this one call to wasm code.
it.next();
......
......@@ -57,8 +57,7 @@ class IndirectFunctionTableEntry {
inline IndirectFunctionTableEntry(Handle<WasmInstanceObject>, int index);
void clear();
void set(int sig_id, WasmInstanceObject* instance,
const wasm::WasmCode* wasm_code);
void set(int sig_id, WasmInstanceObject* instance, Address call_target);
WasmInstanceObject* instance();
int sig_id();
......@@ -89,7 +88,7 @@ class ImportedFunctionEntry {
const wasm::WasmCode* wasm_to_js_wrapper);
// Initialize this entry as a WASM to WASM call.
void set_wasm_to_wasm(WasmInstanceObject* target_instance,
const wasm::WasmCode* wasm_function);
Address call_target);
WasmInstanceObject* instance();
JSReceiver* callable();
......@@ -176,7 +175,7 @@ class WasmTableObject : public JSObject {
Handle<WasmTableObject> table,
int table_index, wasm::FunctionSig* sig,
Handle<WasmInstanceObject> from_instance,
wasm::WasmCode* wasm_code);
Address call_target);
static void ClearDispatchTables(Isolate* isolate,
Handle<WasmTableObject> table, int index);
......@@ -377,7 +376,12 @@ class WasmExportedFunction : public JSFunction {
int func_index, int arity,
Handle<Code> export_wrapper);
// TODO(clemensh): Remove this. There might not be a WasmCode object available
// yet.
// TODO(all): Replace all uses by {GetWasmCallTarget()}.
wasm::WasmCode* GetWasmCode();
Address GetWasmCallTarget();
};
// Information for a WasmExportedFunction which is referenced as the function
......
......@@ -120,7 +120,7 @@ Handle<JSFunction> TestingModuleBuilder::WrapCode(uint32_t index) {
Link();
wasm::WasmCode* code = native_module_->code(index);
Handle<Code> ret_code = compiler::CompileJSToWasmWrapper(
isolate_, test_module_ptr_, code, index,
isolate_, test_module_ptr_, code->instruction_start(), index,
trap_handler::IsTrapHandlerEnabled() ? kUseTrapHandler : kNoTrapHandler);
Handle<JSFunction> ret = WasmExportedFunction::New(
isolate_, instance_object(), MaybeHandle<String>(),
......@@ -166,7 +166,8 @@ void TestingModuleBuilder::PopulateIndirectFunctionTable() {
WasmFunction& function = test_module_->functions[table.values[j]];
int sig_id = test_module_->signature_map.Find(function.sig);
auto wasm_code = native_module_->code(function.func_index);
IndirectFunctionTableEntry(instance, j).set(sig_id, *instance, wasm_code);
IndirectFunctionTableEntry(instance, j)
.set(sig_id, *instance, wasm_code->instruction_start());
}
}
}
......
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