-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add detector for type reflection #67
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to make the detection a bit more robust.
Also, can you please make sure that there are no whitespace changes introduced by your editor?
*/ | ||
|
||
export default async () => { | ||
return "Function" in WebAssembly; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don’t think this is enough. IINM, WebAssembly.Function
is also expose by the JSPI proposal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe something like this could work?
return "Function" in WebAssembly && typeof WebAssembly["Function"]["type"] === "function" &&
typeof WebAssembly.Memory.prototype["type"] === "function" &&
typeof WebAssembly.Table.prototype["type"] === "function" &&
typeof WebAssembly.Global.prototype["type"] === "function";
Doing some tests:
- Chrome: Returns true with experimental wasm features enabled
- Safari: Memory, Table and Global have the
type()
method, but it does not haveWebAssembly.Function
and functions exported from aWebAssembly.Instance
do not have thetype()
method - Firefox: All conditions are false
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me try it with d8 with various extra feature flags.
IINM,
WebAssembly.Function
is also expose by the JSPI proposal.
As I understand it, JSPI implies type reflection. E.g., passing --experimental-wasm-stack-switching --experimental-type-reflection
is indistinguishable from just --experimental-wasm-stack-switching
. To test this I made a little Python script:
I made feature_detect.js
:
console.log(
"Function" in WebAssembly,
"Function" in WebAssembly &&
typeof WebAssembly["Function"]["type"] === "function" &&
typeof WebAssembly.Memory.prototype["type"] === "function" &&
typeof WebAssembly.Table.prototype["type"] === "function" &&
typeof WebAssembly.Global.prototype["type"] === "function"
);
and then tested with V8 version 11.5.69
$ v8 --experimental-wasm-type-reflection feature_detect.js
true true
$ v8 --experimental-wasm-stack-switching feature_detect.js
true true
$ v8 feature_detect.js
false false
For good measure I listed out all experimental flags with:
v8 --help | grep -o -E -- '--experimental[a-z0-9-]*' | sort -u
and checked that the script returns true true
if either of these two flags is present and false false
with any other collection of experimental flags. (Well I picked the other flags at random so I only tested a random sample.)
Test script
import subprocess
from random import randrange
from itertools import product
import sys
result = subprocess.run(
"v8 --help | grep -o -E -- '--experimental-[a-z0-9-]*' | sort -u",
shell=True,
capture_output=True,
encoding="utf8",
check=True
)
experimental_flags = set([x for x in result.stdout.splitlines() if x])
experimental_flags.discard("--experimental-wasm-stack-switching")
experimental_flags.discard("--experimental-wasm-type-reflection")
def random_flags():
return set(filter(lambda x: randrange(2), experimental_flags))
for [stack_switch, type_refl] in product([False, True], repeat=2):
if stack_switch or type_refl:
expected = "true true"
else:
expected = "false false"
flags = []
if stack_switch:
flags.append("--experimental-wasm-stack-switching")
if type_refl:
flags.append("--experimental-wasm-type-reflection")
for i in range(1000):
rand_flags = random_flags()
r = subprocess.run(
["/home/hood/.jsvu/v8", *flags, *rand_flags, "a.js"],
capture_output=True,
encoding="utf8",
)
if r.stdout.strip() != expected:
from pprint import pprint
pprint(flags + list(rand_flags))
sys.exit(1)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the moral of the story is that both approaches should do the same thing, at least on v8. Node is a similar story. I guess I should check also with firefox...
Anyways if you folks prefer, I am fine with switching to the more detailed check. I think we should add a comment though.
See also Emscripten's feature detection:
// If the type reflection proposal is available, use the new
// "WebAssembly.Function" constructor.
// Otherwise, construct a minimal wasm module importing the JS function and
// re-exporting it.
if (typeof WebAssembly.Function == "function") {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sbc100 do you have an opinion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I guess I may be overly focusing on v8 checks here...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the check as written seems like it should be fine.
JSPI depends on the type reflection proposal, but I don' think that needs to effect this test. JSPI itself doesn't provide this symbol.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahah: in firefox nightly v115.0a1 I get:
true false
but if I fix:
typeof WebAssembly["Function"]["type"] === "function" &&
to
typeof WebAssembly.Function.prototype["type"] === "function" &&
then I get true true
again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In Safari Version 16.3 (18614.4.6.1.6),
console.log(
"Function" in WebAssembly,
"Function" in WebAssembly &&
typeof WebAssembly.Function.protype.type === "function",
typeof WebAssembly.Memory.prototype["type"] === "function",
typeof WebAssembly.Table.prototype["type"] === "function",
typeof WebAssembly.Global.prototype["type"] === "function"
);
gives false false true true true
as @juancastillo0 said.
In Safari Technology Preview Release 169 (Safari 16.4, WebKit 18616.1.12.2) I get the same thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks everyone! Sounds like we can leave this as is!
@surma I am confused about the whitespace -- as far as I can tell README.md is a generated file. I committed exactly what |
I assumed that maybe your editor ran a different formatter. If that is not happening, ignore the whitespace problem 🤷 |
No description provided.