Skip to content
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 exception paragraph to JSPI article #703

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Conversation

tomayac
Copy link
Contributor

@tomayac tomayac commented Jul 18, 2023

This came up as a developer question.

src/blog/jspi.md Outdated Show resolved Hide resolved
Copy link
Contributor

@tlively tlively left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, assuming you think this will be clear enough for the target audience.

Copy link
Contributor

@fgmccabe fgmccabe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, I am not sure that this is good advice for someone using JSPI.

JSPI does include an exception handling provision: a rejected Promise returned by a call to an import becomes an exception in your code: your import call raises an exception.

Similarly, if your main program raises an exception, it becomes a rejected Promise.

OTOH, if you are using a language that does not have an exception mechanism, then, yes, you need to map rejected promises into a return code of some kind.

@tlively
Copy link
Contributor

tlively commented Jul 18, 2023

Are there any toolchains that actually handle the exceptions thrown by JSPI properly? @aheejin or @brendandahl, do you know if Emscripten supports this?

If so, it would be good to add an example of this to the docs, otherwise I think the current recommendation in this PR makes sense.

@aheejin
Copy link

aheejin commented Jul 18, 2023

As long as they are JS exceptions, Wasm EH instructions will treat that as such, meaning, catch_all will catch it and tagged catch can also catch it if a module imports the JS tag (WebAssembly/exception-handling#269).

@brendandahl
Copy link

I haven't experimented with JSPI and exceptions. Maybe @SPY knows the status in V8?

@tlively
Copy link
Contributor

tlively commented Jul 19, 2023

But does that work out of the box with Emscripten, @aheejin?

@aheejin
Copy link

aheejin commented Jul 19, 2023

For catch_all catching JS exceptions, it has been supported for long time now.

For catch catching JS exceptions with the imported JS tag, it was recently added in V8 and I haven't tested it myself, but if you use Emscripten's Wasm EH support and fix the js files manually and run it with V8, I think you should be able run them. V8's test code has an example:
https://github.com/v8/v8/blob/8f6ab4d613bcdb498aac91235694ac0d478ef5d4/test/mjsunit/wasm/exceptions-api.js#L269-L305

But this JS tag spec has not landed yet in the EH repo. I think we shouldn't assume this feature as finished at this point.

@tlively
Copy link
Contributor

tlively commented Jul 20, 2023

Thanks. Since Emscripten does not support smooth interop with JSPI exceptions (or any JS exceptions) at the moment, I think this PR should be good to land as-is.

@tomayac tomayac enabled auto-merge (squash) July 20, 2023 06:24
@fgmccabe
Copy link
Contributor

I am drafting some text to more fully explain this. However, it turns out that returning multiple values (result+errorcode) from JS into wasm/C is completely non-trivial :(

@fgmccabe
Copy link
Contributor

I propose the following wording re exceptions:

Some programming languages, such as C, do not have explicit mechanisms for handling exceptions. In addition, dealing with foreign exceptions in languages that do support exceptions is always likely to be difficult and not very portable. So, while JSPI does support exceptions -- in the sense that a rejected Promise associated with a wrapped import results in an exception being thrown -- you may need to avoid dealing with exceptions in your code.

One way of dealing with this is to map the result of an operation into a combination of a result value and an error code. In this strategy, you would need to modify the JS of the function you are calling to catch all exceptions and map them into the result code/result value pair. For example, one might write:

function suspFun(args...){
  try{
    return [ok,realFun(args)];
  } catch (E){
    return [bad,E];
  }
}

On the WebAssembly side, you would need to have code that checked the result code to ensure that the results are as expected. In this case, though, it is unfortunately very awkward to deal with arrays coming from JS in C. What we actually have to write is closer to:

const ok = 0;
const bad = 1;
function suspFun(ptr,args...){
  try{
     setValue(ptr,ok,i32);
     setValue(ptr+4,realFun(args),i32)); // depending on the return type of realFun
    return ptr;
  } catch (E){
    setValue(ptr,bad,i32);
    setValue(ptr+4,E,*);      // We can't really handle exceptions in C
    return ptr;
  }
}

On the C/WebAssembly side, the call to the suspFun import would look something like:

struct{
  enum{ok,bad} code;
  void *result
} RetSpec;

suspFun(&RetSpec,arg0,..,argn);

This code is understandably fairly ugly, but this complexity is not specifically due to JSPI but rather because C and JavaScript are very different languages; and the boundaries between them have not been fully 'smoothed out'.

@tlively
Copy link
Contributor

tlively commented Jul 21, 2023

Perhaps we can simplify things by having an example where the suspended function just returns 0 on success and -1 on failure. The problem of returning multiple values into Wasm is a real problem, but not directly related to JSPI.

@fgmccabe
Copy link
Contributor

Or we can not change the blog post at all; given that the issues are not actually JSPI-related.

@tlively
Copy link
Contributor

tlively commented Jul 24, 2023

I think saying something about how to handle errors would be useful. This PR was motivated by a partner asking us about error handling with JSPI, and I'm sure other developers would wonder the same thing. The current content of this PR is the best advice we can give that works today with existing toolchains (i.e. Emscripten), so perhaps we can add "In the future, toolchains may make it easier to handle JS exceptions directly" and land this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants