Commit 02f18b2d authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[wasm] Refactor indirect function calls

This is the combined second and third step of refactoring indirect
function calls through tables with index > 0 to work without runtime
calls.

The first CL introduces the WasmIndirectFunctionTable heap object. For
a table of type anyfunc within a WebAssembly instance,
WasmIndirectFunctionTable stores the size, the signature id's, the
call targets, and the reference parameters for that table. I used the
names that are already used for the matching fields of the
WasmInstanceObject.

The second CL expands the IndirectFunctionTableEntry to work also on
WasmIndirectFunctionTable objects. All changes to a function table go
through this class.

The third CL introduces uses of the WasmIndirectFunctionTable. In this
CL I change the code generation in TurboFan to replace runime calls with
direct accesses to the new WasmIndirectFunctionTable. Additionally I
extended the initialization of WasmIndirectFunctionTable, and also
implement Table.grow.

R=mstarzinger@chromium.org

Bug: v8:7581
Change-Id: Ic7615c0138562d27897683358ddc0943add1acfe
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1684186
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62515}
parent d3472765
...@@ -2854,25 +2854,69 @@ Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args, Node*** rets, ...@@ -2854,25 +2854,69 @@ Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args, Node*** rets,
Node* WasmGraphBuilder::CallIndirect(uint32_t table_index, uint32_t sig_index, Node* WasmGraphBuilder::CallIndirect(uint32_t table_index, uint32_t sig_index,
Node** args, Node*** rets, Node** args, Node*** rets,
wasm::WasmCodePosition position) { wasm::WasmCodePosition position) {
if (table_index == 0) {
return BuildIndirectCall(sig_index, args, rets, position, kCallContinues);
}
return BuildIndirectCall(table_index, sig_index, args, rets, position, return BuildIndirectCall(table_index, sig_index, args, rets, position,
kCallContinues); kCallContinues);
} }
Node* WasmGraphBuilder::BuildIndirectCall(uint32_t sig_index, Node** args, void WasmGraphBuilder::LoadIndirectFunctionTable(uint32_t table_index,
Node** ift_size,
Node** ift_sig_ids,
Node** ift_targets,
Node** ift_instances) {
if (table_index == 0) {
*ift_size =
LOAD_INSTANCE_FIELD(IndirectFunctionTableSize, MachineType::Uint32());
*ift_sig_ids = LOAD_INSTANCE_FIELD(IndirectFunctionTableSigIds,
MachineType::Pointer());
*ift_targets = LOAD_INSTANCE_FIELD(IndirectFunctionTableTargets,
MachineType::Pointer());
*ift_instances = LOAD_INSTANCE_FIELD(
IndirectFunctionTableRefs, MachineType::TypeCompressedTaggedPointer());
return;
}
Node* ift_tables = LOAD_INSTANCE_FIELD(
IndirectFunctionTables, MachineType::TypeCompressedTaggedPointer());
Node* ift_table = LOAD_FIXED_ARRAY_SLOT_ANY(ift_tables, table_index);
*ift_size = LOAD_RAW(
ift_table,
wasm::ObjectAccess::ToTagged(WasmIndirectFunctionTable::kSizeOffset),
MachineType::Int32());
*ift_sig_ids = LOAD_RAW(
ift_table,
wasm::ObjectAccess::ToTagged(WasmIndirectFunctionTable::kSigIdsOffset),
MachineType::Pointer());
*ift_targets = LOAD_RAW(
ift_table,
wasm::ObjectAccess::ToTagged(WasmIndirectFunctionTable::kTargetsOffset),
MachineType::Pointer());
*ift_instances = LOAD_RAW(
ift_table,
wasm::ObjectAccess::ToTagged(WasmIndirectFunctionTable::kRefsOffset),
MachineType::TypeCompressedTaggedPointer());
}
Node* WasmGraphBuilder::BuildIndirectCall(uint32_t table_index,
uint32_t sig_index, Node** args,
Node*** rets, Node*** rets,
wasm::WasmCodePosition position, wasm::WasmCodePosition position,
IsReturnCall continuation) { IsReturnCall continuation) {
DCHECK_NOT_NULL(args[0]); DCHECK_NOT_NULL(args[0]);
DCHECK_NOT_NULL(env_); DCHECK_NOT_NULL(env_);
// Assume only one table for now. // First we have to load the table.
wasm::FunctionSig* sig = env_->module->signatures[sig_index]; Node* ift_size;
Node* ift_sig_ids;
Node* ift_targets;
Node* ift_instances;
LoadIndirectFunctionTable(table_index, &ift_size, &ift_sig_ids, &ift_targets,
&ift_instances);
Node* ift_size = wasm::FunctionSig* sig = env_->module->signatures[sig_index];
LOAD_INSTANCE_FIELD(IndirectFunctionTableSize, MachineType::Uint32());
MachineOperatorBuilder* machine = mcgraph()->machine(); MachineOperatorBuilder* machine = mcgraph()->machine();
Node* key = args[0]; Node* key = args[0];
...@@ -2895,9 +2939,6 @@ Node* WasmGraphBuilder::BuildIndirectCall(uint32_t sig_index, Node** args, ...@@ -2895,9 +2939,6 @@ Node* WasmGraphBuilder::BuildIndirectCall(uint32_t sig_index, Node** args,
} }
// Load signature from the table and check. // Load signature from the table and check.
Node* ift_sig_ids =
LOAD_INSTANCE_FIELD(IndirectFunctionTableSigIds, MachineType::Pointer());
int32_t expected_sig_id = env_->module->signature_ids[sig_index]; int32_t expected_sig_id = env_->module->signature_ids[sig_index];
Node* int32_scaled_key = Uint32ToUintptr( Node* int32_scaled_key = Uint32ToUintptr(
graph()->NewNode(machine->Word32Shl(), key, Int32Constant(2))); graph()->NewNode(machine->Word32Shl(), key, Int32Constant(2)));
...@@ -2910,11 +2951,6 @@ Node* WasmGraphBuilder::BuildIndirectCall(uint32_t sig_index, Node** args, ...@@ -2910,11 +2951,6 @@ Node* WasmGraphBuilder::BuildIndirectCall(uint32_t sig_index, Node** args,
TrapIfFalse(wasm::kTrapFuncSigMismatch, sig_match, position); TrapIfFalse(wasm::kTrapFuncSigMismatch, sig_match, position);
Node* ift_targets =
LOAD_INSTANCE_FIELD(IndirectFunctionTableTargets, MachineType::Pointer());
Node* ift_instances = LOAD_INSTANCE_FIELD(
IndirectFunctionTableRefs, MachineType::TypeCompressedTaggedPointer());
Node* tagged_scaled_key; Node* tagged_scaled_key;
if (kTaggedSize == kInt32Size) { if (kTaggedSize == kInt32Size) {
tagged_scaled_key = int32_scaled_key; tagged_scaled_key = int32_scaled_key;
...@@ -2956,48 +2992,6 @@ Node* WasmGraphBuilder::BuildIndirectCall(uint32_t sig_index, Node** args, ...@@ -2956,48 +2992,6 @@ Node* WasmGraphBuilder::BuildIndirectCall(uint32_t sig_index, Node** args,
} }
} }
Node* WasmGraphBuilder::BuildIndirectCall(uint32_t table_index,
uint32_t sig_index, Node** args,
Node*** rets,
wasm::WasmCodePosition position,
IsReturnCall continuation) {
DCHECK_NOT_NULL(args[0]);
Node* entry_index = args[0];
DCHECK_NOT_NULL(env_);
BoundsCheckTable(table_index, entry_index, position, wasm::kTrapFuncInvalid,
nullptr);
DCHECK(Smi::IsValid(table_index));
DCHECK(Smi::IsValid(sig_index));
Node* runtime_args[]{
graph()->NewNode(mcgraph()->common()->NumberConstant(table_index)),
BuildChangeUint31ToSmi(entry_index),
graph()->NewNode(mcgraph()->common()->NumberConstant(sig_index))};
Node* target_instance = BuildCallToRuntime(
Runtime::kWasmIndirectCallCheckSignatureAndGetTargetInstance,
runtime_args, arraysize(runtime_args));
// We reuse the runtime_args array here, even though we only need the first
// two arguments.
Node* call_target = BuildCallToRuntime(
Runtime::kWasmIndirectCallGetTargetAddress, runtime_args, 2);
wasm::FunctionSig* sig = env_->module->signatures[sig_index];
args[0] = call_target;
const UseRetpoline use_retpoline =
untrusted_code_mitigations_ ? kRetpoline : kNoRetpoline;
switch (continuation) {
case kCallContinues:
return BuildWasmCall(sig, args, rets, position, target_instance,
use_retpoline);
case kReturnCall:
return BuildWasmReturnCall(sig, args, position, target_instance,
use_retpoline);
}
}
Node* WasmGraphBuilder::ReturnCall(uint32_t index, Node** args, Node* WasmGraphBuilder::ReturnCall(uint32_t index, Node** args,
wasm::WasmCodePosition position) { wasm::WasmCodePosition position) {
DCHECK_NULL(args[0]); DCHECK_NULL(args[0]);
...@@ -3020,9 +3014,6 @@ Node* WasmGraphBuilder::ReturnCall(uint32_t index, Node** args, ...@@ -3020,9 +3014,6 @@ Node* WasmGraphBuilder::ReturnCall(uint32_t index, Node** args,
Node* WasmGraphBuilder::ReturnCallIndirect(uint32_t table_index, Node* WasmGraphBuilder::ReturnCallIndirect(uint32_t table_index,
uint32_t sig_index, Node** args, uint32_t sig_index, Node** args,
wasm::WasmCodePosition position) { wasm::WasmCodePosition position) {
if (table_index == 0) {
return BuildIndirectCall(sig_index, args, nullptr, position, kReturnCall);
}
return BuildIndirectCall(table_index, sig_index, args, nullptr, position, return BuildIndirectCall(table_index, sig_index, args, nullptr, position,
kReturnCall); kReturnCall);
} }
......
...@@ -490,10 +490,10 @@ class WasmGraphBuilder { ...@@ -490,10 +490,10 @@ class WasmGraphBuilder {
Node* BuildCallNode(wasm::FunctionSig* sig, Node** args, Node* BuildCallNode(wasm::FunctionSig* sig, Node** args,
wasm::WasmCodePosition position, Node* instance_node, wasm::WasmCodePosition position, Node* instance_node,
const Operator* op); const Operator* op);
// Special implementation for CallIndirect for table 0. // Helper function for {BuildIndirectCall}.
Node* BuildIndirectCall(uint32_t sig_index, Node** args, Node*** rets, void LoadIndirectFunctionTable(uint32_t table_index, Node** ift_size,
wasm::WasmCodePosition position, Node** ift_sig_ids, Node** ift_targets,
IsReturnCall continuation); Node** ift_instances);
Node* BuildIndirectCall(uint32_t table_index, uint32_t sig_index, Node** args, Node* BuildIndirectCall(uint32_t table_index, uint32_t sig_index, Node** args,
Node*** rets, wasm::WasmCodePosition position, Node*** rets, wasm::WasmCodePosition position,
IsReturnCall continuation); IsReturnCall continuation);
......
...@@ -479,122 +479,6 @@ RUNTIME_FUNCTION(Runtime_WasmFunctionTableSet) { ...@@ -479,122 +479,6 @@ RUNTIME_FUNCTION(Runtime_WasmFunctionTableSet) {
return ReadOnlyRoots(isolate).undefined_value(); return ReadOnlyRoots(isolate).undefined_value();
} }
RUNTIME_FUNCTION(Runtime_WasmIndirectCallCheckSignatureAndGetTargetInstance) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
auto instance =
Handle<WasmInstanceObject>(GetWasmInstanceOnStackTop(isolate), isolate);
CONVERT_UINT32_ARG_CHECKED(table_index, 0);
CONVERT_UINT32_ARG_CHECKED(entry_index, 1);
CONVERT_UINT32_ARG_CHECKED(sig_index, 2);
DCHECK(isolate->context().is_null());
isolate->set_context(instance->native_context());
DCHECK_LT(table_index, instance->tables().length());
auto table_obj = handle(
WasmTableObject::cast(instance->tables().get(table_index)), isolate);
// This check is already done in generated code.
DCHECK(WasmTableObject::IsInBounds(isolate, table_obj, entry_index));
bool is_valid;
bool is_null;
MaybeHandle<WasmInstanceObject> maybe_target_instance;
int function_index;
MaybeHandle<WasmJSFunction> maybe_js_function;
WasmTableObject::GetFunctionTableEntry(
isolate, table_obj, entry_index, &is_valid, &is_null,
&maybe_target_instance, &function_index, &maybe_js_function);
CHECK(is_valid);
if (is_null) {
// We throw a signature mismatch trap to be in sync with the generated
// code. There we do a signature check instead of a null-check. Trap
// reasons are not defined in the spec. Otherwise, a null-check is
// performed before a signature, according to the spec.
return ThrowWasmError(isolate, MessageTemplate::kWasmTrapFuncSigMismatch);
}
// TODO(7742): Test and implement indirect calls for non-zero tables.
CHECK(maybe_js_function.is_null());
// Now we do the signature check.
Handle<WasmInstanceObject> target_instance =
maybe_target_instance.ToHandleChecked();
const wasm::WasmModule* target_module =
target_instance->module_object().native_module()->module();
wasm::FunctionSig* target_sig = target_module->functions[function_index].sig;
auto target_sig_id = instance->module()->signature_map.Find(*target_sig);
uint32_t expected_sig_id = instance->module()->signature_ids[sig_index];
if (expected_sig_id != static_cast<uint32_t>(target_sig_id)) {
return ThrowWasmError(isolate, MessageTemplate::kWasmTrapFuncSigMismatch);
}
if (function_index <
static_cast<int>(target_instance->module()->num_imported_functions)) {
// The function in the target instance was imported. Use its imports table,
// which contains a tuple needed by the import wrapper.
ImportedFunctionEntry entry(target_instance, function_index);
return entry.object_ref();
}
return *target_instance;
}
RUNTIME_FUNCTION(Runtime_WasmIndirectCallGetTargetAddress) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
auto instance =
Handle<WasmInstanceObject>(GetWasmInstanceOnStackTop(isolate), isolate);
CONVERT_UINT32_ARG_CHECKED(table_index, 0);
CONVERT_UINT32_ARG_CHECKED(entry_index, 1);
DCHECK_LT(table_index, instance->tables().length());
auto table_obj = handle(
WasmTableObject::cast(instance->tables().get(table_index)), isolate);
DCHECK(WasmTableObject::IsInBounds(isolate, table_obj, entry_index));
bool is_valid;
bool is_null;
MaybeHandle<WasmInstanceObject> maybe_target_instance;
int function_index;
MaybeHandle<WasmJSFunction> maybe_js_function;
WasmTableObject::GetFunctionTableEntry(
isolate, table_obj, entry_index, &is_valid, &is_null,
&maybe_target_instance, &function_index, &maybe_js_function);
CHECK(is_valid);
// The null-check should already have been done in
// Runtime_WasmIndirectCallCheckSignatureAndGetTargetInstance. That runtime
// function should always be called first.
CHECK(!is_null);
// TODO(7742): Test and implement indirect calls for non-zero tables.
CHECK(maybe_js_function.is_null());
Handle<WasmInstanceObject> target_instance =
maybe_target_instance.ToHandleChecked();
Address call_target = 0;
if (function_index <
static_cast<int>(target_instance->module()->num_imported_functions)) {
// The function in the target instance was imported. Use its imports table,
// which contains a tuple needed by the import wrapper.
ImportedFunctionEntry entry(target_instance, function_index);
call_target = entry.target();
} else {
// The function in the target instance was not imported.
call_target = target_instance->GetCallTarget(function_index);
}
// The return value is an address and not a SMI. However, the address is
// always aligned, and a SMI uses the same space as {Address}.
CHECK(HAS_SMI_TAG(call_target));
return Smi(call_target);
}
RUNTIME_FUNCTION(Runtime_WasmTableInit) { RUNTIME_FUNCTION(Runtime_WasmTableInit) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(5, args.length()); DCHECK_EQ(5, args.length());
......
...@@ -528,29 +528,27 @@ namespace internal { ...@@ -528,29 +528,27 @@ namespace internal {
F(TypedArraySet, 2, 1) \ F(TypedArraySet, 2, 1) \
F(TypedArraySortFast, 1, 1) F(TypedArraySortFast, 1, 1)
#define FOR_EACH_INTRINSIC_WASM(F, I) \ #define FOR_EACH_INTRINSIC_WASM(F, I) \
F(ThrowWasmError, 1, 1) \ F(ThrowWasmError, 1, 1) \
F(ThrowWasmStackOverflow, 0, 1) \ F(ThrowWasmStackOverflow, 0, 1) \
F(WasmI32AtomicWait, 4, 1) \ F(WasmI32AtomicWait, 4, 1) \
F(WasmI64AtomicWait, 5, 1) \ F(WasmI64AtomicWait, 5, 1) \
F(WasmAtomicNotify, 3, 1) \ F(WasmAtomicNotify, 3, 1) \
F(WasmExceptionGetValues, 1, 1) \ F(WasmExceptionGetValues, 1, 1) \
F(WasmExceptionGetTag, 1, 1) \ F(WasmExceptionGetTag, 1, 1) \
F(WasmMemoryGrow, 2, 1) \ F(WasmMemoryGrow, 2, 1) \
F(WasmRunInterpreter, 2, 1) \ F(WasmRunInterpreter, 2, 1) \
F(WasmStackGuard, 0, 1) \ F(WasmStackGuard, 0, 1) \
F(WasmThrowCreate, 2, 1) \ F(WasmThrowCreate, 2, 1) \
F(WasmThrowTypeError, 0, 1) \ F(WasmThrowTypeError, 0, 1) \
F(WasmRefFunc, 1, 1) \ F(WasmRefFunc, 1, 1) \
F(WasmFunctionTableGet, 3, 1) \ F(WasmFunctionTableGet, 3, 1) \
F(WasmFunctionTableSet, 4, 1) \ F(WasmFunctionTableSet, 4, 1) \
F(WasmTableInit, 5, 1) \ F(WasmTableInit, 5, 1) \
F(WasmTableCopy, 5, 1) \ F(WasmTableCopy, 5, 1) \
F(WasmTableGrow, 3, 1) \ F(WasmTableGrow, 3, 1) \
F(WasmTableFill, 4, 1) \ F(WasmTableFill, 4, 1) \
F(WasmIndirectCallCheckSignatureAndGetTargetInstance, 3, 1) \ F(WasmIsValidAnyFuncValue, 1, 1) \
F(WasmIndirectCallGetTargetAddress, 2, 1) \
F(WasmIsValidAnyFuncValue, 1, 1) \
F(WasmCompileLazy, 2, 1) F(WasmCompileLazy, 2, 1)
#define FOR_EACH_INTRINSIC_RETURN_PAIR_IMPL(F, I) \ #define FOR_EACH_INTRINSIC_RETURN_PAIR_IMPL(F, I) \
......
...@@ -178,7 +178,7 @@ class InstanceBuilder { ...@@ -178,7 +178,7 @@ class InstanceBuilder {
// Initialize imported tables of type anyfunc. // Initialize imported tables of type anyfunc.
bool InitializeImportedIndirectFunctionTable( bool InitializeImportedIndirectFunctionTable(
Handle<WasmInstanceObject> instance, int import_index, Handle<WasmInstanceObject> instance, int table_index, int import_index,
Handle<WasmTableObject> table_object); Handle<WasmTableObject> table_object);
// Process a single imported table. // Process a single imported table.
...@@ -231,7 +231,7 @@ class InstanceBuilder { ...@@ -231,7 +231,7 @@ class InstanceBuilder {
// and globals. // and globals.
void ProcessExports(Handle<WasmInstanceObject> instance); void ProcessExports(Handle<WasmInstanceObject> instance);
void InitializeIndirectFunctionTable(Handle<WasmInstanceObject> instance); void InitializeIndirectFunctionTables(Handle<WasmInstanceObject> instance);
void LoadTableSegments(Handle<WasmInstanceObject> instance); void LoadTableSegments(Handle<WasmInstanceObject> instance);
...@@ -437,7 +437,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() { ...@@ -437,7 +437,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
// Initialize the indirect tables. // Initialize the indirect tables.
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
if (table_count > 0) { if (table_count > 0) {
InitializeIndirectFunctionTable(instance); InitializeIndirectFunctionTables(instance);
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
...@@ -895,14 +895,12 @@ bool InstanceBuilder::ProcessImportedFunction( ...@@ -895,14 +895,12 @@ bool InstanceBuilder::ProcessImportedFunction(
} }
bool InstanceBuilder::InitializeImportedIndirectFunctionTable( bool InstanceBuilder::InitializeImportedIndirectFunctionTable(
Handle<WasmInstanceObject> instance, int import_index, Handle<WasmInstanceObject> instance, int table_index, int import_index,
Handle<WasmTableObject> table_object) { Handle<WasmTableObject> table_object) {
int imported_table_size = table_object->entries().length(); int imported_table_size = table_object->entries().length();
// Allocate a new dispatch table. // Allocate a new dispatch table.
if (!instance->has_indirect_function_table()) { WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize( instance, table_index, imported_table_size);
instance, imported_table_size);
}
// Initialize the dispatch table with the (foreign) JS functions // Initialize the dispatch table with the (foreign) JS functions
// that are already in the table. // that are already in the table.
for (int i = 0; i < imported_table_size; ++i) { for (int i = 0; i < imported_table_size; ++i) {
...@@ -922,8 +920,8 @@ bool InstanceBuilder::InitializeImportedIndirectFunctionTable( ...@@ -922,8 +920,8 @@ bool InstanceBuilder::InitializeImportedIndirectFunctionTable(
if (is_null) continue; if (is_null) continue;
Handle<WasmJSFunction> js_function; Handle<WasmJSFunction> js_function;
if (maybe_js_function.ToHandle(&js_function)) { if (maybe_js_function.ToHandle(&js_function)) {
WasmInstanceObject::ImportWasmJSFunctionIntoTable(isolate_, instance, i, WasmInstanceObject::ImportWasmJSFunctionIntoTable(
js_function); isolate_, instance, table_index, i, js_function);
continue; continue;
} }
...@@ -937,7 +935,7 @@ bool InstanceBuilder::InitializeImportedIndirectFunctionTable( ...@@ -937,7 +935,7 @@ bool InstanceBuilder::InitializeImportedIndirectFunctionTable(
// Look up the signature's canonical id. If there is no canonical // Look up the signature's canonical id. If there is no canonical
// id, then the signature does not appear at all in this module, // id, then the signature does not appear at all in this module,
// so putting {-1} in the table will cause checks to always fail. // so putting {-1} in the table will cause checks to always fail.
IndirectFunctionTableEntry(instance, i) IndirectFunctionTableEntry(instance, table_index, i)
.Set(module_->signature_map.Find(*sig), target_instance, .Set(module_->signature_map.Find(*sig), target_instance,
function_index); function_index);
} }
...@@ -992,10 +990,9 @@ bool InstanceBuilder::ProcessImportedTable(Handle<WasmInstanceObject> instance, ...@@ -992,10 +990,9 @@ bool InstanceBuilder::ProcessImportedTable(Handle<WasmInstanceObject> instance,
return false; return false;
} }
// The indirect function table only exists for table 0. if (table.type == kWasmAnyFunc &&
if (table.type == kWasmAnyFunc && table_index == 0 && !InitializeImportedIndirectFunctionTable(instance, table_index,
!InitializeImportedIndirectFunctionTable(instance, import_index, import_index, table_object)) {
table_object)) {
return false; return false;
} }
...@@ -1609,15 +1606,15 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) { ...@@ -1609,15 +1606,15 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
} }
} }
void InstanceBuilder::InitializeIndirectFunctionTable( void InstanceBuilder::InitializeIndirectFunctionTables(
Handle<WasmInstanceObject> instance) { Handle<WasmInstanceObject> instance) {
DCHECK_GT(module_->tables.size(), 0); for (int i = 0; i < static_cast<int>(module_->tables.size()); ++i) {
const WasmTable& table = module_->tables[i];
const WasmTable& table = module_->tables[0]; if (table.type == kWasmAnyFunc) {
WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
if (!instance->has_indirect_function_table() && table.type == kWasmAnyFunc) { instance, i, table.initial_size);
WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize( }
instance, table.initial_size);
} }
} }
...@@ -1640,7 +1637,9 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance, ...@@ -1640,7 +1637,9 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
if (func_index == WasmElemSegment::kNullIndex) { if (func_index == WasmElemSegment::kNullIndex) {
if (table_object->type() == kWasmAnyFunc) { if (table_object->type() == kWasmAnyFunc) {
IndirectFunctionTableEntry(instance, entry_index).clear(); IndirectFunctionTableEntry(instance, elem_segment.table_index,
entry_index)
.clear();
} }
WasmTableObject::Set(isolate, table_object, entry_index, WasmTableObject::Set(isolate, table_object, entry_index,
isolate->factory()->null_value()); isolate->factory()->null_value());
...@@ -1649,13 +1648,11 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance, ...@@ -1649,13 +1648,11 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
const WasmFunction* function = &module->functions[func_index]; const WasmFunction* function = &module->functions[func_index];
// Update the local dispatch table first if necessary. We only have to // Update the local dispatch table first if necessary.
// update the dispatch table if the first table of the instance is changed. if (table_object->type() == kWasmAnyFunc) {
// For all other tables, function calls do not use a dispatch table at
// the moment.
if (elem_segment.table_index == 0 && table_object->type() == kWasmAnyFunc) {
uint32_t sig_id = module->signature_ids[function->sig_index]; uint32_t sig_id = module->signature_ids[function->sig_index];
IndirectFunctionTableEntry(instance, entry_index) IndirectFunctionTableEntry(instance, elem_segment.table_index,
entry_index)
.Set(sig_id, instance, func_index); .Set(sig_id, instance, func_index);
} }
......
...@@ -3687,7 +3687,7 @@ class ThreadImpl { ...@@ -3687,7 +3687,7 @@ class ThreadImpl {
return {ExternalCallResult::INVALID_FUNC}; return {ExternalCallResult::INVALID_FUNC};
} }
IndirectFunctionTableEntry entry(instance_object_, entry_index); IndirectFunctionTableEntry entry(instance_object_, 0, entry_index);
// Signature check. // Signature check.
if (entry.sig_id() != static_cast<int32_t>(expected_sig_id)) { if (entry.sig_id() != static_cast<int32_t>(expected_sig_id)) {
return {ExternalCallResult::SIGNATURE_MISMATCH}; return {ExternalCallResult::SIGNATURE_MISMATCH};
......
...@@ -267,10 +267,6 @@ ACCESSORS(WasmInstanceObject, centry_stub, Code, kCEntryStubOffset) ...@@ -267,10 +267,6 @@ ACCESSORS(WasmInstanceObject, centry_stub, Code, kCEntryStubOffset)
OPTIONAL_ACCESSORS(WasmInstanceObject, wasm_exported_functions, FixedArray, OPTIONAL_ACCESSORS(WasmInstanceObject, wasm_exported_functions, FixedArray,
kWasmExportedFunctionsOffset) kWasmExportedFunctionsOffset)
inline bool WasmInstanceObject::has_indirect_function_table() {
return indirect_function_table_sig_ids() != nullptr;
}
void WasmInstanceObject::clear_padding() { void WasmInstanceObject::clear_padding() {
if (FIELD_SIZE(kOptionalPaddingOffset) != 0) { if (FIELD_SIZE(kOptionalPaddingOffset) != 0) {
DCHECK_EQ(4, FIELD_SIZE(kOptionalPaddingOffset)); DCHECK_EQ(4, FIELD_SIZE(kOptionalPaddingOffset));
...@@ -280,10 +276,29 @@ void WasmInstanceObject::clear_padding() { ...@@ -280,10 +276,29 @@ void WasmInstanceObject::clear_padding() {
} }
IndirectFunctionTableEntry::IndirectFunctionTableEntry( IndirectFunctionTableEntry::IndirectFunctionTableEntry(
Handle<WasmInstanceObject> instance, int index) Handle<WasmInstanceObject> instance, int table_index, int entry_index)
: instance_(instance), index_(index) { : instance_(table_index == 0 ? instance
DCHECK_GE(index, 0); : Handle<WasmInstanceObject>::null()),
DCHECK_LT(index, instance->indirect_function_table_size()); table_(table_index != 0
? handle(WasmIndirectFunctionTable::cast(
instance->indirect_function_tables().get(
table_index)),
instance->GetIsolate())
: Handle<WasmIndirectFunctionTable>::null()),
index_(entry_index) {
DCHECK_GE(entry_index, 0);
DCHECK_LT(entry_index, table_index == 0
? instance->indirect_function_table_size()
: table_->size());
}
IndirectFunctionTableEntry::IndirectFunctionTableEntry(
Handle<WasmIndirectFunctionTable> table, int entry_index)
: instance_(Handle<WasmInstanceObject>::null()),
table_(table),
index_(entry_index) {
DCHECK_GE(entry_index, 0);
DCHECK_LT(entry_index, table_->size());
} }
ImportedFunctionEntry::ImportedFunctionEntry( ImportedFunctionEntry::ImportedFunctionEntry(
......
This diff is collapsed.
...@@ -44,6 +44,7 @@ class WasmExportedFunction; ...@@ -44,6 +44,7 @@ class WasmExportedFunction;
class WasmInstanceObject; class WasmInstanceObject;
class WasmJSFunction; class WasmJSFunction;
class WasmModuleObject; class WasmModuleObject;
class WasmIndirectFunctionTable;
template <class CppType> template <class CppType>
class Managed; class Managed;
...@@ -61,7 +62,11 @@ class Managed; ...@@ -61,7 +62,11 @@ class Managed;
// - target = entrypoint to Wasm code or import wrapper code // - target = entrypoint to Wasm code or import wrapper code
class IndirectFunctionTableEntry { class IndirectFunctionTableEntry {
public: public:
inline IndirectFunctionTableEntry(Handle<WasmInstanceObject>, int index); inline IndirectFunctionTableEntry(Handle<WasmInstanceObject>, int table_index,
int entry_index);
inline IndirectFunctionTableEntry(Handle<WasmIndirectFunctionTable> table,
int entry_index);
void clear(); void clear();
V8_EXPORT_PRIVATE void Set(int sig_id, V8_EXPORT_PRIVATE void Set(int sig_id,
...@@ -77,6 +82,7 @@ class IndirectFunctionTableEntry { ...@@ -77,6 +82,7 @@ class IndirectFunctionTableEntry {
private: private:
Handle<WasmInstanceObject> const instance_; Handle<WasmInstanceObject> const instance_;
Handle<WasmIndirectFunctionTable> const table_;
int const index_; int const index_;
}; };
...@@ -552,9 +558,8 @@ class WasmInstanceObject : public JSObject { ...@@ -552,9 +558,8 @@ class WasmInstanceObject : public JSObject {
V8_EXPORT_PRIVATE const wasm::WasmModule* module(); V8_EXPORT_PRIVATE const wasm::WasmModule* module();
V8_EXPORT_PRIVATE static bool EnsureIndirectFunctionTableWithMinimumSize( V8_EXPORT_PRIVATE static bool EnsureIndirectFunctionTableWithMinimumSize(
Handle<WasmInstanceObject> instance, uint32_t minimum_size); Handle<WasmInstanceObject> instance, int table_index,
uint32_t minimum_size);
bool has_indirect_function_table();
V8_EXPORT_PRIVATE void SetRawMemory(byte* mem_start, size_t mem_size); V8_EXPORT_PRIVATE void SetRawMemory(byte* mem_start, size_t mem_size);
...@@ -568,6 +573,10 @@ class WasmInstanceObject : public JSObject { ...@@ -568,6 +573,10 @@ class WasmInstanceObject : public JSObject {
Address GetCallTarget(uint32_t func_index); Address GetCallTarget(uint32_t func_index);
static int IndirectFunctionTableSize(Isolate* isolate,
Handle<WasmInstanceObject> instance,
uint32_t table_index);
// Copies table entries. Returns {false} if the ranges are out-of-bounds. // Copies table entries. Returns {false} if the ranges are out-of-bounds.
static bool CopyTableEntries(Isolate* isolate, static bool CopyTableEntries(Isolate* isolate,
Handle<WasmInstanceObject> instance, Handle<WasmInstanceObject> instance,
...@@ -609,7 +618,7 @@ class WasmInstanceObject : public JSObject { ...@@ -609,7 +618,7 @@ class WasmInstanceObject : public JSObject {
// {WasmJSFunction} is instance-independent and just wraps a JS callable. // {WasmJSFunction} is instance-independent and just wraps a JS callable.
static void ImportWasmJSFunctionIntoTable(Isolate* isolate, static void ImportWasmJSFunctionIntoTable(Isolate* isolate,
Handle<WasmInstanceObject> instance, Handle<WasmInstanceObject> instance,
int table_index, int table_index, int entry_index,
Handle<WasmJSFunction> js_function); Handle<WasmJSFunction> js_function);
OBJECT_CONSTRUCTORS(WasmInstanceObject, JSObject); OBJECT_CONSTRUCTORS(WasmInstanceObject, JSObject);
...@@ -734,6 +743,8 @@ class WasmIndirectFunctionTable : public Struct { ...@@ -734,6 +743,8 @@ class WasmIndirectFunctionTable : public Struct {
DECL_ACCESSORS(refs, FixedArray) DECL_ACCESSORS(refs, FixedArray)
static Handle<WasmIndirectFunctionTable> New(Isolate* isolate, uint32_t size); static Handle<WasmIndirectFunctionTable> New(Isolate* isolate, uint32_t size);
static void Resize(Isolate* isolate, Handle<WasmIndirectFunctionTable> table,
uint32_t new_size);
DECL_CAST(WasmIndirectFunctionTable) DECL_CAST(WasmIndirectFunctionTable)
......
...@@ -172,7 +172,7 @@ void TestingModuleBuilder::AddIndirectFunctionTable( ...@@ -172,7 +172,7 @@ void TestingModuleBuilder::AddIndirectFunctionTable(
table.has_maximum_size = true; table.has_maximum_size = true;
table.type = kWasmAnyFunc; table.type = kWasmAnyFunc;
WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize( WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
instance_object(), table_size); instance_object(), 0, table_size);
Handle<WasmTableObject> table_obj = Handle<WasmTableObject> table_obj =
WasmTableObject::New(isolate_, table.type, table.initial_size, WasmTableObject::New(isolate_, table.type, table.initial_size,
table.has_maximum_size, table.maximum_size, nullptr); table.has_maximum_size, table.maximum_size, nullptr);
...@@ -184,7 +184,7 @@ void TestingModuleBuilder::AddIndirectFunctionTable( ...@@ -184,7 +184,7 @@ void TestingModuleBuilder::AddIndirectFunctionTable(
for (uint32_t i = 0; i < table_size; ++i) { for (uint32_t i = 0; i < table_size; ++i) {
WasmFunction& function = test_module_->functions[function_indexes[i]]; WasmFunction& function = test_module_->functions[function_indexes[i]];
int sig_id = test_module_->signature_map.Find(*function.sig); int sig_id = test_module_->signature_map.Find(*function.sig);
IndirectFunctionTableEntry(instance, i) IndirectFunctionTableEntry(instance, 0, i)
.Set(sig_id, instance, function.func_index); .Set(sig_id, instance, function.func_index);
WasmTableObject::SetFunctionTablePlaceholder( WasmTableObject::SetFunctionTablePlaceholder(
isolate_, table_obj, i, instance_object_, function_indexes[i]); isolate_, table_obj, i, instance_object_, function_indexes[i]);
......
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