diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index 8e8c295f2ca..18378fe8e02 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -1796,7 +1796,16 @@ BinaryenExpressionRef BinaryenArrayNewData(BinaryenModuleRef module,
       .makeArrayNewData(
         HeapType(type), name, (Expression*)offset, (Expression*)size));
 }
-
+BinaryenExpressionRef BinaryenArrayNewElem(BinaryenModuleRef module,
+                                           BinaryenHeapType type,
+                                           const char* name,
+                                           BinaryenExpressionRef offset,
+                                           BinaryenExpressionRef size) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module)
+      .makeArrayNewElem(
+        HeapType(type), name, (Expression*)offset, (Expression*)size));
+}
 BinaryenExpressionRef BinaryenArrayNewFixed(BinaryenModuleRef module,
                                             BinaryenHeapType type,
                                             BinaryenExpressionRef* values,
@@ -1843,6 +1852,43 @@ BinaryenExpressionRef BinaryenArrayCopy(BinaryenModuleRef module,
                                                    (Expression*)srcIndex,
                                                    (Expression*)length));
 }
+BinaryenExpressionRef BinaryenArrayFill(BinaryenModuleRef module,
+                                        BinaryenExpressionRef ref,
+                                        BinaryenExpressionRef index,
+                                        BinaryenExpressionRef value,
+                                        BinaryenExpressionRef size) {
+  return static_cast<Expression*>(Builder(*(Module*)module)
+                                    .makeArrayFill((Expression*)ref,
+                                                   (Expression*)index,
+                                                   (Expression*)value,
+                                                   (Expression*)size));
+}
+BinaryenExpressionRef BinaryenArrayInitData(BinaryenModuleRef module,
+                                            const char* name,
+                                            BinaryenExpressionRef ref,
+                                            BinaryenExpressionRef index,
+                                            BinaryenExpressionRef offset,
+                                            BinaryenExpressionRef size) {
+  return static_cast<Expression*>(Builder(*(Module*)module)
+                                    .makeArrayInitData(name,
+                                                       (Expression*)ref,
+                                                       (Expression*)index,
+                                                       (Expression*)offset,
+                                                       (Expression*)size));
+}
+BinaryenExpressionRef BinaryenArrayInitElem(BinaryenModuleRef module,
+                                            const char* seg,
+                                            BinaryenExpressionRef ref,
+                                            BinaryenExpressionRef index,
+                                            BinaryenExpressionRef offset,
+                                            BinaryenExpressionRef size) {
+  return static_cast<Expression*>(Builder(*(Module*)module)
+                                    .makeArrayInitElem(seg,
+                                                       (Expression*)ref,
+                                                       (Expression*)index,
+                                                       (Expression*)offset,
+                                                       (Expression*)size));
+}
 BinaryenExpressionRef BinaryenStringNew(BinaryenModuleRef module,
                                         BinaryenOp op,
                                         BinaryenExpressionRef ptr,
@@ -4276,6 +4322,76 @@ BinaryenArrayNewFixedRemoveValueAt(BinaryenExpressionRef expr,
   assert(expression->is<ArrayNewFixed>());
   return static_cast<ArrayNewFixed*>(expression)->values.removeAt(index);
 }
+// ArrayNewData
+const char* BinaryenArrayNewDataGetSegment(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayNewData>());
+  return static_cast<ArrayNewData*>(expression)->segment.str.data();
+}
+void BinaryenArrayNewDataSetSegment(BinaryenExpressionRef expr,
+                                    const char* segment) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayNewData>());
+  static_cast<ArrayNewData*>(expression)->segment = Name(segment);
+}
+BinaryenExpressionRef
+BinaryenArrayNewDataGetOffset(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayNewData>());
+  return static_cast<ArrayNewData*>(expression)->offset;
+}
+void BinaryenArrayNewDataSetOffset(BinaryenExpressionRef expr,
+                                   BinaryenExpressionRef offset) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayNewData>());
+  static_cast<ArrayNewData*>(expression)->offset = offset;
+}
+BinaryenExpressionRef BinaryenArrayNewDataGetSize(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayNewData>());
+  return static_cast<ArrayNewData*>(expression)->size;
+}
+void BinaryenArrayNewDataSetSize(BinaryenExpressionRef expr,
+                                 BinaryenExpressionRef size) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayNewData>());
+  static_cast<ArrayNewData*>(expression)->size = size;
+}
+// ArrayNewElem
+const char* BinaryenArrayNewElemGetSegment(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayNewElem>());
+  return static_cast<ArrayNewElem*>(expression)->segment.str.data();
+}
+void BinaryenArrayNewElemSetSegment(BinaryenExpressionRef expr,
+                                    const char* segment) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayNewElem>());
+  static_cast<ArrayNewElem*>(expression)->segment = Name(segment);
+}
+BinaryenExpressionRef
+BinaryenArrayNewElemGetOffset(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayNewElem>());
+  return static_cast<ArrayNewElem*>(expression)->offset;
+}
+void BinaryenArrayNewElemSetOffset(BinaryenExpressionRef expr,
+                                   BinaryenExpressionRef offset) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayNewElem>());
+  static_cast<ArrayNewElem*>(expression)->offset = offset;
+}
+BinaryenExpressionRef BinaryenArrayNewElemGetSize(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayNewElem>());
+  return static_cast<ArrayNewElem*>(expression)->size;
+}
+void BinaryenArrayNewElemSetSize(BinaryenExpressionRef expr,
+                                 BinaryenExpressionRef size) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayNewElem>());
+  static_cast<ArrayNewElem*>(expression)->size = size;
+}
 // ArrayGet
 BinaryenExpressionRef BinaryenArrayGetGetRef(BinaryenExpressionRef expr) {
   auto* expression = (Expression*)expr;
@@ -4361,6 +4477,55 @@ void BinaryenArrayLenSetRef(BinaryenExpressionRef expr,
   assert(refExpr);
   static_cast<ArrayLen*>(expression)->ref = (Expression*)refExpr;
 }
+// ArrayFill
+BinaryenExpressionRef BinaryenArrayFillGetRef(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayFill>());
+  return static_cast<ArrayFill*>(expression)->ref;
+}
+void BinaryenArrayFillSetRef(BinaryenExpressionRef expr,
+                             BinaryenExpressionRef refExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayFill>());
+  assert(refExpr);
+  static_cast<ArrayFill*>(expression)->ref = (Expression*)refExpr;
+}
+BinaryenExpressionRef BinaryenArrayFillGetIndex(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayFill>());
+  return static_cast<ArrayFill*>(expression)->index;
+}
+void BinaryenArrayFillSetIndex(BinaryenExpressionRef expr,
+                               BinaryenExpressionRef indexExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayFill>());
+  assert(indexExpr);
+  static_cast<ArrayFill*>(expression)->index = (Expression*)indexExpr;
+}
+BinaryenExpressionRef BinaryenArrayFillGetValue(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayFill>());
+  return static_cast<ArrayFill*>(expression)->value;
+}
+void BinaryenArrayFillSetValue(BinaryenExpressionRef expr,
+                               BinaryenExpressionRef valueExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayFill>());
+  assert(valueExpr);
+  static_cast<ArrayFill*>(expression)->value = (Expression*)valueExpr;
+}
+BinaryenExpressionRef BinaryenArrayFillGetSize(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayFill>());
+  return static_cast<ArrayFill*>(expression)->size;
+}
+void BinaryenArrayFillSetSize(BinaryenExpressionRef expr,
+                              BinaryenExpressionRef sizeExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayFill>());
+  assert(sizeExpr);
+  static_cast<ArrayFill*>(expression)->size = (Expression*)sizeExpr;
+}
 // ArrayCopy
 BinaryenExpressionRef BinaryenArrayCopyGetDestRef(BinaryenExpressionRef expr) {
   auto* expression = (Expression*)expr;
@@ -4423,6 +4588,122 @@ void BinaryenArrayCopySetLength(BinaryenExpressionRef expr,
   assert(lengthExpr);
   static_cast<ArrayCopy*>(expression)->length = (Expression*)lengthExpr;
 }
+// ArrayInitData
+const char* BinaryenArrayInitDataGetSegment(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitData>());
+  return static_cast<ArrayInitData*>(expression)->segment.str.data();
+}
+void BinaryenArrayInitDataSetSegment(BinaryenExpressionRef expr,
+                                     const char* segment) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitData>());
+  static_cast<ArrayInitData*>(expression)->segment = Name(segment);
+}
+BinaryenExpressionRef BinaryenArrayInitDataGetRef(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitData>());
+  return static_cast<ArrayInitData*>(expression)->ref;
+}
+void BinaryenArrayInitDataSetRef(BinaryenExpressionRef expr,
+                                 BinaryenExpressionRef ref) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitData>());
+  static_cast<ArrayInitData*>(expression)->ref = ref;
+}
+BinaryenExpressionRef
+BinaryenArrayInitDataGetIndex(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitData>());
+  return static_cast<ArrayInitData*>(expression)->index;
+}
+void BinaryenArrayInitDataSetIndex(BinaryenExpressionRef expr,
+                                   BinaryenExpressionRef index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitData>());
+  static_cast<ArrayInitData*>(expression)->index = index;
+}
+BinaryenExpressionRef
+BinaryenArrayInitDataGetOffset(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitData>());
+  return static_cast<ArrayInitData*>(expression)->offset;
+}
+void BinaryenArrayInitDataSetOffset(BinaryenExpressionRef expr,
+                                    BinaryenExpressionRef offset) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitData>());
+  static_cast<ArrayInitData*>(expression)->offset = offset;
+}
+BinaryenExpressionRef BinaryenArrayInitDataGetSize(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitData>());
+  return static_cast<ArrayInitData*>(expression)->size;
+}
+void BinaryenArrayInitDataSetSize(BinaryenExpressionRef expr,
+                                  BinaryenExpressionRef size) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitData>());
+  static_cast<ArrayInitData*>(expression)->size = size;
+}
+// ArrayInitElem
+const char* BinaryenArrayInitElemGetSegment(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitElem>());
+  return static_cast<ArrayInitElem*>(expression)->segment.str.data();
+}
+void BinaryenArrayInitElemSetSegment(BinaryenExpressionRef expr,
+                                     const char* segment) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitElem>());
+  static_cast<ArrayInitElem*>(expression)->segment = Name(segment);
+}
+BinaryenExpressionRef BinaryenArrayInitElemGetRef(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitElem>());
+  return static_cast<ArrayInitElem*>(expression)->ref;
+}
+void BinaryenArrayInitElemSetRef(BinaryenExpressionRef expr,
+                                 BinaryenExpressionRef ref) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitElem>());
+  static_cast<ArrayInitElem*>(expression)->ref = ref;
+}
+BinaryenExpressionRef
+BinaryenArrayInitElemGetIndex(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitElem>());
+  return static_cast<ArrayInitElem*>(expression)->index;
+}
+void BinaryenArrayInitElemSetIndex(BinaryenExpressionRef expr,
+                                   BinaryenExpressionRef index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitElem>());
+  static_cast<ArrayInitElem*>(expression)->index = index;
+}
+BinaryenExpressionRef
+BinaryenArrayInitElemGetOffset(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitElem>());
+  return static_cast<ArrayInitElem*>(expression)->offset;
+}
+void BinaryenArrayInitElemSetOffset(BinaryenExpressionRef expr,
+                                    BinaryenExpressionRef offset) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitElem>());
+  static_cast<ArrayInitElem*>(expression)->offset = offset;
+}
+BinaryenExpressionRef BinaryenArrayInitElemGetSize(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitElem>());
+  return static_cast<ArrayInitElem*>(expression)->size;
+}
+void BinaryenArrayInitElemSetSize(BinaryenExpressionRef expr,
+                                  BinaryenExpressionRef size) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<ArrayInitElem>());
+  static_cast<ArrayInitElem*>(expression)->size = size;
+}
 // StringNew
 BinaryenOp BinaryenStringNewGetOp(BinaryenExpressionRef expr) {
   auto* expression = (Expression*)expr;
diff --git a/src/binaryen-c.h b/src/binaryen-c.h
index 65a2f12f451..67948d8b79c 100644
--- a/src/binaryen-c.h
+++ b/src/binaryen-c.h
@@ -1050,7 +1050,6 @@ BINARYEN_API BinaryenExpressionRef BinaryenArrayNew(BinaryenModuleRef module,
                                                     BinaryenHeapType type,
                                                     BinaryenExpressionRef size,
                                                     BinaryenExpressionRef init);
-
 BINARYEN_API BinaryenExpressionRef
 BinaryenArrayNewData(BinaryenModuleRef module,
                      BinaryenHeapType type,
@@ -1058,6 +1057,12 @@ BinaryenArrayNewData(BinaryenModuleRef module,
                      BinaryenExpressionRef offset,
                      BinaryenExpressionRef size);
 BINARYEN_API BinaryenExpressionRef
+BinaryenArrayNewElem(BinaryenModuleRef module,
+                     BinaryenHeapType type,
+                     const char* seg,
+                     BinaryenExpressionRef offset,
+                     BinaryenExpressionRef size);
+BINARYEN_API BinaryenExpressionRef
 BinaryenArrayNewFixed(BinaryenModuleRef module,
                       BinaryenHeapType type,
                       BinaryenExpressionRef* values,
@@ -1082,11 +1087,31 @@ BinaryenArrayCopy(BinaryenModuleRef module,
                   BinaryenExpressionRef srcIndex,
                   BinaryenExpressionRef length);
 BINARYEN_API BinaryenExpressionRef
+BinaryenArrayFill(BinaryenModuleRef module,
+                  BinaryenExpressionRef ref,
+                  BinaryenExpressionRef index,
+                  BinaryenExpressionRef value,
+                  BinaryenExpressionRef size);
+BINARYEN_API BinaryenExpressionRef
 BinaryenStringNew(BinaryenModuleRef module,
                   BinaryenOp op,
                   BinaryenExpressionRef ref,
                   BinaryenExpressionRef start,
                   BinaryenExpressionRef end);
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayInitData(BinaryenModuleRef module,
+                      const char* name,
+                      BinaryenExpressionRef ref,
+                      BinaryenExpressionRef index,
+                      BinaryenExpressionRef offset,
+                      BinaryenExpressionRef size);
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayInitElem(BinaryenModuleRef module,
+                      const char* seg,
+                      BinaryenExpressionRef ref,
+                      BinaryenExpressionRef index,
+                      BinaryenExpressionRef offset,
+                      BinaryenExpressionRef size);
 BINARYEN_API BinaryenExpressionRef BinaryenStringConst(BinaryenModuleRef module,
                                                        const char* name);
 BINARYEN_API BinaryenExpressionRef BinaryenStringMeasure(
@@ -2444,6 +2469,36 @@ BinaryenArrayNewFixedInsertValueAt(BinaryenExpressionRef expr,
 BINARYEN_API BinaryenExpressionRef BinaryenArrayNewFixedRemoveValueAt(
   BinaryenExpressionRef expr, BinaryenIndex index);
 
+// ArrayNewData
+
+BINARYEN_API const char*
+BinaryenArrayNewDataGetSegment(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayNewDataSetSegment(BinaryenExpressionRef expr,
+                                                 const char* segment);
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayNewDataGetOffset(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayNewDataSetOffset(BinaryenExpressionRef expr,
+                                                BinaryenExpressionRef offset);
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayNewDataGetSize(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayNewDataSetSize(BinaryenExpressionRef expr,
+                                              BinaryenExpressionRef size);
+
+// ArrayNewElem
+
+BINARYEN_API const char*
+BinaryenArrayNewElemGetSegment(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayNewElemSetSegment(BinaryenExpressionRef expr,
+                                                 const char* segment);
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayNewElemGetOffset(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayNewElemSetOffset(BinaryenExpressionRef expr,
+                                                BinaryenExpressionRef offset);
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayNewElemGetSize(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayNewElemSetSize(BinaryenExpressionRef expr,
+                                              BinaryenExpressionRef size);
+
 // ArrayGet
 
 BINARYEN_API BinaryenExpressionRef
@@ -2480,6 +2535,25 @@ BinaryenArrayLenGetRef(BinaryenExpressionRef expr);
 BINARYEN_API void BinaryenArrayLenSetRef(BinaryenExpressionRef expr,
                                          BinaryenExpressionRef refExpr);
 
+// ArrayFill
+
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayFillGetRef(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayFillSetRef(BinaryenExpressionRef expr,
+                                          BinaryenExpressionRef refExpr);
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayFillGetIndex(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayFillSetIndex(BinaryenExpressionRef expr,
+                                            BinaryenExpressionRef indexExpr);
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayFillGetValue(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayFillSetValue(BinaryenExpressionRef expr,
+                                            BinaryenExpressionRef valueExpr);
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayFillGetSize(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayFillSetSize(BinaryenExpressionRef expr,
+                                           BinaryenExpressionRef sizeExpr);
+
 // ArrayCopy
 
 BINARYEN_API BinaryenExpressionRef
@@ -2506,6 +2580,52 @@ BinaryenArrayCopyGetLength(BinaryenExpressionRef expr);
 BINARYEN_API void BinaryenArrayCopySetLength(BinaryenExpressionRef expr,
                                              BinaryenExpressionRef lengthExpr);
 
+// ArrayInitData
+
+BINARYEN_API const char*
+BinaryenArrayInitDataGetSegment(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayInitDataSetSegment(BinaryenExpressionRef expr,
+                                                  const char* segment);
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayInitDataGetRef(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayInitDataSetRef(BinaryenExpressionRef expr,
+                                              BinaryenExpressionRef ref);
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayInitDataGetIndex(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayInitDataSetIndex(BinaryenExpressionRef expr,
+                                                BinaryenExpressionRef index);
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayInitDataGetOffset(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayInitDataSetOffset(BinaryenExpressionRef expr,
+                                                 BinaryenExpressionRef offset);
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayInitDataGetSize(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayInitDataSetSize(BinaryenExpressionRef expr,
+                                               BinaryenExpressionRef size);
+
+// ArrayInitElem
+
+BINARYEN_API const char*
+BinaryenArrayInitElemGetSegment(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayInitElemSetSegment(BinaryenExpressionRef expr,
+                                                  const char* segment);
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayInitElemGetRef(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayInitElemSetRef(BinaryenExpressionRef expr,
+                                              BinaryenExpressionRef ref);
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayInitElemGetIndex(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayInitElemSetIndex(BinaryenExpressionRef expr,
+                                                BinaryenExpressionRef index);
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayInitElemGetOffset(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayInitElemSetOffset(BinaryenExpressionRef expr,
+                                                 BinaryenExpressionRef offset);
+BINARYEN_API BinaryenExpressionRef
+BinaryenArrayInitElemGetSize(BinaryenExpressionRef expr);
+BINARYEN_API void BinaryenArrayInitElemSetSize(BinaryenExpressionRef expr,
+                                               BinaryenExpressionRef size);
+
 // StringNew
 
 BINARYEN_API BinaryenOp BinaryenStringNewGetOp(BinaryenExpressionRef expr);
diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js
index 6d886d26b1d..5521cc6cca8 100644
--- a/src/js/binaryen.js-post.js
+++ b/src/js/binaryen.js-post.js
@@ -40,12 +40,22 @@ function initializeConstants() {
     ['i31ref', 'I31ref'],
     ['structref', 'Structref'],
     ['stringref', 'Stringref'],
+    ['nullref', 'Nullref'],
+    ['nullexternref', 'NullExternref'],
+    ['nullfuncref', 'NullFuncref'],
     ['unreachable', 'Unreachable'],
     ['auto', 'Auto']
   ].forEach(entry => {
     Module[entry[0]] = Module['_BinaryenType' + entry[1]]();
   });
 
+  [ ['notPacked', 'NotPacked'],
+    ['i8', 'Int8'],
+    ['i16', 'Int16']
+  ].forEach(entry => {
+    Module[entry[0]] = Module['_BinaryenPackedType' + entry[1]]();
+  });
+
   // Expression ids
   Module['ExpressionIds'] = {};
   [ 'Invalid',
@@ -113,10 +123,15 @@ function initializeConstants() {
     'StructSet',
     'ArrayNew',
     'ArrayNewFixed',
+    'ArrayNewData',
+    'ArrayNewElem',
     'ArrayGet',
     'ArraySet',
     'ArrayLen',
+    'ArrayFill',
     'ArrayCopy',
+    'ArrayInitData',
+    'ArrayInitElem',
     'RefAs',
     'StringNew',
     'StringConst',
@@ -705,54 +720,54 @@ function wrapModule(module, self = {}) {
 
   self['global'] = {
     'get'(name, type) {
-      return Module['_BinaryenGlobalGet'](module, strToStack(name), type);
+      return preserveStack(() => Module['_BinaryenGlobalGet'](module, strToStack(name), type));
     },
     'set'(name, value) {
-      return Module['_BinaryenGlobalSet'](module, strToStack(name), value);
+      return preserveStack(() => Module['_BinaryenGlobalSet'](module, strToStack(name), value));
     }
   }
 
   self['table'] = {
     'get'(name, index, type) {
-      return Module['_BinaryenTableGet'](module, strToStack(name), index, type);
+      return preserveStack(() => Module['_BinaryenTableGet'](module, strToStack(name), index, type));
     },
     'set'(name, index, value) {
-      return Module['_BinaryenTableSet'](module, strToStack(name), index, value);
+      return preserveStack(() => Module['_BinaryenTableSet'](module, strToStack(name), index, value));
     },
     'size'(name) {
-      return Module['_BinaryenTableSize'](module, strToStack(name));
+      return preserveStack(() => Module['_BinaryenTableSize'](module, strToStack(name)));
     },
     'grow'(name, value, delta) {
-      return Module['_BinaryenTableGrow'](module, strToStack(name), value, delta);
+      return preserveStack(() => Module['_BinaryenTableGrow'](module, strToStack(name), value, delta));
     }
   }
 
   self['memory'] = {
     // memory64 defaults to undefined/false.
     'size'(name, memory64) {
-      return Module['_BinaryenMemorySize'](module, strToStack(name), memory64);
+      return preserveStack(() => Module['_BinaryenMemorySize'](module, strToStack(name), memory64));
     },
     'grow'(value, name, memory64) {
-      return Module['_BinaryenMemoryGrow'](module, value, strToStack(name), memory64);
+      return preserveStack(() => Module['_BinaryenMemoryGrow'](module, value, strToStack(name), memory64));
     },
     'init'(segment, dest, offset, size, name) {
       return preserveStack(() => Module['_BinaryenMemoryInit'](module, strToStack(segment), dest, offset, size, strToStack(name)));
     },
     'copy'(dest, source, size, destMemory, sourceMemory) {
-      return Module['_BinaryenMemoryCopy'](module, dest, source, size, strToStack(destMemory), strToStack(sourceMemory));
+      return preserveStack(() => Module['_BinaryenMemoryCopy'](module, dest, source, size, strToStack(destMemory), strToStack(sourceMemory)));
     },
     'fill'(dest, value, size, name) {
-      return Module['_BinaryenMemoryFill'](module, dest, value, size, strToStack(name));
+      return preserveStack(() => Module['_BinaryenMemoryFill'](module, dest, value, size, strToStack(name)));
     },
     'atomic': {
       'notify'(ptr, notifyCount, name) {
-        return Module['_BinaryenAtomicNotify'](module, ptr, notifyCount, strToStack(name));
+        return preserveStack(() => Module['_BinaryenAtomicNotify'](module, ptr, notifyCount, strToStack(name)));
       },
       'wait32'(ptr, expected, timeout, name) {
-        return Module['_BinaryenAtomicWait'](module, ptr, expected, timeout, Module['i32'], strToStack(name));
+        return preserveStack(() => Module['_BinaryenAtomicWait'](module, ptr, expected, timeout, Module['i32'], strToStack(name)));
       },
       'wait64'(ptr, expected, timeout, name) {
-        return Module['_BinaryenAtomicWait'](module, ptr, expected, timeout, Module['i64'], strToStack(name));
+        return preserveStack(() => Module['_BinaryenAtomicWait'](module, ptr, expected, timeout, Module['i64'], strToStack(name)));
       }
     }
   }
@@ -765,28 +780,28 @@ function wrapModule(module, self = {}) {
 
   self['i32'] = {
     'load'(offset, align, ptr, name) {
-      return Module['_BinaryenLoad'](module, 4, true, offset, align, Module['i32'], ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenLoad'](module, 4, true, offset, align, Module['i32'], ptr, strToStack(name)));
     },
     'load8_s'(offset, align, ptr, name) {
-      return Module['_BinaryenLoad'](module, 1, true, offset, align, Module['i32'], ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenLoad'](module, 1, true, offset, align, Module['i32'], ptr, strToStack(name)));
     },
     'load8_u'(offset, align, ptr, name) {
-      return Module['_BinaryenLoad'](module, 1, false, offset, align, Module['i32'], ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenLoad'](module, 1, false, offset, align, Module['i32'], ptr, strToStack(name)));
     },
     'load16_s'(offset, align, ptr, name) {
-      return Module['_BinaryenLoad'](module, 2, true, offset, align, Module['i32'], ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenLoad'](module, 2, true, offset, align, Module['i32'], ptr, strToStack(name)));
     },
     'load16_u'(offset, align, ptr, name) {
-      return Module['_BinaryenLoad'](module, 2, false, offset, align, Module['i32'], ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenLoad'](module, 2, false, offset, align, Module['i32'], ptr, strToStack(name)));
     },
     'store'(offset, align, ptr, value, name) {
-      return Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['i32'], strToStack(name));
+      return preserveStack(() => Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['i32'], strToStack(name)));
     },
     'store8'(offset, align, ptr, value, name) {
-      return Module['_BinaryenStore'](module, 1, offset, align, ptr, value, Module['i32'], strToStack(name));
+      return preserveStack(() => Module['_BinaryenStore'](module, 1, offset, align, ptr, value, Module['i32'], strToStack(name)));
     },
     'store16'(offset, align, ptr, value, name) {
-      return Module['_BinaryenStore'](module, 2, offset, align, ptr, value, Module['i32'], strToStack(name));
+      return preserveStack(() => Module['_BinaryenStore'](module, 2, offset, align, ptr, value, Module['i32'], strToStack(name)));
     },
     'const'(x) {
       return preserveStack(() => {
@@ -928,90 +943,111 @@ function wrapModule(module, self = {}) {
     },
     'atomic': {
       'load'(offset, ptr, name) {
-        return Module['_BinaryenAtomicLoad'](module, 4, offset, Module['i32'], ptr, strToStack(name));
+        return preserveStack(() => Module['_BinaryenAtomicLoad'](module, 4, offset, Module['i32'], ptr, strToStack(name)));
       },
       'load8_u'(offset, ptr, name) {
-        return Module['_BinaryenAtomicLoad'](module, 1, offset, Module['i32'], ptr, strToStack(name));
+        return preserveStack(() => Module['_BinaryenAtomicLoad'](module, 1, offset, Module['i32'], ptr, strToStack(name)));
       },
       'load16_u'(offset, ptr, name) {
-        return Module['_BinaryenAtomicLoad'](module, 2, offset, Module['i32'], ptr, strToStack(name));
+        return preserveStack(() => Module['_BinaryenAtomicLoad'](module, 2, offset, Module['i32'], ptr, strToStack(name)));
       },
       'store'(offset, ptr, value, name) {
-        return Module['_BinaryenAtomicStore'](module, 4, offset, ptr, value, Module['i32'], strToStack(name));
+        return preserveStack(() => Module['_BinaryenAtomicStore'](module, 4, offset, ptr, value, Module['i32'], strToStack(name)));
       },
       'store8'(offset, ptr, value, name) {
-        return Module['_BinaryenAtomicStore'](module, 1, offset, ptr, value, Module['i32'], strToStack(name));
+        return preserveStack(() => Module['_BinaryenAtomicStore'](module, 1, offset, ptr, value, Module['i32'], strToStack(name)));
       },
       'store16'(offset, ptr, value, name) {
-        return Module['_BinaryenAtomicStore'](module, 2, offset, ptr, value, Module['i32'], strToStack(name));
+        return preserveStack(() => Module['_BinaryenAtomicStore'](module, 2, offset, ptr, value, Module['i32'], strToStack(name)));
       },
       'rmw': {
         'add'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 4, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 4, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'sub'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 4, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 4, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'and'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 4, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 4, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'or'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 4, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 4, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'xor'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 4, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 4, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'xchg'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 4, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 4, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'cmpxchg'(offset, ptr, expected, replacement, name) {
-          return Module['_BinaryenAtomicCmpxchg'](module, 4, offset, ptr, expected, replacement, Module['i32'], strToStack(name))
+          return preserveStack(() =>
+            Module['_BinaryenAtomicCmpxchg'](module, 4, offset, ptr, expected, replacement, Module['i32'], strToStack(name)));
         },
       },
       'rmw8_u': {
         'add'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 1, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 1, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'sub'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 1, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 1, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'and'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 1, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 1, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'or'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 1, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 1, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'xor'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 1, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 1, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'xchg'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 1, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 1, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'cmpxchg'(offset, ptr, expected, replacement, name) {
-          return Module['_BinaryenAtomicCmpxchg'](module, 1, offset, ptr, expected, replacement, Module['i32'], strToStack(name))
+          return preserveStack(() =>
+            Module['_BinaryenAtomicCmpxchg'](module, 1, offset, ptr, expected, replacement, Module['i32'], strToStack(name)));
         },
       },
       'rmw16_u': {
         'add'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 2, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 2, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'sub'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 2, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 2, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'and'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 2, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 2, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'or'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 2, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 2, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'xor'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 2, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 2, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'xchg'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 2, offset, ptr, value, Module['i32'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 2, offset, ptr, value, Module['i32'], strToStack(name)));
         },
         'cmpxchg'(offset, ptr, expected, replacement, name) {
-          return Module['_BinaryenAtomicCmpxchg'](module, 2, offset, ptr, expected, replacement, Module['i32'], strToStack(name))
+          return preserveStack(() =>
+            Module['_BinaryenAtomicCmpxchg'](module, 2, offset, ptr, expected, replacement, Module['i32'], strToStack(name)));
         },
       },
     },
@@ -1022,37 +1058,37 @@ function wrapModule(module, self = {}) {
 
   self['i64'] = {
     'load'(offset, align, ptr, name) {
-      return Module['_BinaryenLoad'](module, 8, true, offset, align, Module['i64'], ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenLoad'](module, 8, true, offset, align, Module['i64'], ptr, strToStack(name)));
     },
     'load8_s'(offset, align, ptr, name) {
-      return Module['_BinaryenLoad'](module, 1, true, offset, align, Module['i64'], ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenLoad'](module, 1, true, offset, align, Module['i64'], ptr, strToStack(name)));
     },
     'load8_u'(offset, align, ptr, name) {
-      return Module['_BinaryenLoad'](module, 1, false, offset, align, Module['i64'], ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenLoad'](module, 1, false, offset, align, Module['i64'], ptr, strToStack(name)));
     },
     'load16_s'(offset, align, ptr, name) {
-      return Module['_BinaryenLoad'](module, 2, true, offset, align, Module['i64'], ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenLoad'](module, 2, true, offset, align, Module['i64'], ptr, strToStack(name)));
     },
     'load16_u'(offset, align, ptr, name) {
-      return Module['_BinaryenLoad'](module, 2, false, offset, align, Module['i64'], ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenLoad'](module, 2, false, offset, align, Module['i64'], ptr, strToStack(name)));
     },
     'load32_s'(offset, align, ptr, name) {
-      return Module['_BinaryenLoad'](module, 4, true, offset, align, Module['i64'], ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenLoad'](module, 4, true, offset, align, Module['i64'], ptr, strToStack(name)));
     },
     'load32_u'(offset, align, ptr, name) {
-      return Module['_BinaryenLoad'](module, 4, false, offset, align, Module['i64'], ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenLoad'](module, 4, false, offset, align, Module['i64'], ptr, strToStack(name)));
     },
     'store'(offset, align, ptr, value, name) {
-      return Module['_BinaryenStore'](module, 8, offset, align, ptr, value, Module['i64'], strToStack(name));
+      return preserveStack(() => Module['_BinaryenStore'](module, 8, offset, align, ptr, value, Module['i64'], strToStack(name)));
     },
     'store8'(offset, align, ptr, value, name) {
-      return Module['_BinaryenStore'](module, 1, offset, align, ptr, value, Module['i64'], strToStack(name));
+      return preserveStack(() => Module['_BinaryenStore'](module, 1, offset, align, ptr, value, Module['i64'], strToStack(name)));
     },
     'store16'(offset, align, ptr, value, name) {
-      return Module['_BinaryenStore'](module, 2, offset, align, ptr, value, Module['i64'], strToStack(name));
+      return preserveStack(() => Module['_BinaryenStore'](module, 2, offset, align, ptr, value, Module['i64'], strToStack(name)));
     },
     'store32'(offset, align, ptr, value, name) {
-      return Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['i64'], strToStack(name));
+      return preserveStack(() => Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['i64'], strToStack(name)));
     },
     'const'(x, y) {
       return preserveStack(() => {
@@ -1200,119 +1236,147 @@ function wrapModule(module, self = {}) {
     },
     'atomic': {
       'load'(offset, ptr, name) {
-        return Module['_BinaryenAtomicLoad'](module, 8, offset, Module['i64'], ptr, strToStack(name));
+        return preserveStack(() => Module['_BinaryenAtomicLoad'](module, 8, offset, Module['i64'], ptr, strToStack(name)));
       },
       'load8_u'(offset, ptr, name) {
-        return Module['_BinaryenAtomicLoad'](module, 1, offset, Module['i64'], ptr, strToStack(name));
+        return preserveStack(() => Module['_BinaryenAtomicLoad'](module, 1, offset, Module['i64'], ptr, strToStack(name)));
       },
       'load16_u'(offset, ptr, name) {
-        return Module['_BinaryenAtomicLoad'](module, 2, offset, Module['i64'], ptr, strToStack(name));
+        return preserveStack(() => Module['_BinaryenAtomicLoad'](module, 2, offset, Module['i64'], ptr, strToStack(name)));
       },
       'load32_u'(offset, ptr, name) {
-        return Module['_BinaryenAtomicLoad'](module, 4, offset, Module['i64'], ptr, strToStack(name));
+        return preserveStack(() => Module['_BinaryenAtomicLoad'](module, 4, offset, Module['i64'], ptr, strToStack(name)));
       },
       'store'(offset, ptr, value, name) {
-        return Module['_BinaryenAtomicStore'](module, 8, offset, ptr, value, Module['i64'], strToStack(name));
+        return preserveStack(() => Module['_BinaryenAtomicStore'](module, 8, offset, ptr, value, Module['i64'], strToStack(name)));
       },
       'store8'(offset, ptr, value, name) {
-        return Module['_BinaryenAtomicStore'](module, 1, offset, ptr, value, Module['i64'], strToStack(name));
+        return preserveStack(() => Module['_BinaryenAtomicStore'](module, 1, offset, ptr, value, Module['i64'], strToStack(name)));
       },
       'store16'(offset, ptr, value, name) {
-        return Module['_BinaryenAtomicStore'](module, 2, offset, ptr, value, Module['i64'], strToStack(name));
+        return preserveStack(() => Module['_BinaryenAtomicStore'](module, 2, offset, ptr, value, Module['i64'], strToStack(name)));
       },
       'store32'(offset, ptr, value, name) {
-        return Module['_BinaryenAtomicStore'](module, 4, offset, ptr, value, Module['i64'], strToStack(name));
+        return preserveStack(() => Module['_BinaryenAtomicStore'](module, 4, offset, ptr, value, Module['i64'], strToStack(name)));
       },
       'rmw': {
         'add'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 8, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 8, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'sub'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 8, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 8, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'and'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 8, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 8, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'or'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 8, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 8, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'xor'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 8, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 8, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'xchg'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 8, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 8, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'cmpxchg'(offset, ptr, expected, replacement, name) {
-          return Module['_BinaryenAtomicCmpxchg'](module, 8, offset, ptr, expected, replacement, Module['i64'], strToStack(name))
+          return preserveStack(() =>
+            Module['_BinaryenAtomicCmpxchg'](module, 8, offset, ptr, expected, replacement, Module['i64'], strToStack(name)));
         },
       },
       'rmw8_u': {
         'add'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 1, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 1, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'sub'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 1, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 1, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'and'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 1, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 1, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'or'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 1, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 1, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'xor'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 1, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 1, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'xchg'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 1, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 1, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'cmpxchg'(offset, ptr, expected, replacement, name) {
-          return Module['_BinaryenAtomicCmpxchg'](module, 1, offset, ptr, expected, replacement, Module['i64'], strToStack(name))
+          return preserveStack(() =>
+            Module['_BinaryenAtomicCmpxchg'](module, 1, offset, ptr, expected, replacement, Module['i64'], strToStack(name)));
         },
       },
       'rmw16_u': {
         'add'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 2, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 2, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'sub'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 2, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 2, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'and'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 2, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 2, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'or'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 2, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 2, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'xor'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 2, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 2, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'xchg'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 2, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 2, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'cmpxchg'(offset, ptr, expected, replacement, name) {
-          return Module['_BinaryenAtomicCmpxchg'](module, 2, offset, ptr, expected, replacement, Module['i64'], strToStack(name))
+          return preserveStack(() =>
+            Module['_BinaryenAtomicCmpxchg'](module, 2, offset, ptr, expected, replacement, Module['i64'], strToStack(name)));
         },
       },
       'rmw32_u': {
         'add'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 4, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 4, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'sub'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 4, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 4, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'and'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 4, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 4, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'or'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 4, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 4, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'xor'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 4, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 4, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'xchg'(offset, ptr, value, name) {
-          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 4, offset, ptr, value, Module['i64'], strToStack(name));
+          return preserveStack(() =>
+            Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 4, offset, ptr, value, Module['i64'], strToStack(name)));
         },
         'cmpxchg'(offset, ptr, expected, replacement, name) {
-          return Module['_BinaryenAtomicCmpxchg'](module, 4, offset, ptr, expected, replacement, Module['i64'], strToStack(name))
+          return preserveStack(() =>
+            Module['_BinaryenAtomicCmpxchg'](module, 4, offset, ptr, expected, replacement, Module['i64'], strToStack(name)));
         },
       },
     },
@@ -1323,10 +1387,10 @@ function wrapModule(module, self = {}) {
 
   self['f32'] = {
     'load'(offset, align, ptr, name) {
-      return Module['_BinaryenLoad'](module, 4, true, offset, align, Module['f32'], ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenLoad'](module, 4, true, offset, align, Module['f32'], ptr, strToStack(name)));
     },
     'store'(offset, align, ptr, value, name) {
-      return Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['f32'], strToStack(name));
+      return preserveStack(() => Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['f32'], strToStack(name)));
     },
     'const'(x) {
       return preserveStack(() => {
@@ -1431,10 +1495,10 @@ function wrapModule(module, self = {}) {
 
   self['f64'] = {
     'load'(offset, align, ptr, name) {
-      return Module['_BinaryenLoad'](module, 8, true, offset, align, Module['f64'], ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenLoad'](module, 8, true, offset, align, Module['f64'], ptr, strToStack(name)));
     },
     'store'(offset, align, ptr, value, name) {
-      return Module['_BinaryenStore'](module, 8, offset, align, ptr, value, Module['f64'], strToStack(name));
+      return preserveStack(() => Module['_BinaryenStore'](module, 8, offset, align, ptr, value, Module['f64'], strToStack(name)));
     },
     'const'(x) {
       return preserveStack(() => {
@@ -1539,70 +1603,78 @@ function wrapModule(module, self = {}) {
 
   self['v128'] = {
     'load'(offset, align, ptr, name) {
-      return Module['_BinaryenLoad'](module, 16, false, offset, align, Module['v128'], ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenLoad'](module, 16, false, offset, align, Module['v128'], ptr, strToStack(name)));
     },
     'load8_splat'(offset, align, ptr, name) {
-      return Module['_BinaryenSIMDLoad'](module, Module['Load8SplatVec128'], offset, align, ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenSIMDLoad'](module, Module['Load8SplatVec128'], offset, align, ptr, strToStack(name)));
     },
     'load16_splat'(offset, align, ptr, name) {
-      return Module['_BinaryenSIMDLoad'](module, Module['Load16SplatVec128'], offset, align, ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenSIMDLoad'](module, Module['Load16SplatVec128'], offset, align, ptr, strToStack(name)));
     },
     'load32_splat'(offset, align, ptr, name) {
-      return Module['_BinaryenSIMDLoad'](module, Module['Load32SplatVec128'], offset, align, ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenSIMDLoad'](module, Module['Load32SplatVec128'], offset, align, ptr, strToStack(name)));
     },
     'load64_splat'(offset, align, ptr, name) {
-      return Module['_BinaryenSIMDLoad'](module, Module['Load64SplatVec128'], offset, align, ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenSIMDLoad'](module, Module['Load64SplatVec128'], offset, align, ptr, strToStack(name)));
     },
     'load8x8_s'(offset, align, ptr, name) {
-      return Module['_BinaryenSIMDLoad'](module, Module['Load8x8SVec128'], offset, align, ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenSIMDLoad'](module, Module['Load8x8SVec128'], offset, align, ptr, strToStack(name)));
     },
     'load8x8_u'(offset, align, ptr, name) {
-      return Module['_BinaryenSIMDLoad'](module, Module['Load8x8UVec128'], offset, align, ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenSIMDLoad'](module, Module['Load8x8UVec128'], offset, align, ptr, strToStack(name)));
     },
     'load16x4_s'(offset, align, ptr, name) {
-      return Module['_BinaryenSIMDLoad'](module, Module['Load16x4SVec128'], offset, align, ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenSIMDLoad'](module, Module['Load16x4SVec128'], offset, align, ptr, strToStack(name)));
     },
     'load16x4_u'(offset, align, ptr, name) {
-      return Module['_BinaryenSIMDLoad'](module, Module['Load16x4UVec128'], offset, align, ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenSIMDLoad'](module, Module['Load16x4UVec128'], offset, align, ptr, strToStack(name)));
     },
     'load32x2_s'(offset, align, ptr, name) {
-      return Module['_BinaryenSIMDLoad'](module, Module['Load32x2SVec128'], offset, align, ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenSIMDLoad'](module, Module['Load32x2SVec128'], offset, align, ptr, strToStack(name)));
     },
     'load32x2_u'(offset, align, ptr, name) {
-      return Module['_BinaryenSIMDLoad'](module, Module['Load32x2UVec128'], offset, align, ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenSIMDLoad'](module, Module['Load32x2UVec128'], offset, align, ptr, strToStack(name)));
     },
     'load32_zero'(offset, align, ptr, name) {
-      return Module['_BinaryenSIMDLoad'](module, Module['Load32ZeroVec128'], offset, align, ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenSIMDLoad'](module, Module['Load32ZeroVec128'], offset, align, ptr, strToStack(name)));
     },
     'load64_zero'(offset, align, ptr, name) {
-      return Module['_BinaryenSIMDLoad'](module, Module['Load64ZeroVec128'], offset, align, ptr, strToStack(name));
+      return preserveStack(() => Module['_BinaryenSIMDLoad'](module, Module['Load64ZeroVec128'], offset, align, ptr, strToStack(name)));
     },
     'load8_lane'(offset, align, index, ptr, vec, name) {
-      return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Load8LaneVec128'], offset, align, index, ptr, vec, strToStack(name));
+      return preserveStack(() =>
+        Module['_BinaryenSIMDLoadStoreLane'](module, Module['Load8LaneVec128'], offset, align, index, ptr, vec, strToStack(name)));
     },
     'load16_lane'(offset, align, index, ptr, vec, name) {
-      return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Load16LaneVec128'], offset, align, index, ptr, vec, strToStack(name));
+      return preserveStack(() =>
+        Module['_BinaryenSIMDLoadStoreLane'](module, Module['Load16LaneVec128'], offset, align, index, ptr, vec, strToStack(name)));
     },
     'load32_lane'(offset, align, index, ptr, vec, name) {
-      return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Load32LaneVec128'], offset, align, index, ptr, vec, strToStack(name));
+      return preserveStack(() =>
+        Module['_BinaryenSIMDLoadStoreLane'](module, Module['Load32LaneVec128'], offset, align, index, ptr, vec, strToStack(name)));
     },
     'load64_lane'(offset, align, index, ptr, vec, name) {
-      return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Load64LaneVec128'], offset, align, index, ptr, vec, strToStack(name));
+      return preserveStack(() =>
+        Module['_BinaryenSIMDLoadStoreLane'](module, Module['Load64LaneVec128'], offset, align, index, ptr, vec, strToStack(name)));
     },
     'store8_lane'(offset, align, index, ptr, vec, name) {
-      return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Store8LaneVec128'], offset, align, index, ptr, vec, strToStack(name));
+      return preserveStack(() =>
+        Module['_BinaryenSIMDLoadStoreLane'](module, Module['Store8LaneVec128'], offset, align, index, ptr, vec, strToStack(name)));
     },
     'store16_lane'(offset, align, index, ptr, vec, name) {
-      return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Store16LaneVec128'], offset, align, index, ptr, vec, strToStack(name));
+      return preserveStack(() =>
+        Module['_BinaryenSIMDLoadStoreLane'](module, Module['Store16LaneVec128'], offset, align, index, ptr, vec, strToStack(name)));
     },
     'store32_lane'(offset, align, index, ptr, vec, name) {
-      return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Store32LaneVec128'], offset, align, index, ptr, vec, strToStack(name));
+      return preserveStack(() =>
+        Module['_BinaryenSIMDLoadStoreLane'](module, Module['Store32LaneVec128'], offset, align, index, ptr, vec, strToStack(name)));
     },
     'store64_lane'(offset, align, index, ptr, vec, name) {
-      return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Store64LaneVec128'], offset, align, index, ptr, vec, strToStack(name));
+      return preserveStack(() =>
+        Module['_BinaryenSIMDLoadStoreLane'](module, Module['Store64LaneVec128'], offset, align, index, ptr, vec, strToStack(name)));
     },
     'store'(offset, align, ptr, value, name) {
-      return Module['_BinaryenStore'](module, 16, offset, align, ptr, value, Module['v128'], strToStack(name));
+      return preserveStack(() => Module['_BinaryenStore'](module, 16, offset, align, ptr, value, Module['v128'], strToStack(name)));
     },
     'const'(i8s) {
       return preserveStack(() => {
@@ -2333,6 +2405,12 @@ function wrapModule(module, self = {}) {
     },
     'eq'(left, right) {
       return Module['_BinaryenRefEq'](module, left, right);
+    },
+    'test'(value, castType) {
+      return Module['_BinaryenRefTest'](module, value, castType);
+    },
+    'cast'(value, castType) {
+      return Module['_BinaryenRefCast'](module, value, castType);
     }
   };
 
@@ -2366,7 +2444,7 @@ function wrapModule(module, self = {}) {
     return preserveStack(() => Module['_BinaryenThrow'](module, strToStack(tag), i32sToStack(operands), operands.length));
   };
   self['rethrow'] = function(target) {
-    return Module['_BinaryenRethrow'](module, strToStack(target));
+    return preserveStack(() => Module['_BinaryenRethrow'](module, strToStack(target)));
   };
 
   self['tuple'] = {
@@ -2387,13 +2465,90 @@ function wrapModule(module, self = {}) {
     }
   };
 
-  // TODO: any.convert_extern
-  // TODO: extern.convert_any
-  // TODO: ref.test
-  // TODO: ref.cast
-  // TODO: br_on_*
-  // TODO: struct.*
-  // TODO: array.*
+  self['any'] = {
+    'convert_extern'() {
+      return Module['_BinaryenRefAsAnyConvertExtern']();
+    }
+  };
+
+  self['extern'] = {
+    'convert_any'() {
+      return Module['_BinaryenRefAsExternConvertAny']();
+    }
+  };
+
+  self['br_on_null'] = function(name, value) {
+    return preserveStack(() => Module['_BinaryenBrOn'](module, Module['BrOnNull'], strToStack(name), value, Module['unreachable']));
+  };
+
+  self['br_on_non_null'] = function(name, value) {
+    return preserveStack(() => Module['_BinaryenBrOn'](module, Module['BrOnNonNull'], strToStack(name), value, Module['unreachable']));
+  };
+
+  self['br_on_cast'] = function(name, value, castType) {
+    return preserveStack(() => Module['_BinaryenBrOn'](module, Module['BrOnCast'], strToStack(name), value, castType));
+  };
+
+  self['br_on_cast_fail'] = function(name, value, castType) {
+    return preserveStack(() => Module['_BinaryenBrOn'](module, Module['BrOnCastFail'], strToStack(name), value, castType));
+  };
+
+  self['struct'] = {
+    'new'(operands, type) {
+      return preserveStack(() => Module['_BinaryenStructNew'](module, i32sToStack(operands), operands.length, type));
+    },
+    'new_default'(type) {
+      // Passing in null for |operands| (and 0 for |numOperands|) implies this is
+      // struct.new_default.
+      return Module['_BinaryenStructNew'](module, 0, 0, type);
+    },
+    'get'(index, ref, type, isSigned) {
+      return Module['_BinaryenStructGet'](module, index, ref, type, isSigned);
+    },
+    'set'(index, ref, value) {
+      return Module['_BinaryenStructSet'](module, index, ref, value);
+    }
+  };
+
+  self['array'] = {
+    'new'(type, size, init) {
+      return Module['_BinaryenArrayNew'](module, type, size, init);
+    },
+    'new_default'(type, size) {
+      return Module['_BinaryenArrayNew'](module, type, size, 0);
+    },
+    'new_fixed'(type, values) {
+      return preserveStack(() => Module['_BinaryenArrayNewFixed'](module, type, i32sToStack(values), values.length));
+    },
+    'new_data'(type, name, offset, size) {
+      return preserveStack(() => Module['_BinaryenArrayNewData'](module, type, strToStack(name), offset, size));
+    },
+    'new_elem'(type, name, offset, size) {
+      return preserveStack(() => Module['_BinaryenArrayNewElem'](module, type, strToStack(name), offset, size));
+    },
+    'get'(ref, index, type, isSigned) {
+      return Module['_BinaryenArrayGet'](module, ref, index, type, isSigned);
+    },
+    'set'(ref, index, value) {
+      return Module['_BinaryenArraySet'](module, ref, index, value);
+    },
+    'len'(ref) {
+      return Module['_BinaryenArrayLen'](module, ref);
+    },
+    'fill'(ref, index, value, size) {
+      return Module['_BinaryenArrayFill'](module, ref, index, value, size);
+    },
+    'copy'(destRef, destIndex, srcRef, srcIndex, length) {
+      return Module['_BinaryenArrayCopy'](module, destRef, destIndex, srcRef, srcIndex, length);
+    },
+    'init_data'(name, ref, index, offset, size) {
+      return preserveStack(() => Module['_BinaryenArrayInitData'](module, strToStack(name), ref, index, offset, size));
+    },
+    'init_elem'(name, ref, index, offset, size) {
+      return preserveStack(() => Module['_BinaryenArrayInitElem'](module, strToStack(name), ref, index, offset, size));
+    }
+  };
+  
   // TODO: string.*
 
   // 'Module' operations
@@ -2556,40 +2711,44 @@ function wrapModule(module, self = {}) {
     return Boolean(Module['_BinaryenHasMemory'](module));
   };
   self['getMemoryInfo'] = function(name) {
-    var memoryInfo = {
-      'module': UTF8ToString(Module['_BinaryenMemoryImportGetModule'](module, strToStack(name))),
-      'base': UTF8ToString(Module['_BinaryenMemoryImportGetBase'](module, strToStack(name))),
-      'initial': Module['_BinaryenMemoryGetInitial'](module, strToStack(name)),
-      'shared': Boolean(Module['_BinaryenMemoryIsShared'](module, strToStack(name))),
-      'is64': Boolean(Module['_BinaryenMemoryIs64'](module, strToStack(name))),
-    };
-    if (Module['_BinaryenMemoryHasMax'](module, strToStack(name))) {
-      memoryInfo['max'] = Module['_BinaryenMemoryGetMax'](module, strToStack(name));
-    }
-    return memoryInfo;
+    return preserveStack(() => {
+      var memoryInfo = {
+        'module': UTF8ToString(Module['_BinaryenMemoryImportGetModule'](module, strToStack(name))),
+        'base': UTF8ToString(Module['_BinaryenMemoryImportGetBase'](module, strToStack(name))),
+        'initial': Module['_BinaryenMemoryGetInitial'](module, strToStack(name)),
+        'shared': Boolean(Module['_BinaryenMemoryIsShared'](module, strToStack(name))),
+        'is64': Boolean(Module['_BinaryenMemoryIs64'](module, strToStack(name))),
+      };
+      if (Module['_BinaryenMemoryHasMax'](module, strToStack(name))) {
+        memoryInfo['max'] = Module['_BinaryenMemoryGetMax'](module, strToStack(name));
+      }
+      return memoryInfo;
+    });
   };
   self['getNumMemorySegments'] = function() {
     return Module['_BinaryenGetNumMemorySegments'](module);
   };
   self['getMemorySegmentInfo'] = function(name) {
-    const passive = Boolean(Module['_BinaryenGetMemorySegmentPassive'](module, strToStack(name)));
-    let offset = null;
-    if (!passive) {
-      offset = Module['_BinaryenGetMemorySegmentByteOffset'](module, strToStack(name));
-    }
-    return {
-      'offset': offset,
-      'data': (function(){
-        const size = Module['_BinaryenGetMemorySegmentByteLength'](module, strToStack(name));
-        const ptr = _malloc(size);
-        Module['_BinaryenCopyMemorySegmentData'](module, strToStack(name), ptr);
-        const res = new Uint8Array(size);
-        res.set(HEAP8.subarray(ptr, ptr + size));
-        _free(ptr);
-        return res.buffer;
-      })(),
-      'passive': passive
-    };
+    return preserveStack(() => {
+      const passive = Boolean(Module['_BinaryenGetMemorySegmentPassive'](module, strToStack(name)));
+      let offset = null;
+      if (!passive) {
+        offset = Module['_BinaryenGetMemorySegmentByteOffset'](module, strToStack(name));
+      }
+      return {
+        'offset': offset,
+        'data': (function(){
+          const size = Module['_BinaryenGetMemorySegmentByteLength'](module, strToStack(name));
+          const ptr = _malloc(size);
+          Module['_BinaryenCopyMemorySegmentData'](module, strToStack(name), ptr);
+          const res = new Uint8Array(size);
+          res.set(HEAP8.subarray(ptr, ptr + size));
+          _free(ptr);
+          return res.buffer;
+        })(),
+        'passive': passive
+      };
+    });
   };
   self['setStart'] = function(start) {
     return Module['_BinaryenSetStart'](module, start);
@@ -2603,6 +2762,16 @@ function wrapModule(module, self = {}) {
   self['setFeatures'] = function(features) {
     Module['_BinaryenModuleSetFeatures'](module, features);
   };
+  self['setTypeName'] = function(heapType, name) {
+    return preserveStack(() =>
+      Module['_BinaryenModuleSetTypeName'](module, heapType, strToStack(name))
+    );
+  };
+  self['setFieldName'] = function(heapType, index, name) {
+    return preserveStack(() =>
+      Module['_BinaryenModuleSetFieldName'](module, heapType, index, strToStack(name))
+    );
+  };
   self['addCustomSection'] = function(name, contents) {
     return preserveStack(() =>
       Module['_BinaryenAddCustomSection'](module, strToStack(name), i8sToStack(contents), contents.length)
@@ -2724,6 +2893,92 @@ function wrapModule(module, self = {}) {
 }
 Module['wrapModule'] = wrapModule;
 
+// 'TypeBuilder' interface
+/** @constructor */
+Module['TypeBuilder'] = function(size) {
+  const builder = Module['_TypeBuilderCreate'](size);
+  this['ptr'] = builder;
+
+  this['grow'] = function(count) {
+    Module['_TypeBuilderGrow'](builder, count);
+  };
+  this['getSize'] = function() {
+    return Module['_TypeBuilderGetSize'](builder);
+  };
+  this['setSignatureType'] = function(index, paramTypes, resultTypes) {
+    Module['_TypeBuilderSetSignatureType'](builder, index, paramTypes, resultTypes);
+  };
+  this['setStructType'] = function(index, fields = []) {
+    // fields are assumed to be { type: type ref, packedType: type ref, mutable: bool }
+    preserveStack(() => {
+      const numFields = fields.length;
+      const types = new Array(numFields);
+      const packedTypes = new Array(numFields);
+      const mutables = new Array(numFields);
+      for (let i = 0; i < numFields; i++) {
+        const { ['type']: type, ['packedType']: packedType, ['mutable']: mutable } = fields[i];
+        types[i] = type;
+        packedTypes[i] = packedType;
+        mutables[i] = mutable;
+      }
+      Module['_TypeBuilderSetStructType'](builder,
+        index,
+        i32sToStack(types), i32sToStack(packedTypes),
+        i8sToStack(mutables),
+        numFields
+      );
+    });
+  };
+  this['setArrayType'] = function(index, elementType, elementPackedType, elementMutable) {
+    Module['_TypeBuilderSetArrayType'](builder,
+      index, elementType, elementPackedType, elementMutable
+    );
+  };
+  this['getTempHeapType'] = function(index) {
+    return Module['_TypeBuilderGetTempHeapType'](builder, index);
+  };
+  this['getTempTupleType'] = function(types) {
+    return preserveStack(() => {
+      return Module['_TypeBuilderGetTempTupleType'](builder, i32sToStack(types), types.length);
+    });
+  };
+  this['getTempRefType'] = function(heapType, nullable) {
+    return Module['_TypeBuilderGetTempRefType'](builder, heapType, nullable);
+  };
+  this['setSubType'] = function(index, superType) {
+    Module['_TypeBuilderSetSubType'](builder, index, superType);
+  };
+  this['setOpen'] = function(index) {
+    Module['_TypeBuilderSetOpen'](builder, index);
+  };
+  this['createRecGroup'] = function(index, length) {
+    Module['_TypeBuilderCreateRecGroup'](builder, index, length);
+  };
+  this['buildAndDispose'] = function() {
+    return preserveStack(() => {
+      const numTypes = this['getSize']();
+      const array = stackAlloc(numTypes << 2);
+      if (!Module['_TypeBuilderBuildAndDispose'](builder, array, 0, 0))
+        throw new TypeError('TypeBuilder.buildAndDispose failed');
+      const types = new Array(numTypes);
+      for (let i = 0; i < numTypes; i++) {
+        types[i] = HEAPU32[(array >>> 2) + i];
+      }
+      return types;
+    });
+  };
+}
+
+// Gets the type from a heap type generated by TypeBuilder
+Module['getTypeFromHeapType'] = function(heapType, nullable) {
+  return Module['_BinaryenTypeFromHeapType'](heapType, nullable);
+};
+
+// Gets the heap type of a type
+Module['getHeapType'] = function(type) {
+  return Module['_BinaryenTypeGetHeapType'](type);
+};
+
 // 'Relooper' interface
 /** @constructor */
 Module['Relooper'] = function(module) {
@@ -2803,7 +3058,7 @@ Module['getExpressionType'] = function(expr) {
 Module['getExpressionInfo'] = function(expr) {
   const id = Module['_BinaryenExpressionGetId'](expr);
   const type = Module['_BinaryenExpressionGetType'](expr);
-  switch (id) {
+  switch (id) { // TODO: GC instructions
     case Module['BlockId']:
       return {
         'id': id,
@@ -4693,6 +4948,406 @@ Module['RefEq'] = makeExpressionWrapper({
   }
 });
 
+Module['RefTest'] = makeExpressionWrapper({
+  'getRef'(expr) {
+    return Module['_BinaryenRefTestGetRef'](expr);
+  },
+  'setRef'(expr, ref) {
+    Module['_BinaryenRefTestSetRef'](expr, ref);
+  },
+  'getCastType'(expr) {
+    return Module['_BinaryenRefTestGetCastType'](expr);
+  },
+  'setCastType'(expr, castType) {
+    Module['_BinaryenRefTestSetCastType'](expr, castType);
+  }
+});
+
+Module['RefCast'] = makeExpressionWrapper({
+  'getRef'(expr) {
+    return Module['_BinaryenRefCastGetRef'](expr);
+  },
+  'setRef'(expr, ref) {
+    Module['_BinaryenRefCastSetRef'](expr, ref);
+  }
+});
+
+// TODO: any.convert_extern
+// TODO: extern.convert_any
+
+Module['BrOn'] = makeExpressionWrapper({
+  'getOp'(expr) {
+    return Module['_BinaryenBrOnGetOp'](expr);
+  },
+  'setOp'(expr, op) {
+    Module['_BinaryenBrOnSetOp'](expr, op);
+  },
+  'getName'(expr) {
+    return UTF8ToString(Module['_BinaryenBrOnGetName'](expr));
+  },
+  'setName'(expr, name) {
+    preserveStack(() => Module['_BinaryenBrOnSetName'](expr, strToStack(name)));
+  },
+  'getRef'(expr) {
+    return Module['_BinaryenBrOnGetRef'](expr);
+  },
+  'setRef'(expr, ref) {
+    Module['_BinaryenBrOnSetRef'](expr, ref);
+  },
+  'getCastType'(expr) {
+    return Module['_BinaryenBrOnGetCastType'](expr);
+  },
+  'setCastType'(expr, castType) {
+    Module['_BinaryenBrOnSetCastType'](expr, castType);
+  }
+});
+
+Module['StructNew'] = makeExpressionWrapper({
+  'getNumOperands'(expr) {
+    return Module['_BinaryenStructNewGetNumOperands'](expr);
+  },
+  'getOperands'(expr) {
+    return getAllNested(expr, Module['_BinaryenStructNewGetNumOperands'], Module['_BinaryenStructNewGetOperandAt']);
+  },
+  'setOperands'(expr, operands) {
+    setAllNested(
+      expr,
+      operands,
+      Module['_BinaryenStructNewGetNumOperands'],
+      Module['_BinaryenStructNewSetOperandAt'],
+      Module['_BinaryenStructNewAppendOperand'],
+      Module['_BinaryenStructNewRemoveOperandAt']
+    );
+  },
+  'getOperandAt'(expr, index) {
+    return Module['_BinaryenStructNewGetOperandAt'](expr, index);
+  },
+  'setOperandAt'(expr, index, operandExpr) {
+    Module['_BinaryenStructNewSetOperandAt'](expr, index, operandExpr);
+  },
+  'appendOperand'(expr, operandExpr) {
+    return Module['_BinaryenStructNewAppendOperand'](expr, operandExpr);
+  },
+  'insertOperandAt'(expr, index, operandExpr) {
+    Module['_BinaryenStructNewInsertOperandAt'](expr, index, operandExpr);
+  },
+  'removeOperandAt'(expr, index) {
+    return Module['_BinaryenStructNewRemoveOperandAt'](expr, index);
+  }
+});
+
+Module['StructGet'] = makeExpressionWrapper({
+  'getIndex'(expr) {
+    return Module['_BinaryenStructGetGetIndex'](expr);
+  },
+  'setIndex'(expr, index) {
+    Module['_BinaryenStructGetSetIndex'](expr, index);
+  },
+  'getRef'(expr) {
+    return Module['_BinaryenStructGetGetRef'](expr);
+  },
+  'setRef'(expr, ref) {
+    Module['_BinaryenStructGetSetRef'](expr, ref);
+  },
+  'isSigned'(expr) {
+    return Boolean(Module['_BinaryenStructGetIsSigned'](expr));
+  },
+  'setSigned'(expr, signed) {
+    Module['_BinaryenStructGetSetSigned'](expr, signed);
+  }
+});
+
+Module['StructSet'] = makeExpressionWrapper({
+  'getIndex'(expr) {
+    return Module['_BinaryenStructSetGetIndex'](expr);
+  },
+  'setIndex'(expr, index) {
+    Module['_BinaryenStructSetSetIndex'](expr, index);
+  },
+  'getRef'(expr) {
+    return Module['_BinaryenStructSetGetRef'](expr);
+  },
+  'setRef'(expr, ref) {
+    Module['_BinaryenStructSetSetRef'](expr, ref);
+  },
+  'getValue'(expr) {
+    return Module['_BinaryenStructSetGetValue'](expr);
+  },
+  'setValue'(expr, value) {
+    Module['_BinaryenStructSetSetValue'](expr, value);
+  }
+});
+
+Module['ArrayNew'] = makeExpressionWrapper({
+  'getInit'(expr) {
+    return Module['_BinaryenArrayNewGetInit'](expr);
+  },
+  'setInit'(expr, init) {
+    Module['_BinaryenArrayNewSetInit'](expr, init);
+  },
+  'getSize'(expr) {
+    return Module['_BinaryenArrayNewGetSize'](expr);
+  },
+  'setSize'(expr, size) {
+    Module['_BinaryenArrayNewSetSize'](expr, size);
+  }
+});
+
+Module['ArrayNewFixed'] = makeExpressionWrapper({
+  'getNumValues'(expr) {
+    return Module['_BinaryenArrayNewFixedGetNumValues'](expr);
+  },
+  'getValues'(expr) {
+    return getAllNested(expr,
+                        Module['_BinaryenArrayNewFixedGetNumValues'],
+                        Module['_BinaryenArrayNewFixedGetValueAt']);
+  },
+  'setValues'(expr, values) {
+    setAllNested(
+      expr,
+      values,
+      Module['_BinaryenArrayNewFixedGetNumValues'],
+      Module['_BinaryenArrayNewFixedSetValueAt'],
+      Module['_BinaryenArrayNewFixedAppendValue'],
+      Module['_BinaryenArrayNewFixedRemoveValueAt']
+    );
+  },
+  'getValueAt'(expr, index) {
+    return Module['_BinaryenArrayNewFixedGetValueAt'](expr, index);
+  },
+  'setValueAt'(expr, index, valueExpr) {
+    Module['_BinaryenArrayNewFixedSetValueAt'](expr, index, valueExpr);
+  },
+  'appendValue'(expr, valueExpr) {
+    return Module['_BinaryenArrayNewFixedAppendValue'](expr, valueExpr);
+  },
+  'insertValueAt'(expr, index, valueExpr) {
+    Module['_BinaryenArrayNewFixedInsertValueAt'](expr, index, valueExpr);
+  },
+  'removeValueAt'(expr, index) {
+    return Module['_BinaryenArrayNewFixedRemoveValueAt'](expr, index);
+  }
+});
+
+Module['ArrayNewData'] = makeExpressionWrapper({
+  'getSegment'(expr) {
+    return UTF8ToString(Module['_BinaryenArrayNewDataGetSegment'](expr));
+  },
+  'setSegment'(expr, segment) {
+    preserveStack(() => Module['_BinaryenArrayNewDataSetSegment'](expr, strToStack(segment)));
+  },
+  'getOffset'(expr) {
+    return Module['_BinaryenArrayNewDataGetOffset'](expr);
+  },
+  'setOffset'(expr, offset) {
+    Module['_BinaryenArrayNewDataSetOffset'](expr, offset);
+  },
+  'getSize'(expr) {
+    return Module['_BinaryenArrayNewDataGetSize'](expr);
+  },
+  'setSize'(expr, size) {
+    Module['_BinaryenArrayNewDataSetSize'](expr, size);
+  }
+});
+
+Module['ArrayNewElem'] = makeExpressionWrapper({
+  'getSegment'(expr) {
+    return UTF8ToString(Module['_BinaryenArrayNewElemGetSegment'](expr));
+  },
+  'setSegment'(expr, segment) {
+    preserveStack(() => Module['_BinaryenArrayNewElemSetSegment'](expr, strToStack(segment)));
+  },
+  'getOffset'(expr) {
+    return Module['_BinaryenArrayNewElemGetOffset'](expr);
+  },
+  'setOffset'(expr, offset) {
+    Module['_BinaryenArrayNewElemSetOffset'](expr, offset);
+  },
+  'getSize'(expr) {
+    return Module['_BinaryenArrayNewElemGetSize'](expr);
+  },
+  'setSize'(expr, size) {
+    Module['_BinaryenArrayNewElemSetSize'](expr, size);
+  }
+});
+
+Module['ArrayGet'] = makeExpressionWrapper({
+  'getRef'(expr) {
+    return Module['_BinaryenArrayGetGetRef'](expr);
+  },
+  'setRef'(expr, ref) {
+    Module['_BinaryenArrayGetSetRef'](expr, ref);
+  },
+  'getIndex'(expr) {
+    return Module['_BinaryenArrayGetGetIndex'](expr);
+  },
+  'setIndex'(expr, index) {
+    Module['_BinaryenArrayGetSetIndex'](expr, index);
+  },
+  'isSigned'(expr) {
+    return Boolean(Module['_BinaryenArrayGetIsSigned'](expr));
+  },
+  'setSigned'(expr, signed) {
+    Module['_BinaryenArrayGetSetSigned'](expr, signed);
+  }
+});
+
+Module['ArraySet'] = makeExpressionWrapper({
+  'getRef'(expr) {
+    return Module['_BinaryenArraySetGetRef'](expr);
+  },
+  'setRef'(expr, ref) {
+    Module['_BinaryenArraySetSetRef'](expr, ref);
+  },
+  'getIndex'(expr) {
+    return Module['_BinaryenArraySetGetIndex'](expr);
+  },
+  'setIndex'(expr, index) {
+    Module['_BinaryenArraySetSetIndex'](expr, index);
+  },
+  'getValue'(expr) {
+    return Module['_BinaryenArraySetGetValue'](expr);
+  },
+  'setValue'(expr, value) {
+    Module['_BinaryenArraySetSetValue'](expr, value);
+  }
+});
+
+Module['ArrayLen'] = makeExpressionWrapper({
+  'getRef'(expr) {
+    return Module['_BinaryenArrayLenGetRef'](expr);
+  },
+  'setRef'(expr, ref) {
+    Module['_BinaryenArrayLenSetRef'](expr, ref);
+  }
+});
+
+Module['ArrayFill'] = makeExpressionWrapper({
+  'getRef'(expr) {
+    return Module['_BinaryenArrayFillGetRef'](expr);
+  },
+  'setRef'(expr, ref) {
+    Module['_BinaryenArrayFillSetRef'](expr, ref);
+  },
+  'getIndex'(expr) {
+    return Module['_BinaryenArrayFillGetIndex'](expr);
+  },
+  'setIndex'(expr, index) {
+    Module['_BinaryenArrayFillSetIndex'](expr, index);
+  },
+  'getValue'(expr) {
+    return Module['_BinaryenArrayFillGetValue'](expr);
+  },
+  'setValue'(expr, value) {
+    Module['_BinaryenArrayFillSetValue'](expr, value);
+  },
+  'getSize'(expr) {
+    return Module['_BinaryenArrayFillGetSize'](expr);
+  },
+  'setSize'(expr, size) {
+    Module['_BinaryenArrayFillSetSize'](expr, size);
+  }
+});
+
+Module['ArrayCopy'] = makeExpressionWrapper({
+  'getDestRef'(expr) {
+    return Module['_BinaryenArrayCopyGetDestRef'](expr);
+  },
+  'setDestRef'(expr, ref) {
+    Module['_BinaryenArrayCopySetDestRef'](expr, ref);
+  },
+  'getDestIndex'(expr) {
+    return Module['_BinaryenArrayCopyGetDestIndex'](expr);
+  },
+  'setDestIndex'(expr, index) {
+    Module['_BinaryenArrayCopySetDestIndex'](expr, index);
+  },
+  'getSrcRef'(expr) {
+    return Module['_BinaryenArrayCopyGetSrcRef'](expr);
+  },
+  'setSrcRef'(expr, ref) {
+    Module['_BinaryenArrayCopySetSrcRef'](expr, ref);
+  },
+  'getSrcIndex'(expr) {
+    return Module['_BinaryenArrayCopyGetSrcIndex'](expr);
+  },
+  'setSrcIndex'(expr, index) {
+    Module['_BinaryenArrayCopySetSrcIndex'](expr, index);
+  },
+  'getLength'(expr) {
+    return Module['_BinaryenArrayCopyGetLength'](expr);
+  },
+  'setLength'(expr, length) {
+    Module['_BinaryenArrayCopySetLength'](expr, length);
+  }
+});
+
+Module['ArrayInitData'] = makeExpressionWrapper({
+  'getSegment'(expr) {
+    return UTF8ToString(Module['_BinaryenArrayInitDataGetSegment'](expr));
+  },
+  'setSegment'(expr, segment) {
+    preserveStack(() => Module['_BinaryenArrayInitDataSetSegment'](expr, strToStack(segment)));
+  },
+  'getRef'(expr) {
+    return Module['_BinaryenArrayInitDataGetRef'](expr);
+  },
+  'setRef'(expr, ref) {
+    Module['_BinaryenArrayInitDataSetRef'](expr, ref);
+  },
+  'getIndex'(expr) {
+    return Module['_BinaryenArrayInitDataGetIndex'](expr);
+  },
+  'setIndex'(expr, index) {
+    Module['_BinaryenArrayInitDataSetIndex'](expr, index);
+  },
+  'getOffset'(expr) {
+    return Module['_BinaryenArrayInitDataGetOffset'](expr);
+  },
+  'setOffset'(expr, offset) {
+    Module['_BinaryenArrayInitDataSetOffset'](expr, offset);
+  },
+  'getSize'(expr) {
+    return Module['_BinaryenArrayInitDataGetSize'](expr);
+  },
+  'setSize'(expr, size) {
+    Module['_BinaryenArrayInitDataSetSize'](expr, size);
+  }
+});
+
+Module['ArrayInitElem'] = makeExpressionWrapper({
+  'getSegment'(expr) {
+    return UTF8ToString(Module['_BinaryenArrayInitElemGetSegment'](expr));
+  },
+  'setSegment'(expr, segment) {
+    preserveStack(() => Module['_BinaryenArrayInitElemSetSegment'](expr, strToStack(segment)));
+  },
+  'getRef'(expr) {
+    return Module['_BinaryenArrayInitElemGetRef'](expr);
+  },
+  'setRef'(expr, ref) {
+    Module['_BinaryenArrayInitElemSetRef'](expr, ref);
+  },
+  'getIndex'(expr) {
+    return Module['_BinaryenArrayInitElemGetIndex'](expr);
+  },
+  'setIndex'(expr, index) {
+    Module['_BinaryenArrayInitElemSetIndex'](expr, index);
+  },
+  'getOffset'(expr) {
+    return Module['_BinaryenArrayInitElemGetOffset'](expr);
+  },
+  'setOffset'(expr, offset) {
+    Module['_BinaryenArrayInitElemSetOffset'](expr, offset);
+  },
+  'getSize'(expr) {
+    return Module['_BinaryenArrayInitElemGetSize'](expr);
+  },
+  'setSize'(expr, size) {
+    Module['_BinaryenArrayInitElemSetSize'](expr, size);
+  }
+});
+
 Module['Try'] = makeExpressionWrapper({
   'getName'(expr) {
     const name = Module['_BinaryenTryGetName'](expr);
diff --git a/test/binaryen.js/expressions.js b/test/binaryen.js/expressions.js
index 0d1c9669084..544f2b97806 100644
--- a/test/binaryen.js/expressions.js
+++ b/test/binaryen.js/expressions.js
@@ -1531,6 +1531,759 @@ console.log("# RefEq");
   module.dispose();
 })();
 
+console.log("# RefTest");
+(function testRefTest() {
+  const module = new binaryen.Module();
+
+  var ref = module.local.get(0, binaryen.anyref);
+  var castType = binaryen.anyref;
+  const theRefTest = binaryen.RefTest(module.ref.test(ref, castType));
+  assert(theRefTest instanceof binaryen.RefTest);
+  assert(theRefTest instanceof binaryen.Expression);
+  assert(theRefTest.ref === ref);
+  assert(theRefTest.castType === castType);
+  assert(theRefTest.type === binaryen.i32);
+
+  theRefTest.ref = ref = module.local.get(2, binaryen.externref);
+  assert(theRefTest.ref === ref);
+  theRefTest.castType = castType = binaryen.externref;
+  assert(theRefTest.castType === castType);
+  theRefTest.type = binaryen.f64;
+  theRefTest.finalize();
+  assert(theRefTest.type === binaryen.i32);
+
+  console.log(theRefTest.toText());
+  assert(
+    theRefTest.toText()
+    ==
+    "(ref.test externref\n (local.get $2)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# RefCast");
+(function testRefCast() {
+  const module = new binaryen.Module();
+
+  var ref = module.local.get(0, binaryen.anyref);
+  var type = binaryen.anyref;
+  const theRefCast = binaryen.RefCast(module.ref.cast(ref, type));
+  assert(theRefCast instanceof binaryen.RefCast);
+  assert(theRefCast instanceof binaryen.Expression);
+  assert(theRefCast.ref === ref);
+  assert(theRefCast.type === type);
+
+  theRefCast.ref = ref = module.local.get(2, binaryen.externref);
+  assert(theRefCast.ref === ref);
+  theRefCast.type = type = binaryen.externref;
+  theRefCast.finalize();
+  assert(theRefCast.type === type);
+
+  console.log(theRefCast.toText());
+  assert(
+    theRefCast.toText()
+    ==
+    "(ref.cast externref\n (local.get $2)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# BrOn");
+(function testBrOn() {
+  const module = new binaryen.Module();
+
+  var name = "br";
+  var ref = module.local.get(0, binaryen.externref);
+  var op = binaryen.Operations.BrOnNull;
+  var castType = binaryen.unreachable;
+  const theBrOn = binaryen.BrOn(module.br_on_null(name, ref));
+  assert(theBrOn instanceof binaryen.BrOn);
+  assert(theBrOn instanceof binaryen.Expression);
+  assert(theBrOn.name === name);
+  assert(theBrOn.ref === ref);
+  assert(theBrOn.op === op);
+  assert(theBrOn.castType === castType);
+
+  // TODO: What should theBrOn.type be equal to?
+
+  theBrOn.name = name = "br2";
+  assert(theBrOn.name === name);
+  theBrOn.ref = ref = module.local.get(1, binaryen.anyref);
+  assert(theBrOn.ref === ref);
+  theBrOn.op = op = binaryen.Operations.BrOnCast;
+  assert(theBrOn.op === op);
+  theBrOn.castType = castType = binaryen.i31ref;
+  assert(theBrOn.castType === castType);
+  theBrOn.finalize();
+
+  console.log(theBrOn.toText());
+  assert(
+    theBrOn.toText()
+    ==
+    "(br_on_cast $br2 anyref i31ref\n (local.get $1)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# StructNew");
+(function testStructNew() {
+  const builder = new binaryen.TypeBuilder(2);
+  builder.setStructType(0, [
+    { type: binaryen.i32, packedType: binaryen.notPacked, mutable: true },
+  ]);
+  builder.setStructType(1, [
+    { type: binaryen.i32, packedType: binaryen.i16, mutable: true },
+    { type: binaryen.i64, packedType: binaryen.notPacked, mutable: true }
+  ]);
+  var [
+    struct0Type,
+    struct1Type
+  ] = builder.buildAndDispose();
+
+  const module = new binaryen.Module();
+
+  var operands = [
+    module.i32.const(1),
+    module.i32.const(2)
+  ];
+  var type = struct0Type;
+  const theStructNew = binaryen.StructNew(module.struct.new(operands, type));
+  assert(theStructNew instanceof binaryen.StructNew);
+  assert(theStructNew instanceof binaryen.Expression);
+  assertDeepEqual(theStructNew.operands, operands);
+  assertDeepEqual(theStructNew.getOperands(), operands);
+  assert(theStructNew.type === type);
+
+  theStructNew.operands = operands = [
+    module.i32.const(3), // set
+    module.i32.const(4), // set
+    module.i32.const(5)  // append
+  ];
+  assertDeepEqual(theStructNew.operands, operands);
+  operands = [
+    module.i32.const(6) // set
+    // remove
+    // remove
+  ];
+  theStructNew.setOperands(operands);
+  assertDeepEqual(theStructNew.operands, operands);
+  theStructNew.insertOperandAt(0, module.i32.const(7));
+  theStructNew.type = type = struct1Type;
+  theStructNew.finalize();
+  assert(theStructNew.type === type);
+
+  console.log(theStructNew.toText());
+  assert(
+    theStructNew.toText()
+    ==
+    "(struct.new $struct.0\n (i32.const 7)\n (i32.const 6)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# StructGet");
+(function testStructGet() {
+  const builder = new binaryen.TypeBuilder(2);
+  builder.setStructType(0, [
+    { type: binaryen.i32, packedType: binaryen.notPacked, mutable: true },
+  ]);
+  builder.setStructType(1, [
+    { type: binaryen.i32, packedType: binaryen.i16, mutable: true },
+    { type: binaryen.i64, packedType: binaryen.notPacked, mutable: true }
+  ]);
+  var [
+    struct0Type,
+    struct1Type
+  ] = builder.buildAndDispose();
+
+  const module = new binaryen.Module();
+
+  var index = 0;
+  var ref = module.local.get(0, struct0Type);
+  var type = binaryen.i32;
+  var signed = false;
+  const theStructGet = binaryen.StructGet(module.struct.get(index, ref, type, signed));
+  assert(theStructGet instanceof binaryen.StructGet);
+  assert(theStructGet instanceof binaryen.Expression);
+  assert(theStructGet.index === index);
+  assert(theStructGet.ref === ref);
+  assert(theStructGet.signed === signed);
+  assert(theStructGet.type === type);
+
+  theStructGet.index = index = 1;
+  assert(theStructGet.index === index);
+  theStructGet.ref = ref = module.local.get(1, struct1Type);
+  assert(theStructGet.ref === ref);
+  theStructGet.signed = signed = true;
+  assert(theStructGet.signed === signed);
+  theStructGet.type = type = binaryen.i64;
+  theStructGet.finalize();
+  assert(theStructGet.type === type);
+
+  console.log(theStructGet.toText());
+  assert(
+    theStructGet.toText()
+    ==
+    "(struct.get $struct.0 1\n (local.get $1)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# StructSet");
+(function testStructSet() {
+  const builder = new binaryen.TypeBuilder(2);
+  builder.setStructType(0, [
+    { type: binaryen.i32, packedType: binaryen.notPacked, mutable: true },
+  ]);
+  builder.setStructType(1, [
+    { type: binaryen.i32, packedType: binaryen.i16, mutable: true },
+    { type: binaryen.i64, packedType: binaryen.notPacked, mutable: true }
+  ]);
+  var [
+    struct0Type,
+    struct1Type
+  ] = builder.buildAndDispose();
+
+  const module = new binaryen.Module();
+
+  var index = 0;
+  var ref = module.local.get(0, struct0Type);
+  var value = module.local.get(1, binaryen.i32);
+  const theStructSet = binaryen.StructSet(module.struct.set(index, ref, value));
+  assert(theStructSet instanceof binaryen.StructSet);
+  assert(theStructSet instanceof binaryen.Expression);
+  assert(theStructSet.index === index);
+  assert(theStructSet.ref === ref);
+  assert(theStructSet.value === value);
+  assert(theStructSet.type === binaryen.none);
+
+  theStructSet.index = index = 1;
+  assert(theStructSet.index === index);
+  theStructSet.ref = ref = module.local.get(2, struct1Type);
+  assert(theStructSet.ref === ref);
+  theStructSet.value = value = module.local.get(3, binaryen.i64);
+  assert(theStructSet.value === value);
+  theStructSet.type = binaryen.f64;
+  theStructSet.finalize();
+  assert(theStructSet.type === binaryen.none);
+
+  console.log(theStructSet.toText());
+  assert(
+    theStructSet.toText()
+    ==
+    "(struct.set $struct.0 1\n (local.get $2)\n (local.get $3)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# ArrayNew");
+(function testArrayNew() {
+  const builder = new binaryen.TypeBuilder(2);
+  builder.setArrayType(0, binaryen.i32, binaryen.i16, true);
+  builder.setArrayType(1, binaryen.i32, binaryen.notPacked, true);
+  var [
+    array0Type,
+    array1Type
+  ] = builder.buildAndDispose();
+
+  const module = new binaryen.Module();
+
+  var type = array0Type;
+  var size = module.i32.const(2);
+  var init = module.i32.const(1);
+  const theArrayNew = binaryen.ArrayNew(module.array.new(type, size, init));
+  assert(theArrayNew instanceof binaryen.ArrayNew);
+  assert(theArrayNew instanceof binaryen.Expression);
+  assert(theArrayNew.size === size);
+  assert(theArrayNew.init === init);
+  assert(theArrayNew.type === type);
+
+  theArrayNew.size = size = module.i32.const(4);
+  assert(theArrayNew.size === size);
+  theArrayNew.init = init = module.i32.const(3);
+  assert(theArrayNew.init === init);
+  theArrayNew.type = type = array1Type;
+  theArrayNew.finalize();
+  assert(theArrayNew.type === type);
+
+  console.log(theArrayNew.toText());
+  assert(
+    theArrayNew.toText()
+    ==
+    "(array.new $array.0\n (i32.const 3)\n (i32.const 4)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# ArrayNewFixed");
+(function testArrayNewFixed() {
+  const builder = new binaryen.TypeBuilder(2);
+  builder.setArrayType(0, binaryen.i32, binaryen.i16, true);
+  builder.setArrayType(1, binaryen.i32, binaryen.notPacked, true);
+  var [
+    array0Type,
+    array1Type
+  ] = builder.buildAndDispose();
+
+  const module = new binaryen.Module();
+
+  var type = array0Type;
+  var values = [
+    module.i32.const(1),
+    module.i32.const(2)
+  ];
+  const theArrayNewFixed = binaryen.ArrayNewFixed(module.array.new_fixed(type, values));
+  assert(theArrayNewFixed instanceof binaryen.ArrayNewFixed);
+  assert(theArrayNewFixed instanceof binaryen.Expression);
+  assertDeepEqual(theArrayNewFixed.values, values);
+  assertDeepEqual(theArrayNewFixed.getValues(), values);
+  assert(theArrayNewFixed.type === type);
+
+  theArrayNewFixed.values = values = [
+    module.i32.const(3), // set
+    module.i32.const(4), // set
+    module.i32.const(5)  // append
+  ];
+  assertDeepEqual(theArrayNewFixed.values, values);
+  values = [
+    module.i32.const(6) // set
+    // remove
+    // remove
+  ];
+  theArrayNewFixed.setValues(values);
+  assertDeepEqual(theArrayNewFixed.values, values);
+  theArrayNewFixed.insertValueAt(0, module.i32.const(7));
+  theArrayNewFixed.type = type = array1Type;
+  theArrayNewFixed.finalize();
+  assert(theArrayNewFixed.type === type);
+
+  console.log(theArrayNewFixed.toText());
+  assert(
+    theArrayNewFixed.toText()
+    ==
+    "(array.new_fixed $array.0 2\n (i32.const 7)\n (i32.const 6)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# ArrayNewData");
+(function testArrayNewData() {
+  const builder = new binaryen.TypeBuilder(2);
+  builder.setArrayType(0, binaryen.i32, binaryen.i16, true);
+  builder.setArrayType(1, binaryen.i32, binaryen.notPacked, true);
+  var [
+    array0Type,
+    array1Type
+  ] = builder.buildAndDispose();
+
+  const module = new binaryen.Module();
+
+  var type = array0Type;
+  var segment = "0";
+  var offset = module.i32.const(1);
+  var size = module.i32.const(2);
+  const theArrayNewData = binaryen.ArrayNewData(module.array.new_data(type, segment, offset, size));
+  assert(theArrayNewData instanceof binaryen.ArrayNewData);
+  assert(theArrayNewData instanceof binaryen.Expression);
+  assert(theArrayNewData.segment === segment);
+  assert(theArrayNewData.offset === offset);
+  assert(theArrayNewData.size === size);
+  assert(theArrayNewData.type === type);
+
+  theArrayNewData.segment = segment = "3";
+  assert(theArrayNewData.segment === segment);
+  theArrayNewData.offset = offset = module.i32.const(4);
+  assert(theArrayNewData.offset === offset);
+  theArrayNewData.size = size = module.i32.const(5);
+  assert(theArrayNewData.size === size);
+  theArrayNewData.type = type = array1Type;
+  theArrayNewData.finalize();
+  assert(theArrayNewData.type === type);
+
+  console.log(theArrayNewData.toText());
+  assert(
+    theArrayNewData.toText()
+    ==
+    "(array.new_data $array.0 $3\n (i32.const 4)\n (i32.const 5)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# ArrayNewElem");
+(function testArrayNewElem() {
+  const builder = new binaryen.TypeBuilder(2);
+  builder.setArrayType(0, binaryen.i32, binaryen.i16, true);
+  builder.setArrayType(1, binaryen.i32, binaryen.notPacked, true);
+  var [
+    array0Type,
+    array1Type
+  ] = builder.buildAndDispose();
+
+  const module = new binaryen.Module();
+
+  var type = array0Type;
+  var segment = "0";
+  var offset = module.i32.const(1);
+  var size = module.i32.const(2);
+  const theArrayNewElem = binaryen.ArrayNewElem(module.array.new_elem(type, segment, offset, size));
+  assert(theArrayNewElem instanceof binaryen.ArrayNewElem);
+  assert(theArrayNewElem instanceof binaryen.Expression);
+  assert(theArrayNewElem.segment === segment);
+  assert(theArrayNewElem.offset === offset);
+  assert(theArrayNewElem.size === size);
+  assert(theArrayNewElem.type === type);
+
+  theArrayNewElem.segment = segment = "3";
+  assert(theArrayNewElem.segment === segment);
+  theArrayNewElem.offset = offset = module.i32.const(4);
+  assert(theArrayNewElem.offset === offset);
+  theArrayNewElem.size = size = module.i32.const(5);
+  assert(theArrayNewElem.size === size);
+  theArrayNewElem.type = type = array1Type;
+  theArrayNewElem.finalize();
+  assert(theArrayNewElem.type === type);
+
+  console.log(theArrayNewElem.toText());
+  assert(
+    theArrayNewElem.toText()
+    ==
+    "(array.new_elem $array.0 $3\n (i32.const 4)\n (i32.const 5)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# ArrayGet");
+(function testArrayGet() {
+  const builder = new binaryen.TypeBuilder(2);
+  builder.setArrayType(0, binaryen.i32, binaryen.i16, true);
+  builder.setArrayType(1, binaryen.i64, binaryen.notPacked, true);
+  var [
+    array0Type,
+    array1Type
+  ] = builder.buildAndDispose();
+
+  const module = new binaryen.Module();
+
+  var ref = module.local.get(0, array0Type);
+  var index = module.i32.const(0);
+  var type = binaryen.i32;
+  var signed = false;
+  const theArrayGet = binaryen.ArrayGet(module.array.get(ref, index, type, signed));
+  assert(theArrayGet instanceof binaryen.ArrayGet);
+  assert(theArrayGet instanceof binaryen.Expression);
+  assert(theArrayGet.ref === ref);
+  assert(theArrayGet.index === index);
+  assert(theArrayGet.signed === signed);
+  assert(theArrayGet.type === type);
+
+  theArrayGet.ref = ref = module.local.get(1, array1Type);
+  assert(theArrayGet.ref === ref);
+  theArrayGet.index = index = module.i32.const(1);
+  assert(theArrayGet.index === index);
+  theArrayGet.signed = signed = true;
+  assert(theArrayGet.signed === signed);
+  theArrayGet.type = type = binaryen.i64;
+  theArrayGet.finalize();
+  assert(theArrayGet.type === type);
+
+  console.log(theArrayGet.toText());
+  assert(
+    theArrayGet.toText()
+    ==
+    "(array.get $array.0\n (local.get $1)\n (i32.const 1)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# ArraySet");
+(function testArraySet() {
+  const builder = new binaryen.TypeBuilder(2);
+  builder.setArrayType(0, binaryen.i32, binaryen.i16, true);
+  builder.setArrayType(1, binaryen.i64, binaryen.notPacked, true);
+  var [
+    array0Type,
+    array1Type
+  ] = builder.buildAndDispose();
+
+  const module = new binaryen.Module();
+
+  var ref = module.local.get(0, array0Type);
+  var index = module.i32.const(0);
+  var value = module.local.get(1, binaryen.i32);
+  const theArraySet = binaryen.ArraySet(module.array.set(ref, index, value));
+  assert(theArraySet instanceof binaryen.ArraySet);
+  assert(theArraySet instanceof binaryen.Expression);
+  assert(theArraySet.ref === ref);
+  assert(theArraySet.index === index);
+  assert(theArraySet.value === value);
+  assert(theArraySet.type === binaryen.none);
+
+  theArraySet.ref = ref = module.local.get(2, array1Type);
+  assert(theArraySet.ref === ref);
+  theArraySet.index = index = module.i32.const(1);
+  assert(theArraySet.index === index);
+  theArraySet.value = value = module.local.get(3, binaryen.i64);
+  assert(theArraySet.value === value);
+  theArraySet.type = binaryen.i64;
+  theArraySet.finalize();
+  assert(theArraySet.type === binaryen.none);
+
+  console.log(theArraySet.toText());
+  assert(
+    theArraySet.toText()
+    ==
+    "(array.set $array.0\n (local.get $2)\n (i32.const 1)\n (local.get $3)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# ArrayLen");
+(function testArrayLen() {
+  const builder = new binaryen.TypeBuilder(2);
+  builder.setArrayType(0, binaryen.i32, binaryen.i16, true);
+  builder.setArrayType(1, binaryen.i64, binaryen.notPacked, true);
+  var [
+    array0Type,
+    array1Type
+  ] = builder.buildAndDispose();
+
+  const module = new binaryen.Module();
+
+  var ref = module.local.get(0, array0Type);
+  const theArrayLen = binaryen.ArrayLen(module.array.len(ref));
+  assert(theArrayLen instanceof binaryen.ArrayLen);
+  assert(theArrayLen instanceof binaryen.Expression);
+  assert(theArrayLen.ref === ref);
+  assert(theArrayLen.type === binaryen.i32);
+
+  theArrayLen.ref = ref = module.local.get(1, array1Type);
+  assert(theArrayLen.ref === ref);
+  theArrayLen.type = binaryen.i64;
+  theArrayLen.finalize();
+  assert(theArrayLen.type === binaryen.i32);
+
+  console.log(theArrayLen.toText());
+  assert(
+    theArrayLen.toText()
+    ==
+    "(array.len\n (local.get $1)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# ArrayFill");
+(function testArrayFill() {
+  const builder = new binaryen.TypeBuilder(2);
+  builder.setArrayType(0, binaryen.i32, binaryen.i16, true);
+  builder.setArrayType(1, binaryen.i64, binaryen.notPacked, true);
+  var [
+    array0Type,
+    array1Type
+  ] = builder.buildAndDispose();
+
+  const module = new binaryen.Module();
+
+  var ref = module.local.get(0, array0Type);
+  var index = module.i32.const(0);
+  var value = module.local.get(1, binaryen.i32);
+  var size = module.i32.const(1);
+  const theArrayFill = binaryen.ArrayFill(module.array.fill(ref, index, value, size));
+  assert(theArrayFill instanceof binaryen.ArrayFill);
+  assert(theArrayFill instanceof binaryen.Expression);
+  assert(theArrayFill.ref === ref);
+  assert(theArrayFill.index === index);
+  assert(theArrayFill.value === value);
+  assert(theArrayFill.size === size);
+  assert(theArrayFill.type === binaryen.none);
+
+  theArrayFill.ref = ref = module.local.get(2, array1Type);
+  assert(theArrayFill.ref === ref);
+  theArrayFill.index = index = module.i32.const(2);
+  assert(theArrayFill.index === index);
+  theArrayFill.value = value = module.local.get(3, binaryen.i64);
+  assert(theArrayFill.value = value);
+  theArrayFill.size = size = module.i32.const(3);
+  assert(theArrayFill.size === size);
+  theArrayFill.type = binaryen.i64;
+  theArrayFill.finalize();
+  assert(theArrayFill.type === binaryen.none);
+
+  console.log(theArrayFill.toText());
+  assert(
+    theArrayFill.toText()
+    ==
+    "(array.fill $array.0\n (local.get $2)\n (i32.const 2)\n (local.get $3)\n (i32.const 3)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# ArrayCopy");
+(function testArrayCopy() {
+  const builder = new binaryen.TypeBuilder(2);
+  builder.setArrayType(0, binaryen.i32, binaryen.i16, true);
+  builder.setArrayType(1, binaryen.i64, binaryen.notPacked, true);
+  var [
+    array0Type,
+    array1Type
+  ] = builder.buildAndDispose();
+
+  const module = new binaryen.Module();
+
+  var destRef = module.local.get(0, array0Type);
+  var destIndex = module.i32.const(0);
+  var srcRef = module.local.get(1, array0Type);
+  var srcIndex = module.i32.const(1);
+  var length = module.i32.const(1);
+  const theArrayCopy = binaryen.ArrayCopy(module.array.copy(destRef, destIndex, srcRef, srcIndex, length));
+  assert(theArrayCopy instanceof binaryen.ArrayCopy);
+  assert(theArrayCopy instanceof binaryen.Expression);
+  assert(theArrayCopy.destRef === destRef);
+  assert(theArrayCopy.destIndex === destIndex);
+  assert(theArrayCopy.srcRef === srcRef);
+  assert(theArrayCopy.srcIndex === srcIndex);
+  assert(theArrayCopy.length === length);
+  assert(theArrayCopy.type === binaryen.none);
+
+  theArrayCopy.destRef = destRef = module.local.get(2, array1Type);
+  assert(theArrayCopy.destRef === destRef);
+  theArrayCopy.destIndex = destIndex = module.i32.const(2);
+  assert(theArrayCopy.destIndex === destIndex);
+  theArrayCopy.srcRef = srcRef = module.local.get(3, array1Type);
+  assert(theArrayCopy.srcRef === srcRef);
+  theArrayCopy.srcIndex = srcIndex = module.i32.const(3);
+  assert(theArrayCopy.srcIndex === srcIndex);
+  theArrayCopy.length = length = module.i32.const(2);
+  assert(theArrayCopy.length === length);
+  theArrayCopy.type = binaryen.i64;
+  theArrayCopy.finalize();
+  assert(theArrayCopy.type === binaryen.none);
+
+  console.log(theArrayCopy.toText());
+  assert(
+    theArrayCopy.toText()
+    ==
+    "(array.copy $array.0 $array.0\n (local.get $2)\n (i32.const 2)\n (local.get $3)\n (i32.const 3)\n (i32.const 2)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# ArrayInitData");
+(function testArrayInitData() {
+  const builder = new binaryen.TypeBuilder(2);
+  builder.setArrayType(0, binaryen.i32, binaryen.i16, true);
+  builder.setArrayType(1, binaryen.i32, binaryen.notPacked, true);
+  var [
+    array0Type,
+    array1Type
+  ] = builder.buildAndDispose();
+
+  const module = new binaryen.Module();
+
+  var segment = "0";
+  var ref = module.local.get(0, array0Type);
+  var index = module.i32.const(0);
+  var offset = module.i32.const(1);
+  var size = module.i32.const(2);
+  const theArrayInitData = binaryen.ArrayInitData(module.array.init_data(segment, ref, index, offset, size));
+  assert(theArrayInitData instanceof binaryen.ArrayInitData);
+  assert(theArrayInitData instanceof binaryen.Expression);
+  assert(theArrayInitData.segment === segment);
+  assert(theArrayInitData.ref === ref);
+  assert(theArrayInitData.index === index);
+  assert(theArrayInitData.offset === offset);
+  assert(theArrayInitData.size === size);
+  assert(theArrayInitData.type === binaryen.none);
+
+  theArrayInitData.segment = segment = "1";
+  assert(theArrayInitData.segment === segment);
+  theArrayInitData.ref = ref = module.local.get(1, array1Type);
+  assert(theArrayInitData.ref === ref);
+  theArrayInitData.index = index = module.i32.const(3);
+  assert(theArrayInitData.index === index);
+  theArrayInitData.offset = offset = module.i32.const(4);
+  assert(theArrayInitData.offset === offset);
+  theArrayInitData.size = size = module.i32.const(5);
+  assert(theArrayInitData.size === size);
+  theArrayInitData.type = binaryen.i64;
+  theArrayInitData.finalize();
+  assert(theArrayInitData.type === binaryen.none);
+
+  console.log(theArrayInitData.toText());
+  assert(
+    theArrayInitData.toText()
+    ==
+    "(array.init_data $array.0 $1\n (local.get $1)\n (i32.const 3)\n (i32.const 4)\n (i32.const 5)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# ArrayInitElem");
+(function testArrayInitElem() {
+  const builder = new binaryen.TypeBuilder(2);
+  builder.setArrayType(0, binaryen.i32, binaryen.i16, true);
+  builder.setArrayType(1, binaryen.i32, binaryen.notPacked, true);
+  var [
+    array0Type,
+    array1Type
+  ] = builder.buildAndDispose();
+
+  const module = new binaryen.Module();
+
+  var segment = "0";
+  var ref = module.local.get(0, array0Type);
+  var index = module.i32.const(0);
+  var offset = module.i32.const(1);
+  var size = module.i32.const(2);
+  const theArrayInitElem = binaryen.ArrayInitElem(module.array.init_elem(segment, ref, index, offset, size));
+  assert(theArrayInitElem instanceof binaryen.ArrayInitElem);
+  assert(theArrayInitElem instanceof binaryen.Expression);
+  assert(theArrayInitElem.segment === segment);
+  assert(theArrayInitElem.ref === ref);
+  assert(theArrayInitElem.index === index);
+  assert(theArrayInitElem.offset === offset);
+  assert(theArrayInitElem.size === size);
+  assert(theArrayInitElem.type === binaryen.none);
+
+  theArrayInitElem.segment = segment = "1";
+  assert(theArrayInitElem.segment === segment);
+  theArrayInitElem.ref = ref = module.local.get(1, array1Type);
+  assert(theArrayInitElem.ref === ref);
+  theArrayInitElem.index = index = module.i32.const(3);
+  assert(theArrayInitElem.index === index);
+  theArrayInitElem.offset = offset = module.i32.const(4);
+  assert(theArrayInitElem.offset === offset);
+  theArrayInitElem.size = size = module.i32.const(5);
+  assert(theArrayInitElem.size === size);
+  theArrayInitElem.type = binaryen.i64;
+  theArrayInitElem.finalize();
+  assert(theArrayInitElem.type === binaryen.none);
+
+  console.log(theArrayInitElem.toText());
+  assert(
+    theArrayInitElem.toText()
+    ==
+    "(array.init_elem $array.0 $1\n (local.get $1)\n (i32.const 3)\n (i32.const 4)\n (i32.const 5)\n)\n"
+  );
+
+  module.dispose();
+})();
+
 console.log("# Try");
 (function testTry() {
   const module = new binaryen.Module();
diff --git a/test/binaryen.js/expressions.js.txt b/test/binaryen.js/expressions.js.txt
index 5d6c37c6bc6..47d7cf43fb4 100644
--- a/test/binaryen.js/expressions.js.txt
+++ b/test/binaryen.js/expressions.js.txt
@@ -239,6 +239,113 @@
  (local.get $3)
 )
 
+# RefTest
+(ref.test externref
+ (local.get $2)
+)
+
+# RefCast
+(ref.cast externref
+ (local.get $2)
+)
+
+# BrOn
+(br_on_cast $br2 anyref i31ref
+ (local.get $1)
+)
+
+# StructNew
+(struct.new $struct.0
+ (i32.const 7)
+ (i32.const 6)
+)
+
+# StructGet
+(struct.get $struct.0 1
+ (local.get $1)
+)
+
+# StructSet
+(struct.set $struct.0 1
+ (local.get $2)
+ (local.get $3)
+)
+
+# ArrayNew
+(array.new $array.0
+ (i32.const 3)
+ (i32.const 4)
+)
+
+# ArrayNewFixed
+(array.new_fixed $array.0 2
+ (i32.const 7)
+ (i32.const 6)
+)
+
+# ArrayNewData
+(array.new_data $array.0 $3
+ (i32.const 4)
+ (i32.const 5)
+)
+
+# ArrayNewElem
+(array.new_elem $array.0 $3
+ (i32.const 4)
+ (i32.const 5)
+)
+
+# ArrayGet
+(array.get $array.0
+ (local.get $1)
+ (i32.const 1)
+)
+
+# ArraySet
+(array.set $array.0
+ (local.get $2)
+ (i32.const 1)
+ (local.get $3)
+)
+
+# ArrayLen
+(array.len
+ (local.get $1)
+)
+
+# ArrayFill
+(array.fill $array.0
+ (local.get $2)
+ (i32.const 2)
+ (local.get $3)
+ (i32.const 3)
+)
+
+# ArrayCopy
+(array.copy $array.0 $array.0
+ (local.get $2)
+ (i32.const 2)
+ (local.get $3)
+ (i32.const 3)
+ (i32.const 2)
+)
+
+# ArrayInitData
+(array.init_data $array.0 $1
+ (local.get $1)
+ (i32.const 3)
+ (i32.const 4)
+ (i32.const 5)
+)
+
+# ArrayInitElem
+(array.init_elem $array.0 $1
+ (local.get $1)
+ (i32.const 3)
+ (i32.const 4)
+ (i32.const 5)
+)
+
 # Try
 (try (result i32)
  (do
diff --git a/test/binaryen.js/gc.js b/test/binaryen.js/gc.js
new file mode 100644
index 00000000000..0f12184b4c4
--- /dev/null
+++ b/test/binaryen.js/gc.js
@@ -0,0 +1,178 @@
+var builder = new binaryen.TypeBuilder(4);
+builder.setSignatureType(0, binaryen.createType([binaryen.i32]), binaryen.none);
+builder.setStructType(1, [
+  { type: binaryen.i32, packedType: binaryen.i16, mutable: true },
+  { type: binaryen.f64, packedType: binaryen.notPacked, mutable: true }
+]);
+builder.setArrayType(2, binaryen.i32, binaryen.i8, true);
+builder.setArrayType(3, binaryen.funcref, binaryen.notPacked, true);
+var [
+  signatureHeapType,
+  structHeapType,
+  arrayHeapType,
+  funcArrayHeapType
+] = builder.buildAndDispose();
+
+var signatureType = binaryen.getTypeFromHeapType(signatureHeapType, true);
+var structType = binaryen.getTypeFromHeapType(structHeapType, true);
+var arrayType = binaryen.getTypeFromHeapType(arrayHeapType, true);
+var funcArrayType = binaryen.getTypeFromHeapType(funcArrayHeapType, true);
+
+var module = new binaryen.Module();
+module.setFeatures(binaryen.Features.ReferenceTypes | binaryen.Features.BulkMemory | binaryen.Features.GC);
+
+module.addFunction("add", binaryen.createType([binaryen.i32, binaryen.i32]), binaryen.i32, [],
+  module.i32.add(
+    module.local.get("0", binaryen.i32),
+    module.local.get("1", binaryen.i32)
+  )
+);
+
+module.setMemory(1, -1, null, [
+  { offset: module.i32.const(0), data: [4, 3, 2, 1] }
+]);
+
+module.addTable("0", 1, -1);
+module.addActiveElementSegment("0", "0", ["add"]);
+
+module.addGlobal("struct-global",
+  structType,
+  true,
+  module.struct.new_default(
+    binaryen.getHeapType(structType)
+  )
+);
+
+module.addGlobal("array-global",
+  arrayType,
+  true,
+  module.array.new_default(
+    binaryen.getHeapType(arrayType),
+    module.i32.const(4)
+  )
+);
+
+module.addGlobal("funcArray-global",
+  funcArrayType,
+  true,
+  module.array.new_default(
+    binaryen.getHeapType(funcArrayType),
+    module.i32.const(4)
+  )
+);
+
+var valueList = [
+  // ref
+
+  // struct
+  module.struct.new(
+    [
+      module.i32.const(1),
+      module.f64.const(2.3)
+    ],
+    binaryen.getHeapType(structType)
+  ),
+  module.struct.new_default(
+    binaryen.getHeapType(structType)
+  ),
+  module.struct.get(
+    0,
+    module.global.get("struct-global", structType),
+    binaryen.i32,
+    true
+  ),
+  module.struct.set(
+    1,
+    module.global.get("struct-global", structType),
+    module.f64.const(1.23)
+  ),
+
+  // array
+  module.array.new(
+    binaryen.getHeapType(arrayType),
+    module.i32.const(1),
+    module.i32.const(0)
+  ),
+  module.array.new_default(
+    binaryen.getHeapType(arrayType),
+    module.i32.const(1)
+  ),
+  module.array.new_fixed(
+    binaryen.getHeapType(arrayType),
+    [
+      module.i32.const(1),
+      module.i32.const(2),
+      module.i32.const(3)
+    ]
+  ),
+  module.array.new_data(
+    binaryen.getHeapType(arrayType),
+    "0",
+    module.i32.const(0),
+    module.i32.const(4)
+  ),
+  module.array.new_elem(
+    binaryen.getHeapType(funcArrayType),
+    "0",
+    module.i32.const(0),
+    module.i32.const(1)
+  ),
+  module.array.get(
+    module.global.get("array-global", arrayType),
+    module.i32.const(0),
+    binaryen.i32,
+    true
+  ),
+  module.array.set(
+    module.global.get("array-global", arrayType),
+    module.i32.const(1),
+    module.i32.const(2)
+  ),
+  module.array.len(
+    module.global.get("array-global", arrayType)
+  ),
+  module.array.fill(
+    module.global.get("array-global", arrayType),
+    module.i32.const(0),
+    module.i32.const(1),
+    module.i32.const(2)
+  ),
+  module.array.copy(
+    module.global.get("array-global", arrayType),
+    module.i32.const(0),
+    module.global.get("array-global", arrayType),
+    module.i32.const(1),
+    module.i32.const(2)
+  ),
+  module.array.init_data(
+    "0",
+    module.global.get("array-global", arrayType),
+    module.i32.const(0),
+    module.i32.const(1),
+    module.i32.const(2)
+  ),
+  module.array.init_elem(
+    "0",
+    module.global.get("funcArray-global", funcArrayType),
+    module.i32.const(0),
+    module.i32.const(1),
+    module.i32.const(2)
+  )
+];
+module.addFunction("main", binaryen.none, binaryen.none, [],
+  module.block(
+    null,
+    valueList.map(value => {
+      var type = binaryen.getExpressionType(value);
+      if (type === binaryen.none || type === binaryen.unreachable)
+        return value;
+      else
+        return module.drop(value);
+    }),
+    binaryen.none
+  )
+);
+
+assert(module.validate());
+
+console.log(module.emitText());
diff --git a/test/binaryen.js/gc.js.txt b/test/binaryen.js/gc.js.txt
new file mode 100644
index 00000000000..7b557c7c743
--- /dev/null
+++ b/test/binaryen.js/gc.js.txt
@@ -0,0 +1,116 @@
+(module
+ (type $0 (array (mut i8)))
+ (type $1 (struct (field (mut i16)) (field (mut f64))))
+ (type $2 (array (mut funcref)))
+ (type $3 (func (param i32 i32) (result i32)))
+ (type $4 (func))
+ (global $struct-global (mut (ref null $1)) (struct.new_default $1))
+ (global $array-global (mut (ref null $0)) (array.new_default $0
+  (i32.const 4)
+ ))
+ (global $funcArray-global (mut (ref null $2)) (array.new_default $2
+  (i32.const 4)
+ ))
+ (memory $0 1)
+ (data $0 (i32.const 0) "\04\03\02\01")
+ (table $0 1 funcref)
+ (elem $0 (i32.const 0) $add)
+ (func $add (type $3) (param $0 i32) (param $1 i32) (result i32)
+  (i32.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $main (type $4)
+  (drop
+   (struct.new $1
+    (i32.const 1)
+    (f64.const 2.3)
+   )
+  )
+  (drop
+   (struct.new_default $1)
+  )
+  (drop
+   (struct.get_s $1 0
+    (global.get $struct-global)
+   )
+  )
+  (struct.set $1 1
+   (global.get $struct-global)
+   (f64.const 1.23)
+  )
+  (drop
+   (array.new $0
+    (i32.const 0)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (array.new_default $0
+    (i32.const 1)
+   )
+  )
+  (drop
+   (array.new_fixed $0 3
+    (i32.const 1)
+    (i32.const 2)
+    (i32.const 3)
+   )
+  )
+  (drop
+   (array.new_data $0 $0
+    (i32.const 0)
+    (i32.const 4)
+   )
+  )
+  (drop
+   (array.new_elem $2 $0
+    (i32.const 0)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (array.get_s $0
+    (global.get $array-global)
+    (i32.const 0)
+   )
+  )
+  (array.set $0
+   (global.get $array-global)
+   (i32.const 1)
+   (i32.const 2)
+  )
+  (drop
+   (array.len
+    (global.get $array-global)
+   )
+  )
+  (array.fill $0
+   (global.get $array-global)
+   (i32.const 0)
+   (i32.const 1)
+   (i32.const 2)
+  )
+  (array.copy $0 $0
+   (global.get $array-global)
+   (i32.const 0)
+   (global.get $array-global)
+   (i32.const 1)
+   (i32.const 2)
+  )
+  (array.init_data $0 $0
+   (global.get $array-global)
+   (i32.const 0)
+   (i32.const 1)
+   (i32.const 2)
+  )
+  (array.init_elem $2 $0
+   (global.get $funcArray-global)
+   (i32.const 0)
+   (i32.const 1)
+   (i32.const 2)
+  )
+ )
+)
+
diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c
index c97de45a366..85937929d7e 100644
--- a/test/example/c-api-kitchen-sink.c
+++ b/test/example/c-api-kitchen-sink.c
@@ -518,25 +518,29 @@ void test_core() {
   BinaryenType v128 = BinaryenTypeVec128();
   BinaryenType i8Array;
   BinaryenType i16Array;
+  BinaryenType funcArray;
   BinaryenType i32Struct;
   {
-    TypeBuilderRef tb = TypeBuilderCreate(3);
+    TypeBuilderRef tb = TypeBuilderCreate(4);
     TypeBuilderSetArrayType(
       tb, 0, BinaryenTypeInt32(), BinaryenPackedTypeInt8(), true);
     TypeBuilderSetArrayType(
       tb, 1, BinaryenTypeInt32(), BinaryenPackedTypeInt16(), true);
+    TypeBuilderSetArrayType(
+      tb, 2, BinaryenTypeFuncref(), BinaryenPackedTypeNotPacked(), true);
     TypeBuilderSetStructType(
       tb,
-      2,
+      3,
       (BinaryenType[]){BinaryenTypeInt32()},
       (BinaryenPackedType[]){BinaryenPackedTypeNotPacked()},
       (bool[]){true},
       1);
-    BinaryenHeapType builtHeapTypes[3];
+    BinaryenHeapType builtHeapTypes[4];
     TypeBuilderBuildAndDispose(tb, (BinaryenHeapType*)&builtHeapTypes, 0, 0);
     i8Array = BinaryenTypeFromHeapType(builtHeapTypes[0], true);
     i16Array = BinaryenTypeFromHeapType(builtHeapTypes[1], true);
-    i32Struct = BinaryenTypeFromHeapType(builtHeapTypes[2], true);
+    funcArray = BinaryenTypeFromHeapType(builtHeapTypes[2], true);
+    i32Struct = BinaryenTypeFromHeapType(builtHeapTypes[3], true);
   }
 
   // Memory. Add it before creating any memory-using instructions.
@@ -1170,12 +1174,30 @@ void test_core() {
                      makeInt32(module, 42)),
     BinaryenArrayLen(module,
                      BinaryenGlobalGet(module, "i8Array-global", i8Array)),
+    BinaryenArrayFill(module,
+                      BinaryenGlobalGet(module, "i8Array-global", i8Array),
+                      makeInt32(module, 0),
+                      makeInt32(module, 1),
+                      makeInt32(module, 2)),
     BinaryenArrayCopy(module,
                       BinaryenGlobalGet(module, "i8Array-global", i8Array),
                       makeInt32(module, 0),
                       BinaryenGlobalGet(module, "i8Array-global", i8Array),
                       makeInt32(module, 1),
                       makeInt32(module, 2)),
+    BinaryenArrayInitData(module,
+                          "0",
+                          BinaryenGlobalGet(module, "i8Array-global", i8Array),
+                          makeInt32(module, 0),
+                          makeInt32(module, 1),
+                          makeInt32(module, 2)),
+    BinaryenArrayInitElem(
+      module,
+      "0",
+      BinaryenGlobalGet(module, "funcArray-global", funcArray),
+      makeInt32(module, 0),
+      makeInt32(module, 1),
+      makeInt32(module, 2)),
     // Strings
     BinaryenStringNew(module,
                       BinaryenStringNewLossyUTF8Array(),
@@ -1302,6 +1324,15 @@ void test_core() {
     true,
     BinaryenArrayNew(
       module, BinaryenTypeGetHeapType(i16Array), makeInt32(module, 0), 0));
+  BinaryenAddGlobal(
+    module,
+    "funcArray-global",
+    funcArray,
+    true,
+    BinaryenArrayNew(module,
+                     BinaryenTypeGetHeapType(funcArray),
+                     makeInt32(module, 0),
+                     BinaryenRefNull(module, BinaryenTypeNullFuncref())));
   BinaryenAddGlobal(
     module,
     "i32Struct-global",
diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt
index 78f1c73552f..1961547c5a1 100644
--- a/test/example/c-api-kitchen-sink.txt
+++ b/test/example/c-api-kitchen-sink.txt
@@ -67,17 +67,22 @@ BinaryenFeatureAll: 4194303
  (type $0 (array (mut i8)))
  (type $1 (struct (field (mut i32))))
  (type $2 (func (param i32 i64 f32 f64) (result i32)))
- (type $3 (array (mut i16)))
- (type $4 (func (param i32)))
- (type $5 (func (param i32 f64) (result f32)))
- (type $6 (func))
- (import "module" "base" (func $an-imported (type $5) (param i32 f64) (result f32)))
+ (type $3 (array (mut funcref)))
+ (type $4 (array (mut i16)))
+ (type $5 (func (param i32)))
+ (type $6 (func (param i32 f64) (result f32)))
+ (type $7 (func))
+ (import "module" "base" (func $an-imported (type $6) (param i32 f64) (result f32)))
  (global $a-global i32 (i32.const 7))
  (global $a-mutable-global (mut f32) (f32.const 7.5))
  (global $i8Array-global (mut (ref null $0)) (array.new_default $0
   (i32.const 0)
  ))
- (global $i16Array-global (mut (ref null $3)) (array.new_default $3
+ (global $i16Array-global (mut (ref null $4)) (array.new_default $4
+  (i32.const 0)
+ ))
+ (global $funcArray-global (mut (ref null $3)) (array.new $3
+  (ref.null nofunc)
   (i32.const 0)
  ))
  (global $i32Struct-global (mut (ref null $1)) (struct.new_default $1))
@@ -91,7 +96,7 @@ BinaryenFeatureAll: 4194303
  (table $0 1 1 funcref)
  (elem $0 (table $0) (i32.const 0) func $"kitchen()sinker")
  (elem $passive func $"kitchen()sinker")
- (tag $a-tag (type $4) (param i32))
+ (tag $a-tag (type $5) (param i32))
  (export "mem" (memory $0))
  (export "kitchen_sinker" (func $"kitchen()sinker"))
  (start $starter)
@@ -2327,6 +2332,12 @@ BinaryenFeatureAll: 4194303
         (global.get $i8Array-global)
        )
       )
+      (array.fill $0
+       (global.get $i8Array-global)
+       (i32.const 0)
+       (i32.const 1)
+       (i32.const 2)
+      )
       (array.copy $0 $0
        (global.get $i8Array-global)
        (i32.const 0)
@@ -2334,6 +2345,18 @@ BinaryenFeatureAll: 4194303
        (i32.const 1)
        (i32.const 2)
       )
+      (array.init_data $0 $0
+       (global.get $i8Array-global)
+       (i32.const 0)
+       (i32.const 1)
+       (i32.const 2)
+      )
+      (array.init_elem $3 $0
+       (global.get $funcArray-global)
+       (i32.const 0)
+       (i32.const 1)
+       (i32.const 2)
+      )
       (drop
        (string.new_lossy_utf8_array
         (global.get $i8Array-global)
@@ -2419,7 +2442,7 @@ BinaryenFeatureAll: 4194303
    (i32.const 42)
   )
  )
- (func $starter (type $6)
+ (func $starter (type $7)
   (nop)
  )
 )