Giter Club home page Giter Club logo

js-types's Introduction

Build Status

Type Reflection Proposal for WebAssembly JS API

This repository is a clone of github.com/WebAssembly/spec/. It is meant for discussion, prototype specification and implementation of a proposal to add type reflection to the WebAssembly JavaScript API.

See the overview for a summary of the proposal.

A formatted version of the spec, including this propsal, is available here: webassembly.github.io/js-types.

spec

This repository holds the sources for the WebAssembly draft specification (to seed a future WebAssembly Working Group), a reference implementation, and the official testsuite.

A formatted version of the spec is available here: webassembly.github.io/spec,

Participation is welcome. Discussions about new features, significant semantic changes, or any specification change likely to generate substantial discussion should take place in the WebAssembly design repository first, so that this spec repository can remain focused. And please follow the guidelines for contributing.

citing

For citing WebAssembly in LaTeX, use this bibtex file.

js-types's People

Contributors

andrewscheidecker avatar backes avatar binji avatar bnjbvr avatar cellule avatar chfast avatar chicoxyzzy avatar dschuff avatar flagxor avatar gahaas avatar ggreif avatar gumb0 avatar honry avatar ia0 avatar jfbastien avatar keithw avatar kg avatar kripken avatar littledan avatar lukewagner avatar ms2ger avatar ngzhian avatar pepyakin avatar pjuftring avatar ppopth avatar rossberg avatar spy avatar sunfishcode avatar swasey avatar xtuc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

js-types's Issues

JS Promise integration

We are currently working on a proposal to support stack switching in wasm. Specifically, I am referring to the JS Promise integration proposal.

At the moment, we have something of a 'soft dependency' on the js-types proposal. For example, in order to signal a stack switching capability, we wrap imports and exports. A wrapped import will take a regular Promise-returning function and return a suspending version of that function; and we use WebAssembly.Function for that returned value.

However, the status of this entity is pretty hairy: it cannot be called by JS for example.

We are exploring a new style of API that does not use wrapper functions; but instead utilizes an async flag in the WebAssembly.Function object. This flag would have to be writeable (because we also have to mark exports which are not available until after the module is instantiated.)

If we did this, we could dramatically simplify our JS exposed API (essentially, it would disappear completely). But it would require us being able to modify the WebAssembly.Function object as described in this proposal.
The purpose of this issue is to acquire feedback from y'all about changing the js-types proposal in this way.

As a side note; this has obvious echoes of Luke's proposal to also augment WebAssembly.Function with an explicit receiver field. But other than an echo, there is no explicit interdependency as far as I am aware.

`WebAssembly.Module.{imports,exports}`

The import/export reflection APIs are nice but only provide kind: 'global', without any information about what type of global is being imported/exported. Adding additional type info to this API might be within scope of this proposal.

Some additional considerations might be designing the additions with future types like gc structs being kept in mind so we don't make this harder down the road.

What does the WebAssembly.Function constructor do?

What happens if you call the result? Does it forward to the underlying function? Does it do a type conversion? What about getting properties off the result? Does that forward to the underlying function?

Backwards compatability?

If I had an old Wasm module, say, today, that exported a function, would it's prototype now be WebAssembly.Function instead of Function, after this proposal is implemented?

Or, does constructing a WebAssembly.Function result in a plain JS Function?

Allow JS functions to be directly added to via `table.set`?

See WebAssembly/design#1408

I wonder if we can add this to this proposal. It not only avoids having to use the WebAssembly.Function API everywhere but its more flexible because it means we don't need to know ahead of time the signature of the function being implemented in JS and it allows us to take advantage of JS polymorphism in the same way we already can for imports.

Review implementability of WebAssembly.Function

The snippet

interface Function : global.Function {
  static FunctionType type(Function func);
};

is not valid WebIDL, and I don't see a clear way to make it so.

Note that it's already possible (though a little tedious) to create a host function from a JS function:

function host_function(f, { parameters, results }) {
  const builder = new WasmModuleBuilder();
  const functionIndex = builder.addImport("module", "imported", { params: parameters, results });
  builder.addExport("exportedFunction", functionIndex);
  const buffer = builder.toBuffer();

  const module = new WebAssembly.Module(buffer);
  const instance = new WebAssembly.Instance(module, {
    "module": {
      "imported": f,
    }
  });

  return instance.exports.exportedFunction;
}

We could easily introduce this coercion in Table#set() as well, without necessarily introducing this new type.

Passing a WasmExportedFunction to new WebAssembly.Function

What should happen when a WasmExportedFunction is passed as the callable to new WebAssembly.Function? I was not able to find this case in the proposal.

My guess would be that a signature check should happen: if the signature of the WasmExportedFunction matches the signature passed to new WebAssembly.Function, then the WasmExportedFunction is returned. If the signature does not match, then a TypeError is thrown.

Could WebAssembly.Function instead be defined in terms of the Typed Object API?

My assumption with the wasm GC proposal is that wasm GC objects will be reflected in JS as Typed Objects which we'd co-standardize with TC39.

That implies that, for each wasm type that can be used as a field of a wasm GC object, we'd need a corresponding "thing" in Typed Objects. This includes typed function references. When you think of what a typed function reference would look like in JS, it's basically an exported wasm function: a rigid signature and, if you attempted to construct one from an arbitrary JS function, that JS function would get wrapped in the way that wasm wraps imported JS functions.

Allow adding meta data

In response to w3ctag/design-reviews#532

function print(...args) {
  for (let x of args) console.log(x + "\n")
}

let table = new Table({element: "anyfunc", minimum: 10});

let print_i32 = new WebAssembly.Function({parameters: ["i32"], results: []}, print);
table.set(0, print_i32);
let print_f64 = new WebAssembly.Function({parameters: ["f64"], results: []}, print);
table.set(1, print_f64);
let print_i32_i32 = new WebAssembly.Function({parameters: ["i32", "i32"], results: []}, print);
table.set(2, print_i32_i32);

In the above example where you are exporting a JS function to Wasm, wouldn't it makes sense it I could supply meta data (in the WebAssembly.Function call) that would be given to the print method when run, so that I could change the formatting.

Reference types, typed function references

How will this evolve with (notably) the typed function references proposal? Unless I've misunderstood that proposal, it is possible for the new function types to be self-referential, leading to a non-tree structure being required in the js-types proposal; that's going to be a problem for any textual representation at least.

Limits not inlined.

Before this proposal, Limits have been inlined for Memory and Table types. Should we continue to inline the limits or should we allow both inlined and with explicit "limits" property.
If we go with the latter, for backwards compatibility, inlined (at least when using 'initial') should take precedence over using 'limits' property. Please clarify.

consider adding flag to the WebAssembly.Function that passes first argument as JS receiver

At the moment, the JS API specifies that, when calling a host function, undefined is always passed as the receiver. With the addition of externref, it would otherwise be possible to directly call built-in functions without an intermediate JS glue code function, so it's unfortunate to require a glue code function of the form:

function foo_called_from_wasm(receiver, arg1, arg2) {
  foo.call(receiver, arg1, arg2);
}

when calling a method (which is almost every function defined by Web IDL).

As an explicit, configurable way to coerce a JS (including Web IDL) function into a wasm function, I think WebAssembly.Function gives us a nice potential solution to this problem: add an optional dictionary parameter with an optional method field (default false) that indicates that the first wasm parameter should be rerouted to the receiver, as in the glue code above. So, for example, you could convert the DOM appendChild method into something wasm could call via:

new WebAssembly.Function({parameters:["externref", "externref"]}, Node.prototype.appendChild, {method:true});

An aesthetic question is whether "method:true" (or whatever that property should be named) should be merged with the first parameter. It'd look nice, but technically this first parameter is supposed to be describing a wasm function type, so I'm guessing "no".

Function names from WebAssembly.Function

In this simple example, what should be the function's name?

const print_1 = WebAssembly.Function({ parameters: [ "externref" ] }, console.log);

print_1( print_1.name );

Normally, when importing a function, it gets it's name from the order that it was imported in, so if this were to create a whole module to wrap it, then print_1.toString would show function 0() { [native code] }.

Should every call to WebAssembly.Function yield a function whose name is 0?

Fix auto-publishing

https://webassembly.github.io/js-types/js-api/index.html is way out of date, probably because CI fails to push to the gh-pages branch:

+git push [email protected]:WebAssembly/js-types.git gh-pages
Warning: Permanently added the RSA host key for IP address '140.82.114.4' to the list of known hosts.
[email protected]: Permission denied (publickey).
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.

from https://travis-ci.com/github/WebAssembly/js-types/builds/203525388

Use instance methods for type()

Currently, the explainer has static methods, to be used like

const t = WebAssembly.Table.type(table);

rather than the rather more ergonomic

const t = table.type();

Apparently this was inspired by Object static methods such as Object.keys. However, the main reason to put new APIs on the Object constructor rather than the prototype (AFAIK) is to avoid collisions with instance properties. That doesn't apply here - we don't really expect people to put arbitrary properties on these objects. In any case, these interfaces already have all of their API on the prototype, so putting the new methods would be more consistent with that as well.

Bind on WebAssembly.Function

TLDR: bind should be overrided for WebAssembly.Function to return regular JS Function.

According to the proposal WebAssembly.Function is a subclass of regular JS Function and Function.prototype in its prototype chain. It makes possible to call Function.prototype.bind on WebAssembly.Function object. It returns Bound Function exotic object with its [[Prototype]] internal field set to a prototype of target - WebAssembly.Function.prototype in our case. After that we get an object indistinguishable from WebAssembly.Function using instanceof machinery, but it couldn't be used as an argument for Table.set.

let wafn = new WebAssembly.Function({parameters: ['i32'], results:[]}, _ => 0)
let pseudo_wafn = wafn.bind(null)
console.log(pseudo_wafn instanceof WebAssembly.Function) // true in current state of things
console.log(pseudo_wafn.type().parameters) // ['i32']? []? but Function.prototype.bind knows nothing about WebAssembly.Function
let table = new WebAssembly.Table({ initial: 1, element: "anyfunc" })
table.set(0, pseudo_wafn) // throws an exception. pseudo_wafn is not a real WebAssembly.Function

To keep it consistent and predictable I propose to override bind on the level of WebAssembly.Function.prototype to behave exactly like original one, but return BoundFunctionObject with a regular function prototype. It allows to keep ergonomic on JS side without changing ecma262 spec.

Preservation of WebAssembly.Function identity upon re-export

We are currently prototyping this proposal in V8 and I wanted to ask for opinions on the preservation of the object identity of a function constructed via WebAssembly.Function when it is re-exported by a module. Should such a re-export preserve object identity? Using a concrete example and looking at the results of the two strict equality comparisons "EQ1" and "EQ2":

(function TestFunctionModuleImportReExport () {
  let builder = new WasmModuleBuilder();
  let fun = new WebAssembly.Function({parameters:[], results:["i32"]}, _ => 7);
  let fun_index = builder.addImport("m", "fun", kSig_i_v)
  builder.addExport("fun1", fun_index);
  builder.addExport("fun2", fun_index);
  let instance = builder.instantiate({ m: { fun: fun }});
  console.log("EQ1", instance.exports.fun1 === instance.exports.fun2);
  console.log("EQ2", fun === instance.exports.fun1);
})();

The current behavior for V8 will yield "EQ1 true" and "EQ2 false" at the moment.

  • For "EQ1" I see that it pretty clearly follows from step (2) in here.
  • For "EQ2" I am however not entirely sure it follows from step (3.4.2) in here, because it's unclear whether a function constructed via WebAssembly.Function has an internal [[FunctionAddress]] slot.

Any thoughts on this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.