WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
Bug 198157
[WASM-References] Add support for Funcref in parameters and return types
https://bugs.webkit.org/show_bug.cgi?id=198157
Summary
[WASM-References] Add support for Funcref in parameters and return types
Justin Michaud
Reported
2019-05-22 21:52:42 PDT
Add support for Funcref as a value type.
Attachments
Patch
(86.96 KB, patch)
2019-06-10 20:44 PDT
,
Justin Michaud
no flags
Details
Formatted Diff
Diff
Patch
(84.17 KB, patch)
2019-06-13 19:02 PDT
,
Justin Michaud
no flags
Details
Formatted Diff
Diff
Patch
(90.98 KB, patch)
2019-06-14 19:47 PDT
,
Justin Michaud
no flags
Details
Formatted Diff
Diff
Patch
(91.46 KB, patch)
2019-06-17 10:39 PDT
,
Justin Michaud
no flags
Details
Formatted Diff
Diff
Patch
(91.45 KB, patch)
2019-06-17 10:59 PDT
,
Justin Michaud
no flags
Details
Formatted Diff
Diff
Show Obsolete
(4)
View All
Add attachment
proposed patch, testcase, etc.
Justin Michaud
Comment 1
2019-06-10 20:44:17 PDT
Created
attachment 371816
[details]
Patch
EWS Watchlist
Comment 2
2019-06-10 20:45:55 PDT
This patch modifies one of the wasm.json files. Please ensure that any changes in one have been mirrored to the other. You can find the wasm.json files at "Source/JavaScriptCore/wasm/wasm.json" and "JSTests/wasm/wasm.json".
Saam Barati
Comment 3
2019-06-11 15:31:59 PDT
Comment on
attachment 371816
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=371816&action=review
> Source/JavaScriptCore/ChangeLog:9 > + a funcref (née anyfunc), we first make sure it is an exported wasm function or null.
remove non-ascii character here.
> Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp:1016 > + } else if (!value.isFunction(*instance->owner<JSObject>()->vm()))
Maybe I'm missing something, but based on the type system, aren't the only options for this value jsNull() or web assembly host function?
> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:606 > + JSValue value = JSValue::decode(encValue); > + if (instance->table()->type() == TableElementType::Anyref) > + instance->table()->set(idx, value); > + else if (instance->table()->type() == TableElementType::Funcref) { > + WebAssemblyFunction* wasmFunction; > + WebAssemblyWrapperFunction* wasmWrapperFunction; > + > + if (isWebAssemblyHostFunction(*instance->owner<JSObject>()->vm(), value, wasmFunction, wasmWrapperFunction)) { > + ASSERT(!!wasmFunction || !!wasmWrapperFunction); > + if (wasmFunction) > + instance->table()->asFuncrefTable()->setFunction(idx, jsCast<JSObject*>(value), wasmFunction->importableFunction(), &wasmFunction->instance()->instance()); > + else > + instance->table()->asFuncrefTable()->setFunction(idx, jsCast<JSObject*>(value), wasmWrapperFunction->importableFunction(), &wasmWrapperFunction->instance()->instance()); > + } else if (!value.isFunction(*instance->owner<JSObject>()->vm())) > + instance->table()->clear(idx); > + else > + ASSERT_NOT_REACHED(); > + } else > + ASSERT_NOT_REACHED();
This is identical to WasmAIRIRGenerator. Let's make a helper for it.
> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:622 > + JSValue val = instance->getFunctionWrapper(index); > + ASSERT(val.isFunction(*instance->owner<JSObject>()->vm())); > + return JSValue::encode(val);
ditto.
> Source/JavaScriptCore/wasm/WasmBBQPlan.cpp:289 > + // TODO check if used in ref.func
?
> Source/JavaScriptCore/wasm/WasmBBQPlan.cpp:290 > + if (m_exportedFunctionIndices.contains(functionIndex) || true) {
oops
> Source/JavaScriptCore/wasm/WasmInstance.cpp:47 > + return (Checked<size_t>(module.moduleInformation().functionIndexSpaceSize()) * sizeof(WriteBarrier<Unknown>)).unsafeGet();
This is not great. We probably only ref.func a few functions, but we're allocating space for all of them. Can we have a mapping from index=>index, where ModuleInformation just has a HashMap from index in function index space to index in this buffer?
> Source/JavaScriptCore/wasm/WasmInstance.cpp:65 > + new (&m_globals.get()[i].anyref) WriteBarrier<Unknown>(UndefinedWriteBarrierTag);
Don't we want the null value to be jsNull? Not undefined?
> Source/JavaScriptCore/wasm/WasmInstance.cpp:67 > + for (unsigned i = 0; i < m_module->moduleInformation().functionIndexSpaceSize(); ++i) > + new (&m_functionWrappers.get()[i]) WriteBarrier<Unknown>(UndefinedWriteBarrierTag);
I think it's ok to just zero this. Since they should all get filled in (see above). Also, based on above, maybe we just want to use Vector?
> Source/JavaScriptCore/wasm/WasmValidate.cpp:191 > + auto type = m_module.tableInformation.type() == TableElementType::Funcref ? Type::Anyfunc : Type::Anyref;
I suggested this helper in the past, but maybe I was wrong. It would be nice if the tableInformation.type() returned Wasm type.
> Source/JavaScriptCore/wasm/WasmValidate.cpp:211 > + WASM_VALIDATOR_FAIL_IF(index >= m_module.functionIndexSpaceSize(), "ref.func index ", index, " is too large");
nit: it'd be nice to get a better error message here, maybe one that contains "index" and "index space size"
> Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp:333 > + emitWasmToJSException(jit, GPRInfo::argumentGPR2, Wasm::ExceptionType::FuncrefNotWasm);
I vote for just going to the slow path instead of this. It makes us have to reason less about if this is a valid place to emit this exception handler. (My guess: this might be wrong, and it might have to do with callee saves.)
> Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp:244 > + return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "imported global", "must be a wasm exported function")));
nit: error message should also say "or null".
Justin Michaud
Comment 4
2019-06-13 19:02:31 PDT
Created
attachment 372095
[details]
Patch
Yusuke Suzuki
Comment 5
2019-06-14 17:07:24 PDT
Comment on
attachment 372095
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=372095&action=review
I found GC bug, so r-, but the code looks really nice!
> Source/JavaScriptCore/wasm/WasmInstance.cpp:98 > +void setWasmTableElement(Wasm::Instance* instance, uint32_t idx, uint64_t encValue)
Is encValue always encoded JSValue? If so, let's use EncodedJSValue type instead. And the name "encodedValue" is better. I also like "index" instead of "idx".
> Source/JavaScriptCore/wasm/WasmInstance.cpp:123 > + JSValue val = instance->getFunctionWrapper(index);
val => value.
> Source/JavaScriptCore/wasm/WasmInstance.h:167 > + HashMap<uint32_t, WriteBarrier<Unknown>, IntHash<uint32_t>, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>> m_functionWrappers;
I think visitChildren handling for m_functionWrappers is missing.
> Source/JavaScriptCore/wasm/js/JSToWasm.cpp:127 > + emitWasmToJSException(jit, GPRInfo::argumentGPR2, argumentsIncludeI64 ? ExceptionType::I64ArgumentType : ExceptionType::I64ReturnType);
I like to see the word "Throw" for such a function. So, "emitThrowWasmToJSException" would be nice.
Justin Michaud
Comment 6
2019-06-14 17:36:44 PDT
Comment on
attachment 372095
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=372095&action=review
>> Source/JavaScriptCore/wasm/WasmInstance.h:167 >> + HashMap<uint32_t, WriteBarrier<Unknown>, IntHash<uint32_t>, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>> m_functionWrappers; > > I think visitChildren handling for m_functionWrappers is missing.
We do it in the JS wrapper, right?
> Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp:98 > + visitor.appendUnbarriered(thisObject->instance().getFunctionWrapper(i));
We do the function wrapper visiting here
Justin Michaud
Comment 7
2019-06-14 19:47:08 PDT
Created
attachment 372170
[details]
Patch
Yusuke Suzuki
Comment 8
2019-06-16 00:16:28 PDT
Comment on
attachment 372170
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=372170&action=review
r=me with several fixes.
> Source/JavaScriptCore/wasm/WasmInstance.cpp:86 > + return m_functionWrappers.contains(i) ? m_functionWrappers.get(i).get() : jsNull();
`contains(i)` and `get(i)` calls are duplicate basically. So we are looking up hash table twice. Can we just use `get(i)`? I think it will return empty WriteBarrier thing. Then, we can convert JSEmpty to JSNull, and we can do this function without using `contains`.
> Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp:98 > + visitor.appendUnbarriered(thisObject->instance().getFunctionWrapper(i));
Ah, I missed it. Why not just iterating the hashmap of wrappers? I think # of wrappers can be much smaller than the total number of function space size. And it also avoids repeated calls of `contains()` / `get()` in getFunctionWrapper. And I think the hashtable can be modified by the user's setFunctionWrapper. So locking is necessary.
Justin Michaud
Comment 9
2019-06-17 10:39:36 PDT
Created
attachment 372256
[details]
Patch
Justin Michaud
Comment 10
2019-06-17 10:59:49 PDT
Created
attachment 372257
[details]
Patch
WebKit Commit Bot
Comment 11
2019-06-17 11:44:24 PDT
Comment on
attachment 372257
[details]
Patch Clearing flags on attachment: 372257 Committed
r246504
: <
https://trac.webkit.org/changeset/246504
>
WebKit Commit Bot
Comment 12
2019-06-17 11:44:26 PDT
All reviewed patches have been landed. Closing bug.
Radar WebKit Bug Importer
Comment 13
2019-06-17 11:47:27 PDT
<
rdar://problem/51814501
>
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug