[wasm] Support {WebAssembly.Function} in tables.
This adds preliminary support for storing constructed WebAssembly functions in tables. Note that for now only tables at index #0 are supported, extending it to other tables indexes will be done as a follow-up. R=ahaas@chromium.org TEST=mjsunit/wasm/type-reflection BUG=v8:7742 Change-Id: I9aa07813e07f0ceb4eafe37af412b45c7d235722 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1640209 Commit-Queue: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Cr-Commit-Position: refs/heads/master@{#62210}
This commit is contained in:
parent
ac79b539ec
commit
f066d764cc
@ -887,6 +887,7 @@ extern class WasmExportedFunctionData extends Struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern class WasmJSFunctionData extends Struct {
|
extern class WasmJSFunctionData extends Struct {
|
||||||
|
callable: JSReceiver;
|
||||||
wrapper_code: Code;
|
wrapper_code: Code;
|
||||||
serialized_return_count: Smi;
|
serialized_return_count: Smi;
|
||||||
serialized_parameter_count: Smi;
|
serialized_parameter_count: Smi;
|
||||||
|
@ -498,9 +498,10 @@ RUNTIME_FUNCTION(Runtime_WasmIndirectCallCheckSignatureAndGetTargetInstance) {
|
|||||||
bool is_null;
|
bool is_null;
|
||||||
MaybeHandle<WasmInstanceObject> maybe_target_instance;
|
MaybeHandle<WasmInstanceObject> maybe_target_instance;
|
||||||
int function_index;
|
int function_index;
|
||||||
|
MaybeHandle<WasmJSFunction> maybe_js_function;
|
||||||
WasmTableObject::GetFunctionTableEntry(
|
WasmTableObject::GetFunctionTableEntry(
|
||||||
isolate, table_obj, entry_index, &is_valid, &is_null,
|
isolate, table_obj, entry_index, &is_valid, &is_null,
|
||||||
&maybe_target_instance, &function_index);
|
&maybe_target_instance, &function_index, &maybe_js_function);
|
||||||
|
|
||||||
CHECK(is_valid);
|
CHECK(is_valid);
|
||||||
if (is_null) {
|
if (is_null) {
|
||||||
@ -510,6 +511,8 @@ RUNTIME_FUNCTION(Runtime_WasmIndirectCallCheckSignatureAndGetTargetInstance) {
|
|||||||
// performed before a signature, according to the spec.
|
// performed before a signature, according to the spec.
|
||||||
return ThrowWasmError(isolate, MessageTemplate::kWasmTrapFuncSigMismatch);
|
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.
|
// Now we do the signature check.
|
||||||
Handle<WasmInstanceObject> target_instance =
|
Handle<WasmInstanceObject> target_instance =
|
||||||
@ -555,15 +558,18 @@ RUNTIME_FUNCTION(Runtime_WasmIndirectCallGetTargetAddress) {
|
|||||||
bool is_null;
|
bool is_null;
|
||||||
MaybeHandle<WasmInstanceObject> maybe_target_instance;
|
MaybeHandle<WasmInstanceObject> maybe_target_instance;
|
||||||
int function_index;
|
int function_index;
|
||||||
|
MaybeHandle<WasmJSFunction> maybe_js_function;
|
||||||
WasmTableObject::GetFunctionTableEntry(
|
WasmTableObject::GetFunctionTableEntry(
|
||||||
isolate, table_obj, entry_index, &is_valid, &is_null,
|
isolate, table_obj, entry_index, &is_valid, &is_null,
|
||||||
&maybe_target_instance, &function_index);
|
&maybe_target_instance, &function_index, &maybe_js_function);
|
||||||
|
|
||||||
CHECK(is_valid);
|
CHECK(is_valid);
|
||||||
// The null-check should already have been done in
|
// The null-check should already have been done in
|
||||||
// Runtime_WasmIndirectCallCheckSignatureAndGetTargetInstance. That runtime
|
// Runtime_WasmIndirectCallCheckSignatureAndGetTargetInstance. That runtime
|
||||||
// function should always be called first.
|
// function should always be called first.
|
||||||
CHECK(!is_null);
|
CHECK(!is_null);
|
||||||
|
// TODO(7742): Test and implement indirect calls for non-zero tables.
|
||||||
|
CHECK(maybe_js_function.is_null());
|
||||||
|
|
||||||
Handle<WasmInstanceObject> target_instance =
|
Handle<WasmInstanceObject> target_instance =
|
||||||
maybe_target_instance.ToHandleChecked();
|
maybe_target_instance.ToHandleChecked();
|
||||||
|
@ -919,15 +919,22 @@ bool InstanceBuilder::InitializeImportedIndirectFunctionTable(
|
|||||||
bool is_null;
|
bool is_null;
|
||||||
MaybeHandle<WasmInstanceObject> maybe_target_instance;
|
MaybeHandle<WasmInstanceObject> maybe_target_instance;
|
||||||
int function_index;
|
int function_index;
|
||||||
|
MaybeHandle<WasmJSFunction> maybe_js_function;
|
||||||
WasmTableObject::GetFunctionTableEntry(isolate_, table_object, i, &is_valid,
|
WasmTableObject::GetFunctionTableEntry(isolate_, table_object, i, &is_valid,
|
||||||
&is_null, &maybe_target_instance,
|
&is_null, &maybe_target_instance,
|
||||||
&function_index);
|
&function_index, &maybe_js_function);
|
||||||
if (!is_valid) {
|
if (!is_valid) {
|
||||||
thrower_->LinkError("table import %d[%d] is not a wasm function",
|
thrower_->LinkError("table import %d[%d] is not a wasm function",
|
||||||
import_index, i);
|
import_index, i);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (is_null) continue;
|
if (is_null) continue;
|
||||||
|
Handle<WasmJSFunction> js_function;
|
||||||
|
if (maybe_js_function.ToHandle(&js_function)) {
|
||||||
|
WasmInstanceObject::ImportWasmJSFunctionIntoTable(isolate_, instance, i,
|
||||||
|
js_function);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Handle<WasmInstanceObject> target_instance =
|
Handle<WasmInstanceObject> target_instance =
|
||||||
maybe_target_instance.ToHandleChecked();
|
maybe_target_instance.ToHandleChecked();
|
||||||
|
@ -323,6 +323,7 @@ SMI_ACCESSORS(WasmJSFunctionData, serialized_parameter_count,
|
|||||||
kSerializedParameterCountOffset)
|
kSerializedParameterCountOffset)
|
||||||
ACCESSORS(WasmJSFunctionData, serialized_signature, PodArray<wasm::ValueType>,
|
ACCESSORS(WasmJSFunctionData, serialized_signature, PodArray<wasm::ValueType>,
|
||||||
kSerializedSignatureOffset)
|
kSerializedSignatureOffset)
|
||||||
|
ACCESSORS(WasmJSFunctionData, callable, JSReceiver, kCallableOffset)
|
||||||
ACCESSORS(WasmJSFunctionData, wrapper_code, Code, kWrapperCodeOffset)
|
ACCESSORS(WasmJSFunctionData, wrapper_code, Code, kWrapperCodeOffset)
|
||||||
|
|
||||||
// WasmCapiFunction
|
// WasmCapiFunction
|
||||||
|
@ -895,10 +895,11 @@ bool WasmTableObject::IsValidElement(Isolate* isolate,
|
|||||||
Handle<Object> entry) {
|
Handle<Object> entry) {
|
||||||
// Anyref tables take everything.
|
// Anyref tables take everything.
|
||||||
if (table->type() == wasm::kWasmAnyRef) return true;
|
if (table->type() == wasm::kWasmAnyRef) return true;
|
||||||
// Anyfunc tables can store {null} or {WasmExportedFunction} or
|
// Anyfunc tables can store {null}, {WasmExportedFunction}, {WasmJSFunction},
|
||||||
// {WasmCapiFunction} objects.
|
// or {WasmCapiFunction} objects.
|
||||||
if (entry->IsNull(isolate)) return true;
|
if (entry->IsNull(isolate)) return true;
|
||||||
return WasmExportedFunction::IsWasmExportedFunction(*entry) ||
|
return WasmExportedFunction::IsWasmExportedFunction(*entry) ||
|
||||||
|
WasmJSFunction::IsWasmJSFunction(*entry) ||
|
||||||
WasmCapiFunction::IsWasmCapiFunction(*entry);
|
WasmCapiFunction::IsWasmCapiFunction(*entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -932,6 +933,9 @@ void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
|
|||||||
DCHECK_NOT_NULL(wasm_function->sig);
|
DCHECK_NOT_NULL(wasm_function->sig);
|
||||||
UpdateDispatchTables(isolate, table, entry_index, wasm_function->sig,
|
UpdateDispatchTables(isolate, table, entry_index, wasm_function->sig,
|
||||||
target_instance, func_index);
|
target_instance, func_index);
|
||||||
|
} else if (WasmJSFunction::IsWasmJSFunction(*entry)) {
|
||||||
|
UpdateDispatchTables(isolate, table, entry_index,
|
||||||
|
Handle<WasmJSFunction>::cast(entry));
|
||||||
} else {
|
} else {
|
||||||
DCHECK(WasmCapiFunction::IsWasmCapiFunction(*entry));
|
DCHECK(WasmCapiFunction::IsWasmCapiFunction(*entry));
|
||||||
UpdateDispatchTables(isolate, table, entry_index,
|
UpdateDispatchTables(isolate, table, entry_index,
|
||||||
@ -1022,6 +1026,33 @@ void WasmTableObject::UpdateDispatchTables(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WasmTableObject::UpdateDispatchTables(Isolate* isolate,
|
||||||
|
Handle<WasmTableObject> table,
|
||||||
|
int entry_index,
|
||||||
|
Handle<WasmJSFunction> function) {
|
||||||
|
// We simply need to update the IFTs for each instance that imports
|
||||||
|
// this table.
|
||||||
|
Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate);
|
||||||
|
DCHECK_EQ(0, dispatch_tables->length() % kDispatchTableNumElements);
|
||||||
|
|
||||||
|
for (int i = 0; i < dispatch_tables->length();
|
||||||
|
i += kDispatchTableNumElements) {
|
||||||
|
int table_index =
|
||||||
|
Smi::cast(dispatch_tables->get(i + kDispatchTableIndexOffset)).value();
|
||||||
|
if (table_index > 0) {
|
||||||
|
// Only table 0 has a dispatch table in the instance at the moment.
|
||||||
|
// TODO(ahaas): Introduce dispatch tables for the other tables as well.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Handle<WasmInstanceObject> instance(
|
||||||
|
WasmInstanceObject::cast(
|
||||||
|
dispatch_tables->get(i + kDispatchTableInstanceOffset)),
|
||||||
|
isolate);
|
||||||
|
WasmInstanceObject::ImportWasmJSFunctionIntoTable(isolate, instance,
|
||||||
|
entry_index, function);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WasmTableObject::UpdateDispatchTables(
|
void WasmTableObject::UpdateDispatchTables(
|
||||||
Isolate* isolate, Handle<WasmTableObject> table, int entry_index,
|
Isolate* isolate, Handle<WasmTableObject> table, int entry_index,
|
||||||
Handle<WasmCapiFunction> capi_function) {
|
Handle<WasmCapiFunction> capi_function) {
|
||||||
@ -1118,7 +1149,7 @@ void WasmTableObject::SetFunctionTablePlaceholder(
|
|||||||
void WasmTableObject::GetFunctionTableEntry(
|
void WasmTableObject::GetFunctionTableEntry(
|
||||||
Isolate* isolate, Handle<WasmTableObject> table, int entry_index,
|
Isolate* isolate, Handle<WasmTableObject> table, int entry_index,
|
||||||
bool* is_valid, bool* is_null, MaybeHandle<WasmInstanceObject>* instance,
|
bool* is_valid, bool* is_null, MaybeHandle<WasmInstanceObject>* instance,
|
||||||
int* function_index) {
|
int* function_index, MaybeHandle<WasmJSFunction>* maybe_js_function) {
|
||||||
DCHECK_EQ(table->type(), wasm::kWasmAnyFunc);
|
DCHECK_EQ(table->type(), wasm::kWasmAnyFunc);
|
||||||
DCHECK_LT(entry_index, table->entries().length());
|
DCHECK_LT(entry_index, table->entries().length());
|
||||||
// We initialize {is_valid} with {true}. We may change it later.
|
// We initialize {is_valid} with {true}. We may change it later.
|
||||||
@ -1132,11 +1163,19 @@ void WasmTableObject::GetFunctionTableEntry(
|
|||||||
auto target_func = Handle<WasmExportedFunction>::cast(element);
|
auto target_func = Handle<WasmExportedFunction>::cast(element);
|
||||||
*instance = handle(target_func->instance(), isolate);
|
*instance = handle(target_func->instance(), isolate);
|
||||||
*function_index = target_func->function_index();
|
*function_index = target_func->function_index();
|
||||||
|
*maybe_js_function = MaybeHandle<WasmJSFunction>();
|
||||||
return;
|
return;
|
||||||
} else if (element->IsTuple2()) {
|
}
|
||||||
|
if (WasmJSFunction::IsWasmJSFunction(*element)) {
|
||||||
|
*instance = MaybeHandle<WasmInstanceObject>();
|
||||||
|
*maybe_js_function = Handle<WasmJSFunction>::cast(element);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (element->IsTuple2()) {
|
||||||
auto tuple = Handle<Tuple2>::cast(element);
|
auto tuple = Handle<Tuple2>::cast(element);
|
||||||
*instance = handle(WasmInstanceObject::cast(tuple->value1()), isolate);
|
*instance = handle(WasmInstanceObject::cast(tuple->value1()), isolate);
|
||||||
*function_index = Smi::cast(tuple->value2()).value();
|
*function_index = Smi::cast(tuple->value2()).value();
|
||||||
|
*maybe_js_function = MaybeHandle<WasmJSFunction>();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*is_valid = false;
|
*is_valid = false;
|
||||||
@ -1860,6 +1899,53 @@ void WasmInstanceObject::SetWasmExportedFunction(
|
|||||||
functions->set(index, *val);
|
functions->set(index, *val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void WasmInstanceObject::ImportWasmJSFunctionIntoTable(
|
||||||
|
Isolate* isolate, Handle<WasmInstanceObject> instance, int table_index,
|
||||||
|
Handle<WasmJSFunction> js_function) {
|
||||||
|
// Deserialize the signature encapsulated with the {WasmJSFunction}.
|
||||||
|
// Note that {SignatureMap::Find} may return {-1} if the signature is
|
||||||
|
// not found; it will simply never match any check.
|
||||||
|
Zone zone(isolate->allocator(), ZONE_NAME);
|
||||||
|
wasm::FunctionSig* sig = js_function->GetSignature(&zone);
|
||||||
|
auto sig_id = instance->module()->signature_map.Find(*sig);
|
||||||
|
|
||||||
|
// Compile a wrapper for the target callable.
|
||||||
|
Handle<JSReceiver> callable(js_function->GetCallable(), isolate);
|
||||||
|
wasm::WasmCodeRefScope code_ref_scope;
|
||||||
|
Address call_target = kNullAddress;
|
||||||
|
if (sig_id >= 0) {
|
||||||
|
wasm::NativeModule* native_module =
|
||||||
|
instance->module_object().native_module();
|
||||||
|
// TODO(mstarzinger): Cache and reuse wrapper code.
|
||||||
|
const wasm::WasmFeatures enabled = native_module->enabled_features();
|
||||||
|
compiler::WasmImportCallKind kind =
|
||||||
|
compiler::GetWasmImportCallKind(callable, sig, enabled.bigint);
|
||||||
|
DCHECK_NE(compiler::WasmImportCallKind::kLinkError, kind);
|
||||||
|
wasm::CompilationEnv env = native_module->CreateCompilationEnv();
|
||||||
|
wasm::WasmCompilationResult result = compiler::CompileWasmImportCallWrapper(
|
||||||
|
isolate->wasm_engine(), &env, kind, sig, false);
|
||||||
|
std::unique_ptr<wasm::WasmCode> wasm_code = native_module->AddCode(
|
||||||
|
result.func_index, result.code_desc, result.frame_slot_count,
|
||||||
|
result.tagged_parameter_slots, std::move(result.protected_instructions),
|
||||||
|
std::move(result.source_positions), GetCodeKind(result),
|
||||||
|
wasm::ExecutionTier::kNone);
|
||||||
|
wasm::WasmCode* published_code =
|
||||||
|
native_module->PublishCode(std::move(wasm_code));
|
||||||
|
isolate->counters()->wasm_generated_code_size()->Increment(
|
||||||
|
published_code->instructions().length());
|
||||||
|
isolate->counters()->wasm_reloc_size()->Increment(
|
||||||
|
published_code->reloc_info().length());
|
||||||
|
call_target = published_code->instruction_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the dispatch table.
|
||||||
|
Handle<Tuple2> tuple =
|
||||||
|
isolate->factory()->NewTuple2(instance, callable, AllocationType::kOld);
|
||||||
|
IndirectFunctionTableEntry(instance, table_index)
|
||||||
|
.Set(sig_id, call_target, *tuple);
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
Handle<WasmExceptionObject> WasmExceptionObject::New(
|
Handle<WasmExceptionObject> WasmExceptionObject::New(
|
||||||
Isolate* isolate, const wasm::FunctionSig* sig,
|
Isolate* isolate, const wasm::FunctionSig* sig,
|
||||||
@ -2158,6 +2244,7 @@ Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
|
|||||||
function_data->set_serialized_return_count(return_count);
|
function_data->set_serialized_return_count(return_count);
|
||||||
function_data->set_serialized_parameter_count(parameter_count);
|
function_data->set_serialized_parameter_count(parameter_count);
|
||||||
function_data->set_serialized_signature(*serialized_sig);
|
function_data->set_serialized_signature(*serialized_sig);
|
||||||
|
function_data->set_callable(*callable);
|
||||||
// TODO(7742): Make this callable by using a proper wrapper code.
|
// TODO(7742): Make this callable by using a proper wrapper code.
|
||||||
function_data->set_wrapper_code(
|
function_data->set_wrapper_code(
|
||||||
isolate->builtins()->builtin(Builtins::kIllegal));
|
isolate->builtins()->builtin(Builtins::kIllegal));
|
||||||
@ -2172,6 +2259,10 @@ Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
|
|||||||
return Handle<WasmJSFunction>::cast(js_function);
|
return Handle<WasmJSFunction>::cast(js_function);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSReceiver WasmJSFunction::GetCallable() const {
|
||||||
|
return shared().wasm_js_function_data().callable();
|
||||||
|
}
|
||||||
|
|
||||||
wasm::FunctionSig* WasmJSFunction::GetSignature(Zone* zone) {
|
wasm::FunctionSig* WasmJSFunction::GetSignature(Zone* zone) {
|
||||||
WasmJSFunctionData function_data = shared().wasm_js_function_data();
|
WasmJSFunctionData function_data = shared().wasm_js_function_data();
|
||||||
int sig_size = function_data.serialized_signature().length();
|
int sig_size = function_data.serialized_signature().length();
|
||||||
|
@ -40,9 +40,10 @@ class SeqOneByteString;
|
|||||||
class WasmCapiFunction;
|
class WasmCapiFunction;
|
||||||
class WasmDebugInfo;
|
class WasmDebugInfo;
|
||||||
class WasmExceptionTag;
|
class WasmExceptionTag;
|
||||||
class WasmInstanceObject;
|
|
||||||
class WasmModuleObject;
|
|
||||||
class WasmExportedFunction;
|
class WasmExportedFunction;
|
||||||
|
class WasmInstanceObject;
|
||||||
|
class WasmJSFunction;
|
||||||
|
class WasmModuleObject;
|
||||||
|
|
||||||
template <class CppType>
|
template <class CppType>
|
||||||
class Managed;
|
class Managed;
|
||||||
@ -292,11 +293,16 @@ class V8_EXPORT_PRIVATE WasmTableObject : public JSObject {
|
|||||||
static void Fill(Isolate* isolate, Handle<WasmTableObject> table,
|
static void Fill(Isolate* isolate, Handle<WasmTableObject> table,
|
||||||
uint32_t start, Handle<Object> entry, uint32_t count);
|
uint32_t start, Handle<Object> entry, uint32_t count);
|
||||||
|
|
||||||
|
// TODO(mstarzinger): Unify these three methods into one.
|
||||||
static void UpdateDispatchTables(Isolate* isolate,
|
static void UpdateDispatchTables(Isolate* isolate,
|
||||||
Handle<WasmTableObject> table,
|
Handle<WasmTableObject> table,
|
||||||
int entry_index, wasm::FunctionSig* sig,
|
int entry_index, wasm::FunctionSig* sig,
|
||||||
Handle<WasmInstanceObject> target_instance,
|
Handle<WasmInstanceObject> target_instance,
|
||||||
int target_func_index);
|
int target_func_index);
|
||||||
|
static void UpdateDispatchTables(Isolate* isolate,
|
||||||
|
Handle<WasmTableObject> table,
|
||||||
|
int entry_index,
|
||||||
|
Handle<WasmJSFunction> function);
|
||||||
static void UpdateDispatchTables(Isolate* isolate,
|
static void UpdateDispatchTables(Isolate* isolate,
|
||||||
Handle<WasmTableObject> table,
|
Handle<WasmTableObject> table,
|
||||||
int entry_index,
|
int entry_index,
|
||||||
@ -312,14 +318,12 @@ class V8_EXPORT_PRIVATE WasmTableObject : public JSObject {
|
|||||||
int func_index);
|
int func_index);
|
||||||
|
|
||||||
// This function reads the content of a function table entry and returns it
|
// This function reads the content of a function table entry and returns it
|
||||||
// through the out parameters {is_valid}, {is_null}, {instance}, and
|
// through the out parameters {is_valid}, {is_null}, {instance},
|
||||||
// {function_index}.
|
// {function_index}, and {maybe_js_function}.
|
||||||
static void GetFunctionTableEntry(Isolate* isolate,
|
static void GetFunctionTableEntry(
|
||||||
Handle<WasmTableObject> table,
|
Isolate* isolate, Handle<WasmTableObject> table, int entry_index,
|
||||||
int entry_index, bool* is_valid,
|
bool* is_valid, bool* is_null, MaybeHandle<WasmInstanceObject>* instance,
|
||||||
bool* is_null,
|
int* function_index, MaybeHandle<WasmJSFunction>* maybe_js_function);
|
||||||
MaybeHandle<WasmInstanceObject>* instance,
|
|
||||||
int* function_index);
|
|
||||||
|
|
||||||
OBJECT_CONSTRUCTORS(WasmTableObject, JSObject);
|
OBJECT_CONSTRUCTORS(WasmTableObject, JSObject);
|
||||||
};
|
};
|
||||||
@ -597,6 +601,14 @@ class WasmInstanceObject : public JSObject {
|
|||||||
int index,
|
int index,
|
||||||
Handle<WasmExportedFunction> val);
|
Handle<WasmExportedFunction> val);
|
||||||
|
|
||||||
|
// Imports a constructed {WasmJSFunction} into the indirect function table of
|
||||||
|
// this instance. Note that this might trigger wrapper compilation, since a
|
||||||
|
// {WasmJSFunction} is instance-independent and just wraps a JS callable.
|
||||||
|
static void ImportWasmJSFunctionIntoTable(Isolate* isolate,
|
||||||
|
Handle<WasmInstanceObject> instance,
|
||||||
|
int table_index,
|
||||||
|
Handle<WasmJSFunction> js_function);
|
||||||
|
|
||||||
OBJECT_CONSTRUCTORS(WasmInstanceObject, JSObject);
|
OBJECT_CONSTRUCTORS(WasmInstanceObject, JSObject);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -681,6 +693,7 @@ class WasmJSFunction : public JSFunction {
|
|||||||
static Handle<WasmJSFunction> New(Isolate* isolate, wasm::FunctionSig* sig,
|
static Handle<WasmJSFunction> New(Isolate* isolate, wasm::FunctionSig* sig,
|
||||||
Handle<JSReceiver> callable);
|
Handle<JSReceiver> callable);
|
||||||
|
|
||||||
|
JSReceiver GetCallable() const;
|
||||||
// Deserializes the signature of this function using the provided zone. Note
|
// Deserializes the signature of this function using the provided zone. Note
|
||||||
// that lifetime of the signature is hence directly coupled to the zone.
|
// that lifetime of the signature is hence directly coupled to the zone.
|
||||||
wasm::FunctionSig* GetSignature(Zone* zone);
|
wasm::FunctionSig* GetSignature(Zone* zone);
|
||||||
@ -761,6 +774,7 @@ class WasmJSFunctionData : public Struct {
|
|||||||
DECL_INT_ACCESSORS(serialized_return_count)
|
DECL_INT_ACCESSORS(serialized_return_count)
|
||||||
DECL_INT_ACCESSORS(serialized_parameter_count)
|
DECL_INT_ACCESSORS(serialized_parameter_count)
|
||||||
DECL_ACCESSORS(serialized_signature, PodArray<wasm::ValueType>)
|
DECL_ACCESSORS(serialized_signature, PodArray<wasm::ValueType>)
|
||||||
|
DECL_ACCESSORS(callable, JSReceiver)
|
||||||
DECL_ACCESSORS(wrapper_code, Code)
|
DECL_ACCESSORS(wrapper_code, Code)
|
||||||
|
|
||||||
DECL_CAST(WasmJSFunctionData)
|
DECL_CAST(WasmJSFunctionData)
|
||||||
|
@ -270,3 +270,26 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
|
|||||||
assertEquals(expected, type)
|
assertEquals(expected, type)
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
(function TestFunctionTableSetAndCall() {
|
||||||
|
let builder = new WasmModuleBuilder();
|
||||||
|
let fun1 = new WebAssembly.Function({parameters:[], results:["i32"]}, _ => 7);
|
||||||
|
let fun2 = new WebAssembly.Function({parameters:[], results:["i32"]}, _ => 9);
|
||||||
|
let fun3 = new WebAssembly.Function({parameters:[], results:["f64"]}, _ => 0);
|
||||||
|
let table = new WebAssembly.Table({element: "anyfunc", initial: 2});
|
||||||
|
let table_index = builder.addImportedTable("m", "table", 2);
|
||||||
|
let sig_index = builder.addType(kSig_i_v);
|
||||||
|
table.set(0, fun1);
|
||||||
|
builder.addFunction('main', kSig_i_i)
|
||||||
|
.addBody([
|
||||||
|
kExprGetLocal, 0,
|
||||||
|
kExprCallIndirect, sig_index, table_index
|
||||||
|
])
|
||||||
|
.exportFunc();
|
||||||
|
let instance = builder.instantiate({ m: { table: table }});
|
||||||
|
assertEquals(7, instance.exports.main(0));
|
||||||
|
table.set(1, fun2);
|
||||||
|
assertEquals(9, instance.exports.main(1));
|
||||||
|
table.set(1, fun3);
|
||||||
|
assertTraps(kTrapFuncSigMismatch, () => instance.exports.main(1));
|
||||||
|
})();
|
||||||
|
Loading…
Reference in New Issue
Block a user