[wasm] Make constructed {WebAssembly.Function} callable.
This makes function objects constructed via the {WebAssembly.Function} constructor callable directly from JavaScript (not just from within WebAssembly modules). Semantics are as if the function performed the transition JS-to-Wasm and then Wasm-to-JS in sequence. R=clemensh@chromium.org TEST=mjsunit/wasm/type-reflection BUG=v8:7742 Change-Id: Ic7dcf36ccfda1b473f2541e49419f4d2ee38bc2c Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1720809 Commit-Queue: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Clemens Hammacher <clemensh@chromium.org> Cr-Commit-Position: refs/heads/master@{#62953}
This commit is contained in:
parent
695c40f08e
commit
ba77172be1
@ -277,7 +277,7 @@ Node* WasmGraphBuilder::EffectPhi(unsigned count, Node** effects,
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::RefNull() {
|
||||
Node* isolate_root = LOAD_INSTANCE_FIELD(IsolateRoot, MachineType::Pointer());
|
||||
Node* isolate_root = BuildLoadIsolateRoot();
|
||||
return LOAD_TAGGED_POINTER(
|
||||
isolate_root, IsolateData::root_slot_offset(RootIndex::kNullValue));
|
||||
}
|
||||
@ -295,6 +295,14 @@ Node* WasmGraphBuilder::NoContextConstant() {
|
||||
return mcgraph()->IntPtrConstant(0);
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::BuildLoadIsolateRoot() {
|
||||
// The IsolateRoot is loaded from the instance node so that the generated
|
||||
// code is Isolate independent. This can be overridden by setting a specific
|
||||
// node in {isolate_root_node_} beforehand.
|
||||
if (isolate_root_node_.is_set()) return isolate_root_node_.get();
|
||||
return LOAD_INSTANCE_FIELD(IsolateRoot, MachineType::Pointer());
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::Uint32Constant(uint32_t value) {
|
||||
return mcgraph()->Uint32Constant(value);
|
||||
}
|
||||
@ -3326,9 +3334,9 @@ Node* WasmGraphBuilder::BuildCallToRuntimeWithContext(
|
||||
auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
|
||||
mcgraph()->zone(), f, fun->nargs, Operator::kNoProperties,
|
||||
CallDescriptor::kNoFlags);
|
||||
Node* isolate_root = LOAD_INSTANCE_FIELD(IsolateRoot, MachineType::Pointer());
|
||||
// The CEntryStub is loaded from the instance_node so that generated code is
|
||||
// The CEntryStub is loaded from the IsolateRoot so that generated code is
|
||||
// Isolate independent. At the moment this is only done for CEntryStub(1).
|
||||
Node* isolate_root = BuildLoadIsolateRoot();
|
||||
DCHECK_EQ(1, fun->result_size);
|
||||
auto centry_id =
|
||||
Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit;
|
||||
@ -5051,7 +5059,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
? mcgraph()->RelocatableIntPtrConstant(
|
||||
wasm::WasmCode::kWasmAllocateHeapNumber,
|
||||
RelocInfo::WASM_STUB_CALL)
|
||||
: BuildLoadBuiltinFromInstance(Builtins::kAllocateHeapNumber);
|
||||
: BuildLoadBuiltinFromIsolateRoot(Builtins::kAllocateHeapNumber);
|
||||
if (!allocate_heap_number_operator_.is_set()) {
|
||||
auto call_descriptor = Linkage::GetStubCallDescriptor(
|
||||
mcgraph()->zone(), AllocateHeapNumberDescriptor(), 0,
|
||||
@ -5108,10 +5116,9 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
return undefined_value_node_.get();
|
||||
}
|
||||
|
||||
Node* BuildLoadBuiltinFromInstance(int builtin_index) {
|
||||
Node* BuildLoadBuiltinFromIsolateRoot(int builtin_index) {
|
||||
DCHECK(Builtins::IsBuiltinId(builtin_index));
|
||||
Node* isolate_root =
|
||||
LOAD_INSTANCE_FIELD(IsolateRoot, MachineType::Pointer());
|
||||
Node* isolate_root = BuildLoadIsolateRoot();
|
||||
return LOAD_TAGGED_POINTER(isolate_root,
|
||||
IsolateData::builtin_slot_offset(builtin_index));
|
||||
}
|
||||
@ -5256,7 +5263,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
(stub_mode_ == StubCallMode::kCallWasmRuntimeStub)
|
||||
? mcgraph()->RelocatableIntPtrConstant(
|
||||
wasm::WasmCode::kWasmToNumber, RelocInfo::WASM_STUB_CALL)
|
||||
: BuildLoadBuiltinFromInstance(Builtins::kToNumber);
|
||||
: BuildLoadBuiltinFromIsolateRoot(Builtins::kToNumber);
|
||||
|
||||
Node* result = SetEffect(
|
||||
graph()->NewNode(mcgraph()->common()->Call(call_descriptor), stub_code,
|
||||
@ -5355,7 +5362,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
(stub_mode_ == StubCallMode::kCallWasmRuntimeStub)
|
||||
? mcgraph()->RelocatableIntPtrConstant(
|
||||
wasm::WasmCode::kWasmI64ToBigInt, RelocInfo::WASM_STUB_CALL)
|
||||
: BuildLoadBuiltinFromInstance(Builtins::kI64ToBigInt);
|
||||
: BuildLoadBuiltinFromIsolateRoot(Builtins::kI64ToBigInt);
|
||||
|
||||
return SetEffect(
|
||||
SetControl(graph()->NewNode(mcgraph()->common()->Call(call_descriptor),
|
||||
@ -5377,7 +5384,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
(stub_mode_ == StubCallMode::kCallWasmRuntimeStub)
|
||||
? mcgraph()->RelocatableIntPtrConstant(
|
||||
wasm::WasmCode::kWasmBigIntToI64, RelocInfo::WASM_STUB_CALL)
|
||||
: BuildLoadBuiltinFromInstance(Builtins::kBigIntToI64);
|
||||
: BuildLoadBuiltinFromIsolateRoot(Builtins::kBigIntToI64);
|
||||
|
||||
return SetEffect(SetControl(
|
||||
graph()->NewNode(mcgraph()->common()->Call(call_descriptor), target,
|
||||
@ -5451,8 +5458,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
|
||||
void BuildModifyThreadInWasmFlag(bool new_value) {
|
||||
if (!trap_handler::IsTrapHandlerEnabled()) return;
|
||||
Node* isolate_root =
|
||||
LOAD_INSTANCE_FIELD(IsolateRoot, MachineType::Pointer());
|
||||
Node* isolate_root = BuildLoadIsolateRoot();
|
||||
|
||||
Node* thread_in_wasm_flag_address =
|
||||
LOAD_RAW(isolate_root, Isolate::thread_in_wasm_flag_address_offset(),
|
||||
@ -5692,8 +5698,8 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
LOAD_RAW(callable_node,
|
||||
wasm::ObjectAccess::ContextOffsetInTaggedJSFunction(),
|
||||
MachineType::TypeCompressedTaggedPointer());
|
||||
args[pos++] =
|
||||
BuildLoadBuiltinFromInstance(Builtins::kArgumentsAdaptorTrampoline);
|
||||
args[pos++] = BuildLoadBuiltinFromIsolateRoot(
|
||||
Builtins::kArgumentsAdaptorTrampoline);
|
||||
args[pos++] = callable_node; // target callable
|
||||
args[pos++] = undefined_node; // new target
|
||||
args[pos++] = mcgraph()->Int32Constant(wasm_count); // argument count
|
||||
@ -5837,8 +5843,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
MachineType::Pointer());
|
||||
|
||||
BuildModifyThreadInWasmFlag(false);
|
||||
Node* isolate_root =
|
||||
LOAD_INSTANCE_FIELD(IsolateRoot, MachineType::Pointer());
|
||||
Node* isolate_root = BuildLoadIsolateRoot();
|
||||
Node* fp_value = graph()->NewNode(mcgraph()->machine()->LoadFramePointer());
|
||||
STORE_RAW(isolate_root, Isolate::c_entry_fp_offset(), fp_value,
|
||||
MachineType::PointerRepresentation(), kNoWriteBarrier);
|
||||
@ -5969,6 +5974,79 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
if (ContainsInt64(sig_)) LowerInt64();
|
||||
}
|
||||
|
||||
void BuildJSToJSWrapper() {
|
||||
int wasm_count = static_cast<int>(sig_->parameter_count());
|
||||
|
||||
// Build the start and the parameter nodes.
|
||||
int param_count = 1 /* closure */ + 1 /* receiver */ + wasm_count +
|
||||
1 /* new.target */ + 1 /* #arg */ + 1 /* context */;
|
||||
SetEffect(SetControl(Start(param_count)));
|
||||
Node* closure = Param(Linkage::kJSCallClosureParamIndex);
|
||||
Node* context = Param(Linkage::GetJSCallContextParamIndex(wasm_count + 1));
|
||||
|
||||
// Since JS-to-JS wrappers are specific to one Isolate, it is OK to embed
|
||||
// values (for undefined and root) directly into the instruction stream.
|
||||
isolate_root_node_ = jsgraph()->IntPtrConstant(isolate_->isolate_root());
|
||||
undefined_value_node_ = jsgraph()->UndefinedConstant();
|
||||
|
||||
// Throw a TypeError if the signature is incompatible with JavaScript.
|
||||
if (!wasm::IsJSCompatibleSignature(sig_, enabled_features_.bigint)) {
|
||||
BuildCallToRuntimeWithContext(Runtime::kWasmThrowTypeError, context,
|
||||
nullptr, 0, effect_, Control());
|
||||
Return(jsgraph()->SmiConstant(0));
|
||||
return;
|
||||
}
|
||||
|
||||
// Load the original callable from the closure.
|
||||
Node* shared = LOAD_TAGGED_ANY(
|
||||
closure,
|
||||
wasm::ObjectAccess::ToTagged(JSFunction::kSharedFunctionInfoOffset));
|
||||
Node* func_data = LOAD_TAGGED_ANY(
|
||||
shared,
|
||||
wasm::ObjectAccess::ToTagged(SharedFunctionInfo::kFunctionDataOffset));
|
||||
Node* callable = LOAD_TAGGED_ANY(
|
||||
func_data,
|
||||
wasm::ObjectAccess::ToTagged(WasmJSFunctionData::kCallableOffset));
|
||||
|
||||
// Call the underlying closure.
|
||||
Node** args = Buffer(wasm_count + 7);
|
||||
int pos = 0;
|
||||
args[pos++] =
|
||||
jsgraph()->Constant(BUILTIN_CODE(isolate_, Call_ReceiverIsAny));
|
||||
args[pos++] = callable;
|
||||
args[pos++] = mcgraph()->Int32Constant(wasm_count); // argument count
|
||||
args[pos++] = jsgraph()->UndefinedConstant(); // receiver
|
||||
|
||||
auto call_descriptor = Linkage::GetStubCallDescriptor(
|
||||
graph()->zone(), CallTrampolineDescriptor{}, wasm_count + 1,
|
||||
CallDescriptor::kNoFlags, Operator::kNoProperties,
|
||||
StubCallMode::kCallCodeObject);
|
||||
|
||||
// Convert parameter JS values to wasm numbers and back to JS values.
|
||||
for (int i = 0; i < wasm_count; ++i) {
|
||||
Node* param = Param(i + 1); // Start from index 1 to skip receiver.
|
||||
args[pos++] =
|
||||
ToJS(FromJS(param, context, sig_->GetParam(i)), sig_->GetParam(i));
|
||||
}
|
||||
|
||||
args[pos++] = context;
|
||||
args[pos++] = Effect();
|
||||
args[pos++] = Control();
|
||||
|
||||
Node* call = SetEffect(graph()->NewNode(
|
||||
mcgraph()->common()->Call(call_descriptor), pos, args));
|
||||
|
||||
// TODO(wasm): Extend this to support multi-return.
|
||||
DCHECK_LE(sig_->return_count(), 1);
|
||||
|
||||
// Convert return JS values to wasm numbers and back to JS values.
|
||||
Node* jsval =
|
||||
sig_->return_count() == 0
|
||||
? jsgraph()->UndefinedConstant()
|
||||
: ToJS(FromJS(call, context, sig_->GetReturn()), sig_->GetReturn());
|
||||
Return(jsval);
|
||||
}
|
||||
|
||||
void BuildCWasmEntry() {
|
||||
// +1 offset for first parameter index being -1.
|
||||
SetEffect(SetControl(Start(CWasmEntryParameters::kNumParameters + 1)));
|
||||
@ -6506,6 +6584,54 @@ wasm::WasmCompilationResult CompileWasmInterpreterEntry(
|
||||
return result;
|
||||
}
|
||||
|
||||
MaybeHandle<Code> CompileJSToJSWrapper(Isolate* isolate,
|
||||
wasm::FunctionSig* sig) {
|
||||
std::unique_ptr<Zone> zone =
|
||||
base::make_unique<Zone>(isolate->allocator(), ZONE_NAME);
|
||||
Graph* graph = new (zone.get()) Graph(zone.get());
|
||||
CommonOperatorBuilder common(zone.get());
|
||||
MachineOperatorBuilder machine(
|
||||
zone.get(), MachineType::PointerRepresentation(),
|
||||
InstructionSelector::SupportedMachineOperatorFlags(),
|
||||
InstructionSelector::AlignmentRequirements());
|
||||
JSGraph jsgraph(isolate, graph, &common, nullptr, nullptr, &machine);
|
||||
|
||||
Node* control = nullptr;
|
||||
Node* effect = nullptr;
|
||||
|
||||
WasmWrapperGraphBuilder builder(zone.get(), &jsgraph, sig, nullptr,
|
||||
StubCallMode::kCallCodeObject,
|
||||
wasm::WasmFeaturesFromIsolate(isolate));
|
||||
builder.set_control_ptr(&control);
|
||||
builder.set_effect_ptr(&effect);
|
||||
builder.BuildJSToJSWrapper();
|
||||
|
||||
int wasm_count = static_cast<int>(sig->parameter_count());
|
||||
CallDescriptor* incoming = Linkage::GetJSCallDescriptor(
|
||||
zone.get(), false, wasm_count + 1, CallDescriptor::kNoFlags);
|
||||
|
||||
// Build a name in the form "js-to-js-wrapper:<params>:<returns>".
|
||||
static constexpr size_t kMaxNameLen = 128;
|
||||
auto debug_name = std::unique_ptr<char[]>(new char[kMaxNameLen]);
|
||||
memcpy(debug_name.get(), "js-to-js-wrapper:", 18);
|
||||
AppendSignature(debug_name.get(), kMaxNameLen, sig);
|
||||
|
||||
// Run the compilation job synchronously.
|
||||
std::unique_ptr<OptimizedCompilationJob> job(
|
||||
Pipeline::NewWasmHeapStubCompilationJob(
|
||||
isolate, incoming, std::move(zone), graph, Code::JS_TO_JS_FUNCTION,
|
||||
std::move(debug_name), AssemblerOptions::Default(isolate)));
|
||||
|
||||
if (job->PrepareJob(isolate) == CompilationJob::FAILED ||
|
||||
job->ExecuteJob() == CompilationJob::FAILED ||
|
||||
job->FinalizeJob(isolate) == CompilationJob::FAILED) {
|
||||
return {};
|
||||
}
|
||||
Handle<Code> code = job->compilation_info()->code();
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
MaybeHandle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig) {
|
||||
std::unique_ptr<Zone> zone =
|
||||
base::make_unique<Zone>(isolate->allocator(), ZONE_NAME);
|
||||
|
@ -140,6 +140,12 @@ V8_EXPORT_PRIVATE wasm::WasmCompilationResult CompileWasmInterpreterEntry(
|
||||
wasm::WasmEngine*, const wasm::WasmFeatures& enabled_features,
|
||||
uint32_t func_index, wasm::FunctionSig*);
|
||||
|
||||
// Compiles a stub with JS linkage that serves as an adapter for function
|
||||
// objects constructed via {WebAssembly.Function}. It performs a round-trip
|
||||
// simulating a JS-to-Wasm-to-JS coercion of parameter and return values.
|
||||
MaybeHandle<Code> CompileJSToJSWrapper(Isolate* isolate,
|
||||
wasm::FunctionSig* sig);
|
||||
|
||||
enum CWasmEntryParameters {
|
||||
kCodeEntry,
|
||||
kObjectRef,
|
||||
@ -444,6 +450,7 @@ class WasmGraphBuilder {
|
||||
SetOncePointer<Node> globals_start_;
|
||||
SetOncePointer<Node> imported_mutable_globals_;
|
||||
SetOncePointer<Node> stack_check_code_node_;
|
||||
SetOncePointer<Node> isolate_root_node_;
|
||||
SetOncePointer<const Operator> stack_check_call_operator_;
|
||||
|
||||
Node** cur_buffer_;
|
||||
@ -461,6 +468,8 @@ class WasmGraphBuilder {
|
||||
|
||||
Node* NoContextConstant();
|
||||
|
||||
Node* BuildLoadIsolateRoot();
|
||||
|
||||
Node* MemBuffer(uint32_t offset);
|
||||
// BoundsCheckMem receives a uint32 {index} node and returns a ptrsize index.
|
||||
Node* BoundsCheckMem(uint8_t access_size, Node* index, uint32_t offset,
|
||||
|
@ -579,6 +579,8 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
|
||||
return OPTIMIZED;
|
||||
case Code::JS_TO_WASM_FUNCTION:
|
||||
return JS_TO_WASM;
|
||||
case Code::JS_TO_JS_FUNCTION:
|
||||
return STUB;
|
||||
case Code::C_WASM_ENTRY:
|
||||
return C_WASM_ENTRY;
|
||||
case Code::WASM_FUNCTION:
|
||||
|
@ -1978,6 +1978,10 @@ void ExistingCodeLogger::LogCodeObject(Object object) {
|
||||
description = "A JavaScript to Wasm adapter";
|
||||
tag = CodeEventListener::STUB_TAG;
|
||||
break;
|
||||
case AbstractCode::JS_TO_JS_FUNCTION:
|
||||
description = "A WebAssembly.Function adapter";
|
||||
tag = CodeEventListener::STUB_TAG;
|
||||
break;
|
||||
case AbstractCode::WASM_TO_CAPI_FUNCTION:
|
||||
description = "A Wasm to C-API adapter";
|
||||
tag = CodeEventListener::STUB_TAG;
|
||||
|
@ -45,6 +45,7 @@ class Code : public HeapObject {
|
||||
V(WASM_TO_CAPI_FUNCTION) \
|
||||
V(WASM_TO_JS_FUNCTION) \
|
||||
V(JS_TO_WASM_FUNCTION) \
|
||||
V(JS_TO_JS_FUNCTION) \
|
||||
V(WASM_INTERPRETER_ENTRY) \
|
||||
V(C_WASM_ENTRY)
|
||||
|
||||
|
@ -2298,6 +2298,10 @@ Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
|
||||
if (sig_size > 0) {
|
||||
serialized_sig->copy_in(0, sig->all().begin(), sig_size);
|
||||
}
|
||||
// TODO(mstarzinger): Think about caching and sharing the JS-to-JS wrappers
|
||||
// per signature instead of compiling a new one for every instantiation.
|
||||
Handle<Code> wrapper_code =
|
||||
compiler::CompileJSToJSWrapper(isolate, sig).ToHandleChecked();
|
||||
Handle<WasmJSFunctionData> function_data =
|
||||
Handle<WasmJSFunctionData>::cast(isolate->factory()->NewStruct(
|
||||
WASM_JS_FUNCTION_DATA_TYPE, AllocationType::kOld));
|
||||
@ -2305,9 +2309,7 @@ Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
|
||||
function_data->set_serialized_parameter_count(parameter_count);
|
||||
function_data->set_serialized_signature(*serialized_sig);
|
||||
function_data->set_callable(*callable);
|
||||
// TODO(7742): Make this callable by using a proper wrapper code.
|
||||
function_data->set_wrapper_code(
|
||||
isolate->builtins()->builtin(Builtins::kIllegal));
|
||||
function_data->set_wrapper_code(*wrapper_code);
|
||||
Handle<String> name = isolate->factory()->Function_string();
|
||||
if (callable->IsJSFunction()) {
|
||||
name = JSFunction::GetName(Handle<JSFunction>::cast(callable));
|
||||
@ -2316,6 +2318,7 @@ Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
|
||||
NewFunctionArgs args =
|
||||
NewFunctionArgs::ForWasm(name, function_data, function_map);
|
||||
Handle<JSFunction> js_function = isolate->factory()->NewFunction(args);
|
||||
js_function->shared().set_internal_formal_parameter_count(parameter_count);
|
||||
return Handle<WasmJSFunction>::cast(js_function);
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --experimental-wasm-type-reflection
|
||||
// Flags: --experimental-wasm-type-reflection --expose-gc
|
||||
|
||||
load('test/mjsunit/wasm/wasm-module-builder.js');
|
||||
|
||||
@ -219,8 +219,7 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
|
||||
assertSame(fun.__proto__.__proto__.__proto__, Object.prototype);
|
||||
assertSame(fun.constructor, WebAssembly.Function);
|
||||
assertEquals(typeof fun, 'function');
|
||||
// TODO(7742): Enable once it is callable.
|
||||
// assertDoesNotThrow(() => fun());
|
||||
assertDoesNotThrow(() => fun());
|
||||
})();
|
||||
|
||||
(function TestFunctionExportedFunction() {
|
||||
@ -271,6 +270,49 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
|
||||
});
|
||||
})();
|
||||
|
||||
(function TestFunctionConstructedCoercions() {
|
||||
let obj1 = { valueOf: _ => 123.45 };
|
||||
let obj2 = { toString: _ => "456" };
|
||||
let gcer = { valueOf: _ => gc() };
|
||||
let testcases = [
|
||||
{ params: { sig: ["i32"],
|
||||
val: [23.5],
|
||||
exp: [23], },
|
||||
result: { sig: ["i32"],
|
||||
val: 42.7,
|
||||
exp: 42, },
|
||||
},
|
||||
{ params: { sig: ["i32", "f32", "f64"],
|
||||
val: [obj1, obj2, "789"],
|
||||
exp: [123, 456, 789], },
|
||||
result: { sig: [],
|
||||
val: undefined,
|
||||
exp: undefined, },
|
||||
},
|
||||
{ params: { sig: ["i32", "f32", "f64"],
|
||||
val: [gcer, {}, "xyz"],
|
||||
exp: [0, NaN, NaN], },
|
||||
result: { sig: ["f64"],
|
||||
val: gcer,
|
||||
exp: NaN, },
|
||||
},
|
||||
];
|
||||
testcases.forEach(function({params, result}) {
|
||||
let p = params.sig; let r = result.sig; var params_after;
|
||||
function testFun() { params_after = arguments; return result.val; }
|
||||
let fun = new WebAssembly.Function({parameters:p, results:r}, testFun);
|
||||
let result_after = fun.apply(undefined, params.val);
|
||||
assertArrayEquals(params.exp, params_after);
|
||||
assertEquals(result.exp, result_after);
|
||||
});
|
||||
})();
|
||||
|
||||
(function TestFunctionConstructedIncompatibleSig() {
|
||||
let fun = new WebAssembly.Function({parameters:["i64"], results:[]}, _ => 0);
|
||||
assertThrows(() => fun(), TypeError,
|
||||
/wasm function signature contains illegal type/);
|
||||
})();
|
||||
|
||||
(function TestFunctionTableSetAndCall() {
|
||||
let builder = new WasmModuleBuilder();
|
||||
let fun1 = new WebAssembly.Function({parameters:[], results:["i32"]}, _ => 7);
|
||||
|
Loading…
Reference in New Issue
Block a user