COMMIT_MESSAGE

 1wasm->wasm
 2
 3Changes to the WebAssembly implementation:
 4
 5 - Add a new JSType for WebAssemblyFunction, and use it when creating its
 6 structure. This will be used to quickly detect from wasm whether the import
 7 call is to another wasm module, or whether it's to JS.
 8 - Use cell instead of objects to detect wasm->wasm, the previous code was wrong.
 9 - Improve diagnostic printout for wasm stubs: print the full signature.
 10 - Properly check that wasm -> wasm calls have matching signatures. Add testing for this.
 11 - Test some of the wasm -> wasm calls, not working yet, and more tests need to
 12 get implemented.
 13 - Generate two stubs from the import stub generator: one for wasm->JS and one
 14 for wasm -> wasm. This is done at Module time. Which is called will only be
 15 known at Instance time, once we've received the import object. We want to
 16 avoid codegen at Instance time, so having both around is great.
 17 - Restore the WebAssembly global state (VM top Instance, and pinned registers)
 18 after call / call_indirect, and in the JS->wasm entry stub.
 19
 20Support changes:
 21
 22 - Add a Proxy to Builder.js, which intercepts unknown property lookups. This
 23 creates way better error messages on typos than 'undefined is not a
 24 function', which happens semi-frequently as I typo opcode names (and which
 25 one is a typo is hard to find because we chain builders).
 26 - Add limited support for var{u}int64 (only the 32-bit values).
 27 - Get rid of much of the function index space: we already have all of its
 28 information elsewhere, and as-is it provides no extra efficiency.
 29 - Store Wasm::Memory directly on JSWebAssemblyMemory, instead of through a
 30 unique_ptr. This removes an indirection and useless allocation.
 31 - Remove VM'a WebAssembly memory / size, and obtain them from Instance
 32 instead. This requires an extra indirection, but is cleaner.

JSTests/wasm/Builder.js

@@const _isValidValue = (value, type) => {
3838 switch (type) {
3939 // We allow both signed and unsigned numbers.
4040 case "i32": return Math.round(value) === value && LLB.varint32Min <= value && value <= LLB.varuint32Max;
41  case "i64": throw new Error(`Unimplemented: value check for ${type}`); // FIXME https://bugs.webkit.org/show_bug.cgi?id=163420 64-bit values
 41 case "i64": return true; // FIXME https://bugs.webkit.org/show_bug.cgi?id=163420 64-bit values
4242 case "f32": return typeof(value) === "number" && isFinite(value);
4343 case "f64": return typeof(value) === "number" && isFinite(value);
4444 default: throw new Error(`Implementation problem: unknown type ${type}`);

@@const _normalizeFunctionSignature = (params, ret) => {
5757 return [params, ret];
5858};
5959
 60const _errorHandlingProxyFor = builder => builder["__isProxy"] ? builder : new Proxy(builder, {
 61 get: (target, property, receiver) => {
 62 if (property === "__isProxy")
 63 return true;
 64 if (target[property] === undefined)
 65 throw new Error(`WebAssembly builder received unknown property '${property}'`);
 66 return target[property];
 67 }
 68});
 69
6070const _maybeRegisterType = (builder, type) => {
6171 const typeSection = builder._getSection("Type");
6272 if (typeof(type) === "number") {

@@const _importFunctionContinuation = (builder, section, nextBuilder) => {
100110 section.data.push({ field: field, type: type, kind: "Function", module: module });
101111 // Imports also count in the function index space. Map them as objects to avoid clashing with Code functions' names.
102112 builder._registerFunctionToIndexSpace({ module: module, field: field });
103  return nextBuilder;
 113 return _errorHandlingProxyFor(nextBuilder);
104114 };
105115};
106116

@@const _importMemoryContinuation = (builder, section, nextBuilder) => {
109119 assert.isString(module, `Import Memory module should be a string, got "${module}"`);
110120 assert.isString(field, `Import Memory field should be a string, got "${field}"`);
111121 section.data.push({module, field, kind: "Memory", memoryDescription: {initial, maximum}});
112  return nextBuilder;
 122 return _errorHandlingProxyFor(nextBuilder);
113123 };
114124};
115125

@@const _importTableContinuation = (builder, section, nextBuilder) => {
118128 assert.isString(module, `Import Table module should be a string, got "${module}"`);
119129 assert.isString(field, `Import Table field should be a string, got "${field}"`);
120130 section.data.push({module, field, kind: "Table", tableDescription: {initial, maximum, element}});
121  return nextBuilder;
 131 return _errorHandlingProxyFor(nextBuilder);
122132 };
123133};
124134

@@const _exportFunctionContinuation = (builder, section, nextBuilder) => {
172182 assert.eq(type, exportedImport.type, `Re-exporting import "${exportedImport.field}" as "${field}" has mismatching type`);
173183 }
174184 section.data.push({ field: field, type: type, kind: "Function", index: index });
175  return nextBuilder;
 185 return _errorHandlingProxyFor(nextBuilder);
176186 };
177187};
178188

@@const _exportGlobalContinuation = (builder, section, nextBuilder) => {
189199 return (field, index) => {
190200 assert.isNumber(index, `Global exports only support number indices right now`);
191201 section.data.push({ field, kind: "Global", index });
192  return nextBuilder;
 202 return _errorHandlingProxyFor(nextBuilder);
193203 }
194204};
195205

@@const _exportMemoryContinuation = (builder, section, nextBuilder) => {
197207 return (field, index) => {
198208 assert.isNumber(index, `Memory exports only support number indices`);
199209 section.data.push({field, kind: "Memory", index});
200  return nextBuilder;
 210 return _errorHandlingProxyFor(nextBuilder);
201211 }
202212};
203213

@@const _exportTableContinuation = (builder, section, nextBuilder) => {
205215 return (field, index) => {
206216 assert.isNumber(index, `Table exports only support number indices`);
207217 section.data.push({field, kind: "Table", index});
208  return nextBuilder;
 218 return _errorHandlingProxyFor(nextBuilder);
209219 }
210220};
211221

@@const _importGlobalContinuation = (builder, section, nextBuilder) => {
220230 assert.isString(field, `Import global field should be a string, got "${field}"`);
221231 assert.isString(mutability, `Import global mutability should be a string, got "${mutability}"`);
222232 section.data.push({ globalDescription: { type: op, mutability: _normalizeMutability(mutability) }, module, field, kind: "Global" });
223  return globalBuilder;
 233 return _errorHandlingProxyFor(globalBuilder);
224234 };
225235 }
226  return globalBuilder;
 236 return _errorHandlingProxyFor(globalBuilder);
227237 };
228238};
229239

@@const _createFunctionBuilder = (func, builder, previousBuilder) => {
324334 default:
325335 nextBuilder = functionBuilder;
326336 break;
327  case "End":
 337 case "End":
328338 nextBuilder = previousBuilder;
329  break;
 339 break;
330340 case "Block":
331  case "Loop":
 341 case "Loop":
332342 case "If":
333343 nextBuilder = _createFunctionBuilder(func, builder, functionBuilder);
334344 break;

@@const _createFunctionBuilder = (func, builder, previousBuilder) => {
344354 const stackArgs = []; // FIXME https://bugs.webkit.org/show_bug.cgi?id=162706
345355 func.code.push({ name: op, value: value, arguments: stackArgs, immediates: imms });
346356 if (hasContinuation)
347  return continuation(nextBuilder).End();
348  return nextBuilder;
 357 return _errorHandlingProxyFor(continuation(nextBuilder).End());
 358 return _errorHandlingProxyFor(nextBuilder);
349359 };
350  }
351  return functionBuilder;
 360 };
 361
 362 return _errorHandlingProxyFor(functionBuilder);
352363}
353364
354365const _createFunction = (section, builder, previousBuilder) => {

@@export default class Builder {
449460 Func: (params, ret) => {
450461 [params, ret] = _normalizeFunctionSignature(params, ret);
451462 s.data.push({ params: params, ret: ret });
452  return typeBuilder;
 463 return _errorHandlingProxyFor(typeBuilder);
453464 },
454465 };
455  return typeBuilder;
 466 return _errorHandlingProxyFor(typeBuilder);
456467 };
457468 break;
458469

@@export default class Builder {
466477 importBuilder.Function = _importFunctionContinuation(this, s, importBuilder);
467478 importBuilder.Memory = _importMemoryContinuation(this, s, importBuilder);
468479 importBuilder.Table = _importTableContinuation(this, s, importBuilder);
469  return importBuilder;
 480 return _errorHandlingProxyFor(importBuilder);
470481 };
471482 break;
472483

@@export default class Builder {
477488 End: () => this
478489 // FIXME: add ability to add this with whatever.
479490 };
480  return functionBuilder;
 491 return _errorHandlingProxyFor(functionBuilder);
481492 };
482493 break;
483494

@@export default class Builder {
488499 End: () => this,
489500 Table: ({initial, maximum, element}) => {
490501 s.data.push({tableDescription: {initial, maximum, element}});
491  return tableBuilder;
 502 return _errorHandlingProxyFor(tableBuilder);
492503 }
493504 };
494  return tableBuilder;
 505 return _errorHandlingProxyFor(tableBuilder);
495506 };
496507 break;
497508

@@export default class Builder {
502513 End: () => this,
503514 InitialMaxPages: (initial, max) => {
504515 s.data.push({ initial, max });
505  return memoryBuilder;
 516 return _errorHandlingProxyFor(memoryBuilder);
506517 }
507518 };
508  return memoryBuilder;
 519 return _errorHandlingProxyFor(memoryBuilder);
509520 };
510521 break;
511522

@@export default class Builder {
516527 End: () => this,
517528 GetGlobal: (type, initValue, mutability) => {
518529 s.data.push({ type, op: "get_global", mutability: _normalizeMutability(mutability), initValue });
519  return globalBuilder;
 530 return _errorHandlingProxyFor(globalBuilder);
520531 }
521532 };
522533 for (let op of WASM.description.value_type) {
523534 globalBuilder[_toJavaScriptName(op)] = (initValue, mutability) => {
524535 s.data.push({ type: op, op: op + ".const", mutability: _normalizeMutability(mutability), initValue });
525  return globalBuilder;
 536 return _errorHandlingProxyFor(globalBuilder);
526537 };
527538 }
528  return globalBuilder;
 539 return _errorHandlingProxyFor(globalBuilder);
529540 };
530541 break;
531542

@@export default class Builder {
539550 exportBuilder.Function = _exportFunctionContinuation(this, s, exportBuilder);
540551 exportBuilder.Memory = _exportMemoryContinuation(this, s, exportBuilder);
541552 exportBuilder.Table = _exportTableContinuation(this, s, exportBuilder);
542  return exportBuilder;
 553 return _errorHandlingProxyFor(exportBuilder);
543554 };
544555 break;
545556

@@export default class Builder {
552563 if (typeof(functionIndexOrName) !== "number" && typeof(functionIndexOrName) !== "string")
553564 throw new Error(`Start section's function index must either be a number or a string`);
554565 s.data.push(functionIndexOrName);
555  return startBuilder;
 566 return _errorHandlingProxyFor(startBuilder);
556567 };
557568 break;
558569

@@export default class Builder {
563574 End: () => this,
564575 Element: ({tableIndex = 0, offset, functionIndices}) => {
565576 s.data.push({tableIndex, offset, functionIndices});
566  return elementBuilder;
 577 return _errorHandlingProxyFor(elementBuilder);
567578 }
568579 };
569580
570  return elementBuilder;
 581 return _errorHandlingProxyFor(elementBuilder);
571582 };
572583 break;
573584

@@export default class Builder {
632643 // FIXME in checked mode, test that the type is acceptable for start function. We probably want _registerFunctionToIndexSpace to also register types per index. https://bugs.webkit.org/show_bug.cgi?id=165658
633644 }
634645 }
635  return builder;
 646 return _errorHandlingProxyFor(builder);
636647 },
637648
638649 };
639650 codeBuilder.Function = _createFunction(s, builder, codeBuilder);
640  return codeBuilder;
 651 return _errorHandlingProxyFor(codeBuilder);
641652 };
642653 break;
643654

@@export default class Builder {
660671 Index: index => {
661672 assert.eq(index, 0); // Linear memory index must be zero in MVP.
662673 thisSegment.index = index;
663  return segmentBuilder;
 674 return _errorHandlingProxyFor(segmentBuilder);
664675 },
665676 Offset: offset => {
666677 // FIXME allow complex init_expr here. https://bugs.webkit.org/show_bug.cgi?id=165700
667678 assert.isNumber(offset);
668679 thisSegment.offset = offset;
669  return segmentBuilder;
 680 return _errorHandlingProxyFor(segmentBuilder);
670681 },
671682 };
672  return segmentBuilder;
 683 return _errorHandlingProxyFor(segmentBuilder);
673684 },
674685 };
675  return dataBuilder;
 686 return _errorHandlingProxyFor(dataBuilder);
676687 };
677688 break;
678689

@@export default class Builder {
690701 Byte: b => {
691702 assert.eq(b & 0xFF, b, `Unknown section expected byte, got: "${b}"`);
692703 s.data.push(b);
693  return unknownBuilder;
 704 return _errorHandlingProxyFor(unknownBuilder);
694705 }
695706 };
696  return unknownBuilder;
 707 return _errorHandlingProxyFor(unknownBuilder);
697708 };
698709 }
699710 _addSection(nameOrNumber, extraObject) {

JSTests/wasm/LowLevelBinary.js

@@export default class LowLevelBinary {
170170 this.uint8(0x80 | b);
171171 } while (true);
172172 }
 173 varuint64(v) {
 174 assert.isNumber(v);
 175 if (v < varuint32Min || varuint32Max < v)
 176 throw new RangeError(`unimplemented: varuint64 larger than 32-bit`);
 177 this.varuint32(v); // FIXME implement 64-bit var{u}int https://bugs.webkit.org/show_bug.cgi?id=163420
 178 }
 179 varint64(v) {
 180 assert.isNumber(v);
 181 if (v < varint32Min || varint32Max < v)
 182 throw new RangeError(`unimplemented: varint64 larger than 32-bit`);
 183 this.varint32(v); // FIXME implement 64-bit var{u}int https://bugs.webkit.org/show_bug.cgi?id=163420
 184 }
173185 varuint1(v) {
174186 if (v !== 0 && v !== 1)
175187 throw new RangeError(`Invalid varuint1 ${v} range is [0, 1]`);

JSTests/wasm/function-tests/exceptions.js

@@function makeInstance() {
4545 assert.eq(table.get(0), null);
4646
4747 for (let i = 0; i < 1000; i++) {
48  assert.throws(() => foo(0, i), WebAssembly.RuntimeError, "call_indirect to a null table entry (evaluating 'func(...args)')");
 48 assert.throws(() => foo(0, i), WebAssembly.RuntimeError, "call_indirect to a null table entry");
4949 }
5050
5151 table.set(0, foo);
5252 assert.eq(table.get(0), foo);
5353
5454 for (let i = 0; i < 1000; i++) {
55  assert.throws(() => foo(1 + i, i), WebAssembly.RuntimeError, "Out of bounds call_indirect (evaluating 'func(...args)')");
 55 assert.throws(() => foo(1 + i, i), WebAssembly.RuntimeError, "Out of bounds call_indirect");
5656 }
5757
5858 for (let i = 0; i < 1000; i++) {
59  assert.throws(() => foo(0, i), WebAssembly.RuntimeError, "call_indirect to a signature that does not match (evaluating 'func(...args)')");
 59 assert.throws(() => foo(0, i), WebAssembly.RuntimeError, "call_indirect to a signature that does not match");
6060 }
6161
6262 table.set(0, bar);

JSTests/wasm/function-tests/trap-load.js

@@function wasmFrameCountFromError(e) {
2929}
3030
3131for (let i = 0; i < 1000; i++) {
32  const e = assert.throws(() => foo(numPages * pageSize + 1), WebAssembly.RuntimeError, "Out of bounds memory access (evaluating 'func(...args)')");
 32 const e = assert.throws(() => foo(numPages * pageSize + 1), WebAssembly.RuntimeError, "Out of bounds memory access");
3333 assert.eq(wasmFrameCountFromError(e), 2);
3434}

JSTests/wasm/function-tests/trap-store.js

@@const numPages = 10;
2525 const foo = new WebAssembly.Instance(module, {a: {b: new WebAssembly.Memory({initial: numPages})}}).exports.foo;
2626
2727 for (let i = 0; i < 10000; i++)
28  assert.throws(() => foo(i, numPages * pageSize + 1), WebAssembly.RuntimeError, "Out of bounds memory access (evaluating 'func(...args)')");
 28 assert.throws(() => foo(i, numPages * pageSize + 1), WebAssembly.RuntimeError, "Out of bounds memory access");
2929}

JSTests/wasm/js-api/wasm-to-wasm-bad-signature.js

 1import * as assert from '../assert.js';
 2import Builder from '../Builder.js';
 3
 4const importName = "pierOne";
 5const types = ["i32", "i64", "f32", "f64", "void"];
 6const typesNonVoid = ["i32", "i64", "f32", "f64"];
 7const swapType = (type, index) => types[(types.indexOf(type) + index) % types.length];
 8const swapTypeNonVoid = (type, index) => typesNonVoid[(typesNonVoid.indexOf(type) + index) % typesNonVoid.length];
 9
 10const signatures = [
 11 { params: ["i32"], ret: "void" },
 12 { params: ["i64"], ret: "void" },
 13 { params: ["f32"], ret: "void" },
 14 { params: ["f64"], ret: "void" },
 15 { params: ["i32"], ret: "i32" },
 16 { params: ["i64"], ret: "i64" },
 17 { params: ["f32"], ret: "f32" },
 18 { params: ["f64"], ret: "f64" },
 19 { params: ["i32", "f32"], ret: "i32" },
 20 { params: ["f32", "i32"], ret: "i32" },
 21 { params: ["i64", "f64"], ret: "i64" },
 22 { params: ["f64", "i64"], ret: "i64" },
 23 { params: ["i32", "f32", "i32"], ret: "i32" },
 24 { params: ["i32", "f32", "i32"], ret: "i32" },
 25 { params: ["i64", "f64", "i64"], ret: "i64" },
 26 { params: ["i64", "f64", "i64"], ret: "i64" },
 27 { params: Array(32).fill("i32"), ret: "i64" },
 28 { params: Array(32).fill("i64"), ret: "i64" },
 29 { params: Array(32).fill("f32"), ret: "i64" },
 30 { params: Array(32).fill("f64"), ret: "i64" },
 31];
 32
 33const makeImporter = signature => {
 34 const builder = (new Builder())
 35 .Type().End()
 36 .Import().Function("exports", importName, signature).End();
 37 return new WebAssembly.Module(builder.WebAssembly().get());
 38};
 39
 40const makeImportee = signature => {
 41 const builder = (new Builder())
 42 .Type().End()
 43 .Function().End()
 44 .Export()
 45 .Function(importName)
 46 .End()
 47 .Code()
 48 .Function(importName, signature);
 49 switch (signature.ret) {
 50 case "i32": builder.I32Const(0); break;
 51 case "i64": builder.I64Const(0); break;
 52 case "f32": builder.F32Const(0); break;
 53 case "f64": builder.F64Const(0); break;
 54 case "void": break;
 55 }
 56 return new WebAssembly.Instance(new WebAssembly.Module(builder.Return().End().End().WebAssembly().get()));
 57};
 58
 59(function BadSignatureDropStartParams() {
 60 for (let signature of signatures) {
 61 const importee = makeImportee(signature);
 62 for (let i = 1; i <= signature.params.length; ++i) {
 63 const badParamSignature = { params: signature.params.slice(i, signature.params.length), ret: signature.ret };
 64 const importer = makeImporter(badParamSignature);
 65 assert.throws(() => new WebAssembly.Instance(importer, importee), WebAssembly.LinkError, `imported function's signature mismatches the provided WebAssembly function's signature (evaluating 'new WebAssembly.Instance(importer, importee)')`);
 66 }
 67 }
 68})();
 69
 70(function BadSignatureDropEndParams() {
 71 for (let signature of signatures) {
 72 const importee = makeImportee(signature);
 73 for (let i = 1; i < signature.params.length; ++i) {
 74 const badParamSignature = { params: signature.params.slice(0, i), ret: signature.ret };
 75 const importer = makeImporter(badParamSignature);
 76 assert.throws(() => new WebAssembly.Instance(importer, importee), WebAssembly.LinkError, `imported function's signature mismatches the provided WebAssembly function's signature (evaluating 'new WebAssembly.Instance(importer, importee)')`);
 77 }
 78 }
 79})();
 80
 81(function BadSignatureSwapParam() {
 82 for (let signature of signatures) {
 83 const importee = makeImportee(signature);
 84 for (let signatureIndex = 0; signatureIndex < signature.length; ++signatureIndex) {
 85 for (let typeIndex = 1; typeIndex < typesNonVoid.length; ++typeIndex) {
 86 let badParams = signature.params.slice();
 87 badParams[signatureIndex] = swapTypeNonVoid(badParams[signatureIndex], typeIndex);
 88 const badParamSignature = { params: badParams, ret: signature.ret };
 89 const importer = makeImporter(badParamSignature);
 90 assert.throws(() => new WebAssembly.Instance(importer, importee), WebAssembly.LinkError, `imported function's signature mismatches the provided WebAssembly function's signature (evaluating 'new WebAssembly.Instance(importer, importee)')`);
 91 }
 92 }
 93 }
 94})();
 95
 96(function BadSignatureRet() {
 97 for (let signature of signatures) {
 98 const importee = makeImportee(signature);
 99 for (let typeIndex = 1; typeIndex < types.length; ++typeIndex) {
 100 const badParamSignature = { params: signature.params, ret: swapType(signature.ret, typeIndex) };
 101 const importer = makeImporter(badParamSignature);
 102 assert.throws(() => new WebAssembly.Instance(importer, importee), WebAssembly.LinkError, `imported function's signature mismatches the provided WebAssembly function's signature (evaluating 'new WebAssembly.Instance(importer, importee)')`);
 103 }
 104 }
 105})();

JSTests/wasm/js-api/wasm-to-wasm.js

 1import * as assert from '../assert.js';
 2import Builder from '../Builder.js';
 3/*
 4const callerTopBits = 0xC0FEBEEF;
 5const innerReturnHi = 0xDEADFACE;
 6const innerReturnLo = 0xC0FEC0FE;
 7
 8const callerModule = () => {
 9 const builder = (new Builder())
 10 .Type().End()
 11 .Import()
 12 .Function("exports", "callMe", { params: ["i64"], ret: "i64" })
 13 .End()
 14 .Function().End()
 15 .Export()
 16 .Function("entry")
 17 .End()
 18 .Code()
 19 .Function("entry", { params: ["i32"], ret: "i32" }, ["i64"])
 20 .I32Const(callerTopBits).I64ExtendUI32().I32Const(32).I64ExtendUI32().I64Shl() // ((i64)callerTopBits) << 32
 21 .GetLocal(0).I64ExtendUI32()
 22 .I64Or() // value: param | (((i64)callerTopBits << 32))
 23 .Call(0) // Calls exports.callMe(param | (((i64)callerTopBits) << 32)).
 24 .TeeLocal(1).I32WrapI64() // lo: (i32)callResult
 25 .GetLocal(1).I32Const(32).I64ExtendUI32().I64ShrU().I32WrapI64() // hi: (i32)(callResult >> 32)
 26 .I32Xor()
 27 .Return()
 28 .End()
 29 .End();
 30 return new WebAssembly.Module(builder.WebAssembly().get());
 31};
 32
 33const calleeModule = () => {
 34 const builder = (new Builder())
 35 .Type().End()
 36 .Import()
 37 .Function("imp", "func", { params: ["i32", "i32"], ret: "i32" })
 38 .End()
 39 .Function().End()
 40 .Export()
 41 .Function("callMe")
 42 .End()
 43 .Code()
 44 .Function("callMe", { params: ["i64"], ret: "i64" })
 45 .GetLocal(0).I32WrapI64() // lo: (i32)param
 46 .GetLocal(0).I32Const(32).I64ExtendUI32().I64ShrU().I32WrapI64() // hi: (i32)(param >> 32)
 47 .Call(0) // Calls imp.func with the 64-bit value as i32 { hi, lo }.
 48 .Drop()
 49 .I32Const(innerReturnHi).I64ExtendUI32().I32Const(32).I64ExtendUI32().I64Shl().I32Const(innerReturnLo).I64ExtendUI32().I64Or() // ((i64)hi << 32) | (i64)lo
 50 .Return()
 51 .End()
 52 .End();
 53 return new WebAssembly.Module(builder.WebAssembly().get());
 54};
 55
 56(function WasmToWasm() {
 57 let value;
 58 const func = (hi, lo) => { value = { hi: hi, lo: lo }; print(`${Error.stack}`); return hi ^ lo; };
 59 const callee = new WebAssembly.Instance(calleeModule(), { imp: { func: func } });
 60 const caller = new WebAssembly.Instance(callerModule(), callee);
 61 for (let i = 0; i < 4096; ++i) {
 62 assert.eq(caller.exports.entry(i), innerReturnHi ^ innerReturnLo);
 63 assert.eq(value.hi, callerTopBits);
 64 assert.eq(value.lo, i);
 65 }
 66})();
 67
 68
 69// FIXME: test wasm->wasm using 32-bit things (including float), as well as 64-bit NaNs that don't get canonicalized
 70// FIXME: do a throw two-deep
 71// FIXME: check that the first wasm's instance is back in OK state (with table or global?)
 72// FIXME: test calling through a Table
 73*/

Source/JavaScriptCore/jsc.cpp

5454#include "JSString.h"
5555#include "JSTypedArrays.h"
5656#include "JSWebAssemblyCallee.h"
 57#include "JSWebAssemblyInstance.h"
 58#include "JSWebAssemblyModule.h"
5759#include "LLIntData.h"
5860#include "LLIntThunks.h"
5961#include "ObjectConstructor.h"

7072#include "TypeProfilerLog.h"
7173#include "WasmPlan.h"
7274#include "WasmMemory.h"
 75#include "WebAssemblyModuleRecord.h"
7376#include <locale.h>
7477#include <math.h>
7578#include <stdio.h>

@@static EncodedJSValue JSC_HOST_CALL functionTestWasmModuleFunctions(ExecState* e
26002603{
26012604 VM& vm = exec->vm();
26022605 auto scope = DECLARE_THROW_SCOPE(vm);
 2606 auto* globalObject = exec->lexicalGlobalObject();
26032607
26042608 if (!Options::useWebAssembly())
26052609 return throwVMTypeError(exec, scope, ASCIILiteral("testWasmModule should only be called if the useWebAssembly option is set"));

@@static EncodedJSValue JSC_HOST_CALL functionTestWasmModuleFunctions(ExecState* e
26332637 });
26342638 }
26352639
2636  void* memoryBytes = nullptr;
2637  uint32_t memorySize = 0;
2638  std::unique_ptr<Wasm::Memory> memory;
2639  std::unique_ptr<Wasm::ModuleInformation> moduleInformation = plan.takeModuleInformation();
 2640 SymbolTable* exportSymbolTable = SymbolTable::create(vm);
 2641 auto* moduleStructure = InternalFunction::createSubclassStructure(exec, JSValue(), exec->lexicalGlobalObject()->WebAssemblyModuleStructure());
 2642 RETURN_IF_EXCEPTION(scope, encodedJSValue());
 2643 JSWebAssemblyModule* module = JSWebAssemblyModule::create(vm, moduleStructure, plan.takeModuleInformation(), plan.takeCallLinkInfos(), plan.takeWasmExitStubs(), exportSymbolTable, 0);
 2644 Structure* instanceStructure = InternalFunction::createSubclassStructure(exec, JSValue(), globalObject->WebAssemblyInstanceStructure());
 2645 RETURN_IF_EXCEPTION(scope, encodedJSValue());
 2646 Identifier moduleKey = Identifier::fromUid(PrivateName(PrivateName::Description, "WebAssemblyInstance"));
 2647 WebAssemblyModuleRecord* moduleRecord = WebAssemblyModuleRecord::create(exec, vm, globalObject->webAssemblyModuleRecordStructure(), moduleKey, module->moduleInformation());
 2648 RETURN_IF_EXCEPTION(scope, encodedJSValue());
 2649 JSWebAssemblyInstance* instance = JSWebAssemblyInstance::create(vm, instanceStructure, module, moduleRecord->getModuleNamespace(exec));
 2650 RETURN_IF_EXCEPTION(scope, encodedJSValue());
 2651 vm.topJSWebAssemblyInstance = instance;
26402652
2641  if (!!moduleInformation->memory) {
2642  memory = std::make_unique<Wasm::Memory>(moduleInformation->memory.initial(), moduleInformation->memory.maximum());
2643  RELEASE_ASSERT(memory->isValid());
2644  memoryBytes = memory->memory();
2645  memorySize = memory->size();
 2653 if (!!module->moduleInformation().memory) {
 2654 Wasm::Memory memory(module->moduleInformation().memory.initial(), module->moduleInformation().memory.maximum());
 2655 RELEASE_ASSERT(memory.isValid());
 2656 instance->setMemory(vm, JSWebAssemblyMemory::create(vm, globalObject->WebAssemblyMemoryStructure(), WTFMove(memory)));
26462657 }
2647  vm.topWasmMemoryPointer = memoryBytes;
2648  vm.topWasmMemorySize = memorySize;
26492658
26502659 for (uint32_t i = 0; i < functionCount; ++i) {
26512660 JSArray* testCases = jsCast<JSArray*>(exec->argument(i + 2));

Source/JavaScriptCore/runtime/JSType.h

@@enum JSType : uint8_t {
9393 JSMapType,
9494 JSSetType,
9595
 96 WebAssemblyFunctionType,
 97
9698 LastJSCObjectType = JSSetType,
9799 MaxJSType = 0b11111111,
98100};

Source/JavaScriptCore/runtime/VM.h

@@public:
301301 // https://bugs.webkit.org/show_bug.cgi?id=160441
302302 ExecState* topCallFrame;
303303 JSWebAssemblyInstance* topJSWebAssemblyInstance;
304  void* topWasmMemoryPointer;
305  uint32_t topWasmMemorySize;
306304 Strong<Structure> structureStructure;
307305 Strong<Structure> structureRareDataStructure;
308306 Strong<Structure> terminatedExecutionErrorStructure;

Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp

@@public:
155155 return fail(__VA_ARGS__); \
156156 } while (0)
157157
158  B3IRGenerator(VM&, const ModuleInformation&, Procedure&, WasmInternalFunction*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&);
 158 B3IRGenerator(VM&, const ModuleInformation&, Procedure&, WasmInternalFunction*, Vector<UnlinkedWasmToWasmCall>&);
159159
160160 PartialResult WARN_UNUSED_RETURN addArguments(const Signature*);
161161 PartialResult WARN_UNUSED_RETURN addLocal(Type, uint32_t);

@@private:
213213 Value* zeroForType(Type);
214214
215215 VM& m_vm;
216  const ImmutableFunctionIndexSpace& m_functionIndexSpace;
217216 const ModuleInformation& m_info;
218217 Procedure& m_proc;
219218 BasicBlock* m_currentBlock;

@@private:
225224 Value* m_instanceValue;
226225};
227226
228 B3IRGenerator::B3IRGenerator(VM& vm, const ModuleInformation& info, Procedure& procedure, WasmInternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ImmutableFunctionIndexSpace& functionIndexSpace)
 227B3IRGenerator::B3IRGenerator(VM& vm, const ModuleInformation& info, Procedure& procedure, WasmInternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls)
229228 : m_vm(vm)
230  , m_functionIndexSpace(functionIndexSpace)
231229 , m_info(info)
232230 , m_proc(procedure)
233231 , m_unlinkedWasmToWasmCalls(unlinkedWasmToWasmCalls)

@@B3IRGenerator::B3IRGenerator(VM& vm, const ModuleInformation& info, Procedure& p
269267 m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), &m_vm.topJSWebAssemblyInstance));
270268}
271269
 270static void restoreWebAssemblyGlobalState(VM& vm, const MemoryInformation& memory, Value* instance, Procedure& proc, BasicBlock* block)
 271{
 272 block->appendNew<MemoryValue>(proc, Store, Origin(), instance, block->appendNew<ConstPtrValue>(proc, Origin(), &vm.topJSWebAssemblyInstance));
 273
 274 if (!!memory) {
 275 Value* memoryObject = block->appendNew<MemoryValue>(proc, Load, pointerType(), Origin(), instance, JSWebAssemblyInstance::offsetOfMemory());
 276
 277 static_assert(sizeof(decltype(vm.topJSWebAssemblyInstance->memory()->memory()->memory())) == sizeof(void*), "codegen relies on this size");
 278 static_assert(sizeof(decltype(vm.topJSWebAssemblyInstance->memory()->memory()->size())) == sizeof(uint32_t), "codegen relies on this size");
 279 Value* baseMemory = block->appendNew<MemoryValue>(proc, Load, pointerType(), Origin(), memoryObject, JSWebAssemblyMemory::offsetOfMemory());
 280 Value* memorySize = block->appendNew<MemoryValue>(proc, Load, Int32, Origin(), memoryObject, JSWebAssemblyMemory::offsetOfSize());
 281
 282 Vector<Value*> arguments;
 283 arguments.reserveCapacity(1 + memory.pinnedRegisters().sizeRegisters.size());
 284 arguments.append(baseMemory);
 285 for (auto info : memory.pinnedRegisters().sizeRegisters) {
 286 Value* sizeValue = block->appendNew<Value>(proc, Sub, Origin(), memorySize, block->appendNew<Const32Value>(proc, Origin(), info.sizeOffset));
 287 arguments.append(sizeValue);
 288 }
 289
 290 B3::PatchpointValue* patchpoint = block->appendNew<B3::PatchpointValue>(proc, B3::Void, Origin());
 291 patchpoint->effects = Effects::none();
 292 patchpoint->effects.writesPinned = true;
 293 patchpoint->appendVectorWithRep(arguments, ValueRep::SomeRegister);
 294
 295 patchpoint->setGenerator([memory] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
 296 AllowMacroScratchRegisterUsage allowScratch(jit);
 297
 298 jit.move(params[0].gpr(), memory.pinnedRegisters().baseMemoryPointer);
 299 for (uint32_t i = 0; i < memory.pinnedRegisters().sizeRegisters.size(); ++i)
 300 jit.move(params[1 + i].gpr(), memory.pinnedRegisters().sizeRegisters[i].sizeRegister);
 301 });
 302 }
 303}
 304
272305void B3IRGenerator::emitExceptionCheck(CCallHelpers& jit, ExceptionType type)
273306{
274307 jit.move(CCallHelpers::TrustedImm32(static_cast<uint32_t>(type)), GPRInfo::argumentGPR1);

@@auto B3IRGenerator::addCall(uint32_t functionIndex, const Signature* signature,
692725 ASSERT(signature->argumentCount() == args.size());
693726
694727 Type returnType = signature->returnType();
 728 Vector<UnlinkedWasmToWasmCall>* unlinkedWasmToWasmCalls = &m_unlinkedWasmToWasmCalls;
695729
696  result = wasmCallingConvention().setupCall(m_proc, m_currentBlock, Origin(), args, toB3Type(returnType),
697  [&] (PatchpointValue* patchpoint) {
698  patchpoint->effects.writesPinned = true;
699  patchpoint->effects.readsPinned = true;
 730 if (m_info.isImportedFunctionFromFunctionIndexSpace(functionIndex)) {
 731 // FIXME imports can be linked here, instead of generating a patchpoint, because all import stubs are generated before B3 compilation starts. https://bugs.webkit.org/show_bug.cgi?id=166462
 732 ExpressionType functionImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfImportFunction(functionIndex));
 733 ExpressionType jsTypeOfImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load8Z, Origin(), functionImport, JSCell::typeInfoTypeOffset());
 734 Value* isWasmCall = m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), jsTypeOfImport, m_currentBlock->appendNew<Const32Value>(m_proc, Origin(), WebAssemblyFunctionType));
700735
701  Vector<UnlinkedWasmToWasmCall>* unlinkedWasmToWasmCalls = &m_unlinkedWasmToWasmCalls;
702  patchpoint->setGenerator([unlinkedWasmToWasmCalls, functionIndex] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
703  AllowMacroScratchRegisterUsage allowScratch(jit);
 736 BasicBlock* isWasmBlock = m_proc.addBlock();
 737 BasicBlock* isJSBlock = m_proc.addBlock();
 738 BasicBlock* continuation = m_proc.addBlock();
 739 m_currentBlock->appendNewControlValue(m_proc, B3::Branch, Origin(), isWasmCall, FrequentedBlock(isWasmBlock), FrequentedBlock(isJSBlock));
 740
 741 Value* wasmCallResult = wasmCallingConvention().setupCall(m_proc, isWasmBlock, Origin(), args, toB3Type(returnType),
 742 [&] (PatchpointValue* patchpoint) {
 743 patchpoint->effects.writesPinned = true;
 744 patchpoint->effects.readsPinned = true;
 745 patchpoint->setGenerator([unlinkedWasmToWasmCalls, functionIndex] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
 746 AllowMacroScratchRegisterUsage allowScratch(jit);
 747 CCallHelpers::Call call = jit.call();
 748 jit.addLinkTask([unlinkedWasmToWasmCalls, call, functionIndex] (LinkBuffer& linkBuffer) {
 749 bool toJS = false; // Maybe external wasm -> wasm.
 750 unlinkedWasmToWasmCalls->append({ linkBuffer.locationOf(call), functionIndex, toJS });
 751 });
 752 });
 753 });
 754 UpsilonValue* wasmCallResultUpsilon = returnType == Void ? nullptr : isWasmBlock->appendNew<UpsilonValue>(m_proc, Origin(), wasmCallResult);
 755 isWasmBlock->appendNewControlValue(m_proc, Jump, Origin(), continuation);
 756
 757 Value* jsCallResult = wasmCallingConvention().setupCall(m_proc, isJSBlock, Origin(), args, toB3Type(returnType),
 758 [&] (PatchpointValue* patchpoint) {
 759 patchpoint->effects.writesPinned = true;
 760 patchpoint->effects.readsPinned = true;
 761 patchpoint->setGenerator([unlinkedWasmToWasmCalls, functionIndex] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
 762 AllowMacroScratchRegisterUsage allowScratch(jit);
 763 CCallHelpers::Call call = jit.call();
 764 jit.addLinkTask([unlinkedWasmToWasmCalls, call, functionIndex] (LinkBuffer& linkBuffer) {
 765 bool toJS = true; // External wasm -> JS.
 766 unlinkedWasmToWasmCalls->append({ linkBuffer.locationOf(call), functionIndex, toJS });
 767 });
 768 });
 769 });
 770 UpsilonValue* jsCallResultUpsilon = returnType == Void ? nullptr : isJSBlock->appendNew<UpsilonValue>(m_proc, Origin(), jsCallResult);
 771 isJSBlock->appendNewControlValue(m_proc, Jump, Origin(), continuation);
704772
705  CCallHelpers::Call call = jit.call();
 773 m_currentBlock = continuation;
 774
 775 if (returnType == Void)
 776 result = nullptr;
 777 else {
 778 result = continuation->appendNew<Value>(m_proc, Phi, toB3Type(returnType), Origin());
 779 wasmCallResultUpsilon->setPhi(result);
 780 jsCallResultUpsilon->setPhi(result);
 781 }
706782
707  jit.addLinkTask([unlinkedWasmToWasmCalls, call, functionIndex] (LinkBuffer& linkBuffer) {
708  unlinkedWasmToWasmCalls->append({ linkBuffer.locationOf(call), functionIndex });
 783 // The call could have been to another WebAssembly instance, and / or could have modified our Memory.
 784 restoreWebAssemblyGlobalState(m_vm, m_info.memory, m_instanceValue, m_proc, continuation);
 785 } else {
 786 result = wasmCallingConvention().setupCall(m_proc, m_currentBlock, Origin(), args, toB3Type(returnType),
 787 [&] (PatchpointValue* patchpoint) {
 788 patchpoint->effects.writesPinned = true;
 789 patchpoint->effects.readsPinned = true;
 790 patchpoint->setGenerator([unlinkedWasmToWasmCalls, functionIndex] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
 791 AllowMacroScratchRegisterUsage allowScratch(jit);
 792 CCallHelpers::Call call = jit.call();
 793 jit.addLinkTask([unlinkedWasmToWasmCalls, call, functionIndex] (LinkBuffer& linkBuffer) {
 794 bool toJS = false; // Internal wasm -> wasm.
 795 unlinkedWasmToWasmCalls->append({ linkBuffer.locationOf(call), functionIndex, toJS });
 796 });
709797 });
710798 });
711  });
 799 }
 800
712801 return { };
713802}
714803

@@auto B3IRGenerator::addCallIndirect(const Signature* signature, SignatureIndex s
785874 });
786875 });
787876
 877 // The call could have been to another WebAssembly instance, and / or could have modified our Memory.
 878 restoreWebAssemblyGlobalState(m_vm, m_info.memory, m_instanceValue, m_proc, m_currentBlock);
 879
788880 return { };
789881}
790882

@@static void createJSToWasmWrapper(VM& vm, CompilationContext& compilationContext
854946 });
855947 }
856948
857  // Move memory values to the approriate places, if needed.
858  Value* baseMemory = nullptr;
859  Vector<Value*> sizes;
860  if (!!memory) {
861  baseMemory = block->appendNew<MemoryValue>(proc, Load, Int64, Origin(),
862  block->appendNew<ConstPtrValue>(proc, Origin(), &vm.topWasmMemoryPointer));
863  Value* size = block->appendNew<MemoryValue>(proc, Load, Int32, Origin(),
864  block->appendNew<ConstPtrValue>(proc, Origin(), &vm.topWasmMemorySize));
865  sizes.reserveCapacity(memory.pinnedRegisters().sizeRegisters.size());
866  for (auto info : memory.pinnedRegisters().sizeRegisters) {
867  sizes.append(block->appendNew<Value>(proc, Sub, origin, size,
868  block->appendNew<Const32Value>(proc, origin, info.sizeOffset)));
869  }
870  }
 949 // FIXME The instance is currently set by the C++ code in WebAssemblyFunction::call. We shouldn't go through the extra C++ hoop. https://bugs.webkit.org/show_bug.cgi?id=166486
 950 Value* instance = block->appendNew<MemoryValue>(proc, Load, pointerType(), Origin(),
 951 block->appendNew<ConstPtrValue>(proc, Origin(), &vm.topJSWebAssemblyInstance));
 952 restoreWebAssemblyGlobalState(vm, memory, instance, proc, block);
871953
872954 // Get our arguments.
873955 Vector<Value*> arguments;

@@static void createJSToWasmWrapper(VM& vm, CompilationContext& compilationContext
877959
878960 // Move the arguments into place.
879961 Value* result = wasmCallingConvention().setupCall(proc, block, origin, arguments, toB3Type(signature->returnType()), [&] (PatchpointValue* patchpoint) {
880  if (!!memory) {
881  ASSERT(sizes.size() == memory.pinnedRegisters().sizeRegisters.size());
882  patchpoint->append(ConstrainedValue(baseMemory, ValueRep::reg(memory.pinnedRegisters().baseMemoryPointer)));
883  for (unsigned i = 0; i < sizes.size(); ++i)
884  patchpoint->append(ConstrainedValue(sizes[i], ValueRep::reg(memory.pinnedRegisters().sizeRegisters[i].sizeRegister)));
885  }
886 
887962 CompilationContext* context = &compilationContext;
888963 patchpoint->setGenerator([context] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
889964 AllowMacroScratchRegisterUsage allowScratch(jit);

@@static void createJSToWasmWrapper(VM& vm, CompilationContext& compilationContext
917992 function.jsToWasmEntrypoint.calleeSaveRegisters = proc.calleeSaveRegisters();
918993}
919994
920 Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM& vm, CompilationContext& compilationContext, const uint8_t* functionStart, size_t functionLength, const Signature* signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& info, unsigned optLevel)
 995Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM& vm, CompilationContext& compilationContext, const uint8_t* functionStart, size_t functionLength, const Signature* signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ModuleInformation& info, unsigned optLevel)
921996{
922997 auto result = std::make_unique<WasmInternalFunction>();
923998

@@Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM& vm,
9251000 compilationContext.wasmEntrypointJIT = std::make_unique<CCallHelpers>(&vm);
9261001
9271002 Procedure procedure;
928  B3IRGenerator context(vm, info, procedure, result.get(), unlinkedWasmToWasmCalls, functionIndexSpace);
929  FunctionParser<B3IRGenerator> parser(&vm, context, functionStart, functionLength, signature, functionIndexSpace, info);
 1003 B3IRGenerator context(vm, info, procedure, result.get(), unlinkedWasmToWasmCalls);
 1004 FunctionParser<B3IRGenerator> parser(&vm, context, functionStart, functionLength, signature, info);
9301005 WASM_FAIL_IF_HELPER_FAILS(parser.parse());
9311006
9321007 procedure.resetReachability();

Source/JavaScriptCore/wasm/WasmB3IRGenerator.h

@@struct CompilationContext {
4747 CCallHelpers::Call jsEntrypointToWasmEntrypointCall;
4848};
4949
50 Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM&, CompilationContext&, const uint8_t*, size_t, const Signature*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&, const ModuleInformation&, unsigned optLevel = 1);
 50Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM&, CompilationContext&, const uint8_t*, size_t, const Signature*, Vector<UnlinkedWasmToWasmCall>&, const ModuleInformation&, unsigned optLevel = 1);
5151
5252} } // namespace JSC::Wasm
5353

Source/JavaScriptCore/wasm/WasmBinding.cpp

3636
3737namespace JSC { namespace Wasm {
3838
39 WasmToJSStub importStubGenerator(VM* vm, Bag<CallLinkInfo>& callLinkInfos, SignatureIndex signatureIndex, unsigned importIndex)
 39static MacroAssemblerCodeRef wasmToJS(VM* vm, Bag<CallLinkInfo>& callLinkInfos, SignatureIndex signatureIndex, unsigned importIndex)
4040{
4141 const WasmCallingConvention& wasmCC = wasmCallingConvention();
4242 const JSCCallingConvention& jsCC = jscCallingConvention();

@@WasmToJSStub importStubGenerator(VM* vm, Bag<CallLinkInfo>& callLinkInfos, Signa
231231 CodeLocationLabel hotPathBegin(patchBuffer.locationOf(targetToCheck));
232232 CodeLocationNearCall hotPathOther = patchBuffer.locationOfNearCall(fastCall);
233233 callLinkInfo->setCallLocations(callReturnLocation, hotPathBegin, hotPathOther);
234  return FINALIZE_CODE(patchBuffer, ("WebAssembly import[%i] stub for signature %i", importIndex, signatureIndex));
 234 String signatureDescription = SignatureInformation::get(vm, signatureIndex)->toString();
 235 return FINALIZE_CODE(patchBuffer, ("WebAssembly->JavaScript import[%i] %s", importIndex, signatureDescription.ascii().data()));
 236}
 237
 238static MacroAssemblerCodeRef wasmToWasm(VM* vm, Bag<CallLinkInfo>& callLinkInfos, SignatureIndex signatureIndex, unsigned importIndex)
 239{
 240 const WasmCallingConvention& wasmCC = wasmCallingConvention();
 241 const Signature* signature = SignatureInformation::get(vm, signatureIndex);
 242 unsigned argCount = signature->argumentCount();
 243 typedef AssemblyHelpers JIT;
 244 JIT jit(vm, nullptr);
 245
 246 jit.emitFunctionPrologue();
 247 jit.store64(JIT::TrustedImm32(0), JIT::Address(GPRInfo::callFrameRegister, CallFrameSlot::codeBlock * static_cast<int>(sizeof(Register)))); // FIXME Stop using 0 as codeBlocks. https://bugs.webkit.org/show_bug.cgi?id=165321
 248 jit.storePtr(JIT::TrustedImmPtr(vm->webAssemblyToJSCallee.get()), JIT::Address(GPRInfo::callFrameRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register))));
 249
 250 // FIXME perform a stack check before updating SP. https://bugs.webkit.org/show_bug.cgi?id=165546
 251
 252 unsigned numberOfParameters = argCount + 1; // There is a "this" argument.
 253 unsigned numberOfRegsForCall = CallFrame::headerSizeInRegisters + numberOfParameters;
 254 unsigned numberOfBytesForCall = numberOfRegsForCall * sizeof(Register) - sizeof(CallerFrameAndPC);
 255 const unsigned stackOffset = WTF::roundUpToMultipleOf(stackAlignmentBytes(), numberOfBytesForCall);
 256 jit.subPtr(MacroAssembler::TrustedImm32(stackOffset), MacroAssembler::stackPointerRegister);
 257 JIT::Address calleeFrame = CCallHelpers::Address(MacroAssembler::stackPointerRegister, -static_cast<ptrdiff_t>(sizeof(CallerFrameAndPC)));
 258
 259 // FIXME implement this.
 260 jit.breakpoint();
 261
 262 jit.emitFunctionEpilogue();
 263 jit.ret();
 264
 265 LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
 266 String signatureDescription = SignatureInformation::get(vm, signatureIndex)->toString();
 267 return FINALIZE_CODE(patchBuffer, ("WebAssembly->WebAssembly import[%i] %s", importIndex, signatureDescription.ascii().data()));
 268}
 269
 270WasmExitStubs exitStubGenerator(VM* vm, Bag<CallLinkInfo>& callLinkInfos, SignatureIndex signatureIndex, unsigned importIndex)
 271{
 272 WasmExitStubs stubs;
 273 stubs.wasmToJS = wasmToJS(vm, callLinkInfos, signatureIndex, importIndex);
 274 stubs.wasmToWasm = wasmToWasm(vm, callLinkInfos, signatureIndex, importIndex);
 275 return stubs;
235276}
236277
237278} } // namespace JSC::Wasm

Source/JavaScriptCore/wasm/WasmBinding.h

@@class CallLinkInfo;
3838
3939namespace Wasm {
4040
41 WasmToJSStub importStubGenerator(VM*, Bag<CallLinkInfo>&, SignatureIndex, unsigned);
 41WasmExitStubs exitStubGenerator(VM*, Bag<CallLinkInfo>&, SignatureIndex, unsigned);
4242
4343} } // namespace JSC::Wasm
4444

Source/JavaScriptCore/wasm/WasmFormat.h

@@private:
187187};
188188
189189struct ModuleInformation {
190  Vector<SignatureIndex> signatureIndices;
 190 Vector<SignatureIndex> moduleSignatureIndicesToUniquedSignatureIndices;
191191 Vector<Import> imports;
192192 Vector<SignatureIndex> importFunctionSignatureIndices;
193193 Vector<SignatureIndex> internalFunctionSignatureIndices;

@@struct ModuleInformation {
199199 TableInformation tableInformation;
200200 Vector<Global> globals;
201201 unsigned firstInternalGlobal { 0 };
 202 size_t functionIndexSpaceSize() const { return importFunctionSignatureIndices.size() + internalFunctionSignatureIndices.size(); }
 203 bool isImportedFunctionFromFunctionIndexSpace(size_t functionIndex) const
 204 {
 205 ASSERT(functionIndex < functionIndexSpaceSize());
 206 return functionIndex < importFunctionSignatureIndices.size();
 207 }
 208 SignatureIndex signatureIndexFromFunctionIndexSpace(size_t functionIndex) const
 209 {
 210 return isImportedFunctionFromFunctionIndexSpace(functionIndex)
 211 ? importFunctionSignatureIndices[functionIndex]
 212 : internalFunctionSignatureIndices[functionIndex - importFunctionSignatureIndices.size()];
 213 }
202214
203215 ~ModuleInformation();
204216};

@@struct ModuleInformation {
206218struct UnlinkedWasmToWasmCall {
207219 CodeLocationCall callLocation;
208220 size_t functionIndex;
 221 bool toJS;
209222};
210223
211224struct Entrypoint {

@@struct WasmInternalFunction {
221234 Entrypoint jsToWasmEntrypoint;
222235};
223236
224 typedef MacroAssemblerCodeRef WasmToJSStub;
 237struct WasmExitStubs {
 238 MacroAssemblerCodeRef wasmToJS;
 239 MacroAssemblerCodeRef wasmToWasm;
 240};
225241
226242// WebAssembly direct calls and call_indirect use indices into "function index space". This space starts with all imports, and then all internal functions.
227243// CallableFunction and FunctionIndexSpace are only meant as fast lookup tables for these opcodes, and do not own code.

@@struct CallableFunction {
240256};
241257typedef Vector<CallableFunction> FunctionIndexSpace;
242258
243 
244 struct ImmutableFunctionIndexSpace {
245  MallocPtr<CallableFunction> buffer;
246  size_t size;
247 };
248 
249259} } // namespace JSC::Wasm
250260
251261#endif // ENABLE(WEBASSEMBLY)

Source/JavaScriptCore/wasm/WasmFunctionParser.h

@@public:
4646 typedef typename Context::ControlType ControlType;
4747 typedef typename Context::ExpressionList ExpressionList;
4848
49  FunctionParser(VM*, Context&, const uint8_t* functionStart, size_t functionLength, const Signature*, const ImmutableFunctionIndexSpace&, const ModuleInformation&);
 49 FunctionParser(VM*, Context&, const uint8_t* functionStart, size_t functionLength, const Signature*, const ModuleInformation&);
5050
5151 Result WARN_UNUSED_RETURN parse();
5252

@@private:
8282 ExpressionList m_expressionStack;
8383 Vector<ControlEntry> m_controlStack;
8484 const Signature* m_signature;
85  const ImmutableFunctionIndexSpace& m_functionIndexSpace;
8685 const ModuleInformation& m_info;
8786 unsigned m_unreachableBlocks { 0 };
8887};
8988
9089template<typename Context>
91 FunctionParser<Context>::FunctionParser(VM* vm, Context& context, const uint8_t* functionStart, size_t functionLength, const Signature* signature, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& info)
 90FunctionParser<Context>::FunctionParser(VM* vm, Context& context, const uint8_t* functionStart, size_t functionLength, const Signature* signature, const ModuleInformation& info)
9291 : Parser(vm, functionStart, functionLength)
9392 , m_context(context)
9493 , m_signature(signature)
95  , m_functionIndexSpace(functionIndexSpace)
9694 , m_info(info)
9795{
9896 if (verbose)

@@auto FunctionParser<Context>::parseExpression(OpType op) -> PartialResult
308306 case Call: {
309307 uint32_t functionIndex;
310308 WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't parse call's function index");
311  WASM_PARSER_FAIL_IF(functionIndex >= m_functionIndexSpace.size, "call function index ", functionIndex, " exceeds function index space ", m_functionIndexSpace.size);
 309 WASM_PARSER_FAIL_IF(functionIndex >= m_info.functionIndexSpaceSize(), "call function index ", functionIndex, " exceeds function index space ", m_info.functionIndexSpaceSize());
312310
313  SignatureIndex calleeSignatureIndex = m_functionIndexSpace.buffer.get()[functionIndex].signatureIndex;
 311 SignatureIndex calleeSignatureIndex = m_info.signatureIndexFromFunctionIndexSpace(functionIndex);
314312 const Signature* calleeSignature = SignatureInformation::get(m_vm, calleeSignatureIndex);
315313 WASM_PARSER_FAIL_IF(calleeSignature->argumentCount() > m_expressionStack.size(), "call function index ", functionIndex, " has ", calleeSignature->argumentCount(), " arguments, but the expression stack currently holds ", m_expressionStack.size(), " values");
316314

@@auto FunctionParser<Context>::parseExpression(OpType op) -> PartialResult
337335 WASM_PARSER_FAIL_IF(!parseVarUInt32(signatureIndex), "can't get call_indirect's signature index");
338336 WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't get call_indirect's reserved byte");
339337 WASM_PARSER_FAIL_IF(reserved, "call_indirect's 'reserved' varuint1 must be 0x0");
340  WASM_PARSER_FAIL_IF(m_info.signatureIndices.size() <= signatureIndex, "call_indirect's signature index ", signatureIndex, " exceeds known signatures ", m_info.signatureIndices.size());
 338 WASM_PARSER_FAIL_IF(m_info.moduleSignatureIndicesToUniquedSignatureIndices.size() <= signatureIndex, "call_indirect's signature index ", signatureIndex, " exceeds known signatures ", m_info.moduleSignatureIndicesToUniquedSignatureIndices.size());
341339
342  SignatureIndex calleeSignatureIndex = m_info.signatureIndices[signatureIndex];
 340 SignatureIndex calleeSignatureIndex = m_info.moduleSignatureIndicesToUniquedSignatureIndices[signatureIndex];
343341 const Signature* calleeSignature = SignatureInformation::get(m_vm, calleeSignatureIndex);
344342 size_t argumentCount = calleeSignature->argumentCount() + 1; // Add the callee's index.
345343 WASM_PARSER_FAIL_IF(argumentCount > m_expressionStack.size(), "call_indirect expects ", argumentCount, " arguments, but the expression stack currently holds ", m_expressionStack.size(), " values");

Source/JavaScriptCore/wasm/WasmMemory.cpp

3131namespace JSC { namespace Wasm {
3232
3333Memory::Memory(PageCount initial, PageCount maximum)
34  : m_mode(Mode::BoundsChecking)
35  , m_size(initial.bytes())
 34 : m_size(initial.bytes())
3635 , m_capacity(maximum ? maximum.bytes() : PageCount::max().bytes())
3736 , m_initial(initial)
3837 , m_maximum(maximum)
 38 , m_mode(Mode::BoundsChecking)
3939 // FIXME: If we add signal based bounds checking then we need extra space for overflow on load.
4040 // see: https://bugs.webkit.org/show_bug.cgi?id=162693
4141{

Source/JavaScriptCore/wasm/WasmMemory.h

@@class Memory {
3838 WTF_MAKE_NONCOPYABLE(Memory);
3939 WTF_MAKE_FAST_ALLOCATED;
4040public:
 41 Memory(Memory&& other)
 42 : m_memory(other.m_memory)
 43 , m_size(other.m_size)
 44 , m_capacity(other.m_capacity)
 45 , m_initial(other.m_initial)
 46 , m_maximum(other.m_maximum)
 47 , m_mappedCapacity(other.m_mappedCapacity)
 48 , m_mode(other.m_mode)
 49 {
 50 memset(&other, 0, sizeof(other));
 51 }
4152
4253 // FIXME: We should support other modes. see: https://bugs.webkit.org/show_bug.cgi?id=162693
4354 enum class Mode {

@@public:
5768 void* memory() const { return m_memory; }
5869 uint32_t size() const { return m_size; }
5970
60  Mode mode() const { return m_mode; }
61 
6271 PageCount initial() const { return m_initial; }
6372 PageCount maximum() const { return m_maximum; }
6473
 74 Mode mode() const { return m_mode; }
 75
6576 bool grow(uint32_t newSize)
6677 {
6778 ASSERT(m_memory);

@@public:
7182 return !mprotect(m_memory, newSize, PROT_READ | PROT_WRITE);
7283 }
7384
 85 static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(Memory, m_memory); }
7486 static ptrdiff_t offsetOfSize() { return OBJECT_OFFSETOF(Memory, m_size); }
7587
7688
7789private:
7890 void* m_memory { nullptr };
79  Mode m_mode;
8091 uint32_t m_size { 0 };
8192 uint32_t m_capacity { 0 };
8293 PageCount m_initial;
8394 PageCount m_maximum;
8495 uint64_t m_mappedCapacity { 0 };
 96 Mode m_mode { Mode::BoundsChecking };
8597};
8698
8799} } // namespace JSC::Wasm

Source/JavaScriptCore/wasm/WasmModuleParser.cpp

@@auto ModuleParser::parseType() -> PartialResult
9999
100100 WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Type section's count");
101101 WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Type section's count is too big ", count);
102  WASM_PARSER_FAIL_IF(!m_result.module->signatureIndices.tryReserveCapacity(count), "can't allocate enough memory for Type section's ", count, " entries");
 102 WASM_PARSER_FAIL_IF(!m_result.module->moduleSignatureIndicesToUniquedSignatureIndices.tryReserveCapacity(count), "can't allocate enough memory for Type section's ", count, " entries");
103103
104104 for (uint32_t i = 0; i < count; ++i) {
105105 int8_t type;

@@auto ModuleParser::parseType() -> PartialResult
131131 signature->returnType() = returnType;
132132
133133 SignatureIndex signatureIndex = SignatureInformation::adopt(m_vm, signature.release());
134  m_result.module->signatureIndices.uncheckedAppend(signatureIndex);
 134 m_result.module->moduleSignatureIndicesToUniquedSignatureIndices.uncheckedAppend(signatureIndex);
135135 }
136136 return { };
137137}

@@auto ModuleParser::parseImport() -> PartialResult
144144 WASM_PARSER_FAIL_IF(!m_result.module->globals.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " globals"); // FIXME this over-allocates when we fix the FIXMEs below.
145145 WASM_PARSER_FAIL_IF(!m_result.module->imports.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " imports"); // FIXME this over-allocates when we fix the FIXMEs below.
146146 WASM_PARSER_FAIL_IF(!m_result.module->importFunctionSignatureIndices.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " import function signatures"); // FIXME this over-allocates when we fix the FIXMEs below.
147  WASM_PARSER_FAIL_IF(!m_result.functionIndexSpace.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " functions in the index space"); // FIXME this over-allocates when we fix the FIXMEs below. We'll allocate some more here when we know how many functions to expect.
148147
149148 for (uint32_t importNumber = 0; importNumber < importCount; ++importNumber) {
150149 Import imp;

@@auto ModuleParser::parseImport() -> PartialResult
166165 case ExternalKind::Function: {
167166 uint32_t functionSignatureIndex;
168167 WASM_PARSER_FAIL_IF(!parseVarUInt32(functionSignatureIndex), "can't get ", importNumber, "th Import's function signature in module '", moduleString, "' field '", fieldString, "'");
169  WASM_PARSER_FAIL_IF(functionSignatureIndex >= m_result.module->signatureIndices.size(), "invalid function signature for ", importNumber, "th Import, ", functionSignatureIndex, " is out of range of ", m_result.module->signatureIndices.size(), " in module '", moduleString, "' field '", fieldString, "'");
 168 WASM_PARSER_FAIL_IF(functionSignatureIndex >= m_result.module->moduleSignatureIndicesToUniquedSignatureIndices.size(), "invalid function signature for ", importNumber, "th Import, ", functionSignatureIndex, " is out of range of ", m_result.module->moduleSignatureIndicesToUniquedSignatureIndices.size(), " in module '", moduleString, "' field '", fieldString, "'");
170169 imp.kindIndex = m_result.module->importFunctionSignatureIndices.size();
171  SignatureIndex signatureIndex = m_result.module->signatureIndices[functionSignatureIndex];
 170 SignatureIndex signatureIndex = m_result.module->moduleSignatureIndicesToUniquedSignatureIndices[functionSignatureIndex];
172171 m_result.module->importFunctionSignatureIndices.uncheckedAppend(signatureIndex);
173  m_result.functionIndexSpace.uncheckedAppend(signatureIndex);
174172 break;
175173 }
176174 case ExternalKind::Table: {

@@auto ModuleParser::parseFunction() -> PartialResult
212210 WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Function section's count is too big ", count);
213211 WASM_PARSER_FAIL_IF(!m_result.module->internalFunctionSignatureIndices.tryReserveCapacity(count), "can't allocate enough memory for ", count, " Function signatures");
214212 WASM_PARSER_FAIL_IF(!m_result.functionLocationInBinary.tryReserveCapacity(count), "can't allocate enough memory for ", count, "Function locations");
215  WASM_PARSER_FAIL_IF(!m_result.functionIndexSpace.tryReserveCapacity(m_result.functionIndexSpace.size() + count), "can't allocate enough memory for ", count, " more functions in the function index space");
216213
217214 for (uint32_t i = 0; i < count; ++i) {
218215 uint32_t typeNumber;
219216 WASM_PARSER_FAIL_IF(!parseVarUInt32(typeNumber), "can't get ", i, "th Function's type number");
220  WASM_PARSER_FAIL_IF(typeNumber >= m_result.module->signatureIndices.size(), i, "th Function type number is invalid ", typeNumber);
 217 WASM_PARSER_FAIL_IF(typeNumber >= m_result.module->moduleSignatureIndicesToUniquedSignatureIndices.size(), i, "th Function type number is invalid ", typeNumber);
221218
222  SignatureIndex signatureIndex = m_result.module->signatureIndices[typeNumber];
 219 SignatureIndex signatureIndex = m_result.module->moduleSignatureIndicesToUniquedSignatureIndices[typeNumber];
223220 // The Code section fixes up start and end.
224221 size_t start = 0;
225222 size_t end = 0;
226223 m_result.module->internalFunctionSignatureIndices.uncheckedAppend(signatureIndex);
227224 m_result.functionLocationInBinary.uncheckedAppend({ start, end });
228  m_result.functionIndexSpace.uncheckedAppend(signatureIndex);
229225 }
230226
231227 return { };

@@auto ModuleParser::parseExport() -> PartialResult
396392 WASM_PARSER_FAIL_IF(!parseVarUInt32(exp.kindIndex), "can't get ", exportNumber, "th Export's kind index, named '", fieldString, "'");
397393 switch (exp.kind) {
398394 case ExternalKind::Function: {
399  WASM_PARSER_FAIL_IF(exp.kindIndex >= m_result.functionIndexSpace.size(), exportNumber, "th Export has invalid function number ", exp.kindIndex, " it exceeds the function index space ", m_result.functionIndexSpace.size(), ", named '", fieldString, "'");
 395 WASM_PARSER_FAIL_IF(exp.kindIndex >= m_result.module->functionIndexSpaceSize(), exportNumber, "th Export has invalid function number ", exp.kindIndex, " it exceeds the function index space ", m_result.module->functionIndexSpaceSize(), ", named '", fieldString, "'");
400396 break;
401397 }
402398 case ExternalKind::Table: {

@@auto ModuleParser::parseStart() -> PartialResult
426422{
427423 uint32_t startFunctionIndex;
428424 WASM_PARSER_FAIL_IF(!parseVarUInt32(startFunctionIndex), "can't get Start index");
429  WASM_PARSER_FAIL_IF(startFunctionIndex >= m_result.functionIndexSpace.size(), "Start index ", startFunctionIndex, " exceeds function index space ", m_result.functionIndexSpace.size());
430  SignatureIndex signatureIndex = m_result.functionIndexSpace[startFunctionIndex].signatureIndex;
 425 WASM_PARSER_FAIL_IF(startFunctionIndex >= m_result.module->functionIndexSpaceSize(), "Start index ", startFunctionIndex, " exceeds function index space ", m_result.module->functionIndexSpaceSize());
 426 SignatureIndex signatureIndex = m_result.module->signatureIndexFromFunctionIndexSpace(startFunctionIndex);
431427 const Signature* signature = SignatureInformation::get(m_vm, signatureIndex);
432428 WASM_PARSER_FAIL_IF(signature->argumentCount(), "Start function can't have arguments");
433429 WASM_PARSER_FAIL_IF(signature->returnType() != Void, "Start function can't return a value");

@@auto ModuleParser::parseElement() -> PartialResult
477473 for (unsigned index = 0; index < indexCount; ++index) {
478474 uint32_t functionIndex;
479475 WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't get Element section's ", elementNum, "th element's ", index, "th index");
480  WASM_PARSER_FAIL_IF(functionIndex >= m_result.functionIndexSpace.size(), "Element section's ", elementNum, "th element's ", index, "th index is ", functionIndex, " which exceeds the function index space size of ", m_result.functionIndexSpace.size());
 476 WASM_PARSER_FAIL_IF(functionIndex >= m_result.module->functionIndexSpaceSize(), "Element section's ", elementNum, "th element's ", index, "th index is ", functionIndex, " which exceeds the function index space size of ", m_result.module->functionIndexSpaceSize());
481477
482478 element.functionIndices.uncheckedAppend(functionIndex);
483479 }

Source/JavaScriptCore/wasm/WasmModuleParser.h

@@namespace JSC { namespace Wasm {
3636
3737struct ModuleParserResult {
3838 std::unique_ptr<ModuleInformation> module;
39  FunctionIndexSpace functionIndexSpace;
4039 Vector<FunctionLocationInBinary> functionLocationInBinary;
4140};
4241

Source/JavaScriptCore/wasm/WasmPlan.cpp

@@bool Plan::parseAndValidateModule()
7676 }
7777 m_moduleInformation = WTFMove(parseResult->module);
7878 m_functionLocationInBinary = WTFMove(parseResult->functionLocationInBinary);
79  m_functionIndexSpace.size = parseResult->functionIndexSpace.size();
80  m_functionIndexSpace.buffer = parseResult->functionIndexSpace.releaseBuffer();
8179 }
8280
8381 for (unsigned functionIndex = 0; functionIndex < m_functionLocationInBinary.size(); ++functionIndex) {

@@bool Plan::parseAndValidateModule()
8987 SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
9088 const Signature* signature = SignatureInformation::get(m_vm, signatureIndex);
9189
92  auto validationResult = validateFunction(m_vm, functionStart, functionLength, signature, m_functionIndexSpace, *m_moduleInformation);
 90 auto validationResult = validateFunction(m_vm, functionStart, functionLength, signature, *m_moduleInformation);
9391 if (!validationResult) {
9492 if (verbose) {
9593 for (unsigned i = 0; i < functionLength; ++i)

@@void Plan::run()
127125 return true;
128126 };
129127
130  if (!tryReserveCapacity(m_wasmToJSStubs, m_moduleInformation->importFunctionSignatureIndices.size(), " WebAssembly to JavaScript stubs")
 128 if (!tryReserveCapacity(m_wasmExitStubs, m_moduleInformation->importFunctionSignatureIndices.size(), " WebAssembly to JavaScript stubs")
131129 || !tryReserveCapacity(m_unlinkedWasmToWasmCalls, m_functionLocationInBinary.size(), " unlinked WebAssembly to WebAssembly calls")
132130 || !tryReserveCapacity(m_wasmInternalFunctions, m_functionLocationInBinary.size(), " WebAssembly functions")
133131 || !tryReserveCapacity(m_compilationContexts, m_functionLocationInBinary.size(), " compilation contexts"))

@@void Plan::run()
141139 Import* import = &m_moduleInformation->imports[importIndex];
142140 if (import->kind != ExternalKind::Function)
143141 continue;
144  unsigned importFunctionIndex = m_wasmToJSStubs.size();
 142 unsigned importFunctionIndex = m_wasmExitStubs.size();
145143 if (verbose)
146144 dataLogLn("Processing import function number ", importFunctionIndex, ": ", import->module, ": ", import->field);
147145 SignatureIndex signatureIndex = m_moduleInformation->importFunctionSignatureIndices.at(import->kindIndex);
148  m_wasmToJSStubs.uncheckedAppend(importStubGenerator(m_vm, m_callLinkInfos, signatureIndex, importFunctionIndex));
149  m_functionIndexSpace.buffer.get()[importFunctionIndex].code = m_wasmToJSStubs[importFunctionIndex].code().executableAddress();
 146 m_wasmExitStubs.uncheckedAppend(exitStubGenerator(m_vm, m_callLinkInfos, signatureIndex, importFunctionIndex));
150147 }
151148
152149 m_currentIndex = 0;

@@void Plan::run()
167164 ASSERT(functionLength <= m_sourceLength);
168165 SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
169166 const Signature* signature = SignatureInformation::get(m_vm, signatureIndex);
170  unsigned functionIndexSpace = m_wasmToJSStubs.size() + functionIndex;
171  ASSERT_UNUSED(functionIndexSpace, m_functionIndexSpace.buffer.get()[functionIndexSpace].signatureIndex == signatureIndex);
172  ASSERT(validateFunction(m_vm, functionStart, functionLength, signature, m_functionIndexSpace, *m_moduleInformation));
 167 unsigned functionIndexSpace = m_wasmExitStubs.size() + functionIndex;
 168 ASSERT_UNUSED(functionIndexSpace, m_moduleInformation->signatureIndexFromFunctionIndexSpace(functionIndexSpace) == signatureIndex);
 169 ASSERT(validateFunction(m_vm, functionStart, functionLength, signature, *m_moduleInformation));
173170
174171 m_unlinkedWasmToWasmCalls[functionIndex] = Vector<UnlinkedWasmToWasmCall>();
175  auto parseAndCompileResult = parseAndCompile(*m_vm, m_compilationContexts[functionIndex], functionStart, functionLength, signature, m_unlinkedWasmToWasmCalls[functionIndex], m_functionIndexSpace, *m_moduleInformation);
 172 auto parseAndCompileResult = parseAndCompile(*m_vm, m_compilationContexts[functionIndex], functionStart, functionLength, signature, m_unlinkedWasmToWasmCalls[functionIndex], *m_moduleInformation);
176173
177174 if (UNLIKELY(!parseAndCompileResult)) {
178175 auto locker = holdLock(m_lock);

@@void Plan::run()
223220 std::make_unique<B3::Compilation>(FINALIZE_CODE(linkBuffer, ("Wasm JS entrypoint")), WTFMove(context.jsEntrypointByproducts));
224221 }
225222 }
226 
227  unsigned functionIndexSpace = m_wasmToJSStubs.size() + functionIndex;
228  m_functionIndexSpace.buffer.get()[functionIndexSpace].code = m_wasmInternalFunctions[functionIndex]->wasmEntrypoint.compilation->code().executableAddress();
229223 }
230224
231225 if (verbose || Options::reportCompileTimes()) {

@@void Plan::run()
235229
236230 // Patch the call sites for each WebAssembly function.
237231 for (auto& unlinked : m_unlinkedWasmToWasmCalls) {
238  for (auto& call : unlinked)
239  MacroAssembler::repatchCall(call.callLocation, CodeLocationLabel(m_functionIndexSpace.buffer.get()[call.functionIndex].code));
 232 for (auto& call : unlinked) {
 233 void* executableAddress;
 234 if (m_moduleInformation->isImportedFunctionFromFunctionIndexSpace(call.functionIndex)) {
 235 // FIXME imports could have been linked in B3, instead of generating a patchpoint. This condition should be replaced by a RELEASE_ASSERT. https://bugs.webkit.org/show_bug.cgi?id=166462
 236 executableAddress = call.toJS
 237 ? m_wasmExitStubs.at(call.functionIndex).wasmToJS.code().executableAddress()
 238 : m_wasmExitStubs.at(call.functionIndex).wasmToWasm.code().executableAddress();
 239 } else {
 240 ASSERT(!call.toJS);
 241 executableAddress = m_wasmInternalFunctions.at(call.functionIndex - m_wasmExitStubs.size())->wasmEntrypoint.compilation->code().executableAddress();
 242 }
 243 MacroAssembler::repatchCall(call.callLocation, CodeLocationLabel(executableAddress));
 244 }
240245 }
241246
242247 m_failed = false;

Source/JavaScriptCore/wasm/WasmPlan.h

@@public:
8686 return WTFMove(m_callLinkInfos);
8787 }
8888
89  Vector<WasmToJSStub>&& takeWasmToJSStubs()
 89 Vector<WasmExitStubs>&& takeWasmExitStubs()
9090 {
9191 RELEASE_ASSERT(!failed());
92  return WTFMove(m_wasmToJSStubs);
93  }
94 
95  ImmutableFunctionIndexSpace&& takeFunctionIndexSpace()
96  {
97  RELEASE_ASSERT(!failed());
98  return WTFMove(m_functionIndexSpace);
 92 return WTFMove(m_wasmExitStubs);
9993 }
10094
10195private:
10296 std::unique_ptr<ModuleInformation> m_moduleInformation;
10397 Vector<FunctionLocationInBinary> m_functionLocationInBinary;
10498 Bag<CallLinkInfo> m_callLinkInfos;
105  Vector<WasmToJSStub> m_wasmToJSStubs;
 99 Vector<WasmExitStubs> m_wasmExitStubs;
106100 Vector<std::unique_ptr<WasmInternalFunction>> m_wasmInternalFunctions;
107101 Vector<CompilationContext> m_compilationContexts;
108  ImmutableFunctionIndexSpace m_functionIndexSpace;
109102
110103 VM* m_vm;
111104 Vector<Vector<UnlinkedWasmToWasmCall>> m_unlinkedWasmToWasmCalls;

Source/JavaScriptCore/wasm/WasmSignature.cpp

@@const bool verbose = false;
4141
4242const constexpr SignatureIndex Signature::invalidIndex;
4343
 44String Signature::toString() const
 45{
 46 String result(makeString(returnType()));
 47 result.append(" (");
 48 for (SignatureArgCount arg = 0; arg < argumentCount(); ++arg) {
 49 if (arg)
 50 result.append(", ");
 51 result.append(makeString(argument(arg)));
 52 }
 53 result.append(')');
 54 return result;
 55}
 56
4457void Signature::dump(PrintStream& out) const
4558{
4659 out.print(makeString(returnType()), " (");

Source/JavaScriptCore/wasm/WasmSignature.h

@@public:
8282 }
8383 Type argument(SignatureArgCount i) const { return const_cast<Signature*>(this)->argument(i); }
8484
 85 WTF::String toString() const;
8586 void dump(WTF::PrintStream& out) const;
8687 bool operator==(const Signature& rhs) const
8788 {

Source/JavaScriptCore/wasm/WasmValidate.cpp

@@void Validate::dump(const Vector<ControlEntry>&, const ExpressionList&)
362362 // Think of this as penance for the sin of bad error messages.
363363}
364364
365 Expected<void, String> validateFunction(VM* vm, const uint8_t* source, size_t length, const Signature* signature, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& module)
 365Expected<void, String> validateFunction(VM* vm, const uint8_t* source, size_t length, const Signature* signature, const ModuleInformation& module)
366366{
367367 Validate context(module);
368  FunctionParser<Validate> validator(vm, context, source, length, signature, functionIndexSpace, module);
 368 FunctionParser<Validate> validator(vm, context, source, length, signature, module);
369369 WASM_FAIL_IF_HELPER_FAILS(validator.parse());
370370 return { };
371371}

Source/JavaScriptCore/wasm/WasmValidate.h

@@class VM;
3636
3737namespace Wasm {
3838
39 Expected<void, String> validateFunction(VM*, const uint8_t*, size_t, const Signature*, const ImmutableFunctionIndexSpace&, const ModuleInformation&);
 39Expected<void, String> validateFunction(VM*, const uint8_t*, size_t, const Signature*, const ModuleInformation&);
4040
4141} } // namespace JSC::Wasm
4242

Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h

@@public:
8686 return offsetOfImportFunctions() + sizeof(WriteBarrier<JSCell>) * idx;
8787 }
8888
 89 static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_memory); }
8990 static ptrdiff_t offsetOfTable() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_table); }
9091 static ptrdiff_t offsetOfGlobals() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_globals); }
 92 static size_t offsetOfImportFunctions() { return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<JSCell>)>(sizeof(JSWebAssemblyInstance)); }
 93 static size_t offsetOfImportFunction(size_t importFunctionNum) { return offsetOfImportFunctions() + importFunctionNum * sizeof(sizeof(WriteBarrier<JSCell>)); }
9194
9295protected:
9396 JSWebAssemblyInstance(VM&, Structure*, unsigned numImportFunctions);

@@protected:
9598 static void destroy(JSCell*);
9699 static void visitChildren(JSCell*, SlotVisitor&);
97100
98  static size_t offsetOfImportFunctions()
99  {
100  return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<JSCell>)>(sizeof(JSWebAssemblyInstance));
101  }
102 
103101 static size_t allocationSize(unsigned numImportFunctions)
104102 {
105103 return offsetOfImportFunctions() + sizeof(WriteBarrier<JSCell>) * numImportFunctions;

Source/JavaScriptCore/wasm/js/JSWebAssemblyMemory.cpp

@@namespace JSC {
3737
3838const ClassInfo JSWebAssemblyMemory::s_info = { "WebAssembly.Memory", &Base::s_info, 0, CREATE_METHOD_TABLE(JSWebAssemblyMemory) };
3939
40 JSWebAssemblyMemory* JSWebAssemblyMemory::create(VM& vm, Structure* structure, std::unique_ptr<Wasm::Memory>&& memory)
 40JSWebAssemblyMemory* JSWebAssemblyMemory::create(VM& vm, Structure* structure, Wasm::Memory&& memory)
4141{
42  auto* instance = new (NotNull, allocateCell<JSWebAssemblyMemory>(vm.heap)) JSWebAssemblyMemory(vm, structure, WTFMove(memory));
 42 auto* instance = new (NotNull, allocateCell<JSWebAssemblyMemory>(vm.heap)) JSWebAssemblyMemory(vm, structure, std::forward<Wasm::Memory>(memory));
4343 instance->finishCreation(vm);
4444 return instance;
4545}

@@Structure* JSWebAssemblyMemory::createStructure(VM& vm, JSGlobalObject* globalOb
4949 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
5050}
5151
52 JSWebAssemblyMemory::JSWebAssemblyMemory(VM& vm, Structure* structure, std::unique_ptr<Wasm::Memory>&& memory)
 52JSWebAssemblyMemory::JSWebAssemblyMemory(VM& vm, Structure* structure, Wasm::Memory&& memory)
5353 : Base(vm, structure)
5454 , m_memory(WTFMove(memory))
5555{

@@JSArrayBuffer* JSWebAssemblyMemory::buffer(VM& vm, JSGlobalObject* globalObject)
6363 auto destructor = [] (void*) {
6464 // We don't need to do anything here to destroy the memory.
6565 // The ArrayBuffer backing the JSArrayBuffer is only owned by us,
66  // so we guarantee its lifecylce.
 66 // so we guarantee its lifecycle.
6767 };
6868 m_buffer = ArrayBuffer::createFromBytes(memory()->memory(), memory()->size(), WTFMove(destructor));
6969 m_bufferWrapper.set(vm, this, JSArrayBuffer::create(vm, globalObject->m_arrayBufferStructure.get(), m_buffer.get()));

Source/JavaScriptCore/wasm/js/JSWebAssemblyMemory.h

@@class JSWebAssemblyMemory : public JSDestructibleObject {
4141public:
4242 typedef JSDestructibleObject Base;
4343
44  static JSWebAssemblyMemory* create(VM&, Structure*, std::unique_ptr<Wasm::Memory>&&);
 44 static JSWebAssemblyMemory* create(VM&, Structure*, Wasm::Memory&&);
4545 static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
4646
4747 DECLARE_INFO;
4848
49  Wasm::Memory* memory() { return m_memory.get(); }
 49 Wasm::Memory* memory() { return &m_memory; }
5050 JSArrayBuffer* buffer(VM& vm, JSGlobalObject*);
5151
 52 static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(JSWebAssemblyMemory, m_memory) + Wasm::Memory::offsetOfMemory(); }
 53 static ptrdiff_t offsetOfSize() { return OBJECT_OFFSETOF(JSWebAssemblyMemory, m_memory) + Wasm::Memory::offsetOfSize(); }
 54
5255protected:
53  JSWebAssemblyMemory(VM&, Structure*, std::unique_ptr<Wasm::Memory>&&);
 56 JSWebAssemblyMemory(VM&, Structure*, Wasm::Memory&&);
5457 void finishCreation(VM&);
5558 static void destroy(JSCell*);
5659 static void visitChildren(JSCell*, SlotVisitor&);
5760
58  std::unique_ptr<Wasm::Memory> m_memory;
 61 Wasm::Memory m_memory;
5962 WriteBarrier<JSArrayBuffer> m_bufferWrapper;
6063 RefPtr<ArrayBuffer> m_buffer;
6164};

Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.cpp

@@namespace JSC {
3838
3939const ClassInfo JSWebAssemblyModule::s_info = { "WebAssembly.Module", &Base::s_info, nullptr, CREATE_METHOD_TABLE(JSWebAssemblyModule) };
4040
41 JSWebAssemblyModule* JSWebAssemblyModule::create(VM& vm, Structure* structure, std::unique_ptr<Wasm::ModuleInformation>&& moduleInformation, Bag<CallLinkInfo>&& callLinkInfos, Vector<Wasm::WasmToJSStub>&& wasmToJSStubs, Wasm::ImmutableFunctionIndexSpace&& functionIndexSpace, SymbolTable* exportSymbolTable, unsigned calleeCount)
 41JSWebAssemblyModule* JSWebAssemblyModule::create(VM& vm, Structure* structure, std::unique_ptr<Wasm::ModuleInformation>&& moduleInformation, Bag<CallLinkInfo>&& callLinkInfos, Vector<Wasm::WasmExitStubs>&& wasmExitStubs, SymbolTable* exportSymbolTable, unsigned calleeCount)
4242{
43  auto* instance = new (NotNull, allocateCell<JSWebAssemblyModule>(vm.heap, allocationSize(calleeCount))) JSWebAssemblyModule(vm, structure, std::forward<std::unique_ptr<Wasm::ModuleInformation>>(moduleInformation), std::forward<Bag<CallLinkInfo>>(callLinkInfos), std::forward<Vector<Wasm::WasmToJSStub>>(wasmToJSStubs), std::forward<Wasm::ImmutableFunctionIndexSpace>(functionIndexSpace), calleeCount);
 43 auto* instance = new (NotNull, allocateCell<JSWebAssemblyModule>(vm.heap, allocationSize(calleeCount))) JSWebAssemblyModule(vm, structure, std::forward<std::unique_ptr<Wasm::ModuleInformation>>(moduleInformation), std::forward<Bag<CallLinkInfo>>(callLinkInfos), std::forward<Vector<Wasm::WasmExitStubs>>(wasmExitStubs), calleeCount);
4444 instance->finishCreation(vm, exportSymbolTable);
4545 return instance;
4646}

@@Structure* JSWebAssemblyModule::createStructure(VM& vm, JSGlobalObject* globalOb
5050 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
5151}
5252
53 JSWebAssemblyModule::JSWebAssemblyModule(VM& vm, Structure* structure, std::unique_ptr<Wasm::ModuleInformation>&& moduleInformation, Bag<CallLinkInfo>&& callLinkInfos, Vector<Wasm::WasmToJSStub>&& wasmToJSStubs, Wasm::ImmutableFunctionIndexSpace&& functionIndexSpace, unsigned calleeCount)
 53JSWebAssemblyModule::JSWebAssemblyModule(VM& vm, Structure* structure, std::unique_ptr<Wasm::ModuleInformation>&& moduleInformation, Bag<CallLinkInfo>&& callLinkInfos, Vector<Wasm::WasmExitStubs>&& wasmExitStubs, unsigned calleeCount)
5454 : Base(vm, structure)
5555 , m_moduleInformation(WTFMove(moduleInformation))
5656 , m_callLinkInfos(WTFMove(callLinkInfos))
57  , m_wasmToJSStubs(WTFMove(wasmToJSStubs))
58  , m_functionIndexSpace(WTFMove(functionIndexSpace))
 57 , m_wasmExitStubs(WTFMove(wasmExitStubs))
5958 , m_calleeCount(calleeCount)
6059{
6160 memset(callees(), 0, m_calleeCount * sizeof(WriteBarrier<JSWebAssemblyCallee>) * 2);

Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h

@@class JSWebAssemblyModule : public JSDestructibleObject {
4343public:
4444 typedef JSDestructibleObject Base;
4545
46  static JSWebAssemblyModule* create(VM&, Structure*, std::unique_ptr<Wasm::ModuleInformation>&&, Bag<CallLinkInfo>&&, Vector<Wasm::WasmToJSStub>&&, Wasm::ImmutableFunctionIndexSpace&&, SymbolTable*, unsigned);
 46 static JSWebAssemblyModule* create(VM&, Structure*, std::unique_ptr<Wasm::ModuleInformation>&&, Bag<CallLinkInfo>&&, Vector<Wasm::WasmExitStubs>&&, SymbolTable*, unsigned);
4747 static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
4848
4949 DECLARE_INFO;
5050
5151 const Wasm::ModuleInformation& moduleInformation() const { return *m_moduleInformation.get(); }
5252 SymbolTable* exportSymbolTable() const { return m_exportSymbolTable.get(); }
53  Wasm::SignatureIndex signatureForFunctionIndexSpace(unsigned functionIndexSpace) const
 53 Wasm::SignatureIndex signatureIndexFromFunctionIndexSpace(unsigned functionIndexSpace) const
5454 {
55  ASSERT(functionIndexSpace < m_functionIndexSpace.size);
56  return m_functionIndexSpace.buffer.get()[functionIndexSpace].signatureIndex;
 55 return m_moduleInformation->signatureIndexFromFunctionIndexSpace(functionIndexSpace);
5756 }
58  unsigned importCount() const { return m_wasmToJSStubs.size(); }
 57 unsigned importCount() const { return m_wasmExitStubs.size(); }
5958
6059 JSWebAssemblyCallee* jsEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
6160 {

@@public:
9089 return bitwise_cast<WriteBarrier<JSWebAssemblyCallee>*>(bitwise_cast<char*>(this) + offsetOfCallees());
9190 }
9291
93  static ptrdiff_t offsetOfFunctionIndexSpace() { return OBJECT_OFFSETOF(JSWebAssemblyModule, m_functionIndexSpace); }
94 
9592protected:
96  JSWebAssemblyModule(VM&, Structure*, std::unique_ptr<Wasm::ModuleInformation>&&, Bag<CallLinkInfo>&&, Vector<Wasm::WasmToJSStub>&&, Wasm::ImmutableFunctionIndexSpace&&, unsigned calleeCount);
 93 JSWebAssemblyModule(VM&, Structure*, std::unique_ptr<Wasm::ModuleInformation>&&, Bag<CallLinkInfo>&&, Vector<Wasm::WasmExitStubs>&&, unsigned calleeCount);
9794 void finishCreation(VM&, SymbolTable*);
9895 static void destroy(JSCell*);
9996 static void visitChildren(JSCell*, SlotVisitor&);

@@private:
117114 std::unique_ptr<Wasm::ModuleInformation> m_moduleInformation;
118115 Bag<CallLinkInfo> m_callLinkInfos;
119116 WriteBarrier<SymbolTable> m_exportSymbolTable;
120  Vector<Wasm::WasmToJSStub> m_wasmToJSStubs;
121  const Wasm::ImmutableFunctionIndexSpace m_functionIndexSpace;
 117 Vector<Wasm::WasmExitStubs> m_wasmExitStubs;
122118 unsigned m_calleeCount;
123119};
124120

Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp

@@static EncodedJSValue JSC_HOST_CALL callWebAssemblyFunction(ExecState* exec)
105105
106106EncodedJSValue WebAssemblyFunction::call(VM& vm, ProtoCallFrame* protoCallFrame)
107107{
108  // Setup the memory that the entrance loads.
109  if (JSWebAssemblyMemory* memory = instance()->memory()) {
110  Wasm::Memory* wasmMemory = memory->memory();
111  vm.topWasmMemoryPointer = wasmMemory->memory();
112  vm.topWasmMemorySize = wasmMemory->size();
113  } else {
114  vm.topWasmMemoryPointer = nullptr;
115  vm.topWasmMemorySize = 0;
116  }
117 
 108 // FIXME Do away with this entire function, and only use the entrypoint generated by B3. https://bugs.webkit.org/show_bug.cgi?id=166486
118109 JSWebAssemblyInstance* prevJSWebAssemblyInstance = vm.topJSWebAssemblyInstance;
119110 vm.topJSWebAssemblyInstance = instance();
120111 ASSERT(instance());

@@WebAssemblyFunction* WebAssemblyFunction::create(VM& vm, JSGlobalObject* globalO
153144Structure* WebAssemblyFunction::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
154145{
155146 ASSERT(globalObject);
156  return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
 147 return Structure::create(vm, globalObject, prototype, TypeInfo(WebAssemblyFunctionType, StructureFlags), info());
157148}
158149
159150WebAssemblyFunction::WebAssemblyFunction(VM& vm, JSGlobalObject* globalObject, Structure* structure, Wasm::SignatureIndex signatureIndex)

Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp

@@static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyInstance(ExecState* ex
114114 return JSValue::encode(throwException(exec, throwScope, createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("import function must be callable"))));
115115 JSCell* cell = value.asCell();
116116 // ii. If v is an Exported Function Exotic Object:
117  if (WebAssemblyFunction* importedExports = jsDynamicCast<WebAssemblyFunction*>(object)) {
118  // FIXME handle Function Exotic Object properly. https://bugs.webkit.org/show_bug.cgi?id=165282
119  // a. If the signature of v does not match the signature of i, throw a TypeError.
 117 if (WebAssemblyFunction* importedExport = jsDynamicCast<WebAssemblyFunction*>(cell)) {
 118 // a. If the signature of v does not match the signature of i, throw a WebAssembly.LinkError.
 119 Wasm::SignatureIndex importedSignatureIndex = importedExport->signatureIndex();
 120 Wasm::SignatureIndex expectedSignatureIndex = moduleInformation.importFunctionSignatureIndices[import.kindIndex];
 121 if (importedSignatureIndex != expectedSignatureIndex)
 122 return JSValue::encode(throwException(exec, throwScope, createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("imported function's signature mismatches the provided WebAssembly function's signature"))));
120123 // b. Let closure be v.[[Closure]].
121  RELEASE_ASSERT_NOT_REACHED();
122  UNUSED_PARAM(importedExports);
123  break;
124124 }
125125 // iii. Otherwise:
126126 // a. Let closure be a new host function of the given signature which calls v by coercing WebAssembly arguments to JavaScript arguments via ToJSValue and returns the result, if any, by coercing via ToWebAssemblyValue.
127127 // Note: done as part of Plan compilation.
128128 // iv. Append v to funcs.
 129 // Note: adding the JSCell to the instance list fulfills closure requirements b. above (the WebAssembly.Instance wil be kept alive) and v. below (the JSFunction).
129130 instance->setImportFunction(vm, cell, numImportFunctions++);
130131 // v. Append closure to imports.
131132 break;

@@static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyInstance(ExecState* ex
229230 if (moduleInformation.memory && !hasMemoryImport) {
230231 RELEASE_ASSERT(!moduleInformation.memory.isImport());
231232 // We create a memory when it's a memory definition.
232  std::unique_ptr<Wasm::Memory> memory = std::make_unique<Wasm::Memory>(moduleInformation.memory.initial(), moduleInformation.memory.maximum());
233  if (!memory->isValid())
 233 Wasm::Memory memory(moduleInformation.memory.initial(), moduleInformation.memory.maximum());
 234 if (!memory.isValid())
234235 return JSValue::encode(throwException(exec, throwScope, createOutOfMemoryError(exec)));
235236 instance->setMemory(vm,
236237 JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), WTFMove(memory)));

Source/JavaScriptCore/wasm/js/WebAssemblyMemoryConstructor.cpp

@@static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyMemory(ExecState* exec
9696 }
9797 }
9898
99  std::unique_ptr<Wasm::Memory> memory = std::make_unique<Wasm::Memory>(initialPageCount, maximumPageCount);
100  if (!memory->isValid())
 99 Wasm::Memory memory(initialPageCount, maximumPageCount);
 100 if (!memory.isValid())
101101 return JSValue::encode(throwException(exec, throwScope, createOutOfMemoryError(exec)));
102102
103103 return JSValue::encode(JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), WTFMove(memory)));

Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.cpp

@@JSValue WebAssemblyModuleConstructor::createModule(ExecState* state, Structure*
9797
9898 // Only wasm-internal functions have a callee, stubs to JS do not.
9999 unsigned calleeCount = plan.internalFunctionCount();
100  JSWebAssemblyModule* result = JSWebAssemblyModule::create(vm, structure, plan.takeModuleInformation(), plan.takeCallLinkInfos(), plan.takeWasmToJSStubs(), plan.takeFunctionIndexSpace(), exportSymbolTable, calleeCount);
 100 JSWebAssemblyModule* result = JSWebAssemblyModule::create(vm, structure, plan.takeModuleInformation(), plan.takeCallLinkInfos(), plan.takeWasmExitStubs(), exportSymbolTable, calleeCount);
101101 plan.initializeCallees(state->jsCallee()->globalObject(),
102102 [&] (unsigned calleeIndex, JSWebAssemblyCallee* jsEntrypointCallee, JSWebAssemblyCallee* wasmEntrypointCallee) {
103103 result->setJSEntrypointCallee(vm, calleeIndex, jsEntrypointCallee);

Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp

@@void WebAssemblyModuleRecord::link(ExecState* state, JSWebAssemblyInstance* inst
118118 // c. Return func.
119119 JSWebAssemblyCallee* jsEntrypointCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(exp.kindIndex);
120120 JSWebAssemblyCallee* wasmEntrypointCallee = module->wasmEntrypointCalleeFromFunctionIndexSpace(exp.kindIndex);
121  Wasm::SignatureIndex signatureIndex = module->signatureForFunctionIndexSpace(exp.kindIndex);
 121 Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(exp.kindIndex);
122122 const Wasm::Signature* signature = Wasm::SignatureInformation::get(&vm, signatureIndex);
123123 WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->argumentCount(), exp.field.string(), instance, jsEntrypointCallee, wasmEntrypointCallee, signatureIndex);
124124 exportedValue = function;

@@void WebAssemblyModuleRecord::link(ExecState* state, JSWebAssemblyInstance* inst
175175 bool hasStart = !!moduleInformation.startFunctionIndexSpace;
176176 if (hasStart) {
177177 auto startFunctionIndexSpace = moduleInformation.startFunctionIndexSpace.value_or(0);
178  Wasm::SignatureIndex signatureIndex = module->signatureForFunctionIndexSpace(startFunctionIndexSpace);
 178 Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(startFunctionIndexSpace);
179179 const Wasm::Signature* signature = Wasm::SignatureInformation::get(&vm, signatureIndex);
180180 // The start function must not take any arguments or return anything. This is enforced by the parser.
181181 ASSERT(!signature->argumentCount());

@@JSValue WebAssemblyModuleRecord::evaluate(ExecState* state)
238238
239239 JSWebAssemblyCallee* jsEntrypointCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(functionIndex);
240240 JSWebAssemblyCallee* wasmEntrypointCallee = module->wasmEntrypointCalleeFromFunctionIndexSpace(functionIndex);
241  Wasm::SignatureIndex signatureIndex = module->signatureForFunctionIndexSpace(functionIndex);
 241 Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(functionIndex);
242242 const Wasm::Signature* signature = Wasm::SignatureInformation::get(&vm, signatureIndex);
243243 // FIXME: Say we export local function "foo" at funciton index 0.
244244 // What if we also set it to the table an Element w/ index 0.