Ignore:
Timestamp:
Dec 9, 2016, 11:08:31 PM (9 years ago)
Author:
[email protected]
Message:

WebAssembly: implement data section
https://bugs.webkit.org/show_bug.cgi?id=165696

Reviewed by Keith Miller.

As specified in https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#data-section
Note that some of the interesting corner cases are ill-defined by the spec: https://github.com/WebAssembly/design/issues/897

JSTests:

  • wasm/Builder.js: create a data section from JavaScript
  • wasm/Builder_WebAssemblyBinary.js: assemble the data section into the proper binary encoding

(const.emitters.Data):

  • wasm/js-api/test_Data.js: Added.

(DataSection):
(DataSectionOffTheEnd):
(DataSectionPartlyOffTheEnd):
(DataSectionEmptyOffTheEnd):
(DataSectionSeenByStart):

  • wasm/self-test/test_BuilderJSON.js: make sure the JSON structure is fine (this sanity checks before going to binary)

Source/JavaScriptCore:

  • wasm/WasmFormat.h: segments are what represent sections of memory to initialize (similar to ELF's non-zero intializer data / rodata)

(JSC::Wasm::Segment::make):
(JSC::Wasm::Segment::destroy):
(JSC::Wasm::Segment::byte):
(JSC::Wasm::Segment::makePtr):

  • wasm/WasmModuleParser.cpp: parse the data section, and prevent a few overflows if a user passes in UINT_MAX (the loops would overflow)

(JSC::Wasm::ModuleParser::parseType):
(JSC::Wasm::ModuleParser::parseImport):
(JSC::Wasm::ModuleParser::parseFunction):
(JSC::Wasm::ModuleParser::parseExport):
(JSC::Wasm::ModuleParser::parseCode):
(JSC::Wasm::ModuleParser::parseData):

  • wasm/js/WebAssemblyModuleRecord.cpp:

(JSC::WebAssemblyModuleRecord::evaluate): the only sensible time to initialize the data section is after linking, but before calling start, I test for this but the spec isn't clear it's correct yet

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp

    r209642 r209651  
    158158{
    159159    uint32_t count;
    160     if (!parseVarUInt32(count))
     160    if (!parseVarUInt32(count)
     161        || count == std::numeric_limits<uint32_t>::max()
     162        || !m_module->signatures.tryReserveCapacity(count))
    161163        return false;
    162164    if (verbose)
    163         dataLogLn("count: ", count);
    164     if (!m_module->signatures.tryReserveCapacity(count))
    165         return false;
     165        dataLogLn("  count: ", count);
    166166
    167167    for (uint32_t i = 0; i < count; ++i) {
     
    176176
    177177        uint32_t argumentCount;
    178         if (!parseVarUInt32(argumentCount))
    179             return false;
    180 
    181         if (verbose)
    182             dataLogLn("argumentCount: ", argumentCount);
    183 
    184178        Vector<Type> argumentTypes;
    185         if (!argumentTypes.tryReserveCapacity(argumentCount))
    186             return false;
    187 
    188         for (unsigned i = 0; i != argumentCount; ++i) {
     179        if (!parseVarUInt32(argumentCount)
     180            || argumentCount == std::numeric_limits<uint32_t>::max()
     181            || !argumentTypes.tryReserveCapacity(argumentCount))
     182            return false;
     183        if (verbose)
     184            dataLogLn("  argument count: ", argumentCount);
     185
     186        for (unsigned i = 0; i < argumentCount; ++i) {
    189187            Type argumentType;
    190188            if (!parseResultType(argumentType))
     
    217215{
    218216    uint32_t importCount;
    219     if (!parseVarUInt32(importCount))
    220         return false;
    221     if (!m_module->imports.tryReserveCapacity(importCount) // FIXME this over-allocates when we fix the FIXMEs below.
     217    if (!parseVarUInt32(importCount)
     218        || importCount == std::numeric_limits<uint32_t>::max()
     219        || !m_module->imports.tryReserveCapacity(importCount) // FIXME this over-allocates when we fix the FIXMEs below.
    222220        || !m_module->importFunctions.tryReserveCapacity(importCount) // FIXME this over-allocates when we fix the FIXMEs below.
    223221        || !m_functionIndexSpace.tryReserveCapacity(importCount)) // FIXME this over-allocates when we fix the FIXMEs below. We'll allocate some more here when we know how many functions to expect.
    224222        return false;
    225223
    226     for (uint32_t importNumber = 0; importNumber != importCount; ++importNumber) {
     224    for (uint32_t importNumber = 0; importNumber < importCount; ++importNumber) {
    227225        Import imp;
    228226        uint32_t moduleLen;
     
    279277    uint32_t count;
    280278    if (!parseVarUInt32(count)
     279        || count == std::numeric_limits<uint32_t>::max()
    281280        || !m_module->internalFunctionSignatures.tryReserveCapacity(count)
    282281        || !m_functionLocationInBinary.tryReserveCapacity(count)
     
    284283        return false;
    285284
    286     for (uint32_t i = 0; i != count; ++i) {
     285    for (uint32_t i = 0; i < count; ++i) {
    287286        uint32_t typeNumber;
    288287        if (!parseVarUInt32(typeNumber)
     
    375374    uint32_t exportCount;
    376375    if (!parseVarUInt32(exportCount)
     376        || exportCount == std::numeric_limits<uint32_t>::max()
    377377        || !m_module->exports.tryReserveCapacity(exportCount))
    378378        return false;
    379379
    380     for (uint32_t exportNumber = 0; exportNumber != exportCount; ++exportNumber) {
     380    for (uint32_t exportNumber = 0; exportNumber < exportCount; ++exportNumber) {
    381381        Export exp;
    382382        uint32_t fieldLen;
     
    386386            return false;
    387387        exp.field = Identifier::fromString(m_vm, fieldString);
     388
    388389        if (!parseExternalKind(exp.kind))
    389390            return false;
     391
    390392        switch (exp.kind) {
    391393        case External::Function: {
     
    441443    uint32_t count;
    442444    if (!parseVarUInt32(count)
     445        || count == std::numeric_limits<uint32_t>::max()
    443446        || count != m_functionLocationInBinary.size())
    444447        return false;
    445448
    446     for (uint32_t i = 0; i != count; ++i) {
     449    for (uint32_t i = 0; i < count; ++i) {
    447450        uint32_t functionSize;
    448451        if (!parseVarUInt32(functionSize)
     
    461464bool ModuleParser::parseData()
    462465{
    463     // FIXME https://bugs.webkit.org/show_bug.cgi?id=161709
    464     RELEASE_ASSERT_NOT_REACHED();
     466    uint32_t segmentCount;
     467    if (!parseVarUInt32(segmentCount)
     468        || segmentCount == std::numeric_limits<uint32_t>::max()
     469        || !m_module->data.tryReserveCapacity(segmentCount))
     470        return false;
     471    if (verbose)
     472        dataLogLn("  segments: ", segmentCount);
     473
     474    for (uint32_t segmentNumber = 0; segmentNumber < segmentCount; ++segmentNumber) {
     475        if (verbose)
     476            dataLogLn("  segment #", segmentNumber);
     477        uint32_t index;
     478        uint8_t opcode;
     479        uint32_t offset;
     480        uint8_t endOpcode;
     481        uint32_t dataByteLength;
     482        if (!parseVarUInt32(index)
     483            || index)
     484            return false;
     485
     486        // FIXME allow complex init_expr here. https://bugs.webkit.org/show_bug.cgi?id=165700
     487        // For now we only handle i32.const as offset.
     488        if (!parseUInt8(opcode)
     489            || opcode != Wasm::I32Const
     490            || !parseVarUInt32(offset)
     491            || !parseUInt8(endOpcode)
     492            || endOpcode != Wasm::End)
     493            return false;
     494        if (verbose)
     495            dataLogLn("    offset: ", offset);
     496
     497        if (!parseVarUInt32(dataByteLength)
     498            || dataByteLength == std::numeric_limits<uint32_t>::max())
     499            return false;
     500        if (verbose)
     501            dataLogLn("    data bytes: ", dataByteLength);
     502
     503        Segment* segment = Segment::make(offset, dataByteLength);
     504        if (!segment)
     505            return false;
     506        m_module->data.uncheckedAppend(Segment::makePtr(segment));
     507        for (uint32_t dataByte = 0; dataByte < dataByteLength; ++dataByte) {
     508            uint8_t byte;
     509            if (!parseUInt8(byte))
     510                return false;
     511            segment->byte(dataByte) = byte;
     512            if (verbose)
     513                dataLogLn("    [", dataByte, "] = ", segment->byte(dataByte));
     514        }
     515    }
    465516    return true;
    466517}
Note: See TracChangeset for help on using the changeset viewer.