WebAssembly: unique function signatures
authorjfbastien@apple.com <jfbastien@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 20 Dec 2016 18:54:33 +0000 (18:54 +0000)
committerjfbastien@apple.com <jfbastien@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 20 Dec 2016 18:54:33 +0000 (18:54 +0000)
https://bugs.webkit.org/show_bug.cgi?id=165957
<rdar://problem/29735737>

Reviewed by Saam Barati.

JSTests:

* wasm/function-tests/table-basic.js: FIXME is now addressed,
though instance to instance calls still need work which bug
#165282 will address
(i.assert.eq.foo):
* wasm/js-api/unique-signature.js: Added.
(CallIndirectWithDuplicateSignatures):

Source/JavaScriptCore:

Signatures in a Module's Type section can be duplicated, we
therefore need to unique them so that call_indirect only needs to
do a single integer compare to check that a callee's Signature is
the same as the Signature declared at the call site. Without
uniquing we'd either trap when duplicate Signatures are used, or
we'd need to do multiple comparisons. This patch makes that narrow
usecase function correctly.

There's further complication when calling from wasm to
wasm, in which case the Signatures must also match. Such
cross-instance calls will be improved in bug #165282, but this
patch sets the groundwork for it:

- Signatures are now owned by SignatureInformation which lives on
  VM, and is shared by all Modules.
- When parsing a Module, a Signature is created for every Type
  entry, and then uniqued by SignatureInformation's adopt
  method. Duplicate Signatures are dropped and the previous
  SignatureIndex is returned, new Signatures are adopted and a new
  SignatureIndex is created.
- The SignatureIndex values are monotonic. 0 is used to represent
  invalid indices, which trap. This can only occur through Table.
- SignatureInformation is used while generating code to map a
  SignatureIndex back to the Signature* when return / argument
  information is needed. This is a simple lookup into a Vector. It
  isn't used at runtime.
- These Signatures live forever on VM because the bookkeeping
  likely isn't worth it. We may want to empty things out if all
  Modules die, this is tracked in bug #166037.
- We can further improve things by bit-packing SignatureIndex with
  Code*, which is tracked by bug #165511.

* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* runtime/VM.h: wasm signatures are uniqued here, but aren't accessed frequently (only during parsing) so indirection is fine
* wasm/WasmB3IRGenerator.cpp: use SignatureIndex instead of Signature* when appropriate, and when still using Signature* do so with its new API
(JSC::Wasm::createJSToWasmWrapper):
(JSC::Wasm::parseAndCompile):
* wasm/WasmBinding.cpp:
(JSC::Wasm::importStubGenerator): use SignatureIndex
* wasm/WasmBinding.h:
* wasm/WasmCallingConvention.h:
(JSC::Wasm::CallingConvention::loadArguments):
* wasm/WasmFormat.cpp: drive-by move of alloc/free functions to the implementation file, allows the .h file to drop an FastMalloc.h
(JSC::Wasm::Segment::create):
(JSC::Wasm::Segment::destroy):
(JSC::Wasm::Segment::createPtr):
* wasm/WasmFormat.h: move Signature to its own file
(JSC::Wasm::CallableFunction::CallableFunction):
* wasm/WasmFunctionParser.h:
(JSC::Wasm::FunctionParser<Context>::FunctionParser):
* wasm/WasmModuleParser.cpp:
* wasm/WasmModuleParser.h:
(JSC::Wasm::ModuleParser::ModuleParser):
* wasm/WasmParser.h:
(JSC::Wasm::Parser<SuccessType>::Parser):
* wasm/WasmPlan.cpp:
(JSC::Wasm::Plan::parseAndValidateModule):
(JSC::Wasm::Plan::run):
* wasm/WasmSignature.cpp: Added.
(JSC::Wasm::Signature::dump):
(JSC::Wasm::Signature::hash):
(JSC::Wasm::Signature::create):
(JSC::Wasm::Signature::createInvalid):
(JSC::Wasm::Signature::destroy):
(JSC::Wasm::SignatureInformation::~SignatureInformation):
(JSC::Wasm::SignatureInformation::adopt):
(JSC::Wasm::SignatureInformation::get):
* wasm/WasmSignature.h: Added.
(JSC::Wasm::Signature::Signature):
(JSC::Wasm::Signature::storage):
(JSC::Wasm::Signature::allocatedSize):
(JSC::Wasm::Signature::returnType):
(JSC::Wasm::Signature::returnCount):
(JSC::Wasm::Signature::argumentCount):
(JSC::Wasm::Signature::argument):
(JSC::Wasm::Signature::operator==):
(JSC::Wasm::SignatureHash::empty):
(JSC::Wasm::SignatureHash::deleted):
(JSC::Wasm::SignatureHash::SignatureHash):
(JSC::Wasm::SignatureHash::operator==):
(JSC::Wasm::SignatureHash::equal):
(JSC::Wasm::SignatureHash::hash):
(JSC::Wasm::SignatureHash::isHashTableDeletedValue):
* wasm/WasmValidate.cpp:
(JSC::Wasm::validateFunction):
* wasm/WasmValidate.h:
* wasm/js/JSWebAssemblyInstance.cpp:
(JSC::JSWebAssemblyInstance::create):
* wasm/js/JSWebAssemblyModule.h:
(JSC::JSWebAssemblyModule::signatureForFunctionIndexSpace):
* wasm/js/JSWebAssemblyTable.cpp:
(JSC::JSWebAssemblyTable::JSWebAssemblyTable):
(JSC::JSWebAssemblyTable::clearFunction):
(JSC::JSWebAssemblyTable::setFunction):
* wasm/js/WebAssemblyFunction.cpp:
(JSC::callWebAssemblyFunction):
(JSC::WebAssemblyFunction::call):
(JSC::WebAssemblyFunction::create):
(JSC::WebAssemblyFunction::WebAssemblyFunction):
(JSC::WebAssemblyFunction::finishCreation):
* wasm/js/WebAssemblyFunction.h:
(JSC::WebAssemblyFunction::signatureIndex):
* wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::link):
(JSC::WebAssemblyModuleRecord::evaluate):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@210026 268f45cc-cd09-0410-ab3c-d52691b4dbfc

28 files changed:
JSTests/ChangeLog
JSTests/wasm/function-tests/table-basic.js
JSTests/wasm/js-api/unique-signature.js [new file with mode: 0644]
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/runtime/VM.h
Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
Source/JavaScriptCore/wasm/WasmBinding.cpp
Source/JavaScriptCore/wasm/WasmBinding.h
Source/JavaScriptCore/wasm/WasmCallingConvention.h
Source/JavaScriptCore/wasm/WasmFormat.cpp
Source/JavaScriptCore/wasm/WasmFormat.h
Source/JavaScriptCore/wasm/WasmFunctionParser.h
Source/JavaScriptCore/wasm/WasmModuleParser.cpp
Source/JavaScriptCore/wasm/WasmModuleParser.h
Source/JavaScriptCore/wasm/WasmParser.h
Source/JavaScriptCore/wasm/WasmPlan.cpp
Source/JavaScriptCore/wasm/WasmSignature.cpp [new file with mode: 0644]
Source/JavaScriptCore/wasm/WasmSignature.h [new file with mode: 0644]
Source/JavaScriptCore/wasm/WasmValidate.cpp
Source/JavaScriptCore/wasm/WasmValidate.h
Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp
Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h
Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.cpp
Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp
Source/JavaScriptCore/wasm/js/WebAssemblyFunction.h
Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp

index 65fa972..fa26f15 100644 (file)
@@ -1,3 +1,18 @@
+2016-12-20  JF Bastien  <jfbastien@apple.com>
+
+        WebAssembly: unique function signatures
+        https://bugs.webkit.org/show_bug.cgi?id=165957
+        <rdar://problem/29735737>
+
+        Reviewed by Saam Barati.
+
+        * wasm/function-tests/table-basic.js: FIXME is now addressed,
+        though instance to instance calls still need work which bug
+        #165282 will address
+        (i.assert.eq.foo):
+        * wasm/js-api/unique-signature.js: Added.
+        (CallIndirectWithDuplicateSignatures):
+
 2016-12-19  Mark Lam  <mark.lam@apple.com>
 
         Rolling out r209974 and r209952. They break some websites in mysterious ways. Step 2: Rollout r209952.
index 2de8c7d..0ff3b47 100644 (file)
@@ -44,21 +44,15 @@ function makeInstance() {
     table.set(0, exports.bar);
     assert.eq(table.get(0), exports.bar);
 
-    for (let i = 0; i < 1000; i++) {
-        if (foo(0, i) !== i + 42)
-            throw new Error("Bad call indirect");
-    }
+    for (let i = 0; i < 1000; i++)
+        assert.eq(foo(0, i), i + 42, "call_indirect");
 }
 
-// FIXME: make this work cross module. The reason it doesn't
-// now is that we don't unique Signature*.
-// https://bugs.webkit.org/show_bug.cgi?id=165511
 {
     const {instance, table} = makeInstance();
     const foo = instance.exports.foo;
     table.set(0, makeInstance().instance.exports.bar); // Cross instance function.
 
-    for (let i = 0; i < 1000; i++) {
-        assert.throws(() => foo(0, i), WebAssembly.RuntimeError, "call_indirect to a signature that does not match");
-    }
+    for (let i = 0; i < 1000; i++)
+        assert.eq(foo(0, i), i + 42, "call_indirect");
 }
diff --git a/JSTests/wasm/js-api/unique-signature.js b/JSTests/wasm/js-api/unique-signature.js
new file mode 100644 (file)
index 0000000..8f5a55f
--- /dev/null
@@ -0,0 +1,49 @@
+import * as assert from '../assert.js';
+import Builder from '../Builder.js';
+
+(function CallIndirectWithDuplicateSignatures() {
+    const builder = (new Builder())
+        .Type()
+            .Func(["i32"], "i32")         // 0
+            .Func(["i32"], "i32")         // 1
+            .Func(["i32", "i32"], "i32")  // 2
+            .Func(["i32"], "i32")         // 3
+            .Func(["i32"], "i32")         // 4
+            .Func(["i32", "i32"], "i32")  // 5
+            .Func(["f64", "f64"], "f64")  // 6
+            .Func(["i32"], "f64")         // 7
+            .Func(["i32"], "f64")         // 8
+        .End()
+        .Function().End()
+        .Table()
+            .Table({initial: 4, maximum: 4, element: "anyfunc"})
+        .End()
+        .Export()
+            .Function("entry")
+            .Table("table", 0)
+            .Function("callMe")
+        .End()
+        .Code()
+            .Function("entry", 1)
+                .I32Const(42)
+                .GetLocal(0)
+                .I32Add()
+                .I32Const(0) // Function index 0.
+                .CallIndirect(4, 0) // Different signature index, but same signature.
+                .Return()
+            .End()
+            .Function("callMe", 3)
+                .I32Const(3)
+                .GetLocal(0)
+                .I32Add()
+                .Return()
+            .End()
+        .End();
+    const bin = builder.WebAssembly().get();
+    const module = new WebAssembly.Module(bin);
+    let value0 = undefined;
+    const instance = new WebAssembly.Instance(module);
+    let table = instance.exports.table;
+    table.set(0, instance.exports.callMe);
+    assert.eq(instance.exports.entry(5), 5 + 42 + 3);
+}());
index 0c7aac6..716a349 100644 (file)
@@ -906,6 +906,7 @@ set(JavaScriptCore_SOURCES
     wasm/WasmMemoryInformation.cpp
     wasm/WasmModuleParser.cpp
     wasm/WasmPlan.cpp
+    wasm/WasmSignature.cpp
     wasm/WasmValidate.cpp
 
     wasm/js/JSWebAssemblyCallee.cpp
index 004fdd9..2bc235d 100644 (file)
@@ -1,3 +1,118 @@
+2016-12-20  JF Bastien  <jfbastien@apple.com>
+
+        WebAssembly: unique function signatures
+        https://bugs.webkit.org/show_bug.cgi?id=165957
+        <rdar://problem/29735737>
+
+        Reviewed by Saam Barati.
+
+        Signatures in a Module's Type section can be duplicated, we
+        therefore need to unique them so that call_indirect only needs to
+        do a single integer compare to check that a callee's Signature is
+        the same as the Signature declared at the call site. Without
+        uniquing we'd either trap when duplicate Signatures are used, or
+        we'd need to do multiple comparisons. This patch makes that narrow
+        usecase function correctly.
+
+        There's further complication when calling from wasm to
+        wasm, in which case the Signatures must also match. Such
+        cross-instance calls will be improved in bug #165282, but this
+        patch sets the groundwork for it:
+
+        - Signatures are now owned by SignatureInformation which lives on
+          VM, and is shared by all Modules.
+        - When parsing a Module, a Signature is created for every Type
+          entry, and then uniqued by SignatureInformation's adopt
+          method. Duplicate Signatures are dropped and the previous
+          SignatureIndex is returned, new Signatures are adopted and a new
+          SignatureIndex is created.
+        - The SignatureIndex values are monotonic. 0 is used to represent
+          invalid indices, which trap. This can only occur through Table.
+        - SignatureInformation is used while generating code to map a
+          SignatureIndex back to the Signature* when return / argument
+          information is needed. This is a simple lookup into a Vector. It
+          isn't used at runtime.
+        - These Signatures live forever on VM because the bookkeeping
+          likely isn't worth it. We may want to empty things out if all
+          Modules die, this is tracked in bug #166037.
+        - We can further improve things by bit-packing SignatureIndex with
+          Code*, which is tracked by bug #165511.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * runtime/VM.h: wasm signatures are uniqued here, but aren't accessed frequently (only during parsing) so indirection is fine
+        * wasm/WasmB3IRGenerator.cpp: use SignatureIndex instead of Signature* when appropriate, and when still using Signature* do so with its new API
+        (JSC::Wasm::createJSToWasmWrapper):
+        (JSC::Wasm::parseAndCompile):
+        * wasm/WasmBinding.cpp:
+        (JSC::Wasm::importStubGenerator): use SignatureIndex
+        * wasm/WasmBinding.h:
+        * wasm/WasmCallingConvention.h:
+        (JSC::Wasm::CallingConvention::loadArguments):
+        * wasm/WasmFormat.cpp: drive-by move of alloc/free functions to the implementation file, allows the .h file to drop an FastMalloc.h
+        (JSC::Wasm::Segment::create):
+        (JSC::Wasm::Segment::destroy):
+        (JSC::Wasm::Segment::createPtr):
+        * wasm/WasmFormat.h: move Signature to its own file
+        (JSC::Wasm::CallableFunction::CallableFunction):
+        * wasm/WasmFunctionParser.h:
+        (JSC::Wasm::FunctionParser<Context>::FunctionParser):
+        * wasm/WasmModuleParser.cpp:
+        * wasm/WasmModuleParser.h:
+        (JSC::Wasm::ModuleParser::ModuleParser):
+        * wasm/WasmParser.h:
+        (JSC::Wasm::Parser<SuccessType>::Parser):
+        * wasm/WasmPlan.cpp:
+        (JSC::Wasm::Plan::parseAndValidateModule):
+        (JSC::Wasm::Plan::run):
+        * wasm/WasmSignature.cpp: Added.
+        (JSC::Wasm::Signature::dump):
+        (JSC::Wasm::Signature::hash):
+        (JSC::Wasm::Signature::create):
+        (JSC::Wasm::Signature::createInvalid):
+        (JSC::Wasm::Signature::destroy):
+        (JSC::Wasm::SignatureInformation::~SignatureInformation):
+        (JSC::Wasm::SignatureInformation::adopt):
+        (JSC::Wasm::SignatureInformation::get):
+        * wasm/WasmSignature.h: Added.
+        (JSC::Wasm::Signature::Signature):
+        (JSC::Wasm::Signature::storage):
+        (JSC::Wasm::Signature::allocatedSize):
+        (JSC::Wasm::Signature::returnType):
+        (JSC::Wasm::Signature::returnCount):
+        (JSC::Wasm::Signature::argumentCount):
+        (JSC::Wasm::Signature::argument):
+        (JSC::Wasm::Signature::operator==):
+        (JSC::Wasm::SignatureHash::empty):
+        (JSC::Wasm::SignatureHash::deleted):
+        (JSC::Wasm::SignatureHash::SignatureHash):
+        (JSC::Wasm::SignatureHash::operator==):
+        (JSC::Wasm::SignatureHash::equal):
+        (JSC::Wasm::SignatureHash::hash):
+        (JSC::Wasm::SignatureHash::isHashTableDeletedValue):
+        * wasm/WasmValidate.cpp:
+        (JSC::Wasm::validateFunction):
+        * wasm/WasmValidate.h:
+        * wasm/js/JSWebAssemblyInstance.cpp:
+        (JSC::JSWebAssemblyInstance::create):
+        * wasm/js/JSWebAssemblyModule.h:
+        (JSC::JSWebAssemblyModule::signatureForFunctionIndexSpace):
+        * wasm/js/JSWebAssemblyTable.cpp:
+        (JSC::JSWebAssemblyTable::JSWebAssemblyTable):
+        (JSC::JSWebAssemblyTable::clearFunction):
+        (JSC::JSWebAssemblyTable::setFunction):
+        * wasm/js/WebAssemblyFunction.cpp:
+        (JSC::callWebAssemblyFunction):
+        (JSC::WebAssemblyFunction::call):
+        (JSC::WebAssemblyFunction::create):
+        (JSC::WebAssemblyFunction::WebAssemblyFunction):
+        (JSC::WebAssemblyFunction::finishCreation):
+        * wasm/js/WebAssemblyFunction.h:
+        (JSC::WebAssemblyFunction::signatureIndex):
+        * wasm/js/WebAssemblyModuleRecord.cpp:
+        (JSC::WebAssemblyModuleRecord::link):
+        (JSC::WebAssemblyModuleRecord::evaluate):
+
 2016-12-20  Konstantin Tokarev  <annulen@yandex.ru>
 
         Modernize for loops in JSC
index 87deb6b..2004ba9 100644 (file)
                AD4937D41DDD27DE0077C807 /* WebAssemblyFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = AD4937CA1DDD27340077C807 /* WebAssemblyFunction.h */; };
                AD4B1DF91DF244E20071AE32 /* WasmBinding.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD4B1DF71DF244D70071AE32 /* WasmBinding.cpp */; };
                AD4B1DFA1DF244E20071AE32 /* WasmBinding.h in Headers */ = {isa = PBXBuildFile; fileRef = AD4B1DF81DF244D70071AE32 /* WasmBinding.h */; };
+               AD7438C01E0457A400FD0C2A /* WasmSignature.h in Headers */ = {isa = PBXBuildFile; fileRef = AD7438BF1E04579200FD0C2A /* WasmSignature.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               AD7438C11E0457AA00FD0C2A /* WasmSignature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD7438BE1E04579200FD0C2A /* WasmSignature.cpp */; };
                AD86A93E1AA4D88D002FE77F /* WeakGCMapInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = AD86A93D1AA4D87C002FE77F /* WeakGCMapInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
                ADBC54D41DF8EA2B005BF738 /* WebAssemblyToJSCallee.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADBC54D21DF8EA00005BF738 /* WebAssemblyToJSCallee.cpp */; };
                ADBC54D51DF8EA2B005BF738 /* WebAssemblyToJSCallee.h in Headers */ = {isa = PBXBuildFile; fileRef = ADBC54D31DF8EA00005BF738 /* WebAssemblyToJSCallee.h */; };
                AD4937CA1DDD27340077C807 /* WebAssemblyFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebAssemblyFunction.h; path = js/WebAssemblyFunction.h; sourceTree = "<group>"; };
                AD4B1DF71DF244D70071AE32 /* WasmBinding.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmBinding.cpp; sourceTree = "<group>"; };
                AD4B1DF81DF244D70071AE32 /* WasmBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmBinding.h; sourceTree = "<group>"; };
+               AD7438BE1E04579200FD0C2A /* WasmSignature.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmSignature.cpp; sourceTree = "<group>"; };
+               AD7438BF1E04579200FD0C2A /* WasmSignature.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmSignature.h; sourceTree = "<group>"; };
                AD86A93D1AA4D87C002FE77F /* WeakGCMapInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakGCMapInlines.h; sourceTree = "<group>"; };
                ADBC54D21DF8EA00005BF738 /* WebAssemblyToJSCallee.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebAssemblyToJSCallee.cpp; path = js/WebAssemblyToJSCallee.cpp; sourceTree = "<group>"; };
                ADBC54D31DF8EA00005BF738 /* WebAssemblyToJSCallee.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebAssemblyToJSCallee.h; path = js/WebAssemblyToJSCallee.h; sourceTree = "<group>"; };
                                531374BE1D5CE95000AF7A0B /* WasmPlan.cpp */,
                                531374BC1D5CE67600AF7A0B /* WasmPlan.h */,
                                53F40E841D58F9770099A1B6 /* WasmSections.h */,
+                               AD7438BE1E04579200FD0C2A /* WasmSignature.cpp */,
+                               AD7438BF1E04579200FD0C2A /* WasmSignature.h */,
                                53FF7F9A1DBFD2B900A26CCC /* WasmValidate.cpp */,
                                53FF7F981DBFCD9000A26CCC /* WasmValidate.h */,
                        );
                                0F3B3A281544C997003ED0FF /* DFGCFGSimplificationPhase.h in Headers */,
                                0F9D36951AE9CC33000D4DFB /* DFGCleanUpPhase.h in Headers */,
                                A77A424017A0BBFD00A8DB81 /* DFGClobberize.h in Headers */,
+                               AD7438C01E0457A400FD0C2A /* WasmSignature.h in Headers */,
                                A77A424217A0BBFD00A8DB81 /* DFGClobberSet.h in Headers */,
                                0F3C1F1B1B868E7900ABB08B /* DFGClobbersExitState.h in Headers */,
                                0F04396E1B03DC0B009598B7 /* DFGCombinedLiveness.h in Headers */,
                                FED94F2E171E3E2300BE77A4 /* Watchdog.cpp in Sources */,
                                0F919D2515853CE0004A4E7D /* Watchpoint.cpp in Sources */,
                                1ACF7377171CA6FB00C9BB1E /* Weak.cpp in Sources */,
+                               AD7438C11E0457AA00FD0C2A /* WasmSignature.cpp in Sources */,
                                14E84F9E14EE1ACC00D6D5D4 /* WeakBlock.cpp in Sources */,
                                14F7256514EE265E00B1652B /* WeakHandleOwner.cpp in Sources */,
                                A7CA3AE317DA41AE006538AF /* WeakMapConstructor.cpp in Sources */,
index 636f2eb..f340e96 100644 (file)
@@ -147,6 +147,11 @@ class Database;
 namespace DOMJIT {
 class Signature;
 }
+#if ENABLE(WEBASSEMBLY)
+namespace Wasm {
+class SignatureInformation;
+}
+#endif
 
 struct HashTable;
 struct Instruction;
@@ -354,6 +359,11 @@ public:
     Strong<JSCell> iterationTerminator;
     Strong<JSCell> emptyPropertyNameEnumerator;
 
+#if ENABLE(WEBASSEMBLY)
+    std::once_flag m_wasmSignatureInformationOnceFlag;
+    std::unique_ptr<Wasm::SignatureInformation> m_wasmSignatureInformation;
+#endif
+
     AtomicStringTable* m_atomicStringTable;
     WTF::SymbolRegistry m_symbolRegistry;
     TemplateRegistryKeyTable m_templateRegistryKeytable;
index 9f58d13..5f35a28 100644 (file)
@@ -154,7 +154,7 @@ public:
 
     B3IRGenerator(VM&, const ModuleInformation&, Procedure&, WasmInternalFunction*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&);
 
-    PartialResult WARN_UNUSED_RETURN addArguments(const Vector<Type>&);
+    PartialResult WARN_UNUSED_RETURN addArguments(const Signature*);
     PartialResult WARN_UNUSED_RETURN addLocal(Type, uint32_t);
     ExpressionType addConstant(Type, uint64_t);
 
@@ -192,7 +192,7 @@ public:
 
     // Calls
     PartialResult WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature*, Vector<ExpressionType>& args, ExpressionType& result);
-    PartialResult WARN_UNUSED_RETURN addCallIndirect(const Signature*, Vector<ExpressionType>& args, ExpressionType& result);
+    PartialResult WARN_UNUSED_RETURN addCallIndirect(const Signature*, SignatureIndex, Vector<ExpressionType>& args, ExpressionType& result);
     PartialResult WARN_UNUSED_RETURN addUnreachable();
 
     void dump(const Vector<ControlEntry>& controlStack, const ExpressionList& expressionStack);
@@ -302,13 +302,13 @@ auto B3IRGenerator::addLocal(Type type, uint32_t count) -> PartialResult
     return { };
 }
 
-auto B3IRGenerator::addArguments(const Vector<Type>& types) -> PartialResult
+auto B3IRGenerator::addArguments(const Signature* signature) -> PartialResult
 {
     ASSERT(!m_locals.size());
-    WASM_COMPILE_FAIL_IF(!m_locals.tryReserveCapacity(types.size()), "can't allocate memory for ", types.size(), " arguments");
+    WASM_COMPILE_FAIL_IF(!m_locals.tryReserveCapacity(signature->argumentCount()), "can't allocate memory for ", signature->argumentCount(), " arguments");
 
-    m_locals.grow(types.size());
-    wasmCallingConvention().loadArguments(types, m_proc, m_currentBlock, Origin(),
+    m_locals.grow(signature->argumentCount());
+    wasmCallingConvention().loadArguments(signature, m_proc, m_currentBlock, Origin(),
         [&] (ExpressionType argument, unsigned i) {
             Variable* argumentVariable = m_proc.addVariable(argument->type());
             m_locals[i] = argumentVariable;
@@ -682,9 +682,9 @@ auto B3IRGenerator::addEndToUnreachable(ControlEntry& entry) -> PartialResult
 
 auto B3IRGenerator::addCall(uint32_t functionIndex, const Signature* signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult
 {
-    ASSERT(signature->arguments.size() == args.size());
+    ASSERT(signature->argumentCount() == args.size());
 
-    Type returnType = signature->returnType;
+    Type returnType = signature->returnType();
 
     result = wasmCallingConvention().setupCall(m_proc, m_currentBlock, Origin(), args, toB3Type(returnType),
         [&] (PatchpointValue* patchpoint) {
@@ -704,10 +704,11 @@ auto B3IRGenerator::addCall(uint32_t functionIndex, const Signature* signature,
     return { };
 }
 
-auto B3IRGenerator::addCallIndirect(const Signature* signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult
+auto B3IRGenerator::addCallIndirect(const Signature* signature, SignatureIndex signatureIndex, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult
 {
+    ASSERT(signatureIndex != Signature::invalidIndex);
     ExpressionType calleeIndex = args.takeLast();
-    ASSERT(signature->arguments.size() == args.size());
+    ASSERT(signature->argumentCount() == args.size());
 
     ExpressionType callableFunctionBuffer;
     ExpressionType callableFunctionBufferSize;
@@ -736,13 +737,14 @@ auto B3IRGenerator::addCallIndirect(const Signature* signature, Vector<Expressio
         m_currentBlock->appendIntConstant(m_proc, Origin(), pointerType(), sizeof(CallableFunction)));
     ExpressionType callableFunction = m_currentBlock->appendNew<Value>(m_proc, Add, Origin(), callableFunctionBuffer, offset);
 
-    // Check that the CallableFunction is initialized. We trap if it isn't. A null Signature* indicates it's not initialized.
-    ExpressionType calleeSignature = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(), callableFunction, OBJECT_OFFSETOF(CallableFunction, signature));
+    // Check that the CallableFunction is initialized. We trap if it isn't. An "invalid" SignatureIndex indicates it's not initialized.
+    static_assert(sizeof(CallableFunction::signatureIndex) == sizeof(uint32_t), "Load codegen assumes i32");
+    ExpressionType calleeSignatureIndex = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, Origin(), callableFunction, OBJECT_OFFSETOF(CallableFunction, signatureIndex));
     {
         CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(),
-            m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), 
-                calleeSignature
-                m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), 0)));
+            m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(),
+                calleeSignatureIndex,
+                m_currentBlock->appendNew<Const32Value>(m_proc, Origin(), Signature::invalidIndex)));
 
         check->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
             this->emitExceptionCheck(jit, ExceptionType::NullTableEntry);
@@ -751,9 +753,9 @@ auto B3IRGenerator::addCallIndirect(const Signature* signature, Vector<Expressio
 
     // Check the signature matches the value we expect.
     {
-        ExpressionType expectedSignature = m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), signature);
+        ExpressionType expectedSignatureIndex = m_currentBlock->appendNew<Const32Value>(m_proc, Origin(), signatureIndex);
         CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(),
-            m_currentBlock->appendNew<Value>(m_proc, NotEqual, Origin(), calleeSignature, expectedSignature));
+            m_currentBlock->appendNew<Value>(m_proc, NotEqual, Origin(), calleeSignatureIndex, expectedSignatureIndex));
 
         check->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
             this->emitExceptionCheck(jit, ExceptionType::BadSignature);
@@ -762,7 +764,7 @@ auto B3IRGenerator::addCallIndirect(const Signature* signature, Vector<Expressio
 
     ExpressionType calleeCode = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(), callableFunction, OBJECT_OFFSETOF(CallableFunction, code));
 
-    Type returnType = signature->returnType;
+    Type returnType = signature->returnType();
     result = wasmCallingConvention().setupCall(m_proc, m_currentBlock, Origin(), args, toB3Type(returnType),
         [&] (PatchpointValue* patchpoint) {
             patchpoint->effects.writesPinned = true;
@@ -834,7 +836,7 @@ static std::unique_ptr<B3::Compilation> createJSToWasmWrapper(VM& vm, WasmIntern
         Value* argumentCount = block->appendNew<MemoryValue>(proc, Load, Int32, origin,
             block->appendNew<Value>(proc, Add, origin, framePointer, offSetOfArgumentCount));
 
-        Value* expectedArgumentCount = block->appendNew<Const32Value>(proc, origin, signature->arguments.size());
+        Value* expectedArgumentCount = block->appendNew<Const32Value>(proc, origin, signature->argumentCount());
 
         CheckValue* argumentCountCheck = block->appendNew<CheckValue>(proc, Check, origin,
             block->appendNew<Value>(proc, Above, origin, expectedArgumentCount, argumentCount));
@@ -861,12 +863,12 @@ static std::unique_ptr<B3::Compilation> createJSToWasmWrapper(VM& vm, WasmIntern
 
     // Get our arguments.
     Vector<Value*> arguments;
-    jscCallingConvention().loadArguments(signature->arguments, proc, block, origin, [&] (Value* argument, unsigned) {
+    jscCallingConvention().loadArguments(signature, proc, block, origin, [&] (Value* argument, unsigned) {
         arguments.append(argument);
     });
 
     // Move the arguments into place.
-    Value* result = wasmCallingConvention().setupCall(proc, block, origin, arguments, toB3Type(signature->returnType), [&] (PatchpointValue* patchpoint) {
+    Value* result = wasmCallingConvention().setupCall(proc, block, origin, arguments, toB3Type(signature->returnType()), [&] (PatchpointValue* patchpoint) {
         if (!!memory) {
             ASSERT(sizes.size() == memory.pinnedRegisters().sizeRegisters.size());
             patchpoint->append(ConstrainedValue(baseMemory, ValueRep::reg(memory.pinnedRegisters().baseMemoryPointer)));
@@ -885,7 +887,7 @@ static std::unique_ptr<B3::Compilation> createJSToWasmWrapper(VM& vm, WasmIntern
     });
 
     // Return the result, if needed.
-    switch (signature->returnType) {
+    switch (signature->returnType()) {
     case Wasm::Void:
         block->appendNewControlValue(proc, B3::Return, origin);
         break;
@@ -913,7 +915,7 @@ Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM& vm,
 
     Procedure procedure;
     B3IRGenerator context(vm, info, procedure, result.get(), unlinkedWasmToWasmCalls, functionIndexSpace);
-    FunctionParser<B3IRGenerator> parser(context, functionStart, functionLength, signature, functionIndexSpace, info);
+    FunctionParser<B3IRGenerator> parser(&vm, context, functionStart, functionLength, signature, functionIndexSpace, info);
     WASM_FAIL_IF_HELPER_FAILS(parser.parse());
 
     procedure.resetReachability();
index 33064dc..0e59247 100644 (file)
 
 namespace JSC { namespace Wasm {
 
-WasmToJSStub importStubGenerator(VM* vm, Bag<CallLinkInfo>& callLinkInfos, Signature* signature, unsigned importIndex)
+WasmToJSStub importStubGenerator(VM* vm, Bag<CallLinkInfo>& callLinkInfos, SignatureIndex signatureIndex, unsigned importIndex)
 {
     const WasmCallingConvention& wasmCC = wasmCallingConvention();
     const JSCCallingConvention& jsCC = jscCallingConvention();
-    unsigned argCount = signature->arguments.size();
+    const Signature* signature = SignatureInformation::get(vm, signatureIndex);
+    unsigned argCount = signature->argumentCount();
     typedef AssemblyHelpers JIT;
     JIT jit(vm, nullptr);
 
@@ -72,7 +73,7 @@ WasmToJSStub importStubGenerator(VM* vm, Bag<CallLinkInfo>& callLinkInfos, Signa
     unsigned calleeFrameOffset = CallFrameSlot::firstArgument * static_cast<int>(sizeof(Register));
     unsigned frOffset = CallFrameSlot::firstArgument * static_cast<int>(sizeof(Register));
     for (unsigned argNum = 0; argNum < argCount; ++argNum) {
-        Type argType = signature->arguments[argNum];
+        Type argType = signature->argument(argNum);
         switch (argType) {
         case Void:
         case Func:
@@ -161,7 +162,7 @@ WasmToJSStub importStubGenerator(VM* vm, Bag<CallLinkInfo>& callLinkInfos, Signa
     JIT::Call slowCall = jit.nearCall();
     done.link(&jit);
 
-    switch (signature->returnType) {
+    switch (signature->returnType()) {
     case Void:
         // Discard.
         break;
@@ -230,7 +231,7 @@ WasmToJSStub importStubGenerator(VM* vm, Bag<CallLinkInfo>& callLinkInfos, Signa
     CodeLocationLabel hotPathBegin(patchBuffer.locationOf(targetToCheck));
     CodeLocationNearCall hotPathOther = patchBuffer.locationOfNearCall(fastCall);
     callLinkInfo->setCallLocations(callReturnLocation, hotPathBegin, hotPathOther);
-    return FINALIZE_CODE(patchBuffer, ("WebAssembly import[%i] stub for signature %p", importIndex, signature));
+    return FINALIZE_CODE(patchBuffer, ("WebAssembly import[%i] stub for signature %i", importIndex, signatureIndex));
 }
 
 } } // namespace JSC::Wasm
index 9fe3fdb..fd7e03d 100644 (file)
@@ -38,7 +38,7 @@ class CallLinkInfo;
 
 namespace Wasm {
 
-WasmToJSStub importStubGenerator(VM*, Bag<CallLinkInfo>&, Signature*, unsigned);
+WasmToJSStub importStubGenerator(VM*, Bag<CallLinkInfo>&, SignatureIndex, unsigned);
 
 } } // namespace JSC::Wasm
 
index b735937..928ffa5 100644 (file)
@@ -118,7 +118,7 @@ public:
     }
 
     template<typename Functor>
-    void loadArguments(const Vector<Type>& argumentTypes, B3::Procedure& proc, B3::BasicBlock* block, B3::Origin origin, const Functor& functor) const
+    void loadArguments(const Signature* signature, B3::Procedure& proc, B3::BasicBlock* block, B3::Origin origin, const Functor& functor) const
     {
         B3::Value* framePointer = block->appendNew<B3::Value>(proc, B3::FramePointer, origin);
 
@@ -126,8 +126,8 @@ public:
         size_t fpArgumentCount = 0;
         size_t stackOffset = headerSize;
 
-        for (size_t i = 0; i < argumentTypes.size(); ++i) {
-            B3::Type type = toB3Type(argumentTypes[i]);
+        for (size_t i = 0; i < signature->argumentCount(); ++i) {
+            B3::Type type = toB3Type(signature->argument(i));
             B3::Value* argument;
             B3::ValueRep rep = marshallArgument(type, gpArgumentCount, fpArgumentCount, stackOffset);
             if (rep.isReg()) {
index e420b83..40edc52 100644 (file)
 #if ENABLE(WEBASSEMBLY)
 
 #include "WasmMemory.h"
+#include <wtf/FastMalloc.h>
 
 namespace JSC { namespace Wasm {
 
+Segment* Segment::create(uint32_t offset, uint32_t sizeInBytes)
+{
+    auto allocated = tryFastCalloc(sizeof(Segment) + sizeInBytes, 1);
+    Segment* segment;
+    if (!allocated.getValue(segment))
+        return nullptr;
+    segment->offset = offset;
+    segment->sizeInBytes = sizeInBytes;
+    return segment;
+}
+
+void Segment::destroy(Segment *segment)
+{
+    fastFree(segment);
+}
+
+Segment::Ptr Segment::adoptPtr(Segment* segment)
+{
+    return Ptr(segment, &Segment::destroy);
+}
+
 JS_EXPORT_PRIVATE ModuleInformation::~ModuleInformation() { }
 
 } } // namespace JSC::Wasm
index e49a891..359ddcc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -36,8 +36,9 @@
 #include "WasmMemoryInformation.h"
 #include "WasmOps.h"
 #include "WasmPageCount.h"
+#include "WasmSignature.h"
+#include <limits>
 #include <memory>
-#include <wtf/FastMalloc.h>
 #include <wtf/Optional.h>
 #include <wtf/Vector.h>
 
@@ -100,11 +101,6 @@ static inline const char* makeString(ExternalKind kind)
     return "?";
 }
 
-struct Signature {
-    Type returnType;
-    Vector<Type> arguments;
-};
-
 struct Import {
     Identifier module;
     Identifier field;
@@ -146,30 +142,15 @@ struct Segment {
     uint32_t offset;
     uint32_t sizeInBytes;
     // Bytes are allocated at the end.
-    static Segment* make(uint32_t offset, uint32_t sizeInBytes)
-    {
-        auto allocated = tryFastCalloc(sizeof(Segment) + sizeInBytes, 1);
-        Segment* segment;
-        if (!allocated.getValue(segment))
-            return nullptr;
-        segment->offset = offset;
-        segment->sizeInBytes = sizeInBytes;
-        return segment;
-    }
-    static void destroy(Segment *segment)
-    {
-        fastFree(segment);
-    }
     uint8_t& byte(uint32_t pos)
     {
         ASSERT(pos < sizeInBytes);
         return *reinterpret_cast<uint8_t*>(reinterpret_cast<char*>(this) + sizeof(offset) + sizeof(sizeInBytes) + pos);
     }
+    static Segment* create(uint32_t, uint32_t);
+    static void destroy(Segment*);
     typedef std::unique_ptr<Segment, decltype(&Segment::destroy)> Ptr;
-    static Ptr makePtr(Segment* segment)
-    {
-        return Ptr(segment, &Segment::destroy);
-    }
+    static Ptr adoptPtr(Segment*);
 };
 
 struct Element {
@@ -206,10 +187,10 @@ private:
 };
 
 struct ModuleInformation {
-    Vector<Signature> signatures;
+    Vector<SignatureIndex> signatureIndices;
     Vector<Import> imports;
-    Vector<Signature*> importFunctions;
-    Vector<Signature*> internalFunctionSignatures;
+    Vector<SignatureIndex> importFunctionSignatureIndices;
+    Vector<SignatureIndex> internalFunctionSignatureIndices;
     MemoryInformation memory;
     Vector<Export> exports;
     std::optional<uint32_t> startFunctionIndexSpace;
@@ -247,15 +228,14 @@ typedef MacroAssemblerCodeRef WasmToJSStub;
 struct CallableFunction {
     CallableFunction() = default;
 
-    CallableFunction(Signature* signature, void* code = nullptr)
-        : signature(signature)
+    CallableFunction(SignatureIndex signatureIndex, void* code = nullptr)
+        : signatureIndex(signatureIndex)
         , code(code)
     {
     }
 
-    // FIXME pack this inside a (uniqued) integer (for correctness the parser should unique Signatures),
-    // and then pack that integer into the code pointer. https://bugs.webkit.org/show_bug.cgi?id=165511
-    Signature* signature { nullptr }; 
+    // FIXME pack the SignatureIndex and the code pointer into one 64-bit value. https://bugs.webkit.org/show_bug.cgi?id=165511
+    SignatureIndex signatureIndex { Signature::invalidIndex };
     void* code { nullptr };
 };
 typedef Vector<CallableFunction> FunctionIndexSpace;
index e61e337..59092d5 100644 (file)
@@ -45,7 +45,7 @@ public:
     typedef typename Context::ControlType ControlType;
     typedef typename Context::ExpressionList ExpressionList;
 
-    FunctionParser(Context&, const uint8_t* functionStart, size_t functionLength, const Signature*, const ImmutableFunctionIndexSpace&, const ModuleInformation&);
+    FunctionParser(VM*, Context&, const uint8_t* functionStart, size_t functionLength, const Signature*, const ImmutableFunctionIndexSpace&, const ModuleInformation&);
 
     Result WARN_UNUSED_RETURN parse();
 
@@ -88,8 +88,8 @@ private:
 };
 
 template<typename Context>
-FunctionParser<Context>::FunctionParser(Context& context, const uint8_t* functionStart, size_t functionLength, const Signature* signature, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& info)
-    : Parser(functionStart, functionLength)
+FunctionParser<Context>::FunctionParser(VM* vm, Context& context, const uint8_t* functionStart, size_t functionLength, const Signature* signature, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& info)
+    : Parser(vm, functionStart, functionLength)
     , m_context(context)
     , m_signature(signature)
     , m_functionIndexSpace(functionIndexSpace)
@@ -104,7 +104,7 @@ auto FunctionParser<Context>::parse() -> Result
 {
     uint32_t localCount;
 
-    WASM_PARSER_FAIL_IF(!m_context.addArguments(m_signature->arguments), "can't add ", m_signature->arguments.size(), " arguments to Function");
+    WASM_PARSER_FAIL_IF(!m_context.addArguments(m_signature), "can't add ", m_signature->argumentCount(), " arguments to Function");
     WASM_PARSER_FAIL_IF(!parseVarUInt32(localCount), "can't get local count");
     WASM_PARSER_FAIL_IF(localCount == std::numeric_limits<uint32_t>::max(), "Function section's local count is too big ", localCount);
 
@@ -155,7 +155,7 @@ template<typename Context>
 auto FunctionParser<Context>::addReturn() -> PartialResult
 {
     ExpressionList returnValues;
-    if (m_signature->returnType != Void) {
+    if (m_signature->returnType() != Void) {
         ExpressionType returnValue;
         WASM_TRY_POP_EXPRESSION_STACK_INTO(returnValue, "return");
         returnValues.append(returnValue);
@@ -329,12 +329,13 @@ auto FunctionParser<Context>::parseExpression(OpType op) -> PartialResult
         WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't parse call's function index");
         WASM_PARSER_FAIL_IF(functionIndex >= m_functionIndexSpace.size, "call function index ", functionIndex, " exceeds function index space ", m_functionIndexSpace.size);
 
-        const Signature* calleeSignature = m_functionIndexSpace.buffer.get()[functionIndex].signature;
-        WASM_PARSER_FAIL_IF(calleeSignature->arguments.size() > m_expressionStack.size(), "call function index ", functionIndex, " has ", calleeSignature->arguments.size(), " arguments, but the expression stack currently holds ", m_expressionStack.size(), " values");
+        SignatureIndex calleeSignatureIndex = m_functionIndexSpace.buffer.get()[functionIndex].signatureIndex;
+        const Signature* calleeSignature = SignatureInformation::get(m_vm, calleeSignatureIndex);
+        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");
 
-        size_t firstArgumentIndex = m_expressionStack.size() - calleeSignature->arguments.size();
+        size_t firstArgumentIndex = m_expressionStack.size() - calleeSignature->argumentCount();
         Vector<ExpressionType> args;
-        WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(calleeSignature->arguments.size()), "can't allocate enough memory for call's ", calleeSignature->arguments.size(), " arguments");
+        WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(calleeSignature->argumentCount()), "can't allocate enough memory for call's ", calleeSignature->argumentCount(), " arguments");
         for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i)
             args.uncheckedAppend(m_expressionStack[i]);
         m_expressionStack.shrink(firstArgumentIndex);
@@ -355,10 +356,11 @@ auto FunctionParser<Context>::parseExpression(OpType op) -> PartialResult
         WASM_PARSER_FAIL_IF(!parseVarUInt32(signatureIndex), "can't get call_indirect's signature index");
         WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't get call_indirect's reserved byte");
         WASM_PARSER_FAIL_IF(reserved, "call_indirect's 'reserved' varuint1 must be 0x0");
-        WASM_PARSER_FAIL_IF(m_info.signatures.size() <= signatureIndex, "call_indirect's signature index ", signatureIndex, " exceeds known signatures ", m_info.signatures.size());
+        WASM_PARSER_FAIL_IF(m_info.signatureIndices.size() <= signatureIndex, "call_indirect's signature index ", signatureIndex, " exceeds known signatures ", m_info.signatureIndices.size());
 
-        const Signature* calleeSignature = &m_info.signatures[signatureIndex];
-        size_t argumentCount = calleeSignature->arguments.size() + 1; // Add the callee's index.
+        SignatureIndex calleeSignatureIndex = m_info.signatureIndices[signatureIndex];
+        const Signature* calleeSignature = SignatureInformation::get(m_vm, calleeSignatureIndex);
+        size_t argumentCount = calleeSignature->argumentCount() + 1; // Add the callee's index.
         WASM_PARSER_FAIL_IF(argumentCount > m_expressionStack.size(), "call_indirect expects ", argumentCount, " arguments, but the expression stack currently holds ", m_expressionStack.size(), " values");
 
         Vector<ExpressionType> args;
@@ -369,7 +371,7 @@ auto FunctionParser<Context>::parseExpression(OpType op) -> PartialResult
         m_expressionStack.shrink(firstArgumentIndex);
 
         ExpressionType result = Context::emptyExpression;
-        WASM_TRY_ADD_TO_CONTEXT(addCallIndirect(calleeSignature, args, result));
+        WASM_TRY_ADD_TO_CONTEXT(addCallIndirect(calleeSignature, calleeSignatureIndex, args, result));
 
         if (result != Context::emptyExpression)
             m_expressionStack.append(result);
index f4f76b0..8918475 100644 (file)
@@ -99,7 +99,7 @@ auto ModuleParser::parseType() -> PartialResult
 
     WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Type section's count");
     WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Type section's count is too big ", count);
-    WASM_PARSER_FAIL_IF(!m_result.module->signatures.tryReserveCapacity(count), "can't allocate enough memory for Type section's ", count, " entries");
+    WASM_PARSER_FAIL_IF(!m_result.module->signatureIndices.tryReserveCapacity(count), "can't allocate enough memory for Type section's ", count, " entries");
 
     for (uint32_t i = 0; i < count; ++i) {
         int8_t type;
@@ -110,26 +110,28 @@ auto ModuleParser::parseType() -> PartialResult
         WASM_PARSER_FAIL_IF(type != Func, i, "th Type is non-Func ", type);
         WASM_PARSER_FAIL_IF(!parseVarUInt32(argumentCount), "can't get ", i, "th Type's argument count");
         WASM_PARSER_FAIL_IF(argumentCount == std::numeric_limits<uint32_t>::max(), i, "th argument count is too big ", argumentCount);
-        WASM_PARSER_FAIL_IF(!argumentTypes.tryReserveCapacity(argumentCount), "can't allocate enough memory for Type section's ", i, "th ", argumentCount, " arguments");
+        std::unique_ptr<Signature, void (*)(Signature*)> signature(Signature::create(argumentCount), &Signature::destroy);
+        WASM_PARSER_FAIL_IF(!signature, "can't allocate enough memory for Type section's ", i, "th signature");
 
         for (unsigned i = 0; i < argumentCount; ++i) {
             Type argumentType;
             WASM_PARSER_FAIL_IF(!parseResultType(argumentType), "can't get ", i, "th argument Type");
-            argumentTypes.uncheckedAppend(argumentType);
+            signature->argument(i) = argumentType;
         }
 
         uint8_t returnCount;
         WASM_PARSER_FAIL_IF(!parseVarUInt1(returnCount), "can't get ", i, "th Type's return count");
         Type returnType;
-
         if (returnCount) {
             Type value;
             WASM_PARSER_FAIL_IF(!parseValueType(value), "can't get ", i, "th Type's return value");
             returnType = static_cast<Type>(value);
         } else
             returnType = Type::Void;
+        signature->returnType() = returnType;
 
-        m_result.module->signatures.uncheckedAppend({ returnType, WTFMove(argumentTypes) });
+        SignatureIndex signatureIndex = SignatureInformation::adopt(m_vm, signature.release());
+        m_result.module->signatureIndices.uncheckedAppend(signatureIndex);
     }
     return { };
 }
@@ -141,7 +143,7 @@ auto ModuleParser::parseImport() -> PartialResult
     WASM_PARSER_FAIL_IF(importCount == std::numeric_limits<uint32_t>::max(), "Import section's count is too big ", importCount);
     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.
     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.
-    WASM_PARSER_FAIL_IF(!m_result.module->importFunctions.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " import functions"); // FIXME this over-allocates when we fix the FIXMEs below.
+    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.
     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.
 
     for (uint32_t importNumber = 0; importNumber < importCount; ++importNumber) {
@@ -164,11 +166,11 @@ auto ModuleParser::parseImport() -> PartialResult
         case ExternalKind::Function: {
             uint32_t functionSignatureIndex;
             WASM_PARSER_FAIL_IF(!parseVarUInt32(functionSignatureIndex), "can't get ", importNumber, "th Import's function signature in module '", moduleString, "' field '", fieldString, "'");
-            WASM_PARSER_FAIL_IF(functionSignatureIndex >= m_result.module->signatures.size(), "invalid function signature for ", importNumber, "th Import, ", functionSignatureIndex, " is out of range of ", m_result.module->signatures.size(), " in module '", moduleString, "' field '", fieldString, "'");
-            imp.kindIndex = m_result.module->importFunctions.size();
-            Signature* signature = &m_result.module->signatures[functionSignatureIndex];
-            m_result.module->importFunctions.uncheckedAppend(signature);
-            m_result.functionIndexSpace.uncheckedAppend(signature);
+            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, "'");
+            imp.kindIndex = m_result.module->importFunctionSignatureIndices.size();
+            SignatureIndex signatureIndex = m_result.module->signatureIndices[functionSignatureIndex];
+            m_result.module->importFunctionSignatureIndices.uncheckedAppend(signatureIndex);
+            m_result.functionIndexSpace.uncheckedAppend(signatureIndex);
             break;
         }
         case ExternalKind::Table: {
@@ -208,22 +210,22 @@ auto ModuleParser::parseFunction() -> PartialResult
     uint32_t count;
     WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Function section's count");
     WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Function section's count is too big ", count);
-    WASM_PARSER_FAIL_IF(!m_result.module->internalFunctionSignatures.tryReserveCapacity(count), "can't allocate enough memory for ", count, " Function signatures");
+    WASM_PARSER_FAIL_IF(!m_result.module->internalFunctionSignatureIndices.tryReserveCapacity(count), "can't allocate enough memory for ", count, " Function signatures");
     WASM_PARSER_FAIL_IF(!m_result.functionLocationInBinary.tryReserveCapacity(count), "can't allocate enough memory for ", count, "Function locations");
     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");
 
     for (uint32_t i = 0; i < count; ++i) {
         uint32_t typeNumber;
         WASM_PARSER_FAIL_IF(!parseVarUInt32(typeNumber), "can't get ", i, "th Function's type number");
-        WASM_PARSER_FAIL_IF(typeNumber >= m_result.module->signatures.size(), i, "th Function type number is invalid ", typeNumber);
+        WASM_PARSER_FAIL_IF(typeNumber >= m_result.module->signatureIndices.size(), i, "th Function type number is invalid ", typeNumber);
 
-        Signature* signature = &m_result.module->signatures[typeNumber];
+        SignatureIndex signatureIndex = m_result.module->signatureIndices[typeNumber];
         // The Code section fixes up start and end.
         size_t start = 0;
         size_t end = 0;
-        m_result.module->internalFunctionSignatures.uncheckedAppend(signature);
+        m_result.module->internalFunctionSignatureIndices.uncheckedAppend(signatureIndex);
         m_result.functionLocationInBinary.uncheckedAppend({ start, end });
-        m_result.functionIndexSpace.uncheckedAppend(signature);
+        m_result.functionIndexSpace.uncheckedAppend(signatureIndex);
     }
 
     return { };
@@ -425,9 +427,10 @@ auto ModuleParser::parseStart() -> PartialResult
     uint32_t startFunctionIndex;
     WASM_PARSER_FAIL_IF(!parseVarUInt32(startFunctionIndex), "can't get Start index");
     WASM_PARSER_FAIL_IF(startFunctionIndex >= m_result.functionIndexSpace.size(), "Start index ", startFunctionIndex, " exceeds function index space ", m_result.functionIndexSpace.size());
-    Signature* signature = m_result.functionIndexSpace[startFunctionIndex].signature;
-    WASM_PARSER_FAIL_IF(!signature->arguments.isEmpty(), "Start function can't have arguments");
-    WASM_PARSER_FAIL_IF(signature->returnType != Void, "Start function can't return a value");
+    SignatureIndex signatureIndex = m_result.functionIndexSpace[startFunctionIndex].signatureIndex;
+    const Signature* signature = SignatureInformation::get(m_vm, signatureIndex);
+    WASM_PARSER_FAIL_IF(signature->argumentCount(), "Start function can't have arguments");
+    WASM_PARSER_FAIL_IF(signature->returnType() != Void, "Start function can't return a value");
     m_result.module->startFunctionIndexSpace = startFunctionIndex;
     return { };
 }
@@ -594,9 +597,9 @@ auto ModuleParser::parseData() -> PartialResult
         WASM_PARSER_FAIL_IF(!parseVarUInt32(dataByteLength), "can't get ", segmentNumber, "th Data segment's data byte length");
         WASM_PARSER_FAIL_IF(dataByteLength == std::numeric_limits<uint32_t>::max(), segmentNumber, "th Data segment's data byte length is too big ", dataByteLength);
 
-        Segment* segment = Segment::make(offset, dataByteLength);
+        Segment* segment = Segment::create(offset, dataByteLength);
         WASM_PARSER_FAIL_IF(!segment, "can't allocate enough memory for ", segmentNumber, "th Data segment of size ", dataByteLength);
-        m_result.module->data.uncheckedAppend(Segment::makePtr(segment));
+        m_result.module->data.uncheckedAppend(Segment::adoptPtr(segment));
         for (uint32_t dataByte = 0; dataByte < dataByteLength; ++dataByte) {
             uint8_t byte;
             WASM_PARSER_FAIL_IF(!parseUInt8(byte), "can't get ", dataByte, "th data byte from ", segmentNumber, "th Data segment");
index 6a2436e..96c04d4 100644 (file)
@@ -44,8 +44,7 @@ class ModuleParser : public Parser<ModuleParserResult> {
 public:
 
     ModuleParser(VM* vm, const uint8_t* sourceBuffer, size_t sourceLength)
-        : Parser(sourceBuffer, sourceLength)
-        , m_vm(vm)
+        : Parser(vm, sourceBuffer, sourceLength)
     {
     }
     ModuleParser(VM* vm, const Vector<uint8_t>& sourceBuffer)
@@ -67,7 +66,6 @@ private:
     PartialResult WARN_UNUSED_RETURN parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum);
     PartialResult WARN_UNUSED_RETURN parseInitExpr(uint8_t&, uint64_t&);
 
-    VM* m_vm;
     ModuleParserResult m_result;
     bool m_hasTable { false };
 };
index d6ae8c5..5f154c7 100644 (file)
@@ -56,7 +56,7 @@ public:
     typedef Expected<SuccessType, ErrorType> Result;
 
 protected:
-    Parser(const uint8_t*, size_t);
+    Parser(VM*, const uint8_t*, size_t);
 
     bool WARN_UNUSED_RETURN consumeCharacter(char);
     bool WARN_UNUSED_RETURN consumeString(const char*);
@@ -81,6 +81,7 @@ protected:
     const uint8_t* source() const { return m_source; }
     size_t length() const { return m_sourceLength; }
 
+    VM* m_vm;
     size_t m_offset = 0;
 
     template <typename ...Args>
@@ -106,8 +107,9 @@ private:
 };
 
 template<typename SuccessType>
-ALWAYS_INLINE Parser<SuccessType>::Parser(const uint8_t* sourceBuffer, size_t sourceLength)
-    : m_source(sourceBuffer)
+ALWAYS_INLINE Parser<SuccessType>::Parser(VM* vm, const uint8_t* sourceBuffer, size_t sourceLength)
+    : m_vm(vm)
+    , m_source(sourceBuffer)
     , m_sourceLength(sourceLength)
 {
 }
index 9dea8ba..1e59842 100644 (file)
@@ -79,9 +79,10 @@ bool Plan::parseAndValidateModule()
         const uint8_t* functionStart = m_source + m_functionLocationInBinary[functionIndex].start;
         size_t functionLength = m_functionLocationInBinary[functionIndex].end - m_functionLocationInBinary[functionIndex].start;
         ASSERT(Checked<uintptr_t>(bitwise_cast<uintptr_t>(functionStart)) + functionLength <= Checked<uintptr_t>(bitwise_cast<uintptr_t>(m_source)) + m_sourceLength);
-        Signature* signature = m_moduleInformation->internalFunctionSignatures[functionIndex];
+        SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
+        const Signature* signature = SignatureInformation::get(m_vm, signatureIndex);
 
-        auto validationResult = validateFunction(functionStart, functionLength, signature, m_functionIndexSpace, *m_moduleInformation);
+        auto validationResult = validateFunction(m_vm, functionStart, functionLength, signature, m_functionIndexSpace, *m_moduleInformation);
         if (!validationResult) {
             if (verbose) {
                 for (unsigned i = 0; i < functionLength; ++i)
@@ -114,7 +115,7 @@ void Plan::run()
     };
 
     Vector<Vector<UnlinkedWasmToWasmCall>> unlinkedWasmToWasmCalls;
-    if (!tryReserveCapacity(m_wasmToJSStubs, m_moduleInformation->importFunctions.size(), " WebAssembly to JavaScript stubs")
+    if (!tryReserveCapacity(m_wasmToJSStubs, m_moduleInformation->importFunctionSignatureIndices.size(), " WebAssembly to JavaScript stubs")
         || !tryReserveCapacity(unlinkedWasmToWasmCalls, m_functionLocationInBinary.size(), " unlinked WebAssembly to WebAssembly calls")
         || !tryReserveCapacity(m_wasmInternalFunctions, m_functionLocationInBinary.size(), " WebAssembly functions"))
         return;
@@ -126,8 +127,8 @@ void Plan::run()
         unsigned importFunctionIndex = m_wasmToJSStubs.size();
         if (verbose)
             dataLogLn("Processing import function number ", importFunctionIndex, ": ", import->module, ": ", import->field);
-        Signature* signature = m_moduleInformation->importFunctions.at(import->kindIndex);
-        m_wasmToJSStubs.uncheckedAppend(importStubGenerator(m_vm, m_callLinkInfos, signature, importFunctionIndex));
+        SignatureIndex signatureIndex = m_moduleInformation->importFunctionSignatureIndices.at(import->kindIndex);
+        m_wasmToJSStubs.uncheckedAppend(importStubGenerator(m_vm, m_callLinkInfos, signatureIndex, importFunctionIndex));
         m_functionIndexSpace.buffer.get()[importFunctionIndex].code = m_wasmToJSStubs[importFunctionIndex].code().executableAddress();
     }
 
@@ -137,11 +138,12 @@ void Plan::run()
         const uint8_t* functionStart = m_source + m_functionLocationInBinary[functionIndex].start;
         size_t functionLength = m_functionLocationInBinary[functionIndex].end - m_functionLocationInBinary[functionIndex].start;
         ASSERT(functionLength <= m_sourceLength);
-        Signature* signature = m_moduleInformation->internalFunctionSignatures[functionIndex];
+        SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
+        const Signature* signature = SignatureInformation::get(m_vm, signatureIndex);
         unsigned functionIndexSpace = m_wasmToJSStubs.size() + functionIndex;
-        ASSERT(m_functionIndexSpace.buffer.get()[functionIndexSpace].signature == signature);
+        ASSERT(m_functionIndexSpace.buffer.get()[functionIndexSpace].signatureIndex == signatureIndex);
 
-        ASSERT(validateFunction(functionStart, functionLength, signature, m_functionIndexSpace, *m_moduleInformation));
+        ASSERT(validateFunction(m_vm, functionStart, functionLength, signature, m_functionIndexSpace, *m_moduleInformation));
 
         unlinkedWasmToWasmCalls.uncheckedAppend(Vector<UnlinkedWasmToWasmCall>());
         auto parseAndCompileResult = parseAndCompile(*m_vm, functionStart, functionLength, signature, unlinkedWasmToWasmCalls.at(functionIndex), m_functionIndexSpace, *m_moduleInformation);
diff --git a/Source/JavaScriptCore/wasm/WasmSignature.cpp b/Source/JavaScriptCore/wasm/WasmSignature.cpp
new file mode 100644 (file)
index 0000000..6d5b1f6
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WasmSignature.h"
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "VM.h"
+#include <wtf/FastMalloc.h>
+#include <wtf/HashFunctions.h>
+#include <wtf/PrintStream.h>
+
+namespace JSC { namespace Wasm {
+
+namespace {
+const bool verbose = false;
+}
+
+const constexpr SignatureIndex Signature::invalidIndex;
+
+void Signature::dump(PrintStream& out) const
+{
+    out.print(makeString(returnType()), " (");
+    for (SignatureArgCount arg = 0; arg < argumentCount(); ++arg)
+        out.print((arg ? ", " : ""), makeString(argument(arg)));
+    out.print(")");
+}
+
+unsigned Signature::hash() const
+{
+    uint32_t sizeToHash = allocatedSize(argumentCount()) / sizeof(allocationSizeRoundsUpTo);
+    // Assumes over-allocated memory was zero-initialized, and rounded-up to allocationSizeRoundsUpTo so that a wider hash can be performed.
+    ASSERT(sizeToHash * sizeof(allocationSizeRoundsUpTo) == allocatedSize(argumentCount()));
+    unsigned accumulator = 0xa1bcedd8u;
+    const auto* pos = reinterpret_cast<const allocationSizeRoundsUpTo*>(this);
+    for (uint32_t i = 0; i < sizeToHash; ++i)
+        accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<allocationSizeRoundsUpTo>::hash(*pos));
+    return accumulator;
+}
+
+Signature* Signature::create(SignatureArgCount argumentCount)
+{
+    // Hashing relies on allocation zero-initializing trailing elements.
+    auto allocated = tryFastCalloc(allocatedSize(argumentCount), 1);
+    Signature* signature;
+    if (!allocated.getValue(signature))
+        return nullptr;
+    new (signature) Signature(argumentCount);
+    return signature;
+}
+
+Signature* Signature::createInvalid()
+{
+    Signature* signature = create(0);
+    RELEASE_ASSERT(signature);
+    new (signature) Signature(std::numeric_limits<SignatureArgCount>::max());
+    return signature;
+}
+
+void Signature::destroy(Signature* signature)
+{
+    fastFree(signature);
+}
+
+SignatureInformation::~SignatureInformation()
+{
+    for (size_t i = 0; i < m_signatures.size(); ++i)
+        Signature::destroy(m_signatures[i]);
+}
+
+SignatureInformation::SignatureInformation()
+{
+    // The zeroth entry is an invalid signature, to match invalidIndex.
+    ASSERT(!Signature::invalidIndex);
+    Signature* invalidSignature = Signature::createInvalid();
+    auto addResult = m_signatureMap.add(SignatureHash { invalidSignature }, Signature::invalidIndex);
+    RELEASE_ASSERT(addResult.isNewEntry);
+    ASSERT(Signature::invalidIndex == addResult.iterator->value);
+    m_signatures.append(invalidSignature);
+}
+
+SignatureInformation* SignatureInformation::get(VM* vm)
+{
+    std::call_once(vm->m_wasmSignatureInformationOnceFlag, [vm] {
+        vm->m_wasmSignatureInformation = std::unique_ptr<SignatureInformation>(new SignatureInformation());
+    });
+    return vm->m_wasmSignatureInformation.get();
+}
+
+SignatureIndex SignatureInformation::adopt(VM* vm, Signature* signature)
+{
+    SignatureInformation* info = get(vm);
+    LockHolder lock(info->m_lock);
+
+    SignatureIndex nextValue = info->m_signatures.size();
+    auto addResult = info->m_signatureMap.add(SignatureHash { signature }, nextValue);
+    if (addResult.isNewEntry) {
+        ASSERT(nextValue == addResult.iterator->value);
+        if (verbose)
+            dataLogLn("Adopt new signature ", *signature, " with index ", addResult.iterator->value, " hash: ", signature->hash());
+        info->m_signatures.append(signature);
+        return nextValue;
+    }
+    if (verbose)
+        dataLogLn("Existing signature ", *signature, " with index ", addResult.iterator->value, " hash: ", signature->hash());
+    Signature::destroy(signature);
+    ASSERT(addResult.iterator->value != Signature::invalidIndex);
+    return addResult.iterator->value;
+}
+
+const Signature* SignatureInformation::get(VM* vm, SignatureIndex index)
+{
+    ASSERT(index != Signature::invalidIndex);
+    SignatureInformation* info = get(vm);
+    LockHolder lock(info->m_lock);
+
+    if (verbose)
+        dataLogLn("Got signature ", *info->m_signatures.at(index), " at index ", index);
+    return info->m_signatures.at(index);
+}
+
+} } // namespace JSC::Wasm
+
+#endif // ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/wasm/WasmSignature.h b/Source/JavaScriptCore/wasm/WasmSignature.h
new file mode 100644 (file)
index 0000000..0d6c7b5
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "B3Type.h"
+#include "WasmOps.h"
+#include <cstdint>
+#include <cstring>
+#include <wtf/HashMap.h>
+#include <wtf/HashTraits.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/Vector.h>
+
+namespace WTF {
+class PrintStream;
+}
+
+namespace JSC {
+
+class VM;
+
+namespace Wasm {
+
+typedef uint32_t SignatureArgCount;
+typedef uint32_t SignatureIndex;
+
+class Signature {
+    static const constexpr SignatureArgCount s_retCount = 1;
+    typedef uint64_t allocationSizeRoundsUpTo;
+
+    Signature() = delete;
+    Signature(const Signature&) = delete;
+    Signature(SignatureArgCount argCount)
+        : m_argCount(argCount)
+    {
+    }
+
+    Type* storage(SignatureArgCount i)
+    {
+        return i + reinterpret_cast<Type*>(reinterpret_cast<char*>(this) + sizeof(Signature));
+    }
+    Type* storage(SignatureArgCount i) const { return const_cast<Signature*>(this)->storage(i); }
+    static uint32_t allocatedSize(SignatureArgCount argCount)
+    {
+        return WTF::roundUpToMultipleOf<sizeof(allocationSizeRoundsUpTo)>(sizeof(Signature) + (s_retCount + argCount) * sizeof(Type));
+    }
+
+public:
+    Type& returnType() { return *storage(0); }
+    Type returnType() const { return *storage(0); }
+    SignatureArgCount returnCount() const { return s_retCount; }
+    SignatureArgCount argumentCount() const { return m_argCount; }
+    Type& argument(SignatureArgCount i)
+    {
+        ASSERT(i < argumentCount());
+        return *storage(returnCount() + i);
+    }
+    Type argument(SignatureArgCount i) const { return const_cast<Signature*>(this)->argument(i); }
+
+    void dump(WTF::PrintStream& out) const;
+    bool operator==(const Signature& rhs) const
+    {
+        return allocatedSize(argumentCount()) == allocatedSize(rhs.argumentCount()) && !memcmp(this, &rhs, allocatedSize(argumentCount()));
+    }
+    unsigned hash() const;
+
+    static Signature* create(SignatureArgCount);
+    static void destroy(Signature*);
+
+    // Signatures are uniqued and, for call_indirect, validated at runtime. Tables can create invalid SignatureIndex values which cause call_indirect to fail. We use 0 as the invalidIndex so that the codegen can easily test for it and trap, and we add a token invalid entry in SignatureInformation.
+    static const constexpr SignatureIndex invalidIndex = 0;
+
+private:
+    friend class SignatureInformation;
+    static Signature* createInvalid();
+    SignatureArgCount m_argCount;
+    // Return Type and arguments are stored here.
+};
+
+struct SignatureHash {
+    const Signature* key;
+    static const Signature* empty() { return nullptr; }
+    static const Signature* deleted() { return reinterpret_cast<const Signature*>(1); }
+    SignatureHash()
+        : key(empty())
+    {
+    }
+    explicit SignatureHash(const Signature* key)
+        : key(key)
+    {
+        ASSERT(key != empty());
+        ASSERT(key != deleted());
+    }
+    explicit SignatureHash(WTF::HashTableDeletedValueType)
+        : key(deleted())
+    {
+    }
+    bool operator==(const SignatureHash& rhs) const { return equal(*this, rhs); }
+    static bool equal(const SignatureHash& lhs, const SignatureHash& rhs) { return lhs.key == rhs.key || (lhs.key && rhs.key && *lhs.key == *rhs.key); }
+    static unsigned hash(const SignatureHash& signature) { return signature.key->hash(); }
+    static const bool safeToCompareToEmptyOrDeleted = false;
+    bool isHashTableDeletedValue() const { return key == deleted(); }
+};
+
+} } // namespace JSC::Wasm
+
+
+namespace WTF {
+
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<JSC::Wasm::SignatureHash> {
+    typedef JSC::Wasm::SignatureHash Hash;
+};
+
+template<typename T> struct HashTraits;
+template<> struct HashTraits<JSC::Wasm::SignatureHash> : SimpleClassHashTraits<JSC::Wasm::SignatureHash> {
+    static const bool emptyValueIsZero = true;
+};
+
+} // namespace WTF
+
+
+namespace JSC { namespace Wasm {
+
+// Signature information is held globally on VM to allow all signatures to be unique. This is required when wasm calls another wasm instance.
+// Note: signatures are never removed from VM because that would require accounting for all WebAssembly.Module and which signatures they use. The maximum number of signatures is bounded, and isn't worth the counting overhead. We could clear everything when we reach zero outstanding WebAssembly.Module. https://bugs.webkit.org/show_bug.cgi?id=166037
+class SignatureInformation {
+    HashMap<Wasm::SignatureHash, Wasm::SignatureIndex> m_signatureMap;
+    Vector<Signature*> m_signatures;
+    Lock m_lock;
+    static SignatureInformation* get(VM*);
+    SignatureInformation();
+    SignatureInformation(const SignatureInformation&) = delete;
+
+public:
+    ~SignatureInformation();
+    static SignatureIndex WARN_UNUSED_RETURN adopt(VM*, Signature*);
+    static const Signature* WARN_UNUSED_RETURN get(VM*, SignatureIndex);
+};
+
+} } // namespace JSC::Wasm
+
+#endif // ENABLE(WEBASSEMBLY)
index 0a129a9..aee7904 100644 (file)
@@ -92,7 +92,7 @@ public:
         return fail(__VA_ARGS__);                   \
     } while (0)
 
-    Result WARN_UNUSED_RETURN addArguments(const Vector<Type>&);
+    Result WARN_UNUSED_RETURN addArguments(const Signature*);
     Result WARN_UNUSED_RETURN addLocal(Type, uint32_t);
     ExpressionType addConstant(Type type, uint64_t) { return type; }
 
@@ -132,7 +132,7 @@ public:
 
     // Calls
     Result WARN_UNUSED_RETURN addCall(unsigned calleeIndex, const Signature*, const Vector<ExpressionType>& args, ExpressionType& result);
-    Result WARN_UNUSED_RETURN addCallIndirect(const Signature*, const Vector<ExpressionType>& args, ExpressionType& result);
+    Result WARN_UNUSED_RETURN addCallIndirect(const Signature*, SignatureIndex, const Vector<ExpressionType>& args, ExpressionType& result);
 
     bool hasMemory() const { return !!m_module.memory; }
 
@@ -155,10 +155,10 @@ private:
     const ModuleInformation& m_module;
 };
 
-auto Validate::addArguments(const Vector<Type>& args) -> Result
+auto Validate::addArguments(const Signature* signature) -> Result
 {
-    for (Type arg : args)
-        WASM_FAIL_IF_HELPER_FAILS(addLocal(arg, 1));
+    for (size_t i = 0; i < signature->argumentCount(); ++i)
+        WASM_FAIL_IF_HELPER_FAILS(addLocal(signature->argument(i), 1));
     return { };
 }
 
@@ -310,26 +310,28 @@ auto Validate::addEndToUnreachable(ControlEntry& entry) -> Result
 
 auto Validate::addCall(unsigned, const Signature* signature, const Vector<ExpressionType>& args, ExpressionType& result) -> Result
 {
-    WASM_VALIDATOR_FAIL_IF(signature->arguments.size() != args.size(), "arity mismatch in call, got ", args.size(), " arguments, expected ", signature->arguments.size());
+    WASM_VALIDATOR_FAIL_IF(signature->argumentCount() != args.size(), "arity mismatch in call, got ", args.size(), " arguments, expected ", signature->argumentCount());
 
     for (unsigned i = 0; i < args.size(); ++i)
-        WASM_VALIDATOR_FAIL_IF(args[i] != signature->arguments[i], "argument type mismatch in call, got ", args[i], ", expected ", signature->arguments[i]);
+        WASM_VALIDATOR_FAIL_IF(args[i] != signature->argument(i), "argument type mismatch in call, got ", args[i], ", expected ", signature->argument(i));
 
-    result = signature->returnType;
+    result = signature->returnType();
     return { };
 }
 
-auto Validate::addCallIndirect(const Signature* signature, const Vector<ExpressionType>& args, ExpressionType& result) -> Result
+auto Validate::addCallIndirect(const Signature* signature, SignatureIndex signatureIndex, const Vector<ExpressionType>& args, ExpressionType& result) -> Result
 {
-    const auto argumentCount = signature->arguments.size();
+    UNUSED_PARAM(signatureIndex);
+    ASSERT(signatureIndex != Signature::invalidIndex);
+    const auto argumentCount = signature->argumentCount();
     WASM_VALIDATOR_FAIL_IF(argumentCount != args.size() - 1, "arity mismatch in call_indirect, got ", args.size() - 1, " arguments, expected ", argumentCount);
 
     for (unsigned i = 0; i < argumentCount; ++i)
-        WASM_VALIDATOR_FAIL_IF(args[i] != signature->arguments[i], "argument type mismatch in call_indirect, got ", args[i], ", expected ", signature->arguments[i]);
+        WASM_VALIDATOR_FAIL_IF(args[i] != signature->argument(i), "argument type mismatch in call_indirect, got ", args[i], ", expected ", signature->argument(i));
 
     WASM_VALIDATOR_FAIL_IF(args.last() != I32, "non-i32 call_indirect index ", args.last());
 
-    result = signature->returnType;
+    result = signature->returnType();
     return { };
 }
 
@@ -351,10 +353,10 @@ void Validate::dump(const Vector<ControlEntry>&, const ExpressionList&)
     // Think of this as penance for the sin of bad error messages.
 }
 
-Expected<void, String> validateFunction(const uint8_t* source, size_t length, const Signature* signature, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& module)
+Expected<void, String> validateFunction(VM* vm, const uint8_t* source, size_t length, const Signature* signature, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& module)
 {
-    Validate context(signature->returnType, module);
-    FunctionParser<Validate> validator(context, source, length, signature, functionIndexSpace, module);
+    Validate context(signature->returnType(), module);
+    FunctionParser<Validate> validator(vm, context, source, length, signature, functionIndexSpace, module);
     WASM_FAIL_IF_HELPER_FAILS(validator.parse());
     return { };
 }
index 1f00417..14821f2 100644 (file)
 #include "WasmFormat.h"
 #include <wtf/Expected.h>
 
-namespace JSC { namespace Wasm {
+namespace JSC {
 
-Expected<void, String> validateFunction(const uint8_t*, size_t, const Signature*, const ImmutableFunctionIndexSpace&, const ModuleInformation&);
+class VM;
+
+namespace Wasm {
+
+Expected<void, String> validateFunction(VM*, const uint8_t*, size_t, const Signature*, const ImmutableFunctionIndexSpace&, const ModuleInformation&);
 
 } } // namespace JSC::Wasm
 
index 180f570..e7c27e9 100644 (file)
@@ -41,7 +41,7 @@ namespace JSC {
 JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, Structure* structure, JSWebAssemblyModule* module, JSModuleNamespaceObject* moduleNamespaceObject)
 {
     // FIXME: These objects could be pretty big we should try to throw OOM here.
-    auto* instance = new (NotNull, allocateCell<JSWebAssemblyInstance>(vm.heap, allocationSize(module->moduleInformation().importFunctions.size()))) JSWebAssemblyInstance(vm, structure, module->moduleInformation().importFunctions.size());
+    auto* instance = new (NotNull, allocateCell<JSWebAssemblyInstance>(vm.heap, allocationSize(module->moduleInformation().importFunctionSignatureIndices.size()))) JSWebAssemblyInstance(vm, structure, module->moduleInformation().importFunctionSignatureIndices.size());
     instance->finishCreation(vm, module, moduleNamespaceObject);
     return instance;
 }
index cc1257b..2e11361 100644 (file)
@@ -50,7 +50,11 @@ public:
 
     const Wasm::ModuleInformation& moduleInformation() const { return *m_moduleInformation.get(); }
     SymbolTable* exportSymbolTable() const { return m_exportSymbolTable.get(); }
-    Wasm::Signature* signatureForFunctionIndexSpace(unsigned functionIndexSpace) const { ASSERT(functionIndexSpace < m_functionIndexSpace.size); return m_functionIndexSpace.buffer.get()[functionIndexSpace].signature; }
+    Wasm::SignatureIndex signatureForFunctionIndexSpace(unsigned functionIndexSpace) const
+    {
+        ASSERT(functionIndexSpace < m_functionIndexSpace.size);
+        return m_functionIndexSpace.buffer.get()[functionIndexSpace].signatureIndex;
+    }
     unsigned importCount() const { return m_wasmToJSStubs.size(); }
 
     JSWebAssemblyCallee* jsEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
index 684b144..4c29de0 100644 (file)
@@ -67,7 +67,7 @@ JSWebAssemblyTable::JSWebAssemblyTable(VM& vm, Structure* structure, uint32_t in
     m_jsFunctions = MallocPtr<WriteBarrier<WebAssemblyFunction>>::malloc(sizeof(WriteBarrier<WebAssemblyFunction>) * static_cast<size_t>(m_size));
     for (uint32_t i = 0; i < m_size; ++i) {
         new (&m_functions.get()[i]) Wasm::CallableFunction();
-        ASSERT(!m_functions.get()[i].signature); // We rely on this in compiled code.
+        ASSERT(m_functions.get()[i].signatureIndex == Wasm::Signature::invalidIndex); // We rely on this in compiled code.
         new (&m_jsFunctions.get()[i]) WriteBarrier<WebAssemblyFunction>();
     }
 }
@@ -121,14 +121,14 @@ void JSWebAssemblyTable::clearFunction(uint32_t index)
     RELEASE_ASSERT(index < m_size);
     m_jsFunctions.get()[index] = WriteBarrier<WebAssemblyFunction>();
     m_functions.get()[index] = Wasm::CallableFunction();
-    ASSERT(!m_functions.get()[index].signature); // We rely on this in compiled code.
+    ASSERT(m_functions.get()[index].signatureIndex == Wasm::Signature::invalidIndex); // We rely on this in compiled code.
 }
 
 void JSWebAssemblyTable::setFunction(VM& vm, uint32_t index, WebAssemblyFunction* function)
 {
     RELEASE_ASSERT(index < m_size);
     m_jsFunctions.get()[index].set(vm, this, function);
-    m_functions.get()[index] = Wasm::CallableFunction(function->signature(), function->wasmEntrypoint());
+    m_functions.get()[index] = Wasm::CallableFunction(function->signatureIndex(), function->wasmEntrypoint());
 }
 
 } // namespace JSC
index 677c01a..0fa2ef7 100644 (file)
@@ -52,17 +52,18 @@ static EncodedJSValue JSC_HOST_CALL callWebAssemblyFunction(ExecState* exec)
     WebAssemblyFunction* wasmFunction = jsDynamicCast<WebAssemblyFunction*>(exec->jsCallee());
     if (!wasmFunction)
         return JSValue::encode(throwException(exec, scope, createTypeError(exec, "expected a WebAssembly function", defaultSourceAppender, runtimeTypeForValue(exec->jsCallee()))));
-    const Wasm::Signature* signature = wasmFunction->signature();
+    Wasm::SignatureIndex signatureIndex = wasmFunction->signatureIndex();
+    const Wasm::Signature* signature = Wasm::SignatureInformation::get(&vm, signatureIndex);
 
     // FIXME is this the right behavior? https://bugs.webkit.org/show_bug.cgi?id=164876
-    if (exec->argumentCount() != signature->arguments.size())
+    if (exec->argumentCount() != signature->argumentCount())
         return JSValue::encode(throwException(exec, scope, createNotEnoughArgumentsError(exec, defaultSourceAppender)));
 
     // FIXME is this boxing correct? https://bugs.webkit.org/show_bug.cgi?id=164876
     Vector<JSValue> boxedArgs;
     for (unsigned argIndex = 0; argIndex < exec->argumentCount(); ++argIndex) {
         JSValue arg = exec->uncheckedArgument(argIndex);
-        switch (signature->arguments[argIndex]) {
+        switch (signature->argument(argIndex)) {
         case Wasm::I32:
             arg = JSValue::decode(arg.toInt32(exec));
             break;
@@ -121,7 +122,7 @@ EncodedJSValue WebAssemblyFunction::call(VM& vm, ProtoCallFrame* protoCallFrame)
     vm.topJSWebAssemblyInstance = prevJSWebAssemblyInstance;
 
     // FIXME is this correct? https://bugs.webkit.org/show_bug.cgi?id=164876
-    switch (signature()->returnType) {
+    switch (m_returnType) {
     case Wasm::Void:
         return JSValue::encode(jsUndefined());
     case Wasm::I32:
@@ -140,12 +141,12 @@ EncodedJSValue WebAssemblyFunction::call(VM& vm, ProtoCallFrame* protoCallFrame)
     return EncodedJSValue();
 }
 
-WebAssemblyFunction* WebAssemblyFunction::create(VM& vm, JSGlobalObject* globalObject, unsigned length, const String& name, JSWebAssemblyInstance* instance, JSWebAssemblyCallee* jsEntrypoint, JSWebAssemblyCallee* wasmEntrypoint, Wasm::Signature* signature)
+WebAssemblyFunction* WebAssemblyFunction::create(VM& vm, JSGlobalObject* globalObject, unsigned length, const String& name, JSWebAssemblyInstance* instance, JSWebAssemblyCallee* jsEntrypoint, JSWebAssemblyCallee* wasmEntrypoint, Wasm::SignatureIndex signatureIndex)
 {
     NativeExecutable* executable = vm.getHostFunction(callWebAssemblyFunction, NoIntrinsic, callHostFunctionAsConstructor, nullptr, name);
     Structure* structure = globalObject->webAssemblyFunctionStructure();
-    WebAssemblyFunction* function = new (NotNull, allocateCell<WebAssemblyFunction>(vm.heap)) WebAssemblyFunction(vm, globalObject, structure);
-    function->finishCreation(vm, executable, length, name, instance, jsEntrypoint, wasmEntrypoint, signature);
+    WebAssemblyFunction* function = new (NotNull, allocateCell<WebAssemblyFunction>(vm.heap)) WebAssemblyFunction(vm, globalObject, structure, signatureIndex);
+    function->finishCreation(vm, executable, length, name, instance, jsEntrypoint, wasmEntrypoint);
     return function;
 }
 
@@ -155,9 +156,13 @@ Structure* WebAssemblyFunction::createStructure(VM& vm, JSGlobalObject* globalOb
     return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
 }
 
-WebAssemblyFunction::WebAssemblyFunction(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+WebAssemblyFunction::WebAssemblyFunction(VM& vm, JSGlobalObject* globalObject, Structure* structure, Wasm::SignatureIndex signatureIndex)
     : Base(vm, globalObject, structure)
+    , m_signatureIndex(signatureIndex)
 {
+    // Don't cache the signature pointer: it's a global on VM and can change as new WebAssembly.Module are created.
+    const Wasm::Signature* signature = Wasm::SignatureInformation::get(&vm, m_signatureIndex);
+    m_returnType = signature->returnType();
 }
 
 void WebAssemblyFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
@@ -170,7 +175,7 @@ void WebAssemblyFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(thisObject->m_wasmEntrypoint);
 }
 
-void WebAssemblyFunction::finishCreation(VM& vm, NativeExecutable* executable, unsigned length, const String& name, JSWebAssemblyInstance* instance, JSWebAssemblyCallee* jsEntrypoint, JSWebAssemblyCallee* wasmEntrypoint, Wasm::Signature* signature)
+void WebAssemblyFunction::finishCreation(VM& vm, NativeExecutable* executable, unsigned length, const String& name, JSWebAssemblyInstance* instance, JSWebAssemblyCallee* jsEntrypoint, JSWebAssemblyCallee* wasmEntrypoint)
 {
     Base::finishCreation(vm, executable, length, name);
     ASSERT(inherits(info()));
@@ -178,7 +183,6 @@ void WebAssemblyFunction::finishCreation(VM& vm, NativeExecutable* executable, u
     ASSERT(jsEntrypoint != wasmEntrypoint);
     m_jsEntrypoint.set(vm, this, jsEntrypoint);
     m_wasmEntrypoint.set(vm, this, wasmEntrypoint);
-    m_signature = signature;
 }
 
 } // namespace JSC
index 70d1a65..2805753 100644 (file)
@@ -41,10 +41,6 @@ namespace B3 {
 class Compilation;
 }
 
-namespace Wasm {
-struct Signature;
-}
-
 class WebAssemblyFunction : public JSFunction {
 public:
     typedef JSFunction Base;
@@ -53,30 +49,27 @@ public:
 
     DECLARE_EXPORT_INFO;
 
-    JS_EXPORT_PRIVATE static WebAssemblyFunction* create(VM&, JSGlobalObject*, unsigned, const String&, JSWebAssemblyInstance*, JSWebAssemblyCallee* jsEntrypoint, JSWebAssemblyCallee* wasmEntrypoint, Wasm::Signature*);
+    JS_EXPORT_PRIVATE static WebAssemblyFunction* create(VM&, JSGlobalObject*, unsigned, const String&, JSWebAssemblyInstance*, JSWebAssemblyCallee* jsEntrypoint, JSWebAssemblyCallee* wasmEntrypoint, Wasm::SignatureIndex);
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
 
     JSWebAssemblyInstance* instance() const { return m_instance.get(); }
-    Wasm::Signature* signature()
-    { 
-        ASSERT(m_signature);
-        return m_signature;
-    }
+    Wasm::SignatureIndex signatureIndex() const { return m_signatureIndex; }
     EncodedJSValue call(VM&, ProtoCallFrame*);
     void* wasmEntrypoint() { return m_wasmEntrypoint->entrypoint(); }
 
 protected:
     static void visitChildren(JSCell*, SlotVisitor&);
 
-    void finishCreation(VM&, NativeExecutable*, unsigned length, const String& name, JSWebAssemblyInstance*, JSWebAssemblyCallee* jsEntrypoint, JSWebAssemblyCallee* wasmEntrypoint, Wasm::Signature*);
+    void finishCreation(VM&, NativeExecutable*, unsigned length, const String& name, JSWebAssemblyInstance*, JSWebAssemblyCallee* jsEntrypoint, JSWebAssemblyCallee* wasmEntrypoint);
 
 private:
-    WebAssemblyFunction(VM&, JSGlobalObject*, Structure*);
+    WebAssemblyFunction(VM&, JSGlobalObject*, Structure*, Wasm::SignatureIndex);
 
     WriteBarrier<JSWebAssemblyInstance> m_instance;
     WriteBarrier<JSWebAssemblyCallee> m_jsEntrypoint;
     WriteBarrier<JSWebAssemblyCallee> m_wasmEntrypoint;
-    Wasm::Signature* m_signature;
+    Wasm::SignatureIndex m_signatureIndex;
+    Wasm::Type m_returnType;
 };
 
 } // namespace JSC
index 6b599aa..97f8d98 100644 (file)
@@ -36,6 +36,7 @@
 #include "JSWebAssemblyModule.h"
 #include "ProtoCallFrame.h"
 #include "WasmFormat.h"
+#include "WasmSignature.h"
 #include "WebAssemblyFunction.h"
 #include <limits>
 
@@ -119,8 +120,9 @@ void WebAssemblyModuleRecord::link(ExecState* state, JSWebAssemblyInstance* inst
             //     c. Return func.
             JSWebAssemblyCallee* jsEntrypointCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(exp.kindIndex);
             JSWebAssemblyCallee* wasmEntrypointCallee = module->wasmEntrypointCalleeFromFunctionIndexSpace(exp.kindIndex);
-            Wasm::Signature* signature = module->signatureForFunctionIndexSpace(exp.kindIndex);
-            WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->arguments.size(), exp.field.string(), instance, jsEntrypointCallee, wasmEntrypointCallee, signature);
+            Wasm::SignatureIndex signatureIndex = module->signatureForFunctionIndexSpace(exp.kindIndex);
+            const Wasm::Signature* signature = Wasm::SignatureInformation::get(&vm, signatureIndex);
+            WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->argumentCount(), exp.field.string(), instance, jsEntrypointCallee, wasmEntrypointCallee, signatureIndex);
             exportedValue = function;
             if (hasStart && startFunctionIndexSpace == exp.kindIndex)
                 m_startFunction.set(vm, this, function);
@@ -175,16 +177,17 @@ void WebAssemblyModuleRecord::link(ExecState* state, JSWebAssemblyInstance* inst
     }
 
     if (hasStart) {
-        Wasm::Signature* signature = module->signatureForFunctionIndexSpace(startFunctionIndexSpace);
+        Wasm::SignatureIndex signatureIndex = module->signatureForFunctionIndexSpace(startFunctionIndexSpace);
+        const Wasm::Signature* signature = Wasm::SignatureInformation::get(&vm, signatureIndex);
         // The start function must not take any arguments or return anything. This is enforced by the parser.
-        ASSERT(!signature->arguments.size());
-        ASSERT(signature->returnType == Wasm::Void);
+        ASSERT(!signature->argumentCount());
+        ASSERT(signature->returnType() == Wasm::Void);
         // FIXME can start call imports / tables? This assumes not. https://github.com/WebAssembly/design/issues/896
         if (!m_startFunction.get()) {
             // The start function wasn't added above. It must be a purely internal function.
             JSWebAssemblyCallee* jsEntrypointCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
             JSWebAssemblyCallee* wasmEntrypointCallee = module->wasmEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
-            WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->arguments.size(), "start", instance, jsEntrypointCallee, wasmEntrypointCallee, signature);
+            WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->argumentCount(), "start", instance, jsEntrypointCallee, wasmEntrypointCallee, signatureIndex);
             m_startFunction.set(vm, this, function);
         }
     }
@@ -236,13 +239,14 @@ JSValue WebAssemblyModuleRecord::evaluate(ExecState* state)
 
                 JSWebAssemblyCallee* jsEntrypointCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(functionIndex);
                 JSWebAssemblyCallee* wasmEntrypointCallee = module->wasmEntrypointCalleeFromFunctionIndexSpace(functionIndex);
-                Wasm::Signature* signature = module->signatureForFunctionIndexSpace(functionIndex);
+                Wasm::SignatureIndex signatureIndex = module->signatureForFunctionIndexSpace(functionIndex);
+                const Wasm::Signature* signature = Wasm::SignatureInformation::get(&vm, signatureIndex);
                 // FIXME: Say we export local function "foo" at funciton index 0.
                 // What if we also set it to the table an Element w/ index 0.
                 // Does (new Instance(...)).exports.foo === table.get(0)?
                 // https://bugs.webkit.org/show_bug.cgi?id=165825
                 WebAssemblyFunction* function = WebAssemblyFunction::create(
-                    vm, m_instance->globalObject(), signature->arguments.size(), String(), m_instance.get(), jsEntrypointCallee, wasmEntrypointCallee, signature);
+                    vm, m_instance->globalObject(), signature->argumentCount(), String(), m_instance.get(), jsEntrypointCallee, wasmEntrypointCallee, signatureIndex);
 
                 table->setFunction(vm, tableIndex, function);
                 ++tableIndex;