Bug 1253137 - Baldr: update memory section to match BinaryEncoding.md, part 1 (r=sunfish)
☠☠ backed out by 7972152f5978 ☠ ☠
authorLuke Wagner <luke@mozilla.com>
Wed, 02 Mar 2016 21:48:05 -0600
changeset 322973 13ce4c5281ad75eea2e5956f1be8b045d115e558
parent 322972 6705f67ab79807bee6110bf00730171793fcd9e2
child 322974 d82815bf45b2d3232786909adfea96dd452d4693
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssunfish
bugs1253137
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1253137 - Baldr: update memory section to match BinaryEncoding.md, part 1 (r=sunfish) MozReview-Commit-ID: EKCvmgPnLmv
js/src/asmjs/Wasm.cpp
js/src/asmjs/WasmBinary.h
js/src/asmjs/WasmText.cpp
js/src/jit-test/tests/wasm/basic-memory.js
js/src/jit-test/tests/wasm/basic.js
--- a/js/src/asmjs/Wasm.cpp
+++ b/js/src/asmjs/Wasm.cpp
@@ -13,28 +13,31 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "asmjs/Wasm.h"
 
+#include "mozilla/CheckedInt.h"
+
 #include "jsprf.h"
 
 #include "asmjs/WasmGenerator.h"
 #include "asmjs/WasmText.h"
 #include "vm/ArrayBufferObject.h"
 
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::wasm;
 
+using mozilla::CheckedInt;
 using mozilla::IsNaN;
 
 typedef Handle<WasmModuleObject*> HandleWasmModule;
 typedef MutableHandle<WasmModuleObject*> MutableHandleWasmModule;
 
 /*****************************************************************************/
 // reporting
 
@@ -885,38 +888,39 @@ DecodeMemorySection(JSContext* cx, Decod
                     MutableHandle<ArrayBufferObject*> heap)
 {
     uint32_t sectionStart;
     if (!d.startSection(MemoryLabel, &sectionStart))
         return Fail(cx, d, "failed to start section");
     if (sectionStart == Decoder::NotStarted)
         return true;
 
-
-    if (!d.readCStringIf(InitialLabel))
-        return Fail(cx, d, "expected memory section initial field");
-
-    uint32_t initialHeapSize;
-    if (!d.readVarU32(&initialHeapSize))
+    uint32_t initialSizePages;
+    if (!d.readVarU32(&initialSizePages))
         return Fail(cx, d, "expected initial memory size");
 
-    if (initialHeapSize < PageSize || initialHeapSize % PageSize != 0)
-        return Fail(cx, d, "initial memory size not a multiple of 0x10000");
-
-    if (initialHeapSize > INT32_MAX)
+    CheckedInt<int32_t> initialSize = initialSizePages;
+    initialSize *= PageSize;
+    if (!initialSize.isValid())
         return Fail(cx, d, "initial memory size too big");
 
-    if (!d.readCStringIf(EndLabel))
-        return Fail(cx, d, "expected end field of memory section");
+    uint32_t maxSizePages;
+    if (!d.readVarU32(&maxSizePages))
+        return Fail(cx, d, "expected initial memory size");
+
+    CheckedInt<int32_t> maxSize = maxSizePages;
+    maxSize *= PageSize;
+    if (!maxSize.isValid())
+        return Fail(cx, d, "initial memory size too big");
 
     if (!d.finishSection(sectionStart))
         return Fail(cx, d, "memory section byte size mismatch");
 
     bool signalsForOOB = CompileArgs(cx).useSignalHandlersForOOB;
-    heap.set(ArrayBufferObject::createForWasm(cx, initialHeapSize, signalsForOOB));
+    heap.set(ArrayBufferObject::createForWasm(cx, initialSize.value(), signalsForOOB));
     if (!heap)
         return false;
 
     mg.initHeapUsage(HeapUsage::Unshared);
     return true;
 }
 
 typedef HashSet<const char*, CStringHasher> CStringSet;
--- a/js/src/asmjs/WasmBinary.h
+++ b/js/src/asmjs/WasmBinary.h
@@ -49,17 +49,16 @@ static const char SigLabel[]          = 
 static const char ImportLabel[]       = "import";
 static const char DeclLabel[]         = "decl";
 static const char TableLabel[]        = "table";
 static const char MemoryLabel[]       = "memory";
 static const char ExportLabel[]       = "export";
 static const char FuncLabel[]         = "func";
 static const char DataLabel[]         = "data";
 static const char SegmentLabel[]      = "segment";
-static const char InitialLabel[]      = "initial";
 static const char EndLabel[]          = "";
 
 enum class Expr : uint16_t
 {
     // Control opcodes
     Nop,
     Block,
     Loop,
--- a/js/src/asmjs/WasmText.cpp
+++ b/js/src/asmjs/WasmText.cpp
@@ -557,24 +557,28 @@ class WasmAstSegment : public WasmAstNod
     WasmName text() const { return text_; }
 };
 
 typedef WasmAstVector<WasmAstSegment*> WasmAstSegmentVector;
 
 class WasmAstMemory : public WasmAstNode
 {
     uint32_t initialSize_;
+    Maybe<uint32_t> maxSize_;
     WasmAstSegmentVector segments_;
 
   public:
-    explicit WasmAstMemory(uint32_t initialSize, WasmAstSegmentVector&& segments)
+    explicit WasmAstMemory(uint32_t initialSize, Maybe<uint32_t> maxSize,
+                           WasmAstSegmentVector&& segments)
       : initialSize_(initialSize),
+        maxSize_(maxSize),
         segments_(Move(segments))
     {}
     uint32_t initialSize() const { return initialSize_; }
+    const Maybe<uint32_t>& maxSize() const { return maxSize_; }
     const WasmAstSegmentVector& segments() const { return segments_; }
 };
 
 class WasmAstModule : public WasmAstNode
 {
     typedef WasmAstVector<WasmAstFunc*> FuncVector;
     typedef WasmAstVector<WasmAstImport*> ImportVector;
     typedef WasmAstVector<WasmAstExport*> ExportVector;
@@ -2892,26 +2896,31 @@ ParseSegment(WasmParseContext& c)
 
 static WasmAstMemory*
 ParseMemory(WasmParseContext& c)
 {
     WasmToken initialSize;
     if (!c.ts.match(WasmToken::Index, &initialSize, c.error))
         return nullptr;
 
+    Maybe<uint32_t> maxSize;
+    WasmToken token;
+    if (c.ts.getIf(WasmToken::Index, &token))
+        maxSize.emplace(token.index());
+
     WasmAstSegmentVector segments(c.lifo);
     while (c.ts.getIf(WasmToken::OpenParen)) {
         WasmAstSegment* segment = ParseSegment(c);
         if (!segment || !segments.append(segment))
             return nullptr;
         if (!c.ts.match(WasmToken::CloseParen, c.error))
             return nullptr;
     }
 
-    return new(c.lifo) WasmAstMemory(initialSize.index(), Move(segments));
+    return new(c.lifo) WasmAstMemory(initialSize.index(), maxSize, Move(segments));
 }
 
 static WasmAstImport*
 ParseImport(WasmParseContext& c, WasmAstModule* module)
 {
     WasmName name = c.ts.getIfName();
 
     WasmToken moduleName;
@@ -3809,23 +3818,21 @@ EncodeMemorySection(Encoder& e, WasmAstM
         return true;
 
     size_t offset;
     if (!e.startSection(MemoryLabel, &offset))
         return false;
 
     WasmAstMemory& memory = *module.maybeMemory();
 
-    if (!e.writeCString(InitialLabel))
-        return false;
-
     if (!e.writeVarU32(memory.initialSize()))
         return false;
 
-    if (!e.writeCString(EndLabel))
+    uint32_t maxSize = memory.maxSize() ? *memory.maxSize() : memory.initialSize();
+    if (!e.writeVarU32(maxSize))
         return false;
 
     e.finishSection(offset);
     return true;
 }
 
 static bool
 EncodeFunctionExport(Encoder& e, WasmAstExport& exp)
--- a/js/src/jit-test/tests/wasm/basic-memory.js
+++ b/js/src/jit-test/tests/wasm/basic-memory.js
@@ -1,34 +1,34 @@
 load(libdir + "wasm.js");
 
 if (!wasmIsSupported())
     quit();
 
 function testLoad(type, ext, base, offset, align, expect) {
   assertEq(wasmEvalText(
     '(module' +
-    '  (memory 0x10000' +
+    '  (memory 1' +
     '    (segment 0 "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")' +
     '    (segment 16 "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")' +
     '  )' +
     '  (func (param i32) (result ' + type + ')' +
     '    (' + type + '.load' + ext +
     '     offset=' + offset +
     '     ' + (align != 0 ? 'align=' + align : '') +
     '     (get_local 0)' +
     '    )' +
     '  ) (export "" 0))'
   )(base), expect);
 }
 
 function testStore(type, ext, base, offset, align, value) {
   assertEq(wasmEvalText(
     '(module' +
-    '  (memory 0x10000' +
+    '  (memory 1' +
     '    (segment 0 "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")' +
     '    (segment 16 "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")' +
     '  )' +
     '  (func (param i32) (param ' + type + ') (result ' + type + ')' +
     '    (' + type + '.store' + ext +
     '     offset=' + offset +
     '     ' + (align != 0 ? 'align=' + align : '') +
     '     (get_local 0)' +
@@ -36,34 +36,34 @@ function testStore(type, ext, base, offs
     '    )' +
     '  ) (export "" 0))'
   )(base, value), value);
 }
 
 function testLoadError(type, ext, base, offset, align, errorMsg) {
   assertErrorMessage(() => wasmEvalText(
     '(module' +
-    '  (memory 0x10000' +
+    '  (memory 1' +
     '    (segment 0 "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")' +
     '    (segment 16 "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")' +
     '  )' +
     '  (func (param i32) (result ' + type + ')' +
     '    (' + type + '.load' + ext +
     '     offset=' + offset +
     '     ' + (align != 0 ? 'align=' + align : '') +
     '     (get_local 0)' +
     '    )' +
     '  ) (export "" 0))'
   ), Error, errorMsg);
 }
 
 function testStoreError(type, ext, base, offset, align, errorMsg) {
   assertErrorMessage(() => wasmEvalText(
     '(module' +
-    '  (memory 0x10000' +
+    '  (memory 1' +
     '    (segment 0 "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")' +
     '    (segment 16 "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")' +
     '  )' +
     '  (func (param i32) (param ' + type + ') (result ' + type + ')' +
     '    (' + type + '.store' + ext +
     '     offset=' + offset +
     '     ' + (align != 0 ? 'align=' + align : '') +
     '     (get_local 0)' +
@@ -95,17 +95,17 @@ testLoad('f64', '', 0, 0, 0, 7.949928895
 
 testLoad('i32', '8_s', 16, 0, 0, -0x10);
 testLoad('i32', '8_u', 16, 0, 0, 0xf0);
 testLoad('i32', '16_s', 16, 0, 0, -0xe10);
 testLoad('i32', '16_u', 16, 0, 0, 0xf1f0);
 
 // When these tests fail, uncomment the load/store tests below.
 function testLoadNYI(ext) {
-    assertErrorMessage(() => wasmEvalText(`(module (memory 0x10000) (func (i64.load${ext} (i32.const 0))))`), TypeError, /NYI/);
+    assertErrorMessage(() => wasmEvalText(`(module (memory 1) (func (i64.load${ext} (i32.const 0))))`), TypeError, /NYI/);
 }
 testLoadNYI('');
 testLoadNYI('8_s');
 testLoadNYI('8_u');
 testLoadNYI('16_s');
 testLoadNYI('16_u');
 testLoadNYI('32_s');
 testLoadNYI('32_u');
@@ -117,17 +117,17 @@ testLoadNYI('32_u');
 //testLoad('i64', '32_u', 16, 0, 0, 0x8f9fafb); // TODO: i64 NYI
 
 testStore('i32', '', 0, 0, 0, -0x3f3e2c2c);
 //testStore('i32', '', 1, 0, 0, -0x3f3e2c2c); // TODO: unaligned NYI
 //testStore('i32', '', 0, 1, 0, 0xc0c1d3d4); // TODO: offset NYI
 //testStore('i32', '', 1, 1, 4, 0xc0c1d3d4); // TODO: offset NYI
 
 function testStoreNYI(ext) {
-    assertErrorMessage(() => wasmEvalText(`(module (memory 0x10000) (func (i64.store${ext} (i32.const 0) (i32.const 0))))`), TypeError, /NYI/);
+    assertErrorMessage(() => wasmEvalText(`(module (memory 1) (func (i64.store${ext} (i32.const 0) (i32.const 0))))`), TypeError, /NYI/);
 }
 testStoreNYI('');
 testStoreNYI('8');
 testStoreNYI('16');
 testStoreNYI('32');
 //testStore('i64', '', 0, 0, 0, 0xc0c1d3d4e6e7090a); // TODO: i64 NYI
 //testStore('i64', '', 1, 0, 0, 0xc0c1d3d4e6e7090a); // TODO: i64 NYI
 //testStore('i64', '', 0, 1, 0, 0xc0c1d3d4e6e7090a); // TODO: i64 NYI
@@ -146,16 +146,16 @@ testStore('f64', '', 0, 0, 0, 0.89012345
 //testStore('f64', '', 1, 1, 4, 0.89012345); // TODO: offsets NYI
 
 testStore('i32', '8', 0, 0, 0, 0x23);
 testStore('i32', '16', 0, 0, 0, 0x2345);
 
 testLoadError('i32', '', 0, 0, 3, /memory access alignment must be a power of two/);
 testStoreError('i32', '', 0, 0, 3, /memory access alignment must be a power of two/);
 
-assertErrorMessage(() => wasmEvalText('(module (memory 0x10000) (func (f64.store offset=0 (i32.const 0) (i32.const 0))))'), TypeError, mismatchError("i32", "f64"));
-assertErrorMessage(() => wasmEvalText('(module (memory 0x10000) (func (f64.store offset=0 (i32.const 0) (f32.const 0))))'), TypeError, mismatchError("f32", "f64"));
+assertErrorMessage(() => wasmEvalText('(module (memory 1) (func (f64.store offset=0 (i32.const 0) (i32.const 0))))'), TypeError, mismatchError("i32", "f64"));
+assertErrorMessage(() => wasmEvalText('(module (memory 1) (func (f64.store offset=0 (i32.const 0) (f32.const 0))))'), TypeError, mismatchError("f32", "f64"));
 
-assertErrorMessage(() => wasmEvalText('(module (memory 0x10000) (func (f32.store offset=0 (i32.const 0) (i32.const 0))))'), TypeError, mismatchError("i32", "f32"));
-assertErrorMessage(() => wasmEvalText('(module (memory 0x10000) (func (f32.store offset=0 (i32.const 0) (f64.const 0))))'), TypeError, mismatchError("f64", "f32"));
+assertErrorMessage(() => wasmEvalText('(module (memory 1) (func (f32.store offset=0 (i32.const 0) (i32.const 0))))'), TypeError, mismatchError("i32", "f32"));
+assertErrorMessage(() => wasmEvalText('(module (memory 1) (func (f32.store offset=0 (i32.const 0) (f64.const 0))))'), TypeError, mismatchError("f64", "f32"));
 
-assertErrorMessage(() => wasmEvalText('(module (memory 0x10000) (func (i32.store offset=0 (i32.const 0) (f32.const 0))))'), TypeError, mismatchError("f32", "i32"));
-assertErrorMessage(() => wasmEvalText('(module (memory 0x10000) (func (i32.store offset=0 (i32.const 0) (f64.const 0))))'), TypeError, mismatchError("f64", "i32"));
+assertErrorMessage(() => wasmEvalText('(module (memory 1) (func (i32.store offset=0 (i32.const 0) (f32.const 0))))'), TypeError, mismatchError("f32", "i32"));
+assertErrorMessage(() => wasmEvalText('(module (memory 1) (func (i32.store offset=0 (i32.const 0) (f64.const 0))))'), TypeError, mismatchError("f64", "i32"));
--- a/js/src/jit-test/tests/wasm/basic.js
+++ b/js/src/jit-test/tests/wasm/basic.js
@@ -127,79 +127,77 @@ wasmEvalText(code, {a:()=>{}, b:{c:()=>{
 wasmEvalText('(module (import "a" "" (result i32)))', {a: ()=> {}});
 wasmEvalText('(module (import "a" "" (result f32)))', {a: ()=> {}});
 wasmEvalText('(module (import "a" "" (result f64)))', {a: ()=> {}});
 wasmEvalText('(module (import $foo "a" "" (result f64)))', {a: ()=> {}});
 
 // ----------------------------------------------------------------------------
 // memory
 
-wasmEvalText('(module (memory 65536))');
-wasmEvalText('(module (memory 131072))');
-assertErrorMessage(() => wasmEvalText('(module (memory 0))'), TypeError, /not a multiple of 0x10000/);
-assertErrorMessage(() => wasmEvalText('(module (memory 1))'), TypeError, /not a multiple of 0x10000/);
-assertErrorMessage(() => wasmEvalText('(module (memory 65535))'), TypeError, /not a multiple of 0x10000/);
-assertErrorMessage(() => wasmEvalText('(module (memory 131071))'), TypeError, /not a multiple of 0x10000/);
-assertErrorMessage(() => wasmEvalText('(module (memory 2147483648))'), TypeError, /initial memory size too big/);
+wasmEvalText('(module (memory 0))');
+wasmEvalText('(module (memory 1))');
+assertErrorMessage(() => wasmEvalText('(module (memory 65536))'), TypeError, /initial memory size too big/);
+assertErrorMessage(() => wasmEvalText('(module (memory 32768))'), TypeError, /initial memory size too big/);
 
 // May OOM, but must not crash:
 try {
-    wasmEvalText('(module (memory 2147418112))');
+    wasmEvalText('(module (memory 32767))');
 } catch (e) {
+    print(e);
     assertEq(String(e).indexOf("out of memory") != -1, true);
 }
 
 assertErrorMessage(() => wasmEvalText('(module (export "" memory))'), TypeError, /no memory section/);
 
-var buf = wasmEvalText('(module (memory 65536) (export "" memory))');
+var buf = wasmEvalText('(module (memory 1) (export "" memory))');
 assertEq(buf instanceof ArrayBuffer, true);
 assertEq(buf.byteLength, 65536);
 
-assertErrorMessage(() => wasmEvalText('(module (memory 65536) (export "a" memory) (export "a" memory))'), TypeError, /duplicate export/);
-assertErrorMessage(() => wasmEvalText('(module (memory 65536) (func) (export "a" memory) (export "a" 0))'), TypeError, /duplicate export/);
-var {a, b} = wasmEvalText('(module (memory 65536) (export "a" memory) (export "b" memory))');
+assertErrorMessage(() => wasmEvalText('(module (memory 1) (export "a" memory) (export "a" memory))'), TypeError, /duplicate export/);
+assertErrorMessage(() => wasmEvalText('(module (memory 1) (func) (export "a" memory) (export "a" 0))'), TypeError, /duplicate export/);
+var {a, b} = wasmEvalText('(module (memory 1) (export "a" memory) (export "b" memory))');
 assertEq(a instanceof ArrayBuffer, true);
 assertEq(a, b);
 
-var obj = wasmEvalText('(module (memory 65536) (func (result i32) (i32.const 42)) (func (nop)) (export "a" memory) (export "b" 0) (export "c" 1))');
+var obj = wasmEvalText('(module (memory 1) (func (result i32) (i32.const 42)) (func (nop)) (export "a" memory) (export "b" 0) (export "c" 1))');
 assertEq(obj.a instanceof ArrayBuffer, true);
 assertEq(obj.b instanceof Function, true);
 assertEq(obj.c instanceof Function, true);
 assertEq(obj.a.byteLength, 65536);
 assertEq(obj.b(), 42);
 assertEq(obj.c(), undefined);
 
-var obj = wasmEvalText('(module (memory 65536) (func (result i32) (i32.const 42)) (export "" memory) (export "a" 0) (export "b" 0))');
+var obj = wasmEvalText('(module (memory 1) (func (result i32) (i32.const 42)) (export "" memory) (export "a" 0) (export "b" 0))');
 assertEq(obj instanceof ArrayBuffer, true);
 assertEq(obj.a instanceof Function, true);
 assertEq(obj.b instanceof Function, true);
 assertEq(obj.a, obj.b);
 assertEq(obj.byteLength, 65536);
 assertEq(obj.a(), 42);
 
-var buf = wasmEvalText('(module (memory 65536 (segment 0 "")) (export "" memory))');
+var buf = wasmEvalText('(module (memory 1 (segment 0 "")) (export "" memory))');
 assertEq(new Uint8Array(buf)[0], 0);
 
-var buf = wasmEvalText('(module (memory 65536 (segment 65536 "")) (export "" memory))');
+var buf = wasmEvalText('(module (memory 1 (segment 65536 "")) (export "" memory))');
 assertEq(new Uint8Array(buf)[0], 0);
 
-var buf = wasmEvalText('(module (memory 65536 (segment 0 "a")) (export "" memory))');
+var buf = wasmEvalText('(module (memory 1 (segment 0 "a")) (export "" memory))');
 assertEq(new Uint8Array(buf)[0], 'a'.charCodeAt(0));
 
-var buf = wasmEvalText('(module (memory 65536 (segment 0 "a") (segment 2 "b")) (export "" memory))');
+var buf = wasmEvalText('(module (memory 1 (segment 0 "a") (segment 2 "b")) (export "" memory))');
 assertEq(new Uint8Array(buf)[0], 'a'.charCodeAt(0));
 assertEq(new Uint8Array(buf)[1], 0);
 assertEq(new Uint8Array(buf)[2], 'b'.charCodeAt(0));
 
-var buf = wasmEvalText('(module (memory 65536 (segment 65535 "c")) (export "" memory))');
+var buf = wasmEvalText('(module (memory 1 (segment 65535 "c")) (export "" memory))');
 assertEq(new Uint8Array(buf)[0], 0);
 assertEq(new Uint8Array(buf)[65535], 'c'.charCodeAt(0));
 
-assertErrorMessage(() => wasmEvalText('(module (memory 65536 (segment 65536 "a")) (export "" memory))'), TypeError, /data segment does not fit/);
-assertErrorMessage(() => wasmEvalText('(module (memory 65536 (segment 65535 "ab")) (export "" memory))'), TypeError, /data segment does not fit/);
+assertErrorMessage(() => wasmEvalText('(module (memory 1 (segment 65536 "a")) (export "" memory))'), TypeError, /data segment does not fit/);
+assertErrorMessage(() => wasmEvalText('(module (memory 1 (segment 65535 "ab")) (export "" memory))'), TypeError, /data segment does not fit/);
 
 // ----------------------------------------------------------------------------
 // locals
 
 assertEq(wasmEvalText('(module (func (param i32) (result i32) (get_local 0)) (export "" 0))')(), 0);
 assertEq(wasmEvalText('(module (func (param i32) (result i32) (get_local 0)) (export "" 0))')(42), 42);
 assertEq(wasmEvalText('(module (func (param i32) (param i32) (result i32) (get_local 0)) (export "" 0))')(42, 43), 42);
 assertEq(wasmEvalText('(module (func (param i32) (param i32) (result i32) (get_local 1)) (export "" 0))')(42, 43), 43);