Bug 172188 - We don't do context switches for Wasm->Wasm call indirect
Summary: We don't do context switches for Wasm->Wasm call indirect
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Saam Barati
URL:
Keywords: InRadar
Depends on:
Blocks: 172197 165546
  Show dependency treegraph
 
Reported: 2017-05-16 14:26 PDT by Saam Barati
Modified: 2017-05-17 17:24 PDT (History)
11 users (show)

See Also:


Attachments
WIP (8.46 KB, patch)
2017-05-16 15:45 PDT, Saam Barati
no flags Details | Formatted Diff | Diff
WIP (35.40 KB, patch)
2017-05-16 17:36 PDT, Saam Barati
no flags Details | Formatted Diff | Diff
patch (38.99 KB, patch)
2017-05-16 17:49 PDT, Saam Barati
no flags Details | Formatted Diff | Diff
patch (39.57 KB, patch)
2017-05-16 18:00 PDT, Saam Barati
no flags Details | Formatted Diff | Diff
patch (39.60 KB, patch)
2017-05-16 18:34 PDT, Saam Barati
keith_miller: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Saam Barati 2017-05-16 14:26:14 PDT
...
Comment 1 Saam Barati 2017-05-16 14:26:36 PDT
We just read random memory and call it, potentially. Fun stuff
Comment 2 Radar WebKit Bug Importer 2017-05-16 14:27:08 PDT
<rdar://problem/32231828>
Comment 3 Saam Barati 2017-05-16 14:29:46 PDT
For example:
```
import Builder from '../Builder.js'
import * as assert from '../assert.js'

{
    function makeInstance() {
        const tableDescription = {initial: 1, element: "anyfunc"};
        const builder = new Builder()
            .Type()
                .Func([], "void")
            .End()
            .Import()
                .Table("imp", "table", tableDescription)
            .End()
            .Function().End()
            .Export()
                .Function("foo")
            .End()
            .Code()
                .Function("foo", {params:["i32"], ret:"void"})
                    .GetLocal(0) // parameter to call
                    .GetLocal(0) // call index
                    .CallIndirect(0, 0) // calling function of type [] => 'void'
                    .Return()
                .End()
            .End();


        const bin = builder.WebAssembly().get();
        const module = new WebAssembly.Module(bin);
        const table = new WebAssembly.Table(tableDescription);
        return {instance: new WebAssembly.Instance(module, {imp: {table}}), table};
    }

    function makeInstance2() {
        const tableDescription = {initial: 1, element: "anyfunc"};
        const builder = new Builder()
            .Type()
            .End()
            .Import()
                .Function("imp", "f", {params:[], ret:"void"})
            .End()
            .Function().End()
            .Export()
                .Function("foo")
            .End()
            .Code()
                .Function("foo", {params: [], ret: "void" })
                    .Call(0)
                    .Return()
                .End()
            .End();


        const bin = builder.WebAssembly().get();
        const module = new WebAssembly.Module(bin);
        return new WebAssembly.Instance(module, {imp: {f: function() { print("Inside f"); }}});
    }

    const {instance: i1, table: t1} = makeInstance();
    const foo = i1.exports.foo;

    const i2 = makeInstance2();
    t1.set(0, i2.exports.foo);
    
    foo(0);
}
```
Comment 4 Saam Barati 2017-05-16 15:45:08 PDT
Created attachment 310308 [details]
WIP

I'm thinking of moving to a thunk approach, so we're not stuck with this branchiness. Just putting this here since I think it works.
Comment 5 Saam Barati 2017-05-16 15:51:52 PDT
The thunk approach could be like this:

A table has three states:
- NoInstance: not yet tied to an instance, so we hold off on making any thunks, since it's not yet callable from wasm
- SingleInstance: Now, all functions in the table only need thunks to context switch if they're from a different instance
- MultipleInstances: now all functions need context switching thunks regardless, since we don't know what instance is calling us. We could have the thunk branch to see if it's actually performing a context switch.
Comment 6 Saam Barati 2017-05-16 16:22:08 PDT
(In reply to Saam Barati from comment #5)
> The thunk approach could be like this:
> 
> A table has three states:
> - NoInstance: not yet tied to an instance, so we hold off on making any
> thunks, since it's not yet callable from wasm
> - SingleInstance: Now, all functions in the table only need thunks to
> context switch if they're from a different instance
> - MultipleInstances: now all functions need context switching thunks
> regardless, since we don't know what instance is calling us. We could have
> the thunk branch to see if it's actually performing a context switch.

Ima save thunk land for:
https://bugs.webkit.org/show_bug.cgi?id=172197
Comment 7 Saam Barati 2017-05-16 17:36:44 PDT
Created attachment 310330 [details]
WIP

Might be done.
Comment 8 Saam Barati 2017-05-16 17:49:24 PDT
Created attachment 310332 [details]
patch
Comment 9 Saam Barati 2017-05-16 18:00:58 PDT
Created attachment 310336 [details]
patch

added file to cmakelists.
Comment 10 Saam Barati 2017-05-16 18:34:53 PDT
Created attachment 310340 [details]
patch
Comment 11 Saam Barati 2017-05-17 11:36:31 PDT
Comment on attachment 310340 [details]
patch

View in context: https://bugs.webkit.org/attachment.cgi?id=310340&action=review

> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:1155
> +        BasicBlock* continuation = m_proc.addBlock();
> +        BasicBlock* doContextSwitch = m_proc.addBlock();

These should probably be switched for better block ordering.
Comment 12 JF Bastien 2017-05-17 11:54:42 PDT
Comment on attachment 310340 [details]
patch

View in context: https://bugs.webkit.org/attachment.cgi?id=310340&action=review

> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:1170
> +        patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {

I think as a follow-up to this patch I'd rather have this be outlined, and shared between all modules. Kinda like what we do for direct wasm->wasm calls, but cleaned up. I think the code duplication and compile cost aren't worth it, because I don't think inlining exposes any perf win here.

Maybe add a FIXME?
Comment 13 Saam Barati 2017-05-17 11:56:07 PDT
Comment on attachment 310340 [details]
patch

View in context: https://bugs.webkit.org/attachment.cgi?id=310340&action=review

>> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:1170
>> +        patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
> 
> I think as a follow-up to this patch I'd rather have this be outlined, and shared between all modules. Kinda like what we do for direct wasm->wasm calls, but cleaned up. I think the code duplication and compile cost aren't worth it, because I don't think inlining exposes any perf win here.
> 
> Maybe add a FIXME?

I think long term we just want to do this:
https://bugs.webkit.org/show_bug.cgi?id=172197
Comment 14 Keith Miller 2017-05-17 14:38:49 PDT
Comment on attachment 310340 [details]
patch

View in context: https://bugs.webkit.org/attachment.cgi?id=310340&action=review

r=me.

>> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:1155
>> +        BasicBlock* doContextSwitch = m_proc.addBlock();
> 
> These should probably be switched for better block ordering.

I don't think this matters. Doesn't B3 pick the ordering it wants later anyway?

> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:1164
> +        PatchpointValue* patchpoint = doContextSwitch->appendNew<PatchpointValue>(m_proc, B3::Void, origin());

I think you need to say this writes pinned.
Comment 15 Saam Barati 2017-05-17 17:24:13 PDT
landed in:
https://trac.webkit.org/changeset/217017/webkit