[WASM-References] Add support for active mods in element section
https://bugs.webkit.org/show_bug.cgi?id=219192

Patch by Dmitry Bezhetskov <dbezhetskov@igalia.com> on 2020-12-02
Reviewed by Yusuke Suzuki.

JSTests:

Fix builder dsl to produce the right element section.
It produces correct wasm code for the previous spec and for the ref-types spec because the core spec is binary compatible with the ref-types.
https://webassembly.github.io/reference-types/core/binary/modules.html#element-section.
Added basic tests for the element section.

* wasm/Builder.js:
(export.default.Builder.prototype._registerSectionBuilders.const.section.in.WASM.description.section.switch.section.case.string_appeared_here.this.section):
* wasm/Builder_WebAssemblyBinary.js:
(const.emitters.Element):
* wasm/references-spec-tests/ref_null.js:
(module):
* wasm/references/element_active_mod.js: Added.
(module):
(basicTest):
(refNullExternInElemsSection):
* wasm/references/element_parsing.js:
* wasm/references/multitable.js:

Source/JavaScriptCore:

Adjust wasm parser to parse new form of element section.
https://webassembly.github.io/reference-types/core/binary/modules.html#element-section.

* wasm/WasmEntryPlan.cpp:
(JSC::Wasm::EntryPlan::prepare):
* wasm/WasmFormat.h:
(JSC::Wasm::Element::Element):
(JSC::Wasm::Element::active const):
* wasm/WasmSectionParser.cpp:
(JSC::Wasm::SectionParser::parseElement):
(JSC::Wasm::SectionParser::validateElementTableIdx):
(JSC::Wasm::SectionParser::parseI32InitExpr):
(JSC::Wasm::SectionParser::parseElemKind):
(JSC::Wasm::SectionParser::parseIndexCountForElemSection):
(JSC::Wasm::SectionParser::parseFuncIdxFromRefExpForElemSection):
(JSC::Wasm::SectionParser::parseFuncIdxForElemSection):
* wasm/WasmSectionParser.h:
* wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::evaluate):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@270344 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog
index 2e545ed..6b3e5fc 100644
--- a/JSTests/ChangeLog
+++ b/JSTests/ChangeLog
@@ -1,3 +1,29 @@
+2020-12-02  Dmitry Bezhetskov  <dbezhetskov@igalia.com>
+
+        [WASM-References] Add support for active mods in element section
+        https://bugs.webkit.org/show_bug.cgi?id=219192
+
+        Reviewed by Yusuke Suzuki.
+        
+        Fix builder dsl to produce the right element section.
+        It produces correct wasm code for the previous spec and for the ref-types spec because the core spec is binary compatible with the ref-types.
+        https://webassembly.github.io/reference-types/core/binary/modules.html#element-section.
+        Added basic tests for the element section.
+
+
+        * wasm/Builder.js:
+        (export.default.Builder.prototype._registerSectionBuilders.const.section.in.WASM.description.section.switch.section.case.string_appeared_here.this.section):
+        * wasm/Builder_WebAssemblyBinary.js:
+        (const.emitters.Element):
+        * wasm/references-spec-tests/ref_null.js:
+        (module):
+        * wasm/references/element_active_mod.js: Added.
+        (module):
+        (basicTest):
+        (refNullExternInElemsSection):
+        * wasm/references/element_parsing.js:
+        * wasm/references/multitable.js:
+
 2020-11-30  Sergey Rubanov  <chi187@gmail.com>
 
         Add support for the Wasm i64 sign-extension-ops proposal
diff --git a/JSTests/wasm/Builder.js b/JSTests/wasm/Builder.js
index b4d72b1..32ffe6b 100644
--- a/JSTests/wasm/Builder.js
+++ b/JSTests/wasm/Builder.js
@@ -594,8 +594,8 @@
                     const s = this._addSection(section);
                     const elementBuilder = {
                         End: () => this,
-                        Element: ({tableIndex = 0, offset, functionIndices}) => {
-                            s.data.push({tableIndex, offset, functionIndices});
+                        Element: ({tableIndex = 0, offset, elemkind = 0, functionIndices}) => {
+                            s.data.push({tableIndex, offset, elemkind, functionIndices});
                             return _errorHandlingProxyFor(elementBuilder);
                         }
                     };
diff --git a/JSTests/wasm/Builder_WebAssemblyBinary.js b/JSTests/wasm/Builder_WebAssemblyBinary.js
index b0f4387..358bb48 100644
--- a/JSTests/wasm/Builder_WebAssemblyBinary.js
+++ b/JSTests/wasm/Builder_WebAssemblyBinary.js
@@ -197,10 +197,13 @@
     Element: (section, bin) => {
         const data = section.data;
         put(bin, "varuint32", data.length);
-        for (const {tableIndex, offset, functionIndices} of data) {
-            if (tableIndex != 0)
-                put(bin, "uint8", 2);
-            put(bin, "varuint32", tableIndex);
+        for (const {tableIndex, offset, elemkind, functionIndices} of data) {
+            let flags = tableIndex == 0 ? 0 : 2;
+            put(bin, "uint8", flags);
+
+            if (flags == 2) {
+              put(bin, "varuint32", tableIndex);
+            }
 
             let initExpr;
             if (typeof offset === "number")
@@ -209,6 +212,10 @@
                 initExpr = offset;
             putInitExpr(bin, initExpr);
 
+            if (flags == 2) {
+              put(bin, "uint8", elemkind);
+            }
+
             put(bin, "varuint32", functionIndices.length);
             for (const functionIndex of functionIndices)
                 put(bin, "varuint32", functionIndex);
diff --git a/JSTests/wasm/references-spec-tests/ref_null.js b/JSTests/wasm/references-spec-tests/ref_null.js
index 9dda7af..5325aba 100644
--- a/JSTests/wasm/references-spec-tests/ref_null.js
+++ b/JSTests/wasm/references-spec-tests/ref_null.js
@@ -62,7 +62,7 @@
     throw new Error("Wasm validate throws");
   }
   if (validated !== valid) {
-    //throw new Error("Wasm validate failure" + (valid ? "" : " expected"));
+    throw new Error("Wasm validate failure" + (valid ? "" : " expected"));
   }
   return new WebAssembly.Module(buffer);
 }
diff --git a/JSTests/wasm/references/element_active_mod.js b/JSTests/wasm/references/element_active_mod.js
new file mode 100644
index 0000000..c170840
--- /dev/null
+++ b/JSTests/wasm/references/element_active_mod.js
@@ -0,0 +1,59 @@
+//@ runWebAssemblySuite("--useWebAssemblyReferences=true")
+import * as assert from '../assert.js';
+
+function module(bytes, valid = true) {
+  let buffer = new ArrayBuffer(bytes.length);
+  let view = new Uint8Array(buffer);
+  for (let i = 0; i < bytes.length; ++i) {
+    view[i] = bytes.charCodeAt(i);
+  }
+  return new WebAssembly.Module(buffer);
+}
+
+function basicTest() {
+  /*
+  (module
+    (func $f (result i32)
+      (i32.const 37)
+    )
+    (func $g (result i32)
+      (i32.const 42)
+    )
+    (table $t1 10 funcref)
+    (table $t2 20 funcref)
+    (elem (i32.const 3) funcref (ref.func $g) (ref.null func) (ref.func $f) (ref.null func))
+    (elem (table $t2) (i32.const 7) funcref (ref.func $f) (ref.null func) (ref.func $g))
+    (func (export "get_tbl1") (param $idx i32) (result funcref)
+      (table.get $t1 (local.get $idx))
+    )
+    (func (export "get_tbl2") (param $idx i32) (result funcref)
+      (table.get $t2 (local.get $idx))
+    )
+  )
+  */
+  let instance = new WebAssembly.Instance(module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x0a\x02\x60\x00\x01\x7f\x60\x01\x7f\x01\x70\x03\x05\x04\x00\x00\x01\x01\x04\x07\x02\x70\x00\x0a\x70\x00\x14\x07\x17\x02\x08\x67\x65\x74\x5f\x74\x62\x6c\x31\x00\x02\x08\x67\x65\x74\x5f\x74\x62\x6c\x32\x00\x03\x09\x22\x02\x04\x41\x03\x0b\x04\xd2\x01\x0b\xd0\x70\x0b\xd2\x00\x0b\xd0\x70\x0b\x06\x01\x41\x07\x0b\x70\x03\xd2\x00\x0b\xd0\x70\x0b\xd2\x01\x0b\x0a\x19\x04\x04\x00\x41\x25\x0b\x04\x00\x41\x2a\x0b\x06\x00\x20\x00\x25\x00\x0b\x06\x00\x20\x00\x25\x01\x0b"));
+
+  assert.eq(instance.exports.get_tbl1(3)(), 42);
+  assert.eq(instance.exports.get_tbl1(4), null);
+  assert.eq(instance.exports.get_tbl1(5)(), 37);
+  assert.eq(instance.exports.get_tbl1(6), null);
+
+  assert.eq(instance.exports.get_tbl2(7)(), 37);
+  assert.eq(instance.exports.get_tbl2(8), null);
+  assert.eq(instance.exports.get_tbl2(9)(), 42);
+}
+
+function refNullExternInElemsSection() {
+  /*
+  (module
+    (table $t 10 funcref)
+    (elem (i32.const 3) funcref (ref.null extern))
+  )
+  */
+  assert.throws(() => module("\x00\x61\x73\x6d\x01\x00\x00\x00\x04\x04\x01\x70\x00\x0a\x09\x09\x01\x04\x41\x03\x0b\x01\xd0\x6f\x0b"),
+  WebAssembly.CompileError,
+  "WebAssembly.Module doesn't parse at byte 24: ref.null extern is forbidden in element section's, 0th element's 0th index (evaluating 'new WebAssembly.Module(buffer)')");
+}
+
+basicTest();
+refNullExternInElemsSection();
diff --git a/JSTests/wasm/references/element_parsing.js b/JSTests/wasm/references/element_parsing.js
index 93be1fd..01f8902 100644
--- a/JSTests/wasm/references/element_parsing.js
+++ b/JSTests/wasm/references/element_parsing.js
@@ -23,4 +23,4 @@
 //  + "\x02"
     + "\x01"
     + "\x41\x01\x0b\x01\x02\x0a\xd4\x80\x80\x80\x00\x07\x85\x80\x80\x80\x00\x00\x20\x00\xd1\x0b\x85\x80\x80\x80\x00\x00\x20\x00\xd1\x0b\x82\x80\x80\x80\x00\x00\x0b\x88\x80\x80\x80\x00\x00\x41\x01\x20\x00\x26\x00\x0b\x8c\x80\x80\x80\x00\x00\x41\x01\xd0\x26\x00\x41\x01\xd0\x26\x01\x0b\x88\x80\x80\x80\x00\x00\x20\x00\x25\x00\x10\x00\x0b\x88\x80\x80\x80\x00\x00\x20\x00\x25\x01\x10\x01\x0b"),
-    Error, "WebAssembly.Module doesn't parse at byte 143: can't get 0th Element reserved byte, which should be either 0x00 or 0x02 followed by a table index (evaluating 'new WebAssembly.Module(buffer)')");
+    Error, "WebAssembly.Module doesn't parse at byte 143: unsupported 0th Element reserved byte (evaluating 'new WebAssembly.Module(buffer)')");
diff --git a/JSTests/wasm/references/multitable.js b/JSTests/wasm/references/multitable.js
index 48a8560..1007015 100644
--- a/JSTests/wasm/references/multitable.js
+++ b/JSTests/wasm/references/multitable.js
@@ -304,7 +304,7 @@
             .Function("ret42", { params: [], ret: "i32" })
               .I32Const(42)
             .End()
-          .End().WebAssembly().get())), Error, "WebAssembly.Module doesn't parse at byte 41: Table 0 must have type 'funcref' to have an element section (evaluating 'new WebAssembly.Module')")
+          .End().WebAssembly().get())), Error, "WebAssembly.Module doesn't parse at byte 42: Table 0 must have type 'funcref' to have an element section (evaluating 'new WebAssembly.Module')")
 
 assert.throws(() => new WebAssembly.Instance(new WebAssembly.Module((new Builder())
           .Type().End()
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 1d1731e..45c4937 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,30 @@
+2020-12-02  Dmitry Bezhetskov  <dbezhetskov@igalia.com>
+
+        [WASM-References] Add support for active mods in element section
+        https://bugs.webkit.org/show_bug.cgi?id=219192
+
+        Reviewed by Yusuke Suzuki.
+        
+        Adjust wasm parser to parse new form of element section.
+        https://webassembly.github.io/reference-types/core/binary/modules.html#element-section.
+
+        * wasm/WasmEntryPlan.cpp:
+        (JSC::Wasm::EntryPlan::prepare):
+        * wasm/WasmFormat.h:
+        (JSC::Wasm::Element::Element):
+        (JSC::Wasm::Element::active const):
+        * wasm/WasmSectionParser.cpp:
+        (JSC::Wasm::SectionParser::parseElement):
+        (JSC::Wasm::SectionParser::validateElementTableIdx):
+        (JSC::Wasm::SectionParser::parseI32InitExpr):
+        (JSC::Wasm::SectionParser::parseElemKind):
+        (JSC::Wasm::SectionParser::parseIndexCountForElemSection):
+        (JSC::Wasm::SectionParser::parseFuncIdxFromRefExpForElemSection):
+        (JSC::Wasm::SectionParser::parseFuncIdxForElemSection):
+        * wasm/WasmSectionParser.h:
+        * wasm/js/WebAssemblyModuleRecord.cpp:
+        (JSC::WebAssemblyModuleRecord::evaluate):
+
 2020-12-01  Sergey Rubanov  <chi187@gmail.com>
 
         Fix Aarch64 build failure
diff --git a/Source/JavaScriptCore/wasm/WasmEntryPlan.cpp b/Source/JavaScriptCore/wasm/WasmEntryPlan.cpp
index 0a9cf05..943c4da 100644
--- a/Source/JavaScriptCore/wasm/WasmEntryPlan.cpp
+++ b/Source/JavaScriptCore/wasm/WasmEntryPlan.cpp
@@ -143,9 +143,9 @@
     }
 
     for (const auto& element : m_moduleInformation->elements) {
-        for (const uint32_t elementIndex : element.functionIndices) {
-            if (elementIndex >= importFunctionCount)
-                m_exportedFunctionIndices.add(elementIndex - importFunctionCount);
+        for (const uint32_t functionIndex : element.functionIndices) {
+            if (!Element::isNullFuncIndex(functionIndex) && functionIndex >= importFunctionCount)
+                m_exportedFunctionIndices.add(functionIndex - importFunctionCount);
         }
     }
 
diff --git a/Source/JavaScriptCore/wasm/WasmFormat.h b/Source/JavaScriptCore/wasm/WasmFormat.h
index 1fcfdf2..1c7ec47 100644
--- a/Source/JavaScriptCore/wasm/WasmFormat.h
+++ b/Source/JavaScriptCore/wasm/WasmFormat.h
@@ -38,6 +38,7 @@
 #include "WasmOps.h"
 #include "WasmPageCount.h"
 #include "WasmSignature.h"
+#include <cstdint>
 #include <limits>
 #include <memory>
 #include <wtf/Optional.h>
@@ -226,13 +227,34 @@
 
 struct Element {
     WTF_MAKE_STRUCT_FAST_ALLOCATED;
-    Element(uint32_t tableIndex, I32InitExpr offset)
-        : tableIndex(tableIndex)
-        , offset(offset)
+
+    // nullFuncIndex represents the case when an element segment (of type funcref)
+    // contains a null element.
+    constexpr static uint32_t nullFuncIndex = UINT32_MAX;
+
+    enum class Kind : uint8_t {
+        Active,
+        Passive,
+        Declared,
+    };
+
+    Element(Element::Kind kind, TableElementType elementType, uint32_t tableIndex, Optional<I32InitExpr> initExpr)
+        : kind(kind)
+        , elementType(elementType)
+        , tableIndex(tableIndex)
+        , offsetIfActive(initExpr)
     { }
 
+    bool isActive() const { return kind == Kind::Active; }
+
+    static bool isNullFuncIndex(uint32_t idx) { return idx == nullFuncIndex; }
+
+    Kind kind;
+    TableElementType elementType;
     uint32_t tableIndex;
-    I32InitExpr offset;
+    Optional<I32InitExpr> offsetIfActive;
+
+    // Index may be nullFuncIndex.
     Vector<uint32_t> functionIndices;
 };
 
diff --git a/Source/JavaScriptCore/wasm/WasmSectionParser.cpp b/Source/JavaScriptCore/wasm/WasmSectionParser.cpp
index f653e29..d5ad3d0 100644
--- a/Source/JavaScriptCore/wasm/WasmSectionParser.cpp
+++ b/Source/JavaScriptCore/wasm/WasmSectionParser.cpp
@@ -384,41 +384,145 @@
     WASM_PARSER_FAIL_IF(elementCount > maxTableEntries, "Element section's count is too big ", elementCount, " maximum ", maxTableEntries);
     WASM_PARSER_FAIL_IF(!m_info->elements.tryReserveCapacity(elementCount), "can't allocate memory for ", elementCount, " Elements");
     for (unsigned elementNum = 0; elementNum < elementCount; ++elementNum) {
-        uint32_t tableIndex;
-        uint64_t initExprBits;
-        uint8_t initOpcode;
-        uint32_t indexCount;
+        uint8_t elementFlags;
+        WASM_PARSER_FAIL_IF(!parseUInt8(elementFlags), "can't get ", elementNum, "th Element reserved byte, which should be element flags");
 
-        uint8_t magic;
-        WASM_PARSER_FAIL_IF(!parseUInt8(magic) || (magic && magic != 2), "can't get ", elementNum, "th Element reserved byte, which should be either 0x00 or 0x02 followed by a table index");
+        switch (elementFlags) {
+        case 0x00: {
+            constexpr uint32_t tableIndex = 0;
+            WASM_FAIL_IF_HELPER_FAILS(validateElementTableIdx(tableIndex));
 
-        if (magic == 2)
-            WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't get ", elementNum, "th Element table index");
-        else
-            tableIndex = 0;
-        
-        WASM_PARSER_FAIL_IF(tableIndex >= m_info->tableCount(), "Element section for Table ", tableIndex, " exceeds available Table ", m_info->tableCount());
-        WASM_PARSER_FAIL_IF(m_info->tables[tableIndex].type() != TableElementType::Funcref, "Table ", tableIndex, " must have type 'funcref' to have an element section");
-        Type initExprType;
-        WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, initExprBits, initExprType));
-        WASM_PARSER_FAIL_IF(initExprType != I32, "Element init_expr must produce an i32");
-        WASM_PARSER_FAIL_IF(!parseVarUInt32(indexCount), "can't get ", elementNum, "th index count for Element section");
-        WASM_PARSER_FAIL_IF(indexCount == std::numeric_limits<uint32_t>::max(), "Element section's ", elementNum, "th index count is too big ", indexCount);
+            Optional<I32InitExpr> initExpr;
+            WASM_FAIL_IF_HELPER_FAILS(parseI32InitExpr(initExpr));
 
-        ASSERT(!!m_info->tables[tableIndex]);
+            uint32_t indexCount;
+            WASM_FAIL_IF_HELPER_FAILS(parseIndexCountForElementSection(indexCount, elementNum));
+            ASSERT(!!m_info->tables[tableIndex]);
 
-        Element element(tableIndex, makeI32InitExpr(initOpcode, initExprBits));
-        WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices");
+            Element element(Element::Kind::Active, TableElementType::Funcref, tableIndex, WTFMove(initExpr));
+            WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices");
 
-        for (unsigned index = 0; index < indexCount; ++index) {
-            uint32_t functionIndex;
-            WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't get Element section's ", elementNum, "th element's ", index, "th index");
-            WASM_PARSER_FAIL_IF(functionIndex >= m_info->functionIndexSpaceSize(), "Element section's ", elementNum, "th element's ", index, "th index is ", functionIndex, " which exceeds the function index space size of ", m_info->functionIndexSpaceSize());
+            for (uint32_t index = 0; index < indexCount; ++index) {
+                uint32_t funcIdx;
+                WASM_FAIL_IF_HELPER_FAILS(parseFuncIdxForElementSection(funcIdx, elementNum, index));
+                element.functionIndices.uncheckedAppend(funcIdx);
+            }
 
-            element.functionIndices.uncheckedAppend(functionIndex);
+            m_info->elements.uncheckedAppend(WTFMove(element));
+            break;
         }
+        case 0x01: {
+            WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+            WASM_PARSER_FAIL_IF(true, "unsupported ", elementNum, "th Element reserved byte");
+            // Add support for passive element segments and table.init.
+            // FIXME: https://bugs.webkit.org/show_bug.cgi?id=219297
+            break;
+        }
+        case 0x02: {
+            uint32_t tableIndex;
+            WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't get ", elementNum, "th Element table index");
+            WASM_FAIL_IF_HELPER_FAILS(validateElementTableIdx(tableIndex));
 
-        m_info->elements.uncheckedAppend(WTFMove(element));
+            Optional<I32InitExpr> initExpr;
+            WASM_FAIL_IF_HELPER_FAILS(parseI32InitExpr(initExpr));
+
+            uint8_t elementKind;
+            WASM_FAIL_IF_HELPER_FAILS(parseElementKind(elementKind));
+
+            uint32_t indexCount;
+            WASM_FAIL_IF_HELPER_FAILS(parseIndexCountForElementSection(indexCount, elementNum));
+            ASSERT(!!m_info->tables[tableIndex]);
+
+            Element element(Element::Kind::Active, TableElementType::Funcref, tableIndex, WTFMove(initExpr));
+            WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices");
+
+            for (unsigned index = 0; index < indexCount; ++index) {
+                uint32_t funcIdx;
+                WASM_FAIL_IF_HELPER_FAILS(parseFuncIdxForElementSection(funcIdx, elementNum, index));
+                element.functionIndices.uncheckedAppend(funcIdx);
+            }
+
+            m_info->elements.uncheckedAppend(WTFMove(element));
+            break;
+        }
+        case 0x03: {
+            WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+            WASM_PARSER_FAIL_IF(true, "unsupported ", elementNum, "th Element reserved byte");
+            // Add support for declarative element segments.
+            // FIXME: https://bugs.webkit.org/show_bug.cgi?id=219385
+            break;
+        }
+        case 0x04: {
+            WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+            constexpr uint32_t tableIndex = 0;
+            WASM_FAIL_IF_HELPER_FAILS(validateElementTableIdx(tableIndex));
+
+            Optional<I32InitExpr> initExpr;
+            WASM_FAIL_IF_HELPER_FAILS(parseI32InitExpr(initExpr));
+
+            uint32_t indexCount;
+            WASM_FAIL_IF_HELPER_FAILS(parseIndexCountForElementSection(indexCount, elementNum));
+            ASSERT(!!m_info->tables[tableIndex]);
+
+            Element element(Element::Kind::Active, TableElementType::Funcref, tableIndex, WTFMove(initExpr));
+            WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices");
+
+            for (unsigned index = 0; index < indexCount; ++index) {
+                uint32_t funcIdx;
+                WASM_FAIL_IF_HELPER_FAILS(parseFuncIdxFromRefExpForElementSection(funcIdx, elementNum, index));
+                element.functionIndices.uncheckedAppend(funcIdx);
+            }
+
+            m_info->elements.uncheckedAppend(WTFMove(element));
+            break;
+        }
+        case 0x05: {
+            WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+            WASM_PARSER_FAIL_IF(true, "unsupported ", elementNum, "th Element reserved byte");
+            // Add support for passive element segments and table.init.
+            // FIXME: https://bugs.webkit.org/show_bug.cgi?id=219297
+            break;
+        }
+        case 0x06: {
+            WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+
+            uint32_t tableIndex;
+            WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't get ", elementNum, "th Element table index");
+            WASM_FAIL_IF_HELPER_FAILS(validateElementTableIdx(tableIndex));
+
+            Optional<I32InitExpr> initExpr;
+            WASM_FAIL_IF_HELPER_FAILS(parseI32InitExpr(initExpr));
+
+            Type refType;
+            WASM_PARSER_FAIL_IF(!parseRefType(refType), "can't parse reftype in elem section");
+            WASM_PARSER_FAIL_IF(refType != Funcref, "reftype in element section should be funcref");
+
+            uint32_t indexCount;
+            WASM_FAIL_IF_HELPER_FAILS(parseIndexCountForElementSection(indexCount, elementNum));
+            ASSERT(!!m_info->tables[tableIndex]);
+
+            Element element(Element::Kind::Active, TableElementType::Funcref, tableIndex, WTFMove(initExpr));
+            WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices");
+
+            for (unsigned index = 0; index < indexCount; ++index) {
+                uint32_t funcIdx;
+                WASM_FAIL_IF_HELPER_FAILS(parseFuncIdxFromRefExpForElementSection(funcIdx, elementNum, index));
+                element.functionIndices.uncheckedAppend(funcIdx);
+            }
+
+            m_info->elements.uncheckedAppend(WTFMove(element));
+            break;
+        }
+        case 0x07: {
+            WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+            WASM_PARSER_FAIL_IF(true, "unsupported ", elementNum, "th Element reserved byte");
+            // Add support for declarative element segments.
+            // FIXME: https://bugs.webkit.org/show_bug.cgi?id=219385
+            break;
+        }
+        default:
+            WASM_PARSER_FAIL_IF(true, "can't get ", elementNum, "th Element reserved byte");
+        }
     }
 
     return { };
@@ -510,6 +614,80 @@
     return { };
 }
 
+auto SectionParser::validateElementTableIdx(uint32_t tableIndex) -> PartialResult
+{
+    WASM_PARSER_FAIL_IF(tableIndex >= m_info->tableCount(), "Element section for Table ", tableIndex, " exceeds available Table ", m_info->tableCount());
+    WASM_PARSER_FAIL_IF(m_info->tables[tableIndex].type() != TableElementType::Funcref, "Table ", tableIndex, " must have type 'funcref' to have an element section");
+
+    return { };
+}
+
+auto SectionParser::parseI32InitExpr(Optional<I32InitExpr>& initExpr) -> PartialResult
+{
+    uint8_t initOpcode;
+    uint64_t initExprBits;
+    Type initExprType;
+    WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, initExprBits, initExprType));
+    WASM_PARSER_FAIL_IF(initExprType != I32, "Element init_expr must produce an i32");
+    initExpr = makeI32InitExpr(initOpcode, initExprBits);
+
+    return { };
+}
+
+auto SectionParser::parseElementKind(uint8_t& resultElementKind) -> PartialResult
+{
+    uint8_t elementKind;
+    WASM_PARSER_FAIL_IF(!parseUInt8(elementKind), "can't get element kind");
+    WASM_PARSER_FAIL_IF(!!elementKind, "element kind must be zero");
+    resultElementKind = elementKind;
+
+    return { };
+}
+
+auto SectionParser::parseIndexCountForElementSection(uint32_t& resultIndexCount, const unsigned elementNum) -> PartialResult
+{
+    uint32_t indexCount;
+    WASM_PARSER_FAIL_IF(!parseVarUInt32(indexCount), "can't get ", elementNum, "th index count for Element section");
+    WASM_PARSER_FAIL_IF(indexCount == std::numeric_limits<uint32_t>::max(), "Element section's ", elementNum, "th index count is too big ", indexCount);
+    resultIndexCount = indexCount;
+
+    return { };
+}
+
+auto SectionParser::parseFuncIdxFromRefExpForElementSection(uint32_t& funcIdx, const unsigned elementNum, const unsigned index) -> PartialResult
+{
+    uint8_t opcode;
+    WASM_PARSER_FAIL_IF(!parseUInt8(opcode), "can't get opcode for exp in element section's ", elementNum, "th element's ", index, "th index");
+    WASM_PARSER_FAIL_IF((opcode != RefFunc) && (opcode != RefNull), "opcode for exp in element section's should be either ref.func or ref.null ", elementNum, "th element's ", index, "th index");
+
+    if (opcode == RefFunc) {
+        uint32_t functionIndex;
+        WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't get Element section's ", elementNum, "th element's ", index, "th index");
+        WASM_PARSER_FAIL_IF(functionIndex >= m_info->functionIndexSpaceSize(), "Element section's ", elementNum, "th element's ", index, "th index is ", functionIndex, " which exceeds the function index space size of ", m_info->functionIndexSpaceSize());
+        funcIdx = functionIndex;
+    } else {
+        Type typeOfNull;
+        WASM_PARSER_FAIL_IF(!parseRefType(typeOfNull), "ref.null type must be a func type in elem section");
+        WASM_PARSER_FAIL_IF(typeOfNull != Funcref, "ref.null extern is forbidden in element section's, ", elementNum, "th element's ", index, "th index");
+        funcIdx = Element::nullFuncIndex;
+    }
+
+    WASM_PARSER_FAIL_IF(!parseUInt8(opcode), "can't get opcode for exp end in element section's ", elementNum, "th element's ", index, "th index");
+    WASM_PARSER_FAIL_IF(opcode != End, "malformed expr in element section's", elementNum, "th element's ", index, "th index");
+
+    return { };
+}
+
+auto SectionParser::parseFuncIdxForElementSection(uint32_t& funcIdx, const unsigned elementNum, const unsigned index) -> PartialResult
+{
+    uint32_t functionIndex;
+    WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't get Element section's ", elementNum, "th element's ", index, "th index");
+    WASM_PARSER_FAIL_IF(functionIndex >= m_info->functionIndexSpaceSize(), "Element section's ", elementNum, "th element's ", index, "th index is ", functionIndex, " which exceeds the function index space size of ", m_info->functionIndexSpaceSize());
+    funcIdx = functionIndex;
+
+    return { };
+}
+
 auto SectionParser::parseGlobalType(GlobalInformation& global) -> PartialResult
 {
     uint8_t mutability;
diff --git a/Source/JavaScriptCore/wasm/WasmSectionParser.h b/Source/JavaScriptCore/wasm/WasmSectionParser.h
index 86b980a..03a7eec 100644
--- a/Source/JavaScriptCore/wasm/WasmSectionParser.h
+++ b/Source/JavaScriptCore/wasm/WasmSectionParser.h
@@ -67,6 +67,13 @@
     PartialResult WARN_UNUSED_RETURN parseResizableLimits(uint32_t& initial, Optional<uint32_t>& maximum, bool& isShared, LimitsType);
     PartialResult WARN_UNUSED_RETURN parseInitExpr(uint8_t&, uint64_t&, Type& initExprType);
 
+    PartialResult WARN_UNUSED_RETURN validateElementTableIdx(uint32_t);
+    PartialResult WARN_UNUSED_RETURN parseI32InitExpr(Optional<I32InitExpr>&);
+    PartialResult WARN_UNUSED_RETURN parseElementKind(uint8_t& elementKind);
+    PartialResult WARN_UNUSED_RETURN parseIndexCountForElementSection(uint32_t&, const unsigned);
+    PartialResult WARN_UNUSED_RETURN parseFuncIdxFromRefExpForElementSection(uint32_t&, const unsigned, const unsigned);
+    PartialResult WARN_UNUSED_RETURN parseFuncIdxForElementSection(uint32_t&, const unsigned, const unsigned);
+
     size_t m_offsetInSource;
     Ref<ModuleInformation> m_info;
 };
diff --git a/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp b/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp
index 2064a46..e83b829 100644
--- a/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp
+++ b/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp
@@ -555,9 +555,13 @@
             if (!element.functionIndices.size())
                 continue;
 
-            uint32_t elementIndex = element.offset.isGlobalImport()
-                ? static_cast<uint32_t>(m_instance->instance().loadI32Global(element.offset.globalImportIndex()))
-                : element.offset.constValue();
+            if (!element.isActive())
+                continue;
+
+            const auto& offset = *element.offsetIfActive;
+            const uint32_t elementIndex = offset.isGlobalImport()
+                ? static_cast<uint32_t>(m_instance->instance().loadI32Global(offset.globalImportIndex()))
+                : offset.constValue();
 
             fn(element, element.tableIndex, elementIndex);
 
@@ -604,13 +608,19 @@
     if (UNLIKELY(exception))
         return exception.value();
 
-    forEachElement([&] (const Wasm::Element& element, uint32_t tableIndex, uint32_t elementIndex) {
+    forEachElement([&] (const Wasm::Element& element, uint32_t tableIndex, uint32_t startElementIndex) {
         for (uint32_t i = 0; i < element.functionIndices.size(); ++i) {
+            const uint32_t elementIndex = startElementIndex + i;
+            const uint32_t functionIndex = element.functionIndices[i];
+            if (Wasm::Element::isNullFuncIndex(functionIndex)) {
+                m_instance->table(tableIndex)->clear(elementIndex);
+                continue;
+            }
+
             // FIXME: This essentially means we're exporting an import.
             // We need a story here. We need to create a WebAssemblyFunction
             // for the import.
             // https://bugs.webkit.org/show_bug.cgi?id=165510
-            uint32_t functionIndex = element.functionIndices[i];
             Wasm::SignatureIndex signatureIndex = module.signatureIndexFromFunctionIndexSpace(functionIndex);
             if (functionIndex < codeBlock->functionImportCount()) {
                 JSObject* functionImport = m_instance->instance().importFunction<WriteBarrier<JSObject>>(functionIndex)->get();
@@ -621,13 +631,11 @@
                     // the only type this could be is WebAssemblyFunction.
                     RELEASE_ASSERT(wasmFunction);
                     m_instance->table(tableIndex)->set(elementIndex, wasmFunction);
-                    ++elementIndex;
                     continue;
                 }
 
                 m_instance->table(tableIndex)->set(elementIndex,
                     WebAssemblyWrapperFunction::create(vm, globalObject, globalObject->webAssemblyWrapperFunctionStructure(), functionImport, functionIndex, m_instance.get(), signatureIndex));
-                ++elementIndex;
                 continue;
             }
 
@@ -640,9 +648,7 @@
             // https://bugs.webkit.org/show_bug.cgi?id=165825
             WebAssemblyFunction* function = WebAssemblyFunction::create(
                 vm, globalObject, globalObject->webAssemblyFunctionStructure(), signature.argumentCount(), String(), m_instance.get(), embedderEntrypointCallee, entrypointLoadLocation, signatureIndex);
-
             m_instance->table(tableIndex)->set(elementIndex, function);
-            ++elementIndex;
         }
     });