Title: [210419] branches/safari-603-branch
Revision
210419
Author
matthew_han...@apple.com
Date
2017-01-05 17:49:20 -0800 (Thu, 05 Jan 2017)

Log Message

Merge r210201. rdar://problem/29803676

Modified Paths

Added Paths

Diff

Modified: branches/safari-603-branch/JSTests/ChangeLog (210418 => 210419)


--- branches/safari-603-branch/JSTests/ChangeLog	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/JSTests/ChangeLog	2017-01-06 01:49:20 UTC (rev 210419)
@@ -1,5 +1,55 @@
 2017-01-05  Matthew Hanson  <matthew_han...@apple.com>
 
+        Merge r210201. rdar://problem/29803676
+
+    2016-12-28  Saam Barati  <sbar...@apple.com>
+
+            WebAssembly: Implement grow_memory and current_memory
+            https://bugs.webkit.org/show_bug.cgi?id=166448
+            <rdar://problem/29803676>
+
+            Reviewed by Keith Miller.
+
+            I rewrote some of the testWasmModuleFunctions that used Memory to use
+            the JS API since the jsc.cpp version can no longer use memory.
+
+            * wasm.yaml:
+            * wasm/function-tests/add-12.js:
+            (testWasmModuleFunctions):
+            * wasm/function-tests/br-if-loop-less-than.js:
+            (testWasmModuleFunctions):
+            * wasm/function-tests/brTableAsIf.js:
+            (testWasmModuleFunctions):
+            * wasm/function-tests/brTableManyValues.js:
+            (testWasmModuleFunctions):
+            * wasm/function-tests/brTableWithLoop.js:
+            (testWasmModuleFunctions):
+            * wasm/function-tests/dumb-eq-if-then-else.js:
+            * wasm/function-tests/eqz.js:
+            * wasm/function-tests/grow-memory-2.js: Added.
+            (const.func):
+            (assert.eq.instance.exports.foo):
+            * wasm/function-tests/grow-memory-3.js: Added.
+            * wasm/function-tests/grow-memory-4.js: Added.
+            (const.func):
+            * wasm/function-tests/grow-memory.js: Added.
+            (binaryShouldNotParse):
+            (assert.truthy):
+            (assert.eq):
+            (memory.grow):
+            * wasm/function-tests/i32-load.js:
+            (testWasmModuleFunctions):
+            * wasm/function-tests/i32-load8-s.js:
+            * wasm/function-tests/max.js:
+            * wasm/function-tests/min.js:
+            * wasm/js-api/memory-grow.js: Added.
+            (i.i):
+            (assertEq):
+            * wasm/js-api/test_memory.js:
+            * wasm/wasm.json:
+
+2017-01-05  Matthew Hanson  <matthew_han...@apple.com>
+
         Merge r210073. rdar://problem/29762017
 
     2016-12-21  JF Bastien  <jfbast...@apple.com>

Modified: branches/safari-603-branch/JSTests/wasm/function-tests/add-12.js (210418 => 210419)


--- branches/safari-603-branch/JSTests/wasm/function-tests/add-12.js	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/JSTests/wasm/function-tests/add-12.js	2017-01-06 01:49:20 UTC (rev 210419)
@@ -1,60 +1,72 @@
 import Builder from '../Builder.js'
+import * as assert from '../assert.js'
 
 const b = new Builder();
 b.Type().End()
     .Function().End()
+    .Export().Function("f0").Function("f1").End()
     .Code()
-    .Function({ params: ["i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32"], ret: "i32" }, [])
-    .GetLocal(0)
-    .GetLocal(1)
-    .I32Add()
-    .GetLocal(2)
-    .I32Add()
-    .GetLocal(3)
-    .I32Add()
-    .GetLocal(4)
-    .I32Add()
-    .GetLocal(5)
-    .I32Add()
-    .GetLocal(6)
-    .I32Add()
-    .GetLocal(7)
-    .I32Add()
-    .GetLocal(8)
-    .I32Add()
-    .GetLocal(9)
-    .I32Add()
-    .GetLocal(10)
-    .I32Add()
-    .GetLocal(11)
-    .I32Add()
-    .Return()
+        .Function("f0", { params: ["i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32"], ret: "i32" })
+            .GetLocal(0)
+            .GetLocal(1)
+            .I32Add()
+            .GetLocal(2)
+            .I32Add()
+            .GetLocal(3)
+            .I32Add()
+            .GetLocal(4)
+            .I32Add()
+            .GetLocal(5)
+            .I32Add()
+            .GetLocal(6)
+            .I32Add()
+            .GetLocal(7)
+            .I32Add()
+            .GetLocal(8)
+            .I32Add()
+            .GetLocal(9)
+            .I32Add()
+            .GetLocal(10)
+            .I32Add()
+            .GetLocal(11)
+            .I32Add()
+            .Return()
+        .End()
+        .Function("f1", { params: ["i32"], ret: "i32" })
+            .GetLocal(0)
+            .GetLocal(0)
+            .GetLocal(0)
+            .GetLocal(0)
+            .GetLocal(0)
+            .GetLocal(0)
+            .GetLocal(0)
+            .GetLocal(0)
+            .GetLocal(0)
+            .GetLocal(0)
+            .GetLocal(0)
+            .GetLocal(0)
+            .Call(0)
+            .Return()
+        .End()
     .End()
 
-    .Function({ params: ["i32"], ret: "i32" })
-    .GetLocal(0)
-    .GetLocal(0)
-    .GetLocal(0)
-    .GetLocal(0)
-    .GetLocal(0)
-    .GetLocal(0)
-    .GetLocal(0)
-    .GetLocal(0)
-    .GetLocal(0)
-    .GetLocal(0)
-    .GetLocal(0)
-    .GetLocal(0)
-    .Call(0)
-    .End()
+const bin = b.WebAssembly().get();
+const instance = new WebAssembly.Instance(new WebAssembly.Module(bin));
+function testWasmModuleFunctions(...tests) {
+    for (let i = 0; i < tests.length; i++) {
+        const func = instance.exports['f' + i];
+        for (let test of tests[i]) {
+            let result = test[0].value;
+            let args = test[1].map(x => x.value);
+            assert.eq(result, func(...args));
+        }
+    }
+}
 
-const bin = b.WebAssembly()
-bin.trim();
-testWasmModuleFunctions(bin.get(), 2,
-                        [[{ type: "i32", value: 78 }, [{ type: "i32", value: 1 }, { type: "i32", value: 2 }, { type: "i32", value: 3 }, { type: "i32", value: 4 }, { type: "i32", value: 5 }, { type: "i32", value: 6 }, { type: "i32", value: 7 }, { type: "i32", value: 8 }, { type: "i32", value: 9 }, { type: "i32", value: 10 }, { type: "i32", value: 11 }, { type: "i32", value: 12 }]],
+testWasmModuleFunctions([[{ type: "i32", value: 78 }, [{ type: "i32", value: 1 }, { type: "i32", value: 2 }, { type: "i32", value: 3 }, { type: "i32", value: 4 }, { type: "i32", value: 5 }, { type: "i32", value: 6 }, { type: "i32", value: 7 }, { type: "i32", value: 8 }, { type: "i32", value: 9 }, { type: "i32", value: 10 }, { type: "i32", value: 11 }, { type: "i32", value: 12 }]],
                          [{ type: "i32", value: 166 }, [{ type: "i32", value: 1 }, { type: "i32", value: 2 }, { type: "i32", value: 3 }, { type: "i32", value: 4 }, { type: "i32", value: 5 }, { type: "i32", value: 6 }, { type: "i32", value: 7 }, { type: "i32", value: 8 }, { type: "i32", value: 9 }, { type: "i32", value: 10 }, { type: "i32", value: 11 }, { type: "i32", value: 100 }]]
                         ],
                         [[{ type: "i32", value: 12 }, [{ type: "i32", value: 1 }]],
                          [{ type: "i32", value: 1200 }, [{ type: "i32", value: 100 }]],
                          [{ type: "i32", value: 0 }, [{ type: "i32", value: 0 }]],
-                        ]
-                       );
+                        ]);

Modified: branches/safari-603-branch/JSTests/wasm/function-tests/br-if-loop-less-than.js (210418 => 210419)


--- branches/safari-603-branch/JSTests/wasm/function-tests/br-if-loop-less-than.js	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/JSTests/wasm/function-tests/br-if-loop-less-than.js	2017-01-06 01:49:20 UTC (rev 210419)
@@ -1,10 +1,12 @@
 import Builder from '../Builder.js'
+import * as assert from '../assert.js'
 
 const b = new Builder();
 b.Type().End()
     .Function().End()
+    .Export().Function("f0").End()
     .Code()
-    .Function({ params: ["i32", "i32"], ret: "i32" }, [])
+    .Function("f0", { params: ["i32", "i32"], ret: "i32" })
     .Loop("void")
     .Block("void", b =>
            b.Block("void", b =>
@@ -36,10 +38,23 @@
     .End()
     .Unreachable()
     .End()
+    .End()
 
-const bin = b.WebAssembly()
-bin.trim();
-testWasmModuleFunctions(bin.get(), 1, [[{type: "i32", value: 1 }, [{ type: "i32", value: 0 }, { type: "i32", value: 1 }]],
+const bin = b.WebAssembly().get();
+const instance = new WebAssembly.Instance(new WebAssembly.Module(bin));
+
+function testWasmModuleFunctions(...tests) {
+    for (let i = 0; i < tests.length; i++) {
+        const func = instance.exports['f' + i];
+        for (let test of tests[i]) {
+            let result = test[0].value;
+            let args = test[1].map(x => x.value);
+            assert.eq(result, func(...args));
+        }
+    }
+}
+
+testWasmModuleFunctions([[{type: "i32", value: 1 }, [{ type: "i32", value: 0 }, { type: "i32", value: 1 }]],
                                        [{type: "i32", value: 0 }, [{ type: "i32", value: 1 }, { type: "i32", value: 0 }]],
                                        [{type: "i32", value: 0 }, [{ type: "i32", value: 2 }, { type: "i32", value: 1 }]],
                                        [{type: "i32", value: 1 }, [{ type: "i32", value: 1 }, { type: "i32", value: 2 }]],

Modified: branches/safari-603-branch/JSTests/wasm/function-tests/brTableAsIf.js (210418 => 210419)


--- branches/safari-603-branch/JSTests/wasm/function-tests/brTableAsIf.js	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/JSTests/wasm/function-tests/brTableAsIf.js	2017-01-06 01:49:20 UTC (rev 210419)
@@ -1,24 +1,37 @@
 import Builder from '../Builder.js'
+import * as assert from '../assert.js'
 
 const b = new Builder();
 b.Type().End()
     .Function().End()
+    .Export().Function('f0').End()
     .Code()
-    .Function({ params: ["i32"], ret: "i32" }, ["i32"])
-    .Block("void", (b) =>
-           b.Block("void", (b) =>
-                   b.GetLocal(0)
-                   .BrTable(1, 0)
-                   .I32Const(21)
-                   .Return()
-                  ).I32Const(20)
-           .Return()
-          ).I32Const(22)
+        .Function('f0', { params: ["i32"], ret: "i32" }, ["i32"])
+        .Block("void", (b) =>
+               b.Block("void", (b) =>
+                       b.GetLocal(0)
+                       .BrTable(1, 0)
+                       .I32Const(21)
+                       .Return()
+                      ).I32Const(20)
+               .Return()
+              ).I32Const(22)
+        .End()
     .End()
 
-const bin = b.WebAssembly()
-bin.trim();
-testWasmModuleFunctions(bin.get(), 1, [[{type: "i32", value: 22 }, [{ type: "i32", value: 0 }]],
+const bin = b.WebAssembly().get();
+const instance = new WebAssembly.Instance(new WebAssembly.Module(bin));
+function testWasmModuleFunctions(...tests) {
+    for (let i = 0; i < tests.length; i++) {
+        const func = instance.exports['f' + i];
+        for (let test of tests[i]) {
+            let result = test[0].value;
+            let args = test[1].map(x => x.value);
+            assert.eq(result, func(...args));
+        }
+    }
+}
+testWasmModuleFunctions([[{type: "i32", value: 22 }, [{ type: "i32", value: 0 }]],
                                        [{type: "i32", value: 20 }, [{ type: "i32", value: 1 }]],
                                        [{type: "i32", value: 20 }, [{ type: "i32", value: 11 }]],
                                        [{type: "i32", value: 20 }, [{ type: "i32", value: -100 }]]

Modified: branches/safari-603-branch/JSTests/wasm/function-tests/brTableManyValues.js (210418 => 210419)


--- branches/safari-603-branch/JSTests/wasm/function-tests/brTableManyValues.js	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/JSTests/wasm/function-tests/brTableManyValues.js	2017-01-06 01:49:20 UTC (rev 210419)
@@ -1,10 +1,12 @@
 import Builder from '../Builder.js'
+import * as assert from '../assert.js'
 
 const b = new Builder();
 b.Type().End()
     .Function().End()
+    .Export().Function('f0').End()
     .Code()
-    .Function({ params: ["i32"], ret: "i32" }, ["i32"])
+    .Function('f0', { params: ["i32"], ret: "i32" }, ["i32"])
     .Block("i32", (b) =>
            b.Block("i32", (b) =>
                    b.Block("i32", (b) =>
@@ -29,9 +31,21 @@
     .I32Add()
     .Return()
     .End()
-const bin = b.WebAssembly()
-bin.trim();
-testWasmModuleFunctions(bin.get(), 1, [[{type: "i32", value: 213 }, [{ type: "i32", value: 0 }]],
+    .End()
+
+const bin = b.WebAssembly().get();
+const instance = new WebAssembly.Instance(new WebAssembly.Module(bin));
+function testWasmModuleFunctions(...tests) {
+    for (let i = 0; i < tests.length; i++) {
+        const func = instance.exports['f' + i];
+        for (let test of tests[i]) {
+            let result = test[0].value;
+            let args = test[1].map(x => x.value);
+            assert.eq(result, func(...args));
+        }
+    }
+}
+testWasmModuleFunctions([[{type: "i32", value: 213 }, [{ type: "i32", value: 0 }]],
                                        [{type: "i32", value: 212 }, [{ type: "i32", value: 1 }]],
                                        [{type: "i32", value: 211 }, [{ type: "i32", value: 2 }]],
                                        [{type: "i32", value: 210 }, [{ type: "i32", value: 3 }]],

Modified: branches/safari-603-branch/JSTests/wasm/function-tests/brTableWithLoop.js (210418 => 210419)


--- branches/safari-603-branch/JSTests/wasm/function-tests/brTableWithLoop.js	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/JSTests/wasm/function-tests/brTableWithLoop.js	2017-01-06 01:49:20 UTC (rev 210419)
@@ -1,10 +1,12 @@
 import Builder from '../Builder.js'
+import * as assert from '../assert.js'
 
 const b = new Builder();
 b.Type().End()
     .Function().End()
+    .Export().Function('f0').End()
     .Code()
-    .Function({ params: ["i32"], ret: "i32" }, ["i32"])
+    .Function('f0', { params: ["i32"], ret: "i32" }, ["i32"])
     .Loop("void")
     .Block("void", (b) =>
 
@@ -18,12 +20,23 @@
            .I32Sub()
            .SetLocal(0)
            .BrTable(0, 1))
-
     .End()
     .GetLocal(1)
     .End()
-const bin = b.WebAssembly()
-bin.trim();
-testWasmModuleFunctions(bin.get(), 1, [[{type: "i32", value: 1 }, [{ type: "i32", value: 0 }]],
+    .End()
+
+const bin = b.WebAssembly().get();
+const instance = new WebAssembly.Instance(new WebAssembly.Module(bin));
+function testWasmModuleFunctions(...tests) {
+    for (let i = 0; i < tests.length; i++) {
+        const func = instance.exports['f' + i];
+        for (let test of tests[i]) {
+            let result = test[0].value;
+            let args = test[1].map(x => x.value);
+            assert.eq(result, func(...args));
+        }
+    }
+}
+testWasmModuleFunctions([[{type: "i32", value: 1 }, [{ type: "i32", value: 0 }]],
                                        [{type: "i32", value: 2 }, [{ type: "i32", value: 1 }]]
                                       ]);

Modified: branches/safari-603-branch/JSTests/wasm/function-tests/dumb-eq-if-then-else.js (210418 => 210419)


--- branches/safari-603-branch/JSTests/wasm/function-tests/dumb-eq-if-then-else.js	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/JSTests/wasm/function-tests/dumb-eq-if-then-else.js	2017-01-06 01:49:20 UTC (rev 210419)
@@ -3,7 +3,6 @@
 const b = new Builder();
 b.Type().End()
     .Function().End()
-    .Memory().InitialMaxPages(1, 1).End()
     .Code()
     .Function({ params: ["i32", "i32"], ret: "i32" }, [])
     .GetLocal(0)

Modified: branches/safari-603-branch/JSTests/wasm/function-tests/eqz.js (210418 => 210419)


--- branches/safari-603-branch/JSTests/wasm/function-tests/eqz.js	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/JSTests/wasm/function-tests/eqz.js	2017-01-06 01:49:20 UTC (rev 210419)
@@ -3,7 +3,6 @@
 const b = new Builder();
 b.Type().End()
     .Function().End()
-    .Memory().InitialMaxPages(1, 1).End()
     .Code()
     .Function({ params: ["i32"], ret: "i32" }, [])
     .GetLocal(0)

Added: branches/safari-603-branch/JSTests/wasm/function-tests/grow-memory-2.js (0 => 210419)


--- branches/safari-603-branch/JSTests/wasm/function-tests/grow-memory-2.js	                        (rev 0)
+++ branches/safari-603-branch/JSTests/wasm/function-tests/grow-memory-2.js	2017-01-06 01:49:20 UTC (rev 210419)
@@ -0,0 +1,82 @@
+import Builder from '../Builder.js';
+import * as assert from '../assert.js';
+
+{
+    const memoryDescription = {initial: 0, maximum: 2};
+    const builder = (new Builder())
+        .Type().End()
+        .Import()
+            .Memory("imp", "memory", memoryDescription)
+            .Function("imp", "func", {params: [], ret: "void"})
+        .End()
+        .Function().End()
+        .Export()
+            .Function("foo")
+        .End()
+        .Code()
+            .Function("foo", {params: ["i32"], ret: "i32"})
+                .Call(0)
+                .GetLocal(0)
+                .I32Load(0, 0)
+                .Return()
+            .End()
+        .End();
+
+    const bin = builder.WebAssembly().get();
+    const module = new WebAssembly.Module(bin);
+    const memory = new WebAssembly.Memory(memoryDescription);
+
+    const func = () => {
+        memory.grow(1);
+        (new Uint32Array(memory.buffer))[0] = 42;
+    };
+
+    const instance = new WebAssembly.Instance(module, {imp: {memory, func}});
+    assert.eq(instance.exports.foo(0), 42);
+}
+
+{
+    const memoryDescription = {initial: 0, maximum: 2};
+    const tableDescription = {initial: 1, maximum: 1, element: "anyfunc"};
+    const builder = (new Builder())
+        .Type()
+            .Func([], "void")
+        .End()
+        .Import()
+            .Memory("imp", "memory", memoryDescription)
+            .Function("imp", "func", {params: [], ret: "void"})
+            .Table("imp", "table", tableDescription)
+        .End()
+        .Function().End()
+        .Export()
+            .Function("foo")
+            .Function("bar")
+        .End()
+        .Code()
+            .Function("foo", {params: ["i32"], ret: "i32"})
+                .I32Const(0)
+                .CallIndirect(0, 0) // call [] => void
+                .GetLocal(0)
+                .I32Load(0, 0)
+                .Return()
+            .End()
+            .Function("bar", {params: [], ret: "void"})
+                .Call(0)
+                .Return()
+            .End()
+        .End();
+
+    const bin = builder.WebAssembly().get();
+    const module = new WebAssembly.Module(bin);
+    const memory = new WebAssembly.Memory(memoryDescription);
+    const table = new WebAssembly.Table(tableDescription);
+
+    const func = () => {
+        memory.grow(1);
+        (new Uint32Array(memory.buffer))[0] = 0xbadbeef;
+    };
+
+    const instance = new WebAssembly.Instance(module, {imp: {memory, func, table}});
+    table.set(0, instance.exports.bar);
+    assert.eq(instance.exports.foo(0), 0xbadbeef);
+}

Added: branches/safari-603-branch/JSTests/wasm/function-tests/grow-memory-3.js (0 => 210419)


--- branches/safari-603-branch/JSTests/wasm/function-tests/grow-memory-3.js	                        (rev 0)
+++ branches/safari-603-branch/JSTests/wasm/function-tests/grow-memory-3.js	2017-01-06 01:49:20 UTC (rev 210419)
@@ -0,0 +1,34 @@
+import Builder from '../Builder.js';
+import * as assert from '../assert.js';
+
+{
+    const memoryDescription = {initial: 0, maximum: 2};
+    const builder = (new Builder())
+        .Type().End()
+        .Import()
+            .Memory("imp", "memory", memoryDescription)
+        .End()
+        .Function().End()
+        .Export()
+            .Function("foo")
+            .Function("bar")
+        .End()
+        .Code()
+            .Function("foo", {params: [], ret: "void"})
+                .Unreachable()
+                .GrowMemory(0)
+            .End()
+            .Function("bar", {params: [], ret: "void"})
+                .Unreachable()
+                .CurrentMemory(0)
+            .End()
+        .End();
+
+    const bin = builder.WebAssembly().get();
+    const module = new WebAssembly.Module(bin); // Just make sure it parses.
+    const memory = new WebAssembly.Memory(memoryDescription);
+    const instance = new WebAssembly.Instance(module, {imp: {memory}});
+
+    assert.throws(() => instance.exports.foo(), WebAssembly.RuntimeError, "Unreachable code should not be executed")
+    assert.throws(() => instance.exports.bar(), WebAssembly.RuntimeError, "Unreachable code should not be executed")
+}

Added: branches/safari-603-branch/JSTests/wasm/function-tests/grow-memory-4.js (0 => 210419)


--- branches/safari-603-branch/JSTests/wasm/function-tests/grow-memory-4.js	                        (rev 0)
+++ branches/safari-603-branch/JSTests/wasm/function-tests/grow-memory-4.js	2017-01-06 01:49:20 UTC (rev 210419)
@@ -0,0 +1,34 @@
+import Builder from '../Builder.js';
+import * as assert from '../assert.js';
+
+{
+    const memoryDescription = {initial: 0, maximum: 50};
+    const builder = (new Builder())
+        .Type().End()
+        .Import()
+            .Memory("imp", "memory", memoryDescription)
+            .Function("imp", "func", {params: [], ret: "void"})
+        .End()
+        .Function().End()
+        .Export()
+            .Function("foo")
+        .End()
+        .Code()
+            .Function("foo", {params: [], ret: "i32"})
+                .Call(0)
+                .CurrentMemory(0)
+                .Return()
+            .End()
+        .End();
+
+    const bin = builder.WebAssembly().get();
+    const module = new WebAssembly.Module(bin);
+    const memory = new WebAssembly.Memory(memoryDescription);
+
+    const func = () => {
+        memory.grow(42);
+    };
+
+    const instance = new WebAssembly.Instance(module, {imp: {memory, func}});
+    assert.eq(instance.exports.foo(), 42);
+}

Added: branches/safari-603-branch/JSTests/wasm/function-tests/grow-memory.js (0 => 210419)


--- branches/safari-603-branch/JSTests/wasm/function-tests/grow-memory.js	                        (rev 0)
+++ branches/safari-603-branch/JSTests/wasm/function-tests/grow-memory.js	2017-01-06 01:49:20 UTC (rev 210419)
@@ -0,0 +1,207 @@
+import Builder from '../Builder.js';
+import * as assert from '../assert.js';
+
+const pageSize = 64 * 1024;
+const maxPageCount = (2**32) / pageSize;
+
+function binaryShouldNotParse(builder, msg = "") {
+    const bin = builder.WebAssembly().get();
+    let threw = false;
+    try {
+        const module = new WebAssembly.Module(bin);
+    } catch(e) {
+        assert.truthy(e instanceof WebAssembly.CompileError);
+        if (msg)
+            assert.truthy(e.message.indexOf(msg) !== -1);
+        threw = true;
+    }
+    assert.truthy(threw);
+}
+
+{
+    // Can't grow_memory if no memory is defined.
+    const builder = (new Builder())
+        .Type().End()
+        .Function().End()
+        .Export().End()
+        .Code()
+            .Function({ret: "void", params: []})
+                .I32Const(25)
+                .GrowMemory(0)
+                .Drop()
+            .End()
+        .End();
+
+    binaryShouldNotParse(builder, "grow_memory is only valid if a memory is defined or imported");
+}
+
+{
+    // Can't current_memory if no memory is defined.
+    const builder = (new Builder())
+        .Type().End()
+        .Function().End()
+        .Export().End()
+        .Code()
+            .Function({ret: "void", params: []})
+                .I32Const(25)
+                .CurrentMemory(0)
+                .Drop()
+            .End()
+        .End();
+
+    binaryShouldNotParse(builder, "current_memory is only valid if a memory is defined or imported");
+}
+
+{
+    const builder = (new Builder())
+        .Type().End()
+        .Function().End()
+        .Memory().InitialMaxPages(1, 1).End()
+        .Export().End()
+        .Code()
+            .Function({ret: "void", params: []})
+                .I32Const(25)
+                .GrowMemory(1)
+                .Drop()
+            .End()
+        .End();
+
+    binaryShouldNotParse(builder, "reserved varUint1 for grow_memory must be zero");
+}
+
+{
+    const builder = (new Builder())
+        .Type().End()
+        .Function().End()
+        .Memory().InitialMaxPages(1, 1).End()
+        .Export().End()
+        .Code()
+            .Function({ret: "void", params: []})
+                .I32Const(25)
+                .CurrentMemory(1)
+                .Drop()
+            .End()
+        .End();
+
+    binaryShouldNotParse(builder, "reserved varUint1 for current_memory must be zero");
+}
+
+{
+    const builder = (new Builder())
+        .Type().End()
+        .Function().End()
+        .Memory().InitialMaxPages(1, 1).End()
+        .Export().End()
+        .Code()
+            .Function({ret: "void", params: []})
+                .I32Const(25)
+                .CurrentMemory(0xffffff00)
+                .Drop()
+            .End()
+        .End();
+
+    binaryShouldNotParse(builder, "can't parse reserved varUint1 for current_memory");
+}
+
+{
+    const builder = (new Builder())
+        .Type().End()
+        .Function().End()
+        .Memory().InitialMaxPages(1, 1).End()
+        .Export().End()
+        .Code()
+            .Function({ret: "void", params: []})
+                .I32Const(25)
+                .GrowMemory(0xffffff00)
+                .Drop()
+            .End()
+        .End();
+
+    binaryShouldNotParse(builder, "can't parse reserved varUint1 for grow_memory");
+}
+
+{
+    const memoryDescription = {initial: 20, maximum: 50};
+    const builder = (new Builder())
+        .Type().End()
+        .Import().Memory("imp", "memory", memoryDescription).End()
+        .Function().End()
+        .Export()
+            .Function("foo")
+        .End()
+        .Code()
+            .Function("foo", { params: ["i32"], ret: "i32"})
+                .GetLocal(0)
+                .GrowMemory(0)
+                .Return()
+            .End()
+        .End();
+
+    const bin = builder.WebAssembly().get();
+    const module = new WebAssembly.Module(bin);
+    const instance = new WebAssembly.Instance(module, {imp: {memory: new WebAssembly.Memory(memoryDescription)}});
+    let currentPageSize = memoryDescription.initial;
+    for (let i = 0; i < memoryDescription.maximum - memoryDescription.initial; i++) {
+        assert.eq(instance.exports.foo(1), currentPageSize);
+        ++currentPageSize;
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        assert.eq(instance.exports.foo(1), -1);
+        assert.eq(instance.exports.foo(0), currentPageSize);
+    }
+}
+
+{
+    const memoryDescription = {initial: 20, maximum: 100};
+    const builder = (new Builder())
+        .Type().End()
+        .Import().Memory("imp", "memory", memoryDescription).End()
+        .Function().End()
+        .Export()
+            .Function("foo")
+        .End()
+        .Code()
+            .Function("foo", { params: [], ret: "i32"})
+                .CurrentMemory(0)
+                .Return()
+            .End()
+        .End();
+
+    const bin = builder.WebAssembly().get();
+    const module = new WebAssembly.Module(bin);
+    const memory = new WebAssembly.Memory(memoryDescription);
+    const instance = new WebAssembly.Instance(module, {imp: {memory}});
+    let currentPageSize = memoryDescription.initial;
+    for (let i = 0; i < memoryDescription.maximum - memoryDescription.initial; i++) {
+        assert.eq(instance.exports.foo(), currentPageSize);
+        ++currentPageSize;
+        memory.grow(1);
+    }
+}
+
+{
+    const memoryDescription = {initial: 20, maximum: 100};
+    const builder = (new Builder())
+        .Type().End()
+        .Import().Memory("imp", "memory", memoryDescription).End()
+        .Function().End()
+        .Export()
+            .Function("foo")
+        .End()
+        .Code()
+            .Function("foo", { params: [], ret: "i32"})
+                .I32Const(-1)
+                .GrowMemory(0)
+                .Return()
+            .End()
+        .End();
+
+    const bin = builder.WebAssembly().get();
+    const module = new WebAssembly.Module(bin);
+    const memory = new WebAssembly.Memory(memoryDescription);
+    const instance = new WebAssembly.Instance(module, {imp: {memory}});
+    for (let i = 0; i < 20; i++) {
+        assert.eq(instance.exports.foo(), -1);
+    }
+}

Modified: branches/safari-603-branch/JSTests/wasm/function-tests/i32-load.js (210418 => 210419)


--- branches/safari-603-branch/JSTests/wasm/function-tests/i32-load.js	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/JSTests/wasm/function-tests/i32-load.js	2017-01-06 01:49:20 UTC (rev 210419)
@@ -1,11 +1,13 @@
 import Builder from '../Builder.js'
+import * as assert from '../assert.js'
 
 const b = new Builder();
 b.Type().End()
     .Function().End()
     .Memory().InitialMaxPages(1, 1).End()
+    .Export().Function('f0').End()
     .Code()
-    .Function({ params: ["i32", "i32"], ret: "i32" }, [])
+    .Function('f0', { params: ["i32", "i32"], ret: "i32" })
     .GetLocal(1)
     .GetLocal(0)
     .I32Store(2, 0)
@@ -13,10 +15,21 @@
     .I32Load(2, 0)
     .Return()
     .End()
+    .End();
 
-const bin = b.WebAssembly()
-bin.trim();
-testWasmModuleFunctions(bin.get(), 1, [[{type: "i32", value: 0 }, [{ type: "i32", value: 0 }, { type: "i32", value: 10 }]],
+const bin = b.WebAssembly().get();
+const instance = new WebAssembly.Instance(new WebAssembly.Module(bin));
+function testWasmModuleFunctions(...tests) {
+    for (let i = 0; i < tests.length; i++) {
+        const func = instance.exports['f' + i];
+        for (let test of tests[i]) {
+            let result = test[0].value;
+            let args = test[1].map(x => x.value);
+            assert.eq(result, func(...args));
+        }
+    }
+}
+testWasmModuleFunctions([[{type: "i32", value: 0 }, [{ type: "i32", value: 0 }, { type: "i32", value: 10 }]],
                                        [{type: "i32", value: 100 }, [{ type: "i32", value: 100 }, { type: "i32", value: 112 }]],
                                        [{type: "i32", value: 1000000 }, [{ type: "i32", value: 1000000 }, { type: "i32", value: 10 }]]
                                       ]);

Modified: branches/safari-603-branch/JSTests/wasm/function-tests/i32-load8-s.js (210418 => 210419)


--- branches/safari-603-branch/JSTests/wasm/function-tests/i32-load8-s.js	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/JSTests/wasm/function-tests/i32-load8-s.js	2017-01-06 01:49:20 UTC (rev 210419)
@@ -1,22 +1,24 @@
 import Builder from '../Builder.js'
+import * as assert from '../assert.js'
 
 const b = new Builder();
 b.Type().End()
     .Function().End()
     .Memory().InitialMaxPages(1, 1).End()
+    .Export().Function("foo").End()
     .Code()
-    .Function({ params: ["i32", "i32"], ret: "i32" }, [])
-    .GetLocal(1)
-    .GetLocal(0)
-    .I32Store(2, 0)
-    .GetLocal(1)
-    .I32Load8S(2, 0)
-    .Return()
+        .Function("foo", { params: ["i32", "i32"], ret: "i32" })
+            .GetLocal(1)
+            .GetLocal(0)
+            .I32Store(2, 0)
+            .GetLocal(1)
+            .I32Load8S(2, 0)
+            .Return()
+        .End()
     .End()
 
-const bin = b.WebAssembly()
-bin.trim();
-testWasmModuleFunctions(bin.get(), 1, [[{type: "i32", value: 0 }, [{ type: "i32", value: 0 }, { type: "i32", value: 10 }]],
-                                       [{type: "i32", value: 100 }, [{ type: "i32", value: 100 }, { type: "i32", value: 112 }]],
-                                       [{type: "i32", value: 0x40 }, [{ type: "i32", value: 1000000 }, { type: "i32", value: 10 }]]
-                                      ]);
+const bin = b.WebAssembly().get();
+const foo = (new WebAssembly.Instance(new WebAssembly.Module(bin))).exports.foo;
+assert.eq(foo(0, 10), 0);
+assert.eq(foo(100, 112), 100);
+assert.eq(foo(1000000, 10), 0x40);

Modified: branches/safari-603-branch/JSTests/wasm/function-tests/max.js (210418 => 210419)


--- branches/safari-603-branch/JSTests/wasm/function-tests/max.js	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/JSTests/wasm/function-tests/max.js	2017-01-06 01:49:20 UTC (rev 210419)
@@ -3,7 +3,6 @@
 const b = new Builder();
 b.Type().End()
     .Function().End()
-    .Memory().InitialMaxPages(1, 1).End()
     .Code()
     .Function({ params: ["f32", "f32"], ret: "f32" }, [])
     .GetLocal(0)

Modified: branches/safari-603-branch/JSTests/wasm/function-tests/min.js (210418 => 210419)


--- branches/safari-603-branch/JSTests/wasm/function-tests/min.js	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/JSTests/wasm/function-tests/min.js	2017-01-06 01:49:20 UTC (rev 210419)
@@ -3,7 +3,6 @@
 const b = new Builder();
 b.Type().End()
     .Function().End()
-    .Memory().InitialMaxPages(1, 1).End()
     .Code()
     .Function({ params: ["f32", "f32"], ret: "f32" }, [])
     .GetLocal(0)

Added: branches/safari-603-branch/JSTests/wasm/js-api/memory-grow.js (0 => 210419)


--- branches/safari-603-branch/JSTests/wasm/js-api/memory-grow.js	                        (rev 0)
+++ branches/safari-603-branch/JSTests/wasm/js-api/memory-grow.js	2017-01-06 01:49:20 UTC (rev 210419)
@@ -0,0 +1,51 @@
+import { eq as assertEq, throws as assertThrows } from "../assert.js";
+const pageSize = 64*1024;
+
+let buffers = [];
+for (let i = 0; i < 100; i++) {
+    const max = 5;
+    let pageCount = 1;
+    let x = new WebAssembly.Memory({initial: 1, maximum: max});
+    for (let i = 0; i < (max - 1); i++) {
+        let int8Array = new Uint8Array(x.buffer);
+
+        for (let i = 0; i < pageSize; i++) {
+            assertEq(int8Array[pageSize*(pageCount - 1) + i], 0);
+            int8Array[pageSize*(pageCount - 1) + i] = pageCount;
+        }
+
+        for (let i = 0; i < pageCount; i++) {
+            for (let j = 0; j < pageSize; j++) {
+                assertEq(int8Array[i * pageSize + j], i + 1);
+            }
+        }
+
+        let buffer = x.buffer;
+        assertEq(buffer.byteLength, pageCount * pageSize);
+        buffers.push(buffer);
+        let previousPageSize = x.grow(1);
+        assertEq(buffer.byteLength, 0);
+        assertEq(previousPageSize, pageCount);
+        ++pageCount;
+    }
+}
+
+for (let buffer of buffers) {
+    assertEq(buffer.byteLength, 0);
+}
+
+{
+    const memory = new WebAssembly.Memory({initial: 1, maximum: 5});
+    let buffer = memory.buffer;
+    assertEq(buffer.byteLength, 1*64*1024);
+    memory.grow(1);
+    assertEq(buffer.byteLength, 0);
+
+    buffer = memory.buffer;
+    assertEq(buffer.byteLength, 2*64*1024);
+
+    // This shouldn't neuter the buffer since it fails.
+    assertThrows(() => memory.grow(1000), Error, "Out of memory"); 
+    assertEq(buffer.byteLength, 2*64*1024);
+    assertEq(memory.buffer, buffer);
+}

Modified: branches/safari-603-branch/JSTests/wasm/js-api/test_memory.js (210418 => 210419)


--- branches/safari-603-branch/JSTests/wasm/js-api/test_memory.js	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/JSTests/wasm/js-api/test_memory.js	2017-01-06 01:49:20 UTC (rev 210419)
@@ -1,4 +1,3 @@
-// FIXME: use the assert library: https://bugs.webkit.org/show_bug.cgi?id=165684
 import Builder from '../Builder.js';
 import * as assert from '../assert.js';
 

Modified: branches/safari-603-branch/JSTests/wasm/wasm.json (210418 => 210419)


--- branches/safari-603-branch/JSTests/wasm/wasm.json	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/JSTests/wasm/wasm.json	2017-01-06 01:49:20 UTC (rev 210419)
@@ -88,8 +88,8 @@
         "i64.store":           { "category": "memory",     "value":  55, "return": [],           "parameter": ["addr", "i64"],          "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset", "type": "varuint32"}], "description": "store to memory" },
         "f32.store":           { "category": "memory",     "value":  56, "return": [],           "parameter": ["addr", "f32"],          "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset", "type": "varuint32"}], "description": "store to memory" },
         "f64.store":           { "category": "memory",     "value":  57, "return": [],           "parameter": ["addr", "f64"],          "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset", "type": "varuint32"}], "description": "store to memory" },
-        "current_memory":      { "category": "operation",  "value":  63, "return": ["size"],     "parameter": [],                       "immediate": [],                                                                                         "description": "query the size of memory" },
-        "grow_memory":         { "category": "operation",  "value":  64, "return": ["size"],     "parameter": ["size"],                 "immediate": [],                                                                                         "description": "grow the size of memory" },
+        "current_memory":      { "category": "operation",  "value":  63, "return": ["size"],     "parameter": [],                       "immediate": [{"name": "flags", "type": "varuint32"}],                                                                                         "description": "query the size of memory" },
+        "grow_memory":         { "category": "operation",  "value":  64, "return": ["size"],     "parameter": ["size"],                 "immediate": [{"name": "flags", "type": "varuint32"}],                                                                                         "description": "grow the size of memory" },
         "i32.add":             { "category": "arithmetic", "value": 106, "return": ["i32"],      "parameter": ["i32", "i32"],           "immediate": [], "b3op": "Add"          },
         "i32.sub":             { "category": "arithmetic", "value": 107, "return": ["i32"],      "parameter": ["i32", "i32"],           "immediate": [], "b3op": "Sub"          },
         "i32.mul":             { "category": "arithmetic", "value": 108, "return": ["i32"],      "parameter": ["i32", "i32"],           "immediate": [], "b3op": "Mul"          },

Modified: branches/safari-603-branch/JSTests/wasm.yaml (210418 => 210419)


--- branches/safari-603-branch/JSTests/wasm.yaml	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/JSTests/wasm.yaml	2017-01-06 01:49:20 UTC (rev 210419)
@@ -145,7 +145,7 @@
   cmd: runWebAssemblySpecTest :normal
 
 - path: wasm/spec-tests/memory_trap.wast.js
-  cmd: runWebAssemblySpecTest :skip
+  cmd: runWebAssemblySpecTest :normal
 
 - path: wasm/spec-tests/names.wast.js
   cmd: runWebAssemblySpecTest :skip

Modified: branches/safari-603-branch/Source/_javascript_Core/ChangeLog (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/ChangeLog	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/ChangeLog	2017-01-06 01:49:20 UTC (rev 210419)
@@ -1,5 +1,103 @@
 2017-01-05  Matthew Hanson  <matthew_han...@apple.com>
 
+        Merge r210201. rdar://problem/29803676
+
+    2016-12-28  Saam Barati  <sbar...@apple.com>
+
+            WebAssembly: Implement grow_memory and current_memory
+            https://bugs.webkit.org/show_bug.cgi?id=166448
+            <rdar://problem/29803676>
+
+            Reviewed by Keith Miller.
+
+            This patch implements grow_memory, current_memory, and WebAssembly.prototype.grow.
+            See relevant spec texts here:
+
+            https://github.com/WebAssembly/design/blob/master/Semantics.md#linear-memory-accesses
+            https://github.com/WebAssembly/design/blob/master/JS.md#webassemblymemoryprototypegrow
+
+            I also fix a couple miscellaneous bugs:
+
+            1. Data section now understands full init_exprs.
+            2. parseVarUint1 no longer has a bug where we allow values larger than 1 if
+            their bottom 8 bits are zero.
+
+            Since the JS API can now grow memory, we need to make calling an import
+            and call_indirect refresh the base memory register and the size registers.
+
+            * jsc.cpp:
+            (functionTestWasmModuleFunctions):
+            * runtime/Options.h:
+            * runtime/VM.h:
+            * wasm/WasmB3IRGenerator.cpp:
+            (JSC::Wasm::B3IRGenerator::B3IRGenerator):
+            (JSC::Wasm::reloadPinnedRegisters):
+            (JSC::Wasm::B3IRGenerator::emitReloadPinnedRegisters):
+            (JSC::Wasm::createJSToWasmWrapper):
+            (JSC::Wasm::parseAndCompile):
+            * wasm/WasmFormat.cpp:
+            (JSC::Wasm::Segment::create):
+            * wasm/WasmFormat.h:
+            (JSC::Wasm::I32InitExpr::I32InitExpr):
+            (JSC::Wasm::I32InitExpr::globalImport):
+            (JSC::Wasm::I32InitExpr::constValue):
+            (JSC::Wasm::I32InitExpr::isConst):
+            (JSC::Wasm::I32InitExpr::isGlobalImport):
+            (JSC::Wasm::I32InitExpr::globalImportIndex):
+            (JSC::Wasm::Segment::byte):
+            (JSC::Wasm::ModuleInformation::importFunctionCount):
+            (JSC::Wasm::ModuleInformation::hasMemory):
+            * wasm/WasmFunctionParser.h:
+            * wasm/WasmMemory.cpp:
+            (JSC::Wasm::Memory::Memory):
+            (JSC::Wasm::Memory::grow):
+            * wasm/WasmMemory.h:
+            (JSC::Wasm::Memory::size):
+            (JSC::Wasm::Memory::sizeInPages):
+            (JSC::Wasm::Memory::offsetOfMemory):
+            (JSC::Wasm::Memory::isValid): Deleted.
+            (JSC::Wasm::Memory::grow): Deleted.
+            * wasm/WasmModuleParser.cpp:
+            (JSC::Wasm::makeI32InitExpr):
+            * wasm/WasmModuleParser.h:
+            * wasm/WasmPageCount.h:
+            (JSC::Wasm::PageCount::bytes):
+            (JSC::Wasm::PageCount::pageCount):
+            (JSC::Wasm::PageCount::fromBytes):
+            (JSC::Wasm::PageCount::operator+):
+            * wasm/WasmParser.h:
+            (JSC::Wasm::Parser<SuccessType>::parseVarUInt1):
+            * wasm/WasmValidate.cpp:
+            * wasm/js/JSWebAssemblyInstance.h:
+            (JSC::JSWebAssemblyInstance::offsetOfMemory):
+            * wasm/js/JSWebAssemblyMemory.cpp:
+            (JSC::JSWebAssemblyMemory::~JSWebAssemblyMemory):
+            (JSC::JSWebAssemblyMemory::grow):
+            * wasm/js/JSWebAssemblyMemory.h:
+            (JSC::JSWebAssemblyMemory::offsetOfMemory):
+            * wasm/js/JSWebAssemblyModule.h:
+            (JSC::JSWebAssemblyModule::functionImportCount):
+            (JSC::JSWebAssemblyModule::jsEntrypointCalleeFromFunctionIndexSpace):
+            (JSC::JSWebAssemblyModule::wasmEntrypointCalleeFromFunctionIndexSpace):
+            (JSC::JSWebAssemblyModule::importCount): Deleted.
+            * wasm/js/WebAssemblyFunction.cpp:
+            (JSC::callWebAssemblyFunction):
+            * wasm/js/WebAssemblyInstanceConstructor.cpp:
+            (JSC::constructJSWebAssemblyInstance):
+            * wasm/js/WebAssemblyMemoryConstructor.cpp:
+            (JSC::constructJSWebAssemblyMemory):
+            * wasm/js/WebAssemblyMemoryPrototype.cpp:
+            (JSC::getMemory):
+            (JSC::webAssemblyMemoryProtoFuncBuffer):
+            (JSC::webAssemblyMemoryProtoFuncGrow):
+            * wasm/js/WebAssemblyModuleRecord.cpp:
+            (JSC::WebAssemblyModuleRecord::link):
+            (JSC::dataSegmentFail):
+            (JSC::WebAssemblyModuleRecord::evaluate):
+            * wasm/wasm.json:
+
+2017-01-05  Matthew Hanson  <matthew_han...@apple.com>
+
         Merge r210073. rdar://problem/29762017
 
     2016-12-21  JF Bastien  <jfbast...@apple.com>

Modified: branches/safari-603-branch/Source/_javascript_Core/jsc.cpp (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/jsc.cpp	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/jsc.cpp	2017-01-06 01:49:20 UTC (rev 210419)
@@ -2639,8 +2639,9 @@
     std::unique_ptr<Wasm::ModuleInformation> moduleInformation = plan.takeModuleInformation();
 
     if (!!moduleInformation->memory) {
-        memory = std::make_unique<Wasm::Memory>(moduleInformation->memory.initial(), moduleInformation->memory.maximum());
-        RELEASE_ASSERT(memory->isValid());
+        bool failed;
+        memory = std::make_unique<Wasm::Memory>(moduleInformation->memory.initial(), moduleInformation->memory.maximum(), failed);
+        RELEASE_ASSERT(!failed);
         memoryBytes = memory->memory();
         memorySize = memory->size();
     }

Modified: branches/safari-603-branch/Source/_javascript_Core/runtime/Options.h (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/runtime/Options.h	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/runtime/Options.h	2017-01-06 01:49:20 UTC (rev 210419)
@@ -417,6 +417,7 @@
     v(bool, useCodeCache, true, Normal, "If false, the unlinked byte code cache will not be used.") \
     \
     v(bool, useWebAssembly, true, Normal, "Expose the WebAssembly global object.") \
+    v(bool, simulateWebAssemblyLowMemory, false, Normal, "If true, the Memory object won't mmap the full 'maximum' range and instead will allocate the minimum required amount.") \
 
 enum OptionEquivalence {
     SameOption,

Modified: branches/safari-603-branch/Source/_javascript_Core/runtime/VM.h (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/runtime/VM.h	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/runtime/VM.h	2017-01-06 01:49:20 UTC (rev 210419)
@@ -301,8 +301,6 @@
     // https://bugs.webkit.org/show_bug.cgi?id=160441
     ExecState* topCallFrame;
     JSWebAssemblyInstance* topJSWebAssemblyInstance;
-    void* topWasmMemoryPointer;
-    uint32_t topWasmMemorySize;
     Strong<Structure> structureStructure;
     Strong<Structure> structureRareDataStructure;
     Strong<Structure> terminatedExecutionErrorStructure;

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp	2017-01-06 01:49:20 UTC (rev 210419)
@@ -172,6 +172,8 @@
     // Memory
     PartialResult WARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset);
     PartialResult WARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);
+    PartialResult WARN_UNUSED_RETURN addGrowMemory(ExpressionType delta, ExpressionType& result);
+    PartialResult WARN_UNUSED_RETURN addCurrentMemory(ExpressionType& result);
 
     // Basic operators
     template<OpType>
@@ -203,6 +205,8 @@
 
     void emitExceptionCheck(CCallHelpers&, ExceptionType);
 
+    void emitReloadPinnedRegisters();
+
 private:
     ExpressionType emitCheckAndPreparePointer(ExpressionType pointer, uint32_t offset, uint32_t sizeOfOp);
     ExpressionType emitLoadOp(LoadOpType, Origin, ExpressionType pointer, uint32_t offset);
@@ -250,7 +254,7 @@
         }
     }
 
-    if (!!info.memory) {
+    if (info.hasMemory()) {
         m_memoryBaseGPR = info.memory.pinnedRegisters().baseMemoryPointer;
         m_proc.pinRegister(m_memoryBaseGPR);
         ASSERT(!info.memory.pinnedRegisters().sizeRegisters[0].sizeOffset);
@@ -334,6 +338,96 @@
     return { };
 }
 
+static void reloadPinnedRegisters(Procedure& proc, BasicBlock* block, const ModuleInformation& info, Value* instance)
+{
+    if (!info.hasMemory())
+        return;
+
+    const MemoryInformation* memory = &info.memory;
+
+    RegisterSet clobbers;
+    clobbers.set(memory->pinnedRegisters().baseMemoryPointer);
+    for (auto info : memory->pinnedRegisters().sizeRegisters)
+        clobbers.set(info.sizeRegister);
+
+    B3::PatchpointValue* patchpoint = block->appendNew<B3::PatchpointValue>(proc, B3::Void, Origin());
+    patchpoint->effects = Effects::none();
+    patchpoint->effects.writesPinned = true;
+    patchpoint->clobber(clobbers);
+    patchpoint->numGPScratchRegisters = 1;
+
+    patchpoint->append(instance, ValueRep::SomeRegister);
+
+    patchpoint->setGenerator([memory] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
+        AllowMacroScratchRegisterUsage allowScratch(jit);
+
+        GPRReg scratch = params.gpScratch(0);
+        jit.loadPtr(CCallHelpers::Address(params[0].gpr(), JSWebAssemblyInstance::offsetOfMemory()), scratch);
+        jit.loadPtr(CCallHelpers::Address(scratch, JSWebAssemblyMemory::offsetOfMemory()), scratch);
+        jit.loadPtr(CCallHelpers::Address(scratch, Memory::offsetOfMemory()), memory->pinnedRegisters().baseMemoryPointer);
+
+        jit.load64(CCallHelpers::Address(scratch, Memory::offsetOfSize()), scratch);
+        for (unsigned i = 0; i < memory->pinnedRegisters().sizeRegisters.size(); i++) {
+            GPRReg sizeReg = memory->pinnedRegisters().sizeRegisters[i].sizeRegister;
+            jit.move(scratch, sizeReg);
+            jit.sub64(CCallHelpers::TrustedImm32(memory->pinnedRegisters().sizeRegisters[i].sizeOffset), sizeReg);
+        }
+    });
+}
+
+void B3IRGenerator::emitReloadPinnedRegisters()
+{
+    reloadPinnedRegisters(m_proc, m_currentBlock, m_info, m_instanceValue);
+}
+
+
+auto B3IRGenerator::addGrowMemory(ExpressionType delta, ExpressionType& result) -> PartialResult
+{
+    int32_t (*growMemory) (ExecState*, int32_t) = [] (ExecState* exec, int32_t delta) -> int32_t {
+        VM& vm = exec->vm();
+        auto scope = DECLARE_THROW_SCOPE(vm);
+
+        JSWebAssemblyInstance* instance = vm.topJSWebAssemblyInstance;
+        JSWebAssemblyMemory* wasmMemory = instance->memory();
+        RELEASE_ASSERT(wasmMemory); // This would fail validation otherwise.
+
+        if (delta < 0)
+            return -1;
+
+        bool shouldThrowExceptionsOnFailure = false;
+        PageCount result = wasmMemory->grow(exec, static_cast<uint32_t>(delta), shouldThrowExceptionsOnFailure);
+        RELEASE_ASSERT(!scope.exception());
+        if (!result)
+            return -1;
+
+        return result.pageCount();
+    };
+
+    result = m_currentBlock->appendNew<CCallValue>(m_proc, Int32, Origin(),
+        m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), bitwise_cast<void*>(growMemory)),
+        m_currentBlock->appendNew<B3::Value>(m_proc, B3::FramePointer, Origin()), delta);
+
+    emitReloadPinnedRegisters();
+
+    return { };
+}
+
+auto B3IRGenerator::addCurrentMemory(ExpressionType& result) -> PartialResult
+{
+    Value* jsMemory = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfMemory());
+    Value* wasmMemory = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(), jsMemory, JSWebAssemblyMemory::offsetOfMemory());
+    Value* size = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, B3::Int64, Origin(), wasmMemory, Memory::offsetOfSize());
+
+    constexpr uint32_t shiftValue = 16;
+    static_assert(PageCount::pageSize == 1 << shiftValue, "This must hold for the code below to be correct.");
+    Value* numPages = m_currentBlock->appendNew<Value>(m_proc, ZShr, Origin(),
+        size, m_currentBlock->appendNew<Const32Value>(m_proc, Origin(), shiftValue));
+
+    result = m_currentBlock->appendNew<Value>(m_proc, Trunc, Origin(), numPages);
+
+    return { };
+}
+
 auto B3IRGenerator::setLocal(uint32_t index, ExpressionType value) -> PartialResult
 {
     ASSERT(m_locals[index]);
@@ -755,6 +849,10 @@
                 });
             });
         });
+
+    if (functionIndex < m_info.importFunctionCount())
+        emitReloadPinnedRegisters();
+
     return { };
 }
 
@@ -831,6 +929,8 @@
             });
         });
 
+    emitReloadPinnedRegisters();
+
     return { };
 }
 
@@ -871,7 +971,7 @@
     dataLogLn();
 }
 
-static void createJSToWasmWrapper(VM& vm, CompilationContext& compilationContext, WasmInternalFunction& function, const Signature* signature, const MemoryInformation& memory)
+static void createJSToWasmWrapper(VM& vm, CompilationContext& compilationContext, WasmInternalFunction& function, const Signature* signature, const ModuleInformation& info)
 {
     Procedure proc;
     BasicBlock* block = proc.addBlock();
@@ -899,18 +999,10 @@
     }
 
     // Move memory values to the approriate places, if needed.
-    Value* baseMemory = nullptr;
-    Vector<Value*> sizes;
-    if (!!memory) {
-        baseMemory = block->appendNew<MemoryValue>(proc, Load, Int64, Origin(),
-            block->appendNew<ConstPtrValue>(proc, Origin(), &vm.topWasmMemoryPointer));
-        Value* size = block->appendNew<MemoryValue>(proc, Load, Int32, Origin(),
-            block->appendNew<ConstPtrValue>(proc, Origin(), &vm.topWasmMemorySize));
-        sizes.reserveCapacity(memory.pinnedRegisters().sizeRegisters.size());
-        for (auto info : memory.pinnedRegisters().sizeRegisters) {
-            sizes.append(block->appendNew<Value>(proc, Sub, origin, size,
-                block->appendNew<Const32Value>(proc, origin, info.sizeOffset)));
-        }
+    {
+        Value* instance = block->appendNew<MemoryValue>(proc, Load, pointerType(), Origin(),
+            block->appendNew<ConstPtrValue>(proc, Origin(), &vm.topJSWebAssemblyInstance));
+        reloadPinnedRegisters(proc, block, info, instance);
     }
 
     // Get our arguments.
@@ -921,13 +1013,6 @@
 
     // Move the arguments into place.
     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)));
-            for (unsigned i = 0; i < sizes.size(); ++i)
-                patchpoint->append(ConstrainedValue(sizes[i], ValueRep::reg(memory.pinnedRegisters().sizeRegisters[i].sizeRegister)));
-        }
-
         CompilationContext* context = &compilationContext;
         patchpoint->setGenerator([context] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
             AllowMacroScratchRegisterUsage allowScratch(jit);
@@ -989,7 +1074,7 @@
         result->wasmEntrypoint.calleeSaveRegisters = procedure.calleeSaveRegisters();
     }
 
-    createJSToWasmWrapper(vm, compilationContext, *result, signature, info.memory);
+    createJSToWasmWrapper(vm, compilationContext, *result, signature, info);
     return WTFMove(result);
 }
 

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/WasmFormat.cpp (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/WasmFormat.cpp	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/WasmFormat.cpp	2017-01-06 01:49:20 UTC (rev 210419)
@@ -34,7 +34,7 @@
 
 namespace JSC { namespace Wasm {
 
-Segment* Segment::create(uint32_t offset, uint32_t sizeInBytes)
+Segment* Segment::create(I32InitExpr offset, uint32_t sizeInBytes)
 {
     auto allocated = tryFastCalloc(sizeof(Segment) + sizeInBytes, 1);
     Segment* segment;

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/WasmFormat.h (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/WasmFormat.h	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/WasmFormat.h	2017-01-06 01:49:20 UTC (rev 210419)
@@ -138,16 +138,51 @@
     size_t end;
 };
 
+class I32InitExpr {
+    enum Type : uint8_t {
+        Global,
+        Const
+    };
+
+    I32InitExpr(Type type, uint32_t bits)
+        : m_bits(bits)
+        , m_type(type)
+    { }
+
+public:
+    I32InitExpr() = delete;
+
+    static I32InitExpr globalImport(uint32_t globalImportNumber) { return I32InitExpr(Global, globalImportNumber); }
+    static I32InitExpr constValue(uint32_t constValue) { return I32InitExpr(Const, constValue); }
+
+    bool isConst() const { return m_type == Const; }
+    bool isGlobalImport() const { return m_type == Global; }
+    uint32_t constValue() const
+    {
+        RELEASE_ASSERT(isConst());
+        return m_bits;
+    }
+    uint32_t globalImportIndex() const
+    {
+        RELEASE_ASSERT(isGlobalImport());
+        return m_bits;
+    }
+
+private:
+    uint32_t m_bits;
+    Type m_type;
+};
+
 struct Segment {
-    uint32_t offset;
     uint32_t sizeInBytes;
+    I32InitExpr offset;
     // Bytes are allocated at the end.
     uint8_t& byte(uint32_t pos)
     {
         ASSERT(pos < sizeInBytes);
-        return *reinterpret_cast<uint8_t*>(reinterpret_cast<char*>(this) + sizeof(offset) + sizeof(sizeInBytes) + pos);
+        return *reinterpret_cast<uint8_t*>(reinterpret_cast<char*>(this) + sizeof(Segment) + pos);
     }
-    static Segment* create(uint32_t, uint32_t);
+    static Segment* create(I32InitExpr, uint32_t);
     static void destroy(Segment*);
     typedef std::unique_ptr<Segment, decltype(&Segment::destroy)> Ptr;
     static Ptr adoptPtr(Segment*);
@@ -191,7 +226,9 @@
     Vector<Import> imports;
     Vector<SignatureIndex> importFunctionSignatureIndices;
     Vector<SignatureIndex> internalFunctionSignatureIndices;
+
     MemoryInformation memory;
+
     Vector<Export> exports;
     std::optional<uint32_t> startFunctionIndexSpace;
     Vector<Segment::Ptr> data;
@@ -200,6 +237,9 @@
     Vector<Global> globals;
     unsigned firstInternalGlobal { 0 };
 
+    uint32_t importFunctionCount() const { return importFunctionSignatureIndices.size(); }
+    bool hasMemory() const { return !!memory; }
+
     ~ModuleInformation();
 };
 

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/WasmFunctionParser.h (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/WasmFunctionParser.h	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/WasmFunctionParser.h	2017-01-06 01:49:20 UTC (rev 210419)
@@ -478,14 +478,38 @@
         return { };
     }
 
-    case GrowMemory:
-        return fail("not yet implemented: grow_memory"); // FIXME: Not yet implemented.
+    case GrowMemory: {
+        WASM_PARSER_FAIL_IF(!m_info.memory, "grow_memory is only valid if a memory is defined or imported");
 
-    case CurrentMemory:
-        return fail("not yet implemented: current_memory"); // FIXME: Not yet implemented.
+        uint8_t reserved;
+        WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't parse reserved varUint1 for grow_memory");
+        WASM_PARSER_FAIL_IF(reserved != 0, "reserved varUint1 for grow_memory must be zero");
 
+        ExpressionType delta;
+        WASM_TRY_POP_EXPRESSION_STACK_INTO(delta, "expect an i32 argument to grow_memory on the stack");
+
+        ExpressionType result;
+        WASM_TRY_ADD_TO_CONTEXT(addGrowMemory(delta, result));
+        m_expressionStack.append(result);
+
+        return { };
     }
 
+    case CurrentMemory: {
+        WASM_PARSER_FAIL_IF(!m_info.memory, "current_memory is only valid if a memory is defined or imported");
+
+        uint8_t reserved;
+        WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't parse reserved varUint1 for current_memory");
+        WASM_PARSER_FAIL_IF(reserved != 0, "reserved varUint1 for current_memory must be zero");
+
+        ExpressionType result;
+        WASM_TRY_ADD_TO_CONTEXT(addCurrentMemory(result));
+        m_expressionStack.append(result);
+
+        return { };
+    }
+    }
+
     ASSERT_NOT_REACHED();
 }
 
@@ -584,6 +608,13 @@
         return { };
     }
 
+    case GrowMemory:
+    case CurrentMemory: {
+        uint8_t reserved;
+        WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't parse reserved varUint1 for grow_memory/current_memory");
+        return { };
+    }
+
     // no immediate cases
     FOR_EACH_WASM_BINARY_OP(CREATE_CASE)
     FOR_EACH_WASM_UNARY_OP(CREATE_CASE)
@@ -591,9 +622,7 @@
     case Nop:
     case Return:
     case Select:
-    case Drop:
-    case GrowMemory:
-    case CurrentMemory: {
+    case Drop: {
         return { };
     }
     }

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/WasmMemory.cpp (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/WasmMemory.cpp	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/WasmMemory.cpp	2017-01-06 01:49:20 UTC (rev 210419)
@@ -30,37 +30,89 @@
 
 namespace JSC { namespace Wasm {
 
-Memory::Memory(PageCount initial, PageCount maximum)
+static_assert(sizeof(uint64_t) == sizeof(size_t), "We rely on allowing the maximum size of Memory we map to be 2^32 which is larger than fits in a 32-bit integer that we'd pass to mprotect if this didn't hold.");
+
+Memory::Memory(PageCount initial, PageCount maximum, bool& failed)
     : m_mode(Mode::BoundsChecking)
-    , m_size(initial.bytes())
-    , m_capacity(maximum ? maximum.bytes() : PageCount::max().bytes())
     , m_initial(initial)
     , m_maximum(maximum)
+    , m_size(initial.bytes())
     // FIXME: If we add signal based bounds checking then we need extra space for overflow on load.
     // see: https://bugs.webkit.org/show_bug.cgi?id=162693
 {
     RELEASE_ASSERT(!maximum || maximum >= initial); // This should be guaranteed by our caller.
 
-    m_mappedCapacity = m_capacity;
+    m_mappedCapacity = maximum ? maximum.bytes() : PageCount::max().bytes();
+    if (!m_mappedCapacity) {
+        // This means we specified a zero as maximum (which means we also have zero as initial size).
+        RELEASE_ASSERT(m_size == 0);
+        m_mappedCapacity = 0;
+        m_memory = nullptr;
+        failed = false;
+        return;
+    }
+
     // FIXME: It would be nice if we had a VM tag for wasm memory. https://bugs.webkit.org/show_bug.cgi?id=163600
-    void* result = mmap(nullptr, m_mappedCapacity, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
+    void* result = Options::simulateWebAssemblyLowMemory() ? MAP_FAILED : mmap(nullptr, m_mappedCapacity, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
     if (result == MAP_FAILED) {
         // Try again with a different number.
         m_mappedCapacity = m_size;
+        if (!m_mappedCapacity) {
+            m_memory = nullptr;
+            failed = false;
+            return;
+        }
+
         result = mmap(nullptr, m_mappedCapacity, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
-        if (result == MAP_FAILED)
+        if (result == MAP_FAILED) {
+            failed = true;
             return;
+        }
     }
 
     ASSERT(m_size <= m_mappedCapacity);
-    if (mprotect(result, m_size, PROT_READ | PROT_WRITE)) {
-        munmap(result, m_mappedCapacity);
-        return;
+    {
+        bool success = !mprotect(result, static_cast<size_t>(m_size), PROT_READ | PROT_WRITE);
+        RELEASE_ASSERT(success);
     }
 
     m_memory = result;
+    failed = false;
 }
 
+bool Memory::grow(PageCount newSize)
+{
+    RELEASE_ASSERT(newSize > PageCount::fromBytes(m_size));
+
+    if (maximum() && newSize > maximum())
+        return false;
+
+    uint64_t desiredSize = newSize.bytes();
+
+    if (m_memory && desiredSize <= m_mappedCapacity) {
+        bool success = !mprotect(static_cast<uint8_t*>(m_memory) + m_size, static_cast<size_t>(desiredSize - m_size), PROT_READ | PROT_WRITE);
+        RELEASE_ASSERT(success);
+        m_size = desiredSize;
+        return true;
+    }
+
+    // Otherwise, let's try to make some new memory.
+    void* newMemory = mmap(nullptr, desiredSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+    if (newMemory == MAP_FAILED)
+        return false;
+
+    if (m_memory) {
+        memcpy(newMemory, m_memory, m_size);
+        bool success = !munmap(m_memory, m_mappedCapacity);
+        RELEASE_ASSERT(success);
+    }
+    m_memory = newMemory;
+    m_mappedCapacity = desiredSize;
+    m_size = desiredSize;
+
+    return true;
+}
+
 } // namespace JSC
 
 } // namespace Wasm

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/WasmMemory.h (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/WasmMemory.h	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/WasmMemory.h	2017-01-06 01:49:20 UTC (rev 210419)
@@ -44,7 +44,7 @@
         BoundsChecking
     };
 
-    JS_EXPORT_PRIVATE Memory(PageCount initial, PageCount maximum);
+    JS_EXPORT_PRIVATE Memory(PageCount initial, PageCount maximum, bool& failed);
 
     ~Memory()
     {
@@ -52,10 +52,9 @@
             munmap(m_memory, m_mappedCapacity);
     }
 
-    bool isValid() const { return !!m_memory; }
-
     void* memory() const { return m_memory; }
-    uint32_t size() const { return m_size; }
+    uint64_t size() const { return m_size; }
+    PageCount sizeInPages() const { return PageCount::fromBytes(m_size); }
 
     Mode mode() const { return m_mode; }
 
@@ -62,25 +61,17 @@
     PageCount initial() const { return m_initial; }
     PageCount maximum() const { return m_maximum; }
 
-    bool grow(uint32_t newSize)
-    {
-        ASSERT(m_memory);
-        if (newSize > m_capacity)
-            return false;
+    bool grow(PageCount);
 
-        return !mprotect(m_memory, newSize, PROT_READ | PROT_WRITE);
-    }
-
     static ptrdiff_t offsetOfSize() { return OBJECT_OFFSETOF(Memory, m_size); }
-
+    static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(Memory, m_memory); }
     
 private:
     void* m_memory { nullptr };
     Mode m_mode;
-    uint32_t m_size { 0 };
-    uint32_t m_capacity { 0 };
     PageCount m_initial;
     PageCount m_maximum;
+    uint64_t m_size { 0 };
     uint64_t m_mappedCapacity { 0 };
 };
 

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/WasmModuleParser.cpp (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/WasmModuleParser.cpp	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/WasmModuleParser.cpp	2017-01-06 01:49:20 UTC (rev 210419)
@@ -39,6 +39,14 @@
 
 namespace JSC { namespace Wasm {
 
+ALWAYS_INLINE I32InitExpr makeI32InitExpr(uint8_t opcode, uint32_t bits)
+{
+    RELEASE_ASSERT(opcode == I32Const || opcode == GetGlobal);
+    if (opcode == I32Const)
+        return I32InitExpr::constValue(bits);
+    return I32InitExpr::globalImport(bits);
+}
+
 auto ModuleParser::parse() -> Result
 {
     m_result.module = std::make_unique<ModuleInformation>();
@@ -289,7 +297,7 @@
 
 auto ModuleParser::parseMemoryHelper(bool isImport) -> PartialResult
 {
-    WASM_PARSER_FAIL_IF(m_result.module->memory, "Memory section cannot exist if an Import has a memory");
+    WASM_PARSER_FAIL_IF(!!m_result.module->memory, "Memory section cannot exist if an Import has a memory");
 
     PageCount initialPageCount;
     PageCount maximumPageCount;
@@ -342,32 +350,12 @@
         uint8_t initOpcode;
 
         WASM_FAIL_IF_HELPER_FAILS(parseGlobalType(global));
-        WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, global.initialBitsOrImportNumber));
-
-        global.initializationType = Global::FromExpression;
         Type typeForInitOpcode;
-        switch (initOpcode) {
-        case I32Const:
-            typeForInitOpcode = I32;
-            break;
-        case I64Const:
-            typeForInitOpcode = I64;
-            break;
-        case F32Const:
-            typeForInitOpcode = F32;
-            break;
-        case F64Const:
-            typeForInitOpcode = F64;
-            break;
-        case GetGlobal:
-            WASM_PARSER_FAIL_IF(global.initialBitsOrImportNumber >= m_result.module->firstInternalGlobal, globalIndex, "th Global uses get_global ", global.initialBitsOrImportNumber, " which exceeds the first internal global ", m_result.module->firstInternalGlobal);
-            typeForInitOpcode = m_result.module->globals[global.initialBitsOrImportNumber].type;
+        WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, global.initialBitsOrImportNumber, typeForInitOpcode));
+        if (initOpcode == GetGlobal)
             global.initializationType = Global::FromGlobalImport;
-            break;
-        default:
-            RELEASE_ASSERT_NOT_REACHED();
-        }
-
+        else
+            global.initializationType = Global::FromExpression;
         WASM_PARSER_FAIL_IF(typeForInitOpcode != global.type, "Global init_expr opcode of type ", typeForInitOpcode, " doesn't match global's type ", global.type);
 
         m_result.module->globals.uncheckedAppend(WTFMove(global));
@@ -454,7 +442,8 @@
 
         WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't get ", elementNum, "th Element table index");
         WASM_PARSER_FAIL_IF(tableIndex, "Element section can only have one Table for now");
-        WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, offset));
+        Type initExprType;
+        WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, offset, initExprType));
         WASM_PARSER_FAIL_IF(initOpcode != OpType::I32Const, "Element section doesn't support non-i32 init_expr opcode for now, got ", initOpcode);
         WASM_PARSER_FAIL_IF(!parseVarUInt32(indexCount), "can't get ", elementNum, "th index count for Element section");
         WASM_PARSER_FAIL_IF(indexCount == std::numeric_limits<uint32_t>::max(), "Element section's ", elementNum, "th index count is too big ", indexCount);
@@ -512,7 +501,7 @@
     return { };
 }
 
-auto ModuleParser::parseInitExpr(uint8_t& opcode, uint64_t& bitsOrImportNumber) -> PartialResult
+auto ModuleParser::parseInitExpr(uint8_t& opcode, uint64_t& bitsOrImportNumber, Type& resultType) -> PartialResult
 {
     WASM_PARSER_FAIL_IF(!parseUInt8(opcode), "can't get init_expr's opcode");
 
@@ -521,6 +510,7 @@
         int32_t constant;
         WASM_PARSER_FAIL_IF(!parseVarInt32(constant), "can't get constant value for init_expr's i32.const");
         bitsOrImportNumber = static_cast<uint64_t>(constant);
+        resultType = I32;
         break;
     }
 
@@ -528,6 +518,7 @@
         int64_t constant;
         WASM_PARSER_FAIL_IF(!parseVarInt64(constant), "can't get constant value for init_expr's i64.const");
         bitsOrImportNumber = constant;
+        resultType = I64;
         break;
     }
 
@@ -535,6 +526,7 @@
         uint32_t constant;
         WASM_PARSER_FAIL_IF(!parseUInt32(constant), "can't get constant value for init_expr's f32.const");
         bitsOrImportNumber = constant;
+        resultType = F32;
         break;
     }
 
@@ -542,6 +534,7 @@
         uint64_t constant;
         WASM_PARSER_FAIL_IF(!parseUInt64(constant), "can't get constant value for init_expr's f64.const");
         bitsOrImportNumber = constant;
+        resultType = F64;
         break;
     }
 
@@ -554,7 +547,7 @@
         WASM_PARSER_FAIL_IF(import.kindIndex >= m_result.module->firstInternalGlobal, "get_global import kind index ", import.kindIndex, " exceeds the first internal global ", m_result.module->firstInternalGlobal);
 
         ASSERT(m_result.module->globals[import.kindIndex].mutability == Global::Immutable);
-
+        resultType = m_result.module->globals[index].type;
         bitsOrImportNumber = index;
         break;
     }
@@ -589,18 +582,19 @@
 
     for (uint32_t segmentNumber = 0; segmentNumber < segmentCount; ++segmentNumber) {
         uint32_t index;
-        uint64_t offset;
+        uint64_t initExprBits;
         uint8_t initOpcode;
         uint32_t dataByteLength;
 
         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get ", segmentNumber, "th Data segment's index");
         WASM_PARSER_FAIL_IF(index, segmentNumber, "th Data segment has non-zero index ", index);
-        WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, offset));
-        WASM_PARSER_FAIL_IF(initOpcode != OpType::I32Const, segmentNumber, "th Data segment has opcode ", initOpcode, " expected i32.const");
+        Type initExprType;
+        WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, initExprBits, initExprType));
+        WASM_PARSER_FAIL_IF(initExprType != I32, segmentNumber, "th Data segment's init_expr must produce an i32");
         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::create(offset, dataByteLength);
+        Segment* segment = Segment::create(makeI32InitExpr(initOpcode, initExprBits), 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::adoptPtr(segment));
         for (uint32_t dataByte = 0; dataByte < dataByteLength; ++dataByte) {

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/WasmModuleParser.h (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/WasmModuleParser.h	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/WasmModuleParser.h	2017-01-06 01:49:20 UTC (rev 210419)
@@ -64,7 +64,7 @@
     PartialResult WARN_UNUSED_RETURN parseMemoryHelper(bool isImport);
     PartialResult WARN_UNUSED_RETURN parseTableHelper(bool isImport);
     PartialResult WARN_UNUSED_RETURN parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum);
-    PartialResult WARN_UNUSED_RETURN parseInitExpr(uint8_t&, uint64_t&);
+    PartialResult WARN_UNUSED_RETURN parseInitExpr(uint8_t&, uint64_t&, Type& initExprType);
 
     ModuleParserResult m_result;
     bool m_hasTable { false };

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/WasmPageCount.h (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/WasmPageCount.h	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/WasmPageCount.h	2017-01-06 01:49:20 UTC (rev 210419)
@@ -42,7 +42,8 @@
         : m_pageCount(pageCount)
     { }
 
-    size_t bytes() { return m_pageCount * pageSize; }
+    uint64_t bytes() const { return static_cast<uint64_t>(m_pageCount) * static_cast<uint64_t>(pageSize); }
+    uint32_t pageCount() const { return m_pageCount; }
 
     static bool isValid(uint32_t pageCount)
     {
@@ -49,6 +50,14 @@
         return pageCount <= maxPageCount;
     }
 
+    static PageCount fromBytes(uint64_t bytes)
+    {
+        RELEASE_ASSERT(bytes % pageSize == 0);
+        uint32_t numPages = bytes / pageSize;
+        RELEASE_ASSERT(PageCount::isValid(numPages));
+        return PageCount(numPages);
+    }
+
     static PageCount max()
     {
         return PageCount(maxPageCount);
@@ -62,9 +71,18 @@
     bool operator<(const PageCount& other) const { return m_pageCount < other.m_pageCount; }
     bool operator>(const PageCount& other) const { return m_pageCount > other.m_pageCount; }
     bool operator>=(const PageCount& other) const { return m_pageCount >= other.m_pageCount; }
+    PageCount operator+(const PageCount& other) const
+    {
+        if (sumOverflows<uint32_t>(m_pageCount, other.m_pageCount))
+            return PageCount();
+        uint32_t newCount = m_pageCount + other.m_pageCount;
+        if (!PageCount::isValid(newCount))
+            return PageCount();
+        return PageCount(newCount);
+    }
 
+    static constexpr uint32_t pageSize = 64 * KB;
 private:
-    static constexpr uint32_t pageSize = 64 * KB;
     static constexpr uint32_t maxPageCount = static_cast<uint32_t>((1ull << 32) / pageSize);
 
     uint32_t m_pageCount;

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/WasmParser.h (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/WasmParser.h	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/WasmParser.h	2017-01-06 01:49:20 UTC (rev 210419)
@@ -235,8 +235,10 @@
     uint32_t temp;
     if (!parseVarUInt32(temp))
         return false;
+    if (temp > 1)
+        return false;
     result = static_cast<uint8_t>(temp);
-    return temp <= 1;
+    return true;
 }
 
 template<typename SuccessType>

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/WasmValidate.cpp (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/WasmValidate.cpp	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/WasmValidate.cpp	2017-01-06 01:49:20 UTC (rev 210419)
@@ -132,6 +132,8 @@
     Result WARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack);
     Result WARN_UNUSED_RETURN endBlock(ControlEntry&, ExpressionList& expressionStack);
     Result WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&);
+    Result WARN_UNUSED_RETURN addGrowMemory(ExpressionType delta, ExpressionType& result);
+    Result WARN_UNUSED_RETURN addCurrentMemory(ExpressionType& result);
 
     Result WARN_UNUSED_RETURN addUnreachable() { return { }; }
 
@@ -292,6 +294,19 @@
     return checkBranchTarget(defaultTarget, expressionStack);
 }
 
+auto Validate::addGrowMemory(ExpressionType delta, ExpressionType& result) -> Result
+{
+    WASM_VALIDATOR_FAIL_IF(delta != I32, "grow_memory with non-i32 delta");
+    result = I32;
+    return { };
+}
+
+auto Validate::addCurrentMemory(ExpressionType& result) -> Result
+{
+    result = I32;
+    return { };
+}
+
 auto Validate::endBlock(ControlEntry& entry, ExpressionList& stack) -> Result
 {
     WASM_FAIL_IF_HELPER_FAILS(unify(stack, entry.controlData));

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.h (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.h	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.h	2017-01-06 01:49:20 UTC (rev 210419)
@@ -87,6 +87,7 @@
     }
 
     static ptrdiff_t offsetOfTable() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_table); }
+    static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_memory); }
     static ptrdiff_t offsetOfGlobals() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_globals); }
 
 protected:

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyMemory.cpp (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyMemory.cpp	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyMemory.cpp	2017-01-06 01:49:20 UTC (rev 210419)
@@ -30,8 +30,8 @@
 
 #include "JSCInlines.h"
 
+#include "ArrayBuffer.h"
 #include "JSArrayBuffer.h"
-#include "ArrayBuffer.h"
 
 namespace JSC {
 
@@ -55,6 +55,15 @@
 {
 }
 
+JSWebAssemblyMemory::~JSWebAssemblyMemory()
+{
+    if (m_buffer) {
+        ArrayBufferContents dummyContents;
+        m_buffer->transferTo(dummyContents);
+        m_buffer = nullptr;
+    }
+}
+
 JSArrayBuffer* JSWebAssemblyMemory::buffer(VM& vm, JSGlobalObject* globalObject)
 {
     if (m_bufferWrapper)
@@ -71,6 +80,48 @@
     return m_bufferWrapper.get();
 }
 
+Wasm::PageCount JSWebAssemblyMemory::grow(ExecState* exec, uint32_t delta, bool shouldThrowExceptionsOnFailure)
+{
+    VM& vm = exec->vm();
+    auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+    Wasm::PageCount oldPageCount = m_memory->sizeInPages();
+
+    if (!Wasm::PageCount::isValid(delta)) {
+        if (shouldThrowExceptionsOnFailure)
+            throwException(exec, throwScope, createRangeError(exec, ASCIILiteral("WebAssembly.Memory.grow expects the delta to be a valid page count")));
+        return Wasm::PageCount();
+    }
+
+    Wasm::PageCount newSize = oldPageCount + Wasm::PageCount(delta);
+    if (!newSize) {
+        if (shouldThrowExceptionsOnFailure)
+            throwException(exec, throwScope, createRangeError(exec, ASCIILiteral("WebAssembly.Memory.grow expects the grown size to be a valid page count")));
+        return Wasm::PageCount();
+    }
+
+    if (delta) {
+        bool success = m_memory->grow(newSize);
+        if (!success) {
+            if (shouldThrowExceptionsOnFailure)
+                throwException(exec, throwScope, createOutOfMemoryError(exec));
+            return Wasm::PageCount();
+        }
+    }
+
+    // We need to clear out the old array buffer because it might now be pointing
+    // to stale memory.
+    // Neuter the old array.
+    if (m_buffer) {
+        ArrayBufferContents dummyContents;
+        m_buffer->transferTo(dummyContents);
+        m_buffer = nullptr;
+        m_bufferWrapper.clear();
+    }
+
+    return oldPageCount;
+}
+
 void JSWebAssemblyMemory::finishCreation(VM& vm)
 {
     Base::finishCreation(vm);

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyMemory.h (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyMemory.h	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyMemory.h	2017-01-06 01:49:20 UTC (rev 210419)
@@ -48,9 +48,13 @@
 
     Wasm::Memory* memory() { return m_memory.get(); }
     JSArrayBuffer* buffer(VM& vm, JSGlobalObject*);
+    Wasm::PageCount grow(ExecState*, uint32_t delta, bool shouldThrowExceptionsOnFailure);
 
+    static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(JSWebAssemblyMemory, m_memory); }
+
 protected:
     JSWebAssemblyMemory(VM&, Structure*, std::unique_ptr<Wasm::Memory>&&);
+    ~JSWebAssemblyMemory();
     void finishCreation(VM&);
     static void destroy(JSCell*);
     static void visitChildren(JSCell*, SlotVisitor&);

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyModule.h (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyModule.h	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyModule.h	2017-01-06 01:49:20 UTC (rev 210419)
@@ -55,12 +55,12 @@
         ASSERT(functionIndexSpace < m_functionIndexSpace.size);
         return m_functionIndexSpace.buffer.get()[functionIndexSpace].signatureIndex;
     }
-    unsigned importCount() const { return m_wasmToJSStubs.size(); }
+    unsigned functionImportCount() const { return m_wasmToJSStubs.size(); }
 
     JSWebAssemblyCallee* jsEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
     {
-        RELEASE_ASSERT(functionIndexSpace >= importCount());
-        unsigned calleeIndex = functionIndexSpace - importCount();
+        RELEASE_ASSERT(functionIndexSpace >= functionImportCount());
+        unsigned calleeIndex = functionIndexSpace - functionImportCount();
         RELEASE_ASSERT(calleeIndex < m_calleeCount);
         return callees()[calleeIndex].get();
     }
@@ -67,8 +67,8 @@
 
     JSWebAssemblyCallee* wasmEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
     {
-        RELEASE_ASSERT(functionIndexSpace >= importCount());
-        unsigned calleeIndex = functionIndexSpace - importCount();
+        RELEASE_ASSERT(functionIndexSpace >= functionImportCount());
+        unsigned calleeIndex = functionIndexSpace - functionImportCount();
         RELEASE_ASSERT(calleeIndex < m_calleeCount);
         return callees()[calleeIndex + m_calleeCount].get();
     }

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp	2017-01-06 01:49:20 UTC (rev 210419)
@@ -114,15 +114,6 @@
     ProtoCallFrame protoCallFrame;
     protoCallFrame.init(nullptr, wasmFunction, firstArgument, argCount, remainingArgs);
 
-    if (JSWebAssemblyMemory* memory = wasmFunction->instance()->memory()) {
-        Wasm::Memory* wasmMemory = memory->memory();
-        vm.topWasmMemoryPointer = wasmMemory->memory();
-        vm.topWasmMemorySize = wasmMemory->size();
-    } else {
-        vm.topWasmMemoryPointer = nullptr;
-        vm.topWasmMemorySize = 0;
-    }
-
     JSWebAssemblyInstance* prevJSWebAssemblyInstance = vm.topJSWebAssemblyInstance;
     vm.topJSWebAssemblyInstance = wasmFunction->instance();
     ASSERT(wasmFunction->instance());

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyInstanceConstructor.cpp (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyInstanceConstructor.cpp	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyInstanceConstructor.cpp	2017-01-06 01:49:20 UTC (rev 210419)
@@ -229,8 +229,9 @@
         if (moduleInformation.memory && !hasMemoryImport) {
             RELEASE_ASSERT(!moduleInformation.memory.isImport());
             // We create a memory when it's a memory definition.
-            std::unique_ptr<Wasm::Memory> memory = std::make_unique<Wasm::Memory>(moduleInformation.memory.initial(), moduleInformation.memory.maximum());
-            if (!memory->isValid())
+            bool failed;
+            std::unique_ptr<Wasm::Memory> memory = std::make_unique<Wasm::Memory>(moduleInformation.memory.initial(), moduleInformation.memory.maximum(), failed);
+            if (failed)
                 return JSValue::encode(throwException(exec, throwScope, createOutOfMemoryError(exec)));
             instance->setMemory(vm,
                JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), WTFMove(memory)));

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyMemoryConstructor.cpp (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyMemoryConstructor.cpp	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyMemoryConstructor.cpp	2017-01-06 01:49:20 UTC (rev 210419)
@@ -96,8 +96,9 @@
         }
     }
 
-    std::unique_ptr<Wasm::Memory> memory = std::make_unique<Wasm::Memory>(initialPageCount, maximumPageCount);
-    if (!memory->isValid())
+    bool failed;
+    std::unique_ptr<Wasm::Memory> memory = std::make_unique<Wasm::Memory>(initialPageCount, maximumPageCount, failed);
+    if (failed)
         return JSValue::encode(throwException(exec, throwScope, createOutOfMemoryError(exec)));
 
     return JSValue::encode(JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), WTFMove(memory)));

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyMemoryPrototype.cpp (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyMemoryPrototype.cpp	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyMemoryPrototype.cpp	2017-01-06 01:49:20 UTC (rev 210419)
@@ -32,33 +32,69 @@
 #include "JSArrayBuffer.h"
 #include "JSCInlines.h"
 #include "JSWebAssemblyMemory.h"
+#include "JSWebAssemblyHelpers.h"
 
+namespace JSC {
+static EncodedJSValue JSC_HOST_CALL webAssemblyMemoryProtoFuncGrow(ExecState*);
+}
+
 #include "WebAssemblyMemoryPrototype.lut.h"
 
+
 namespace JSC {
 
 const ClassInfo WebAssemblyMemoryPrototype::s_info = { "WebAssembly.Memory.prototype", &Base::s_info, &prototypeTableWebAssemblyMemory, CREATE_METHOD_TABLE(WebAssemblyMemoryPrototype) };
 
 /* Source for WebAssemblyMemoryPrototype.lut.h
- @begin prototypeTableWebAssemblyMemory
- @end
- */
+@begin prototypeTableWebAssemblyMemory
+  grow     webAssemblyMemoryProtoFuncGrow   DontEnum|Function 1
+@end
+*/
 
-static EncodedJSValue JSC_HOST_CALL webAssemblyMemoryProtoFuncBuffer(ExecState*);
+EncodedJSValue JSC_HOST_CALL webAssemblyMemoryProtoFuncBuffer(ExecState*);
 
-EncodedJSValue JSC_HOST_CALL webAssemblyMemoryProtoFuncBuffer(ExecState* exec)
+ALWAYS_INLINE JSWebAssemblyMemory* getMemory(ExecState* exec, JSValue value)
 {
     VM& vm = exec->vm();
     auto throwScope = DECLARE_THROW_SCOPE(vm);
 
-    JSWebAssemblyMemory* memory = jsDynamicCast<JSWebAssemblyMemory*>(exec->thisValue()); 
+    JSWebAssemblyMemory* memory = jsDynamicCast<JSWebAssemblyMemory*>(value); 
     if (!memory) {
-        return JSValue::encode(throwException(exec, throwScope, 
-                    createTypeError(exec, ASCIILiteral("WebAssembly.Memory.prototype.buffer getter called with non WebAssembly.Memory |this| value"))));
+        throwException(exec, throwScope, 
+            createTypeError(exec, ASCIILiteral("WebAssembly.Memory.prototype.buffer getter called with non WebAssembly.Memory |this| value")));
+        return nullptr;
     }
+    return memory;
+}
+
+EncodedJSValue JSC_HOST_CALL webAssemblyMemoryProtoFuncBuffer(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+    JSWebAssemblyMemory* memory = getMemory(exec, exec->thisValue()); 
+    RETURN_IF_EXCEPTION(throwScope, { });
     return JSValue::encode(memory->buffer(exec->vm(), exec->lexicalGlobalObject()));
 }
 
+EncodedJSValue JSC_HOST_CALL webAssemblyMemoryProtoFuncGrow(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+    JSWebAssemblyMemory* memory = getMemory(exec, exec->thisValue()); 
+    RETURN_IF_EXCEPTION(throwScope, { });
+    
+    uint32_t delta = toNonWrappingUint32(exec, exec->argument(0));
+    RETURN_IF_EXCEPTION(throwScope, { });
+
+    bool shouldThrowExceptionsOnFailure = true;
+    Wasm::PageCount result = memory->grow(exec, delta, shouldThrowExceptionsOnFailure);
+    RETURN_IF_EXCEPTION(throwScope, { });
+
+    return JSValue::encode(jsNumber(result.pageCount()));
+}
+
 WebAssemblyMemoryPrototype* WebAssemblyMemoryPrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
 {
     auto* object = new (NotNull, allocateCell<WebAssemblyMemoryPrototype>(vm.heap)) WebAssemblyMemoryPrototype(vm, structure);

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp	2017-01-06 01:49:20 UTC (rev 210419)
@@ -95,7 +95,7 @@
     const Wasm::ModuleInformation& moduleInformation = module->moduleInformation();
 
     SymbolTable* exportSymbolTable = module->exportSymbolTable();
-    unsigned importCount = module->importCount();
+    unsigned functionImportCount = module->functionImportCount();
 
     // FIXME wire up the imports. https://bugs.webkit.org/show_bug.cgi?id=165118
 
@@ -108,7 +108,7 @@
             // 1. If e is a closure c:
             //   i. If there is an Exported Function Exotic Object func in funcs whose func.[[Closure]] equals c, then return func.
             //   ii. (Note: At most one wrapper is created for any closure, so func is unique, even if there are multiple occurrances in the list. Moreover, if the item was an import that is already an Exported Function Exotic Object, then the original function object will be found. For imports that are regular JS functions, a new wrapper will be created.)
-            if (exp.kindIndex < importCount) {
+            if (exp.kindIndex < functionImportCount) {
                 // FIXME Implement re-exporting an import. https://bugs.webkit.org/show_bug.cgi?id=165510
                 RELEASE_ASSERT_NOT_REACHED();
             }
@@ -180,7 +180,7 @@
         // The start function must not take any arguments or return anything. This is enforced by the parser.
         ASSERT(!signature->argumentCount());
         ASSERT(signature->returnType() == Wasm::Void);
-        if (startFunctionIndexSpace < module->importCount()) {
+        if (startFunctionIndexSpace < module->functionImportCount()) {
             JSCell* startFunction = instance->importFunction(startFunctionIndexSpace)->get();
             m_startFunction.set(vm, this, startFunction);
         } else {
@@ -196,8 +196,8 @@
     m_moduleEnvironment.set(vm, this, moduleEnvironment);
 }
 
-template <typename Scope, typename N, typename ...Args>
-NEVER_INLINE static JSValue dataSegmentFail(ExecState* state, VM& vm, Scope& scope, N memorySize, N segmentSize, N offset, Args... args)
+template <typename Scope, typename M, typename N, typename ...Args>
+NEVER_INLINE static JSValue dataSegmentFail(ExecState* state, VM& vm, Scope& scope, M memorySize, N segmentSize, N offset, Args... args)
 {
     return throwException(state, scope, createJSWebAssemblyLinkError(state, vm, makeString(ASCIILiteral("Invalid data segment initialization: segment of "), String::number(segmentSize), ASCIILiteral(" bytes memory of "), String::number(memorySize), ASCIILiteral(" bytes, at offset "), String::number(offset), args...)));
 }
@@ -231,7 +231,7 @@
                 // for the import.
                 // https://bugs.webkit.org/show_bug.cgi?id=165510
                 uint32_t functionIndex = element.functionIndices[i];
-                if (functionIndex < module->importCount()) {
+                if (functionIndex < module->functionImportCount()) {
                     return JSValue::decode(
                         throwVMRangeError(state, scope, ASCIILiteral("Element is setting the table value with an import. This is not yet implemented. FIXME.")));
                 }
@@ -259,15 +259,21 @@
         if (!data.isEmpty()) {
             RELEASE_ASSERT(jsMemory); // It is a validation error for a Data section to exist without a Memory section or import.
             uint8_t* memory = reinterpret_cast<uint8_t*>(jsMemory->memory()->memory());
-            RELEASE_ASSERT(memory);
-            auto sizeInBytes = jsMemory->memory()->size();
+            uint64_t sizeInBytes = jsMemory->memory()->size();
             for (auto& segment : data) {
                 if (segment->sizeInBytes) {
+                    uint32_t offset;
+                    if (segment->offset.isGlobalImport())
+                        offset = static_cast<uint32_t>(m_instance->loadI32Global(segment->offset.globalImportIndex()));
+                    else
+                        offset = segment->offset.constValue();
+
                     if (UNLIKELY(sizeInBytes < segment->sizeInBytes))
-                        return dataSegmentFail(state, vm, scope, sizeInBytes, segment->sizeInBytes, segment->offset, ASCIILiteral(", segment is too big"));
-                    if (UNLIKELY(segment->offset > sizeInBytes - segment->sizeInBytes))
-                        return dataSegmentFail(state, vm, scope, sizeInBytes, segment->sizeInBytes, segment->offset, ASCIILiteral(", segment writes outside of memory"));
-                    memcpy(memory + segment->offset, &segment->byte(0), segment->sizeInBytes);
+                        return dataSegmentFail(state, vm, scope, sizeInBytes, segment->sizeInBytes, offset, ASCIILiteral(", segment is too big"));
+                    if (UNLIKELY(offset > sizeInBytes - segment->sizeInBytes))
+                        return dataSegmentFail(state, vm, scope, sizeInBytes, segment->sizeInBytes, offset, ASCIILiteral(", segment writes outside of memory"));
+                    RELEASE_ASSERT(memory);
+                    memcpy(memory + offset, &segment->byte(0), segment->sizeInBytes);
                 }
             }
         }

Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/wasm.json (210418 => 210419)


--- branches/safari-603-branch/Source/_javascript_Core/wasm/wasm.json	2017-01-06 01:49:05 UTC (rev 210418)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/wasm.json	2017-01-06 01:49:20 UTC (rev 210419)
@@ -88,8 +88,8 @@
         "i64.store":           { "category": "memory",     "value":  55, "return": [],           "parameter": ["addr", "i64"],          "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset", "type": "varuint32"}], "description": "store to memory" },
         "f32.store":           { "category": "memory",     "value":  56, "return": [],           "parameter": ["addr", "f32"],          "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset", "type": "varuint32"}], "description": "store to memory" },
         "f64.store":           { "category": "memory",     "value":  57, "return": [],           "parameter": ["addr", "f64"],          "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset", "type": "varuint32"}], "description": "store to memory" },
-        "current_memory":      { "category": "operation",  "value":  63, "return": ["size"],     "parameter": [],                       "immediate": [],                                                                                         "description": "query the size of memory" },
-        "grow_memory":         { "category": "operation",  "value":  64, "return": ["size"],     "parameter": ["size"],                 "immediate": [],                                                                                         "description": "grow the size of memory" },
+        "current_memory":      { "category": "operation",  "value":  63, "return": ["size"],     "parameter": [],                       "immediate": [{"name": "flags", "type": "varuint32"}],                                                                                         "description": "query the size of memory" },
+        "grow_memory":         { "category": "operation",  "value":  64, "return": ["size"],     "parameter": ["size"],                 "immediate": [{"name": "flags", "type": "varuint32"}],                                                                                         "description": "grow the size of memory" },
         "i32.add":             { "category": "arithmetic", "value": 106, "return": ["i32"],      "parameter": ["i32", "i32"],           "immediate": [], "b3op": "Add"          },
         "i32.sub":             { "category": "arithmetic", "value": 107, "return": ["i32"],      "parameter": ["i32", "i32"],           "immediate": [], "b3op": "Sub"          },
         "i32.mul":             { "category": "arithmetic", "value": 108, "return": ["i32"],      "parameter": ["i32", "i32"],           "immediate": [], "b3op": "Mul"          },
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to