| ... |
... |
@@ -783,25 +783,7 @@ class DyLD { |
|
783
|
783
|
|
|
784
|
784
|
// Wasm memory & table
|
|
785
|
785
|
#memory = new WebAssembly.Memory({ initial: 1 });
|
|
786
|
|
-
|
|
787
|
786
|
#table = new WebAssembly.Table({ element: "anyfunc", initial: 1 });
|
|
788
|
|
- // First free slot, might be invalid when it advances to #table.length
|
|
789
|
|
- #tableFree = 1;
|
|
790
|
|
- // See Note [The evil wasm table grower]
|
|
791
|
|
- #tableGrowInstance = new WebAssembly.Instance(
|
|
792
|
|
- new WebAssembly.Module(
|
|
793
|
|
- new Uint8Array([
|
|
794
|
|
- 0, 97, 115, 109, 1, 0, 0, 0, 1, 6, 1, 96, 1, 127, 1, 127, 2, 35, 1, 3,
|
|
795
|
|
- 101, 110, 118, 25, 95, 95, 105, 110, 100, 105, 114, 101, 99, 116, 95,
|
|
796
|
|
- 102, 117, 110, 99, 116, 105, 111, 110, 95, 116, 97, 98, 108, 101, 1,
|
|
797
|
|
- 112, 0, 0, 3, 2, 1, 0, 7, 31, 1, 27, 95, 95, 103, 104, 99, 95, 119, 97,
|
|
798
|
|
- 115, 109, 95, 106, 115, 102, 102, 105, 95, 116, 97, 98, 108, 101, 95,
|
|
799
|
|
- 103, 114, 111, 119, 0, 0, 10, 11, 1, 9, 0, 208, 112, 32, 0, 252, 15, 0,
|
|
800
|
|
- 11,
|
|
801
|
|
- ])
|
|
802
|
|
- ),
|
|
803
|
|
- { env: { __indirect_function_table: this.#table } }
|
|
804
|
|
- );
|
|
805
|
787
|
|
|
806
|
788
|
// __stack_pointer
|
|
807
|
789
|
#sp = new WebAssembly.Global(
|
| ... |
... |
@@ -846,82 +828,6 @@ class DyLD { |
|
846
|
828
|
// Global STG registers
|
|
847
|
829
|
#regs = {};
|
|
848
|
830
|
|
|
849
|
|
- // Note [The evil wasm table grower]
|
|
850
|
|
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
851
|
|
- // We need to grow the wasm table as we load shared libraries in
|
|
852
|
|
- // wasm dyld. We used to directly call the table.grow() JS API,
|
|
853
|
|
- // which works as expected in Firefox/Chrome, but unfortunately,
|
|
854
|
|
- // WebKit's implementation of the table.grow() JS API is broken:
|
|
855
|
|
- // https://bugs.webkit.org/show_bug.cgi?id=290681, which means that
|
|
856
|
|
- // the wasm dyld simply does not work in WebKit-based browsers like
|
|
857
|
|
- // Safari.
|
|
858
|
|
- //
|
|
859
|
|
- // Now, one simple workaround would be to avoid growing the table at
|
|
860
|
|
- // all: just allocate a huge table upfront (current limitation
|
|
861
|
|
- // agreed by all vendors is 10000000). To avoid unnecessary space
|
|
862
|
|
- // waste on non-WebKit platforms, we could additionally check
|
|
863
|
|
- // navigator.userAgent against some regexes and only allocate
|
|
864
|
|
- // fixed-length table when there's no blink/gecko mention. But this
|
|
865
|
|
- // is fragile and gross, and it's better to stick to a uniform code
|
|
866
|
|
- // path for all browsers.
|
|
867
|
|
- //
|
|
868
|
|
- // Fortunately, it turns out the table.grow wasm instruction work as
|
|
869
|
|
- // expected in WebKit! So we can invoke a wasm function that grows
|
|
870
|
|
- // the table for us. But don't open a champagne yet, where would
|
|
871
|
|
- // that wasm function come from? It can't be put into RTS, or even
|
|
872
|
|
- // libc.so, because loading those libraries would require growing
|
|
873
|
|
- // the table in the first place! Or perhaps, reserve a table upfront
|
|
874
|
|
- // that's just large enough to load RTS and then we can access that
|
|
875
|
|
- // function for subsequent table grows? But then we need to
|
|
876
|
|
- // experiment for a reasonable initial size, and add a magic number
|
|
877
|
|
- // here, which is also fragile and gross and not future-proof!
|
|
878
|
|
- //
|
|
879
|
|
- // So this special wasm function needs to live in a single wasm
|
|
880
|
|
- // module, which is loaded before we load anything else. The full
|
|
881
|
|
- // source code for this module is:
|
|
882
|
|
- //
|
|
883
|
|
- // (module
|
|
884
|
|
- // (type (func (param i32) (result i32)))
|
|
885
|
|
- // (import "env" "__indirect_function_table" (table 0 funcref))
|
|
886
|
|
- // (export "__ghc_wasm_jsffi_table_grow" (func 0))
|
|
887
|
|
- // (func (type 0) (param i32) (result i32)
|
|
888
|
|
- // ref.null func
|
|
889
|
|
- // local.get 0
|
|
890
|
|
- // table.grow 0
|
|
891
|
|
- // )
|
|
892
|
|
- // )
|
|
893
|
|
- //
|
|
894
|
|
- // This module is 103 bytes so that we can inline its blob in dyld,
|
|
895
|
|
- // and use the usually discouraged synchronous
|
|
896
|
|
- // WebAssembly.Instance/WebAssembly.Module constructors to load it.
|
|
897
|
|
- // On non-WebKit platforms, growing tables this way would introduce
|
|
898
|
|
- // a bit of extra JS/Wasm interop overhead, which can be amplified
|
|
899
|
|
- // as we used to call table.grow(1, foo) for every GOT.func item.
|
|
900
|
|
- // Therefore, unless we're about to exceed the hard limit of table
|
|
901
|
|
- // size, we now grow the table exponentially, and use bump
|
|
902
|
|
- // allocation to calculate the table index to be returned.
|
|
903
|
|
- // Exponential growth is only implemented to minimize the JS/Wasm
|
|
904
|
|
- // interop overhead when calling __ghc_wasm_jsffi_table_grow;
|
|
905
|
|
- // V8/SpiderMonkey/WebKit already do their own exponential growth of
|
|
906
|
|
- // the table's backing buffer in their table growth logic.
|
|
907
|
|
- //
|
|
908
|
|
- // Invariants: n >= 0; when v is non-null, n === 1
|
|
909
|
|
- #tableGrow(n, v) {
|
|
910
|
|
- const prev_free = this.#tableFree;
|
|
911
|
|
- if (prev_free + n > this.#table.length) {
|
|
912
|
|
- const min_delta = prev_free + n - this.#table.length;
|
|
913
|
|
- const delta = Math.max(min_delta, this.#table.length);
|
|
914
|
|
- this.#tableGrowInstance.exports.__ghc_wasm_jsffi_table_grow(
|
|
915
|
|
- this.#table.length + delta <= 10000000 ? delta : min_delta
|
|
916
|
|
- );
|
|
917
|
|
- }
|
|
918
|
|
- if (v) {
|
|
919
|
|
- this.#table.set(prev_free, v);
|
|
920
|
|
- }
|
|
921
|
|
- this.#tableFree += n;
|
|
922
|
|
- return prev_free;
|
|
923
|
|
- }
|
|
924
|
|
-
|
|
925
|
831
|
constructor({ args, rpc }) {
|
|
926
|
832
|
this.#rpc = rpc;
|
|
927
|
833
|
|
| ... |
... |
@@ -1116,7 +1022,7 @@ class DyLD { |
|
1116
|
1022
|
|
|
1117
|
1023
|
// __memory_base & __table_base, different for each .so
|
|
1118
|
1024
|
let memory_base;
|
|
1119
|
|
- let table_base = this.#tableGrow(tableSize);
|
|
|
1025
|
+ let table_base = this.#table.grow(tableSize);
|
|
1120
|
1026
|
console.assert(tableP2Align === 0);
|
|
1121
|
1027
|
|
|
1122
|
1028
|
// libc.so is always the first one to be ever loaded and has VIP
|
| ... |
... |
@@ -1220,7 +1126,7 @@ class DyLD { |
|
1220
|
1126
|
if (this.exportFuncs[name]) {
|
|
1221
|
1127
|
this.#gotFunc[name] = new WebAssembly.Global(
|
|
1222
|
1128
|
{ value: "i32", mutable: true },
|
|
1223
|
|
- this.#tableGrow(1, this.exportFuncs[name])
|
|
|
1129
|
+ this.#table.grow(1, this.exportFuncs[name])
|
|
1224
|
1130
|
);
|
|
1225
|
1131
|
continue;
|
|
1226
|
1132
|
}
|
| ... |
... |
@@ -1271,7 +1177,7 @@ class DyLD { |
|
1271
|
1177
|
if (this.#gotFunc[k]) {
|
|
1272
|
1178
|
const got = this.#gotFunc[k];
|
|
1273
|
1179
|
if (got.value === DyLD.#poison) {
|
|
1274
|
|
- const idx = this.#tableGrow(1, v);
|
|
|
1180
|
+ const idx = this.#table.grow(1, v);
|
|
1275
|
1181
|
got.value = idx;
|
|
1276
|
1182
|
} else {
|
|
1277
|
1183
|
this.#table.set(got.value, v);
|
| ... |
... |
@@ -1325,7 +1231,7 @@ class DyLD { |
|
1325
|
1231
|
// Not in GOT.func yet, create the entry on demand
|
|
1326
|
1232
|
if (this.exportFuncs[sym]) {
|
|
1327
|
1233
|
console.assert(!this.#gotFunc[sym]);
|
|
1328
|
|
- const addr = this.#tableGrow(1, this.exportFuncs[sym]);
|
|
|
1234
|
+ const addr = this.#table.grow(1, this.exportFuncs[sym]);
|
|
1329
|
1235
|
this.#gotFunc[sym] = new WebAssembly.Global(
|
|
1330
|
1236
|
{ value: "i32", mutable: true },
|
|
1331
|
1237
|
addr
|