Changeset 270948 in webkit


Ignore:
Timestamp:
Dec 17, 2020 2:25:20 PM (19 months ago)
Author:
commit-queue@webkit.org
Message:

[WASM-References] Add support for memory.copy, memory.init and data.drop
https://bugs.webkit.org/show_bug.cgi?id=219943

Patch by Dmitry Bezhetskov <dbezhetskov> on 2020-12-17
Reviewed by Yusuke Suzuki.

JSTests:

Added ref-types spec tests for memory.copy, memory.init and data.drop:
https://github.com/WebAssembly/reference-types/tree/master/test/core.
Renamed table_instructions_parse_unreachable test into just
parse_unreachable to prevent confusion.

  • wasm.yaml:
  • wasm/references-spec-tests/memory_copy.wast.js: Added.
  • wasm/references-spec-tests/memory_init.wast.js: Added.
  • wasm/references/memory_copy.js: Added.

(async test):

  • wasm/references/memory_copy_shared.js: Added.

(async test):

  • wasm/references/parse_unreachable.js: Renamed from JSTests/wasm/references/table_instructions_parse_unreachable.js.

(invalidMemoryCopyUnreachable):
(invalidMemoryInitUnreachable):
(invalidDataDropUnreachable):

  • wasm/wasm.json:

Source/JavaScriptCore:

Add support for memory.copy [dstAddress, srcAddress, length] -> []
that copies one memory segment to another memory segment.
The memory.copy calls C memcpy function to utilize all possible optimization for copy.
This instruction speedup copying data segments in wasm because without it we need to use a lot
load/store instructions with loops in wasm.

Add support for memory.init data_segment_index [dstAddress, srcAddress, length] -> []
that copies data from a passive data segment into a memory segment.
This instruction is the same as memory.copy but for read-only data segments.
It also utilize C memcpy under the hood.

Add support for data.drop data_segment_index [] -> []
that resize given data segment to zero.
Data.drop makes redundant data segment and prevents usage of it in the next.
BTW, it is just a hint for the host runtime so we don't have to change data segment.

Add support for Data count section.
This section just stores the number of data segments.
We need this to validate memory.init instruction's data index because
Code section comes before Data section.

These instructions are needed to support reference types proposal and bulk proposal.

  • bytecode/BytecodeList.rb:
  • llint/WebAssembly.asm:
  • wasm/WasmAirIRGenerator.cpp:

(JSC::Wasm::AirIRGenerator::addMemoryCopy):
(JSC::Wasm::AirIRGenerator::addMemoryInit):
(JSC::Wasm::AirIRGenerator::addDataDrop):

  • wasm/WasmB3IRGenerator.cpp:

(JSC::Wasm::B3IRGenerator::addMemoryInit):
(JSC::Wasm::B3IRGenerator::addMemoryCopy):
(JSC::Wasm::B3IRGenerator::addDataDrop):

  • wasm/WasmFormat.cpp:

(JSC::Wasm::Segment::create):

  • wasm/WasmFormat.h:

(JSC::Wasm::Segment::isActive const):
(JSC::Wasm::Segment::isPassive const):

  • wasm/WasmFunctionParser.h:

(JSC::Wasm::FunctionParser<Context>::parseDataSegmentIndex):
(JSC::Wasm::FunctionParser<Context>::parseMemoryCopyImmediates):
(JSC::Wasm::FunctionParser<Context>::parseMemoryInitImmediates):
(JSC::Wasm::FunctionParser<Context>::parseExpression):
(JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):

  • wasm/WasmInstance.cpp:

(JSC::Wasm::Instance::Instance):
(JSC::Wasm::Instance::memoryInit):
(JSC::Wasm::Instance::dataDrop):

  • wasm/WasmInstance.h:
  • wasm/WasmLLIntGenerator.cpp:

(JSC::Wasm::LLIntGenerator::addMemoryInit):
(JSC::Wasm::LLIntGenerator::addDataDrop):
(JSC::Wasm::LLIntGenerator::addMemoryCopy):

  • wasm/WasmMemory.cpp:

(JSC::Wasm::Memory::copy):
(JSC::Wasm::Memory::init):

  • wasm/WasmMemory.h:
  • wasm/WasmModuleInformation.h:

(JSC::Wasm::ModuleInformation::dataSegmentsCount const):

  • wasm/WasmOperations.cpp:

(JSC::Wasm::JSC_DEFINE_JIT_OPERATION):

  • wasm/WasmOperations.h:
  • wasm/WasmSectionParser.cpp:

(JSC::Wasm::SectionParser::parseElement):
(JSC::Wasm::SectionParser::parseI32InitExpr):
(JSC::Wasm::SectionParser::parseI32InitExprForElementSection):
(JSC::Wasm::SectionParser::parseI32InitExprForDataSection):
(JSC::Wasm::SectionParser::parseDataSegmentCoreSpec):
(JSC::Wasm::SectionParser::parseDataSegmentReferenceTypesSpec):
(JSC::Wasm::SectionParser::parseGlobalType):
(JSC::Wasm::SectionParser::parseData):
(JSC::Wasm::SectionParser::parseDataCount):

  • wasm/WasmSectionParser.h:
  • wasm/WasmSections.h:

(JSC::Wasm::validateOrder):

  • wasm/WasmSlowPaths.cpp:

(JSC::LLInt::WASM_SLOW_PATH_DECL):

  • wasm/WasmSlowPaths.h:
  • wasm/js/WebAssemblyModuleRecord.cpp:

(JSC::WebAssemblyModuleRecord::evaluate):

  • wasm/wasm.json:
Location:
trunk
Files:
4 added
26 edited
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r270923 r270948  
     12020-12-17  Dmitry Bezhetskov  <dbezhetskov@igalia.com>
     2
     3        [WASM-References] Add support for memory.copy, memory.init and data.drop
     4        https://bugs.webkit.org/show_bug.cgi?id=219943
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        Added ref-types spec tests for memory.copy, memory.init and data.drop:
     9        https://github.com/WebAssembly/reference-types/tree/master/test/core.
     10        Renamed table_instructions_parse_unreachable test into just
     11        parse_unreachable to prevent confusion.
     12
     13        * wasm.yaml:
     14        * wasm/references-spec-tests/memory_copy.wast.js: Added.
     15        * wasm/references-spec-tests/memory_init.wast.js: Added.
     16        * wasm/references/memory_copy.js: Added.
     17        (async test):
     18        * wasm/references/memory_copy_shared.js: Added.
     19        (async test):
     20        * wasm/references/parse_unreachable.js: Renamed from JSTests/wasm/references/table_instructions_parse_unreachable.js.
     21        (invalidMemoryCopyUnreachable):
     22        (invalidMemoryInitUnreachable):
     23        (invalidDataDropUnreachable):
     24        * wasm/wasm.json:
     25
    1262020-12-15  Yusuke Suzuki  <ysuzuki@apple.com>
    227
  • trunk/JSTests/wasm.yaml

    r270855 r270948  
    5959- path: wasm/references-spec-tests/memory_fill.wast.js
    6060  cmd: runWebAssemblyReferenceSpecTest :normal
     61- path: wasm/references-spec-tests/memory_copy.wast.js
     62  cmd: runWebAssemblyReferenceSpecTest :normal
     63- path: wasm/references-spec-tests/memory_init.wast.js
     64  cmd: runWebAssemblyReferenceSpecTest :normal
    6165
    6266- path: wasm/multi-value-spec-tests/block.wast.js
  • trunk/JSTests/wasm/references/parse_unreachable.js

    r270947 r270948  
    283283}
    284284
     285function validMemoryCopyUnreachable() {
     286  /*
     287  (module
     288    (memory $mem0 1)
     289    (func (export "run")
     290      (return)
     291      (memory.copy (i32.const 3) (i32.const 0) (i32.const 1))
     292    )
     293  )
     294  */
     295  let instance = new WebAssembly.Instance(module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x03\x02\x01\x00\x05\x03\x01\x00\x01\x07\x07\x01\x03\x72\x75\x6e\x00\x00\x0a\x0f\x01\x0d\x00\x0f\x41\x03\x41\x00\x41\x01\xfc\x0a\x00\x00\x0b"));
     296  instance.exports.run();
     297}
     298
     299function invalidMemoryCopyUnreachable() {
     300  /*
     301  (module
     302    (memory $mem0 1)
     303    (func (export "run")
     304      (return)
     305      (memory.copy (unsued_1 = 1) (i32.const 3) (i32.const 0) (i32.const 1))
     306    )
     307  )
     308  */
     309  assert.throws(() => module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x03\x02\x01\x00\x05\x03\x01\x00\x01\x07\x07\x01\x03\x72\x75\x6e\x00\x00\x0a\x0f\x01\x0d\x00\x0f\x41\x03\x41\x00\x41\x01\xfc\x0a\x01\x00\x0b"),
     310  WebAssembly.CompileError,
     311  "WebAssembly.Module doesn't parse at byte 11: auxiliary byte for memory.copy should be zero, but got 1, in function at index 0 (evaluating 'new WebAssembly.Module(buffer)')");
     312
     313  /*
     314  (module
     315    (memory $mem0 1)
     316    (func (export "run")
     317      (return)
     318      (memory.copy (unsued_1 = 0, unused_2 = 1) (i32.const 3) (i32.const 0) (i32.const 1))
     319    )
     320  )
     321  */
     322  assert.throws(() => module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x03\x02\x01\x00\x05\x03\x01\x00\x01\x07\x07\x01\x03\x72\x75\x6e\x00\x00\x0a\x0f\x01\x0d\x00\x0f\x41\x03\x41\x00\x41\x01\xfc\x0a\x00\x01\x0b"),
     323  WebAssembly.CompileError,
     324  "WebAssembly.Module doesn't parse at byte 12: auxiliary byte for memory.copy should be zero, but got 1, in function at index 0 (evaluating 'new WebAssembly.Module(buffer)')");
     325}
     326
     327function validMemoryInitUnreachable() {
     328  /*
     329  (module
     330    (memory $mem0 1)
     331    (data $data0 "\02\03\05\07")
     332    (func (export "run")
     333      (return)
     334      (memory.init $data0 (i32.const 4) (i32.const 0) (i32.const 4))
     335    )
     336  )
     337  */
     338  let instance = new WebAssembly.Instance(module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x03\x02\x01\x00\x05\x03\x01\x00\x01\x07\x07\x01\x03\x72\x75\x6e\x00\x00\x0c\x01\x01\x0a\x0f\x01\x0d\x00\x0f\x41\x04\x41\x00\x41\x04\xfc\x08\x00\x00\x0b\x0b\x07\x01\x01\x04\x02\x03\x05\x07"));
     339  instance.exports.run();
     340}
     341
     342function invalidMemoryInitUnreachable() {
     343  /*
     344  (module
     345    (memory $mem0 1)
     346    (data $data0 "\02\03\05\07")
     347    (func (export "run")
     348      (return)
     349      (memory.init 10 (i32.const 4) (i32.const 0) (i32.const 4))
     350    )
     351  )
     352  */
     353  assert.throws(() => module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x03\x02\x01\x00\x05\x03\x01\x00\x01\x07\x07\x01\x03\x72\x75\x6e\x00\x00\x0c\x01\x01\x0a\x0f\x01\x0d\x00\x0f\x41\x04\x41\x00\x41\x04\xfc\x08\x0a\x00\x0b\x0b\x07\x01\x01\x04\x02\x03\x05\x07"),
     354  WebAssembly.CompileError,
     355  "WebAssembly.Module doesn't validate: data segment index 10 is invalid, limit is 1, in function at index 0 (evaluating 'new WebAssembly.Module(buffer)')");
     356}
     357
     358function validDataDropUnreachable() {
     359  /*
     360  (module
     361    (memory 1)
     362    (data $data0 "\37")
     363    (func (export "run")
     364      (return)
     365      (data.drop $data0)
     366    )
     367  )
     368  */
     369  let instance = new WebAssembly.Instance(module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x03\x02\x01\x00\x05\x03\x01\x00\x01\x07\x07\x01\x03\x72\x75\x6e\x00\x00\x0c\x01\x01\x0a\x08\x01\x06\x00\x0f\xfc\x09\x00\x0b\x0b\x04\x01\x01\x01\x37"));
     370  instance.exports.run();
     371}
     372
     373function invalidDataDropUnreachable() {
     374  /*
     375  (module
     376    (memory 1)
     377    (data $data0 "\37")
     378    (func (export "run")
     379      (return)
     380      (data.drop 10)
     381    )
     382  )
     383  */
     384  assert.throws(() => module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x03\x02\x01\x00\x05\x03\x01\x00\x01\x07\x07\x01\x03\x72\x75\x6e\x00\x00\x0c\x01\x01\x0a\x08\x01\x06\x00\x0f\xfc\x09\x0a\x0b\x0b\x04\x01\x01\x01\x37"),
     385  WebAssembly.CompileError,
     386  "WebAssembly.Module doesn't validate: data segment index 10 is invalid, limit is 1, in function at index 0 (evaluating 'new WebAssembly.Module(buffer)')");
     387}
     388
    285389validTableInitUnreachable();
    286390invalidTableInitUnreachable();
     
    306410validMemoryFillUnreachable();
    307411invalidMemoryFillUnreachable();
     412
     413validMemoryCopyUnreachable();
     414invalidMemoryCopyUnreachable();
     415
     416validMemoryInitUnreachable();
     417invalidMemoryInitUnreachable();
     418
     419validDataDropUnreachable();
     420invalidDataDropUnreachable();
  • trunk/JSTests/wasm/wasm.json

    r270855 r270948  
    8080        "table.copy":          { "category": "exttable",   "value":  252, "return": [],                              "parameter": ["i32", "i32", "i32"],          "immediate": [{"name": "dst_index",      "type": "varuint32"}, {"name": "src_index",  "type": "varuint32"}],"description": "copy table elements from dst_table[dstOffset, dstOffset + length] to src_table[srcOffset, srcOffset + length]", "extendedOp": 14 },
    8181        "memory.fill":         { "category": "exttable",   "value":  252, "return": [],                              "parameter": ["i32", "i32", "i32"],          "immediate": [{"name": "unused",         "type": "uint8"}],                                                 "description": "sets all values in a region to a given byte", "extendedOp": 11 },
     82        "memory.copy":         { "category": "exttable",   "value":  252, "return": [],                              "parameter": ["i32", "i32", "i32"],          "immediate": [{"name": "unused",         "type": "uint8"}, {"name": "unused",         "type": "uint8"}],    "description": "copies data from a source memory region to destination region", "extendedOp": 10 },
     83        "memory.init":         { "category": "exttable",   "value":  252, "return": [],                              "parameter": ["i32", "i32", "i32"],          "immediate": [{"name": "segment_index",  "type": "varuint32"}, {"name": "unsued",  "type": "varuint32"}],   "description": "copies data from a passive data segment into a memory", "extendedOp": 8 },
     84        "data.drop":           { "category": "exttable",   "value":  252, "return": [],                              "parameter": [],                             "immediate": [{"name": "segment_index",  "type": "varuint32"}],                                             "description": "shrinks the size of the segment to zero", "extendedOp": 9 },
    8285        "call":                { "category": "call",       "value":  16, "return": ["call"],                         "parameter": ["call"],                       "immediate": [{"name": "function_index", "type": "varuint32"}],                                             "description": "call a function by its index" },
    8386        "call_indirect":       { "category": "call",       "value":  17, "return": ["call"],                         "parameter": ["call"],                       "immediate": [{"name": "type_index",     "type": "varuint32"}, {"name": "table_index","type": "varuint32"}],"description": "call a function indirect with an expected signature" },
  • trunk/Source/JavaScriptCore/ChangeLog

    r270928 r270948  
     12020-12-17  Dmitry Bezhetskov  <dbezhetskov@igalia.com>
     2
     3        [WASM-References] Add support for memory.copy, memory.init and data.drop
     4        https://bugs.webkit.org/show_bug.cgi?id=219943
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        Add support for memory.copy [dstAddress, srcAddress, length] -> []
     9        that copies one  memory segment to another memory segment.
     10        The memory.copy calls C memcpy function to utilize all possible optimization for copy.
     11        This instruction speedup copying data segments in wasm because without it we need to use a lot
     12        load/store instructions with loops in wasm.
     13
     14        Add support for memory.init data_segment_index [dstAddress, srcAddress, length] -> []
     15        that copies data from a passive data segment into a memory segment.
     16        This instruction is the same as memory.copy but for read-only data segments.
     17        It also utilize C memcpy under the hood.
     18
     19        Add support for data.drop data_segment_index [] -> []
     20        that resize given data segment to zero.
     21        Data.drop makes redundant data segment and prevents usage of it in the next.
     22        BTW, it is just a hint for the host runtime so we don't have to change data segment.
     23
     24        Add support for Data count section.
     25        This section just stores the number of data segments.
     26        We need this to validate memory.init instruction's data index because
     27        Code section comes before Data section.
     28
     29        These instructions are needed to support reference types proposal and bulk proposal.
     30
     31        * bytecode/BytecodeList.rb:
     32        * llint/WebAssembly.asm:
     33        * wasm/WasmAirIRGenerator.cpp:
     34        (JSC::Wasm::AirIRGenerator::addMemoryCopy):
     35        (JSC::Wasm::AirIRGenerator::addMemoryInit):
     36        (JSC::Wasm::AirIRGenerator::addDataDrop):
     37        * wasm/WasmB3IRGenerator.cpp:
     38        (JSC::Wasm::B3IRGenerator::addMemoryInit):
     39        (JSC::Wasm::B3IRGenerator::addMemoryCopy):
     40        (JSC::Wasm::B3IRGenerator::addDataDrop):
     41        * wasm/WasmFormat.cpp:
     42        (JSC::Wasm::Segment::create):
     43        * wasm/WasmFormat.h:
     44        (JSC::Wasm::Segment::isActive const):
     45        (JSC::Wasm::Segment::isPassive const):
     46        * wasm/WasmFunctionParser.h:
     47        (JSC::Wasm::FunctionParser<Context>::parseDataSegmentIndex):
     48        (JSC::Wasm::FunctionParser<Context>::parseMemoryCopyImmediates):
     49        (JSC::Wasm::FunctionParser<Context>::parseMemoryInitImmediates):
     50        (JSC::Wasm::FunctionParser<Context>::parseExpression):
     51        (JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):
     52        * wasm/WasmInstance.cpp:
     53        (JSC::Wasm::Instance::Instance):
     54        (JSC::Wasm::Instance::memoryInit):
     55        (JSC::Wasm::Instance::dataDrop):
     56        * wasm/WasmInstance.h:
     57        * wasm/WasmLLIntGenerator.cpp:
     58        (JSC::Wasm::LLIntGenerator::addMemoryInit):
     59        (JSC::Wasm::LLIntGenerator::addDataDrop):
     60        (JSC::Wasm::LLIntGenerator::addMemoryCopy):
     61        * wasm/WasmMemory.cpp:
     62        (JSC::Wasm::Memory::copy):
     63        (JSC::Wasm::Memory::init):
     64        * wasm/WasmMemory.h:
     65        * wasm/WasmModuleInformation.h:
     66        (JSC::Wasm::ModuleInformation::dataSegmentsCount const):
     67        * wasm/WasmOperations.cpp:
     68        (JSC::Wasm::JSC_DEFINE_JIT_OPERATION):
     69        * wasm/WasmOperations.h:
     70        * wasm/WasmSectionParser.cpp:
     71        (JSC::Wasm::SectionParser::parseElement):
     72        (JSC::Wasm::SectionParser::parseI32InitExpr):
     73        (JSC::Wasm::SectionParser::parseI32InitExprForElementSection):
     74        (JSC::Wasm::SectionParser::parseI32InitExprForDataSection):
     75        (JSC::Wasm::SectionParser::parseDataSegmentCoreSpec):
     76        (JSC::Wasm::SectionParser::parseDataSegmentReferenceTypesSpec):
     77        (JSC::Wasm::SectionParser::parseGlobalType):
     78        (JSC::Wasm::SectionParser::parseData):
     79        (JSC::Wasm::SectionParser::parseDataCount):
     80        * wasm/WasmSectionParser.h:
     81        * wasm/WasmSections.h:
     82        (JSC::Wasm::validateOrder):
     83        * wasm/WasmSlowPaths.cpp:
     84        (JSC::LLInt::WASM_SLOW_PATH_DECL):
     85        * wasm/WasmSlowPaths.h:
     86        * wasm/js/WebAssemblyModuleRecord.cpp:
     87        (JSC::WebAssemblyModuleRecord::evaluate):
     88        * wasm/wasm.json:
     89
    1902020-12-16  Yusuke Suzuki  <ysuzuki@apple.com>
    291
  • trunk/Source/JavaScriptCore/bytecode/BytecodeList.rb

    r270874 r270948  
    16831683    }
    16841684
     1685op :memory_copy,
     1686    args: {
     1687        dstAddress: VirtualRegister,
     1688        srcAddress: VirtualRegister,
     1689        count: VirtualRegister,
     1690    }
     1691
     1692op :memory_init,
     1693    args: {
     1694        dstAddress: VirtualRegister,
     1695        srcAddress: VirtualRegister,
     1696        length: VirtualRegister,
     1697        dataSegmentIndex: unsigned,
     1698    }
     1699
     1700op :data_drop,
     1701    args: {
     1702        dataSegmentIndex: unsigned,
     1703    }
     1704
    16851705op :select,
    16861706    args: {
  • trunk/Source/JavaScriptCore/llint/WebAssembly.asm

    r270855 r270948  
    569569slowWasmOp(table_grow)
    570570slowWasmOp(memory_fill)
     571slowWasmOp(memory_copy)
     572slowWasmOp(memory_init)
     573slowWasmOp(data_drop)
    571574slowWasmOp(set_global_ref)
    572575slowWasmOp(set_global_ref_portable_binding)
  • trunk/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp

    r270855 r270948  
    282282    PartialResult WARN_UNUSED_RETURN addCurrentMemory(ExpressionType& result);
    283283    PartialResult WARN_UNUSED_RETURN addMemoryFill(ExpressionType dstAddress, ExpressionType targetValue, ExpressionType count);
     284    PartialResult WARN_UNUSED_RETURN addMemoryCopy(ExpressionType dstAddress, ExpressionType srcAddress, ExpressionType count);
     285    PartialResult WARN_UNUSED_RETURN addMemoryInit(unsigned, ExpressionType dstAddress, ExpressionType srcAddress, ExpressionType length);
     286    PartialResult WARN_UNUSED_RETURN addDataDrop(unsigned);
    284287
    285288    // Atomics
     
    12981301    });
    12991302
     1303    return { };
     1304}
     1305
     1306auto AirIRGenerator::addMemoryCopy(ExpressionType dstAddress, ExpressionType srcAddress, ExpressionType count) -> PartialResult
     1307{
     1308    ASSERT(dstAddress.tmp());
     1309    ASSERT(dstAddress.type() == Type::I32);
     1310
     1311    ASSERT(srcAddress.tmp());
     1312    ASSERT(srcAddress.type() == Type::I32);
     1313
     1314    ASSERT(count.tmp());
     1315    ASSERT(count.type() == Type::I32);
     1316
     1317    auto result = tmpForType(Type::I32);
     1318    emitCCall(
     1319        &operationWasmMemoryCopy, result, instanceValue(),
     1320        dstAddress, srcAddress, count);
     1321
     1322    emitCheck([&] {
     1323        return Inst(BranchTest32, nullptr, Arg::resCond(MacroAssembler::Zero), result, result);
     1324    }, [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
     1325        this->emitThrowException(jit, ExceptionType::OutOfBoundsTableAccess);
     1326    });
     1327
     1328    return { };
     1329}
     1330
     1331auto AirIRGenerator::addMemoryInit(unsigned dataSegmentIndex, ExpressionType dstAddress, ExpressionType srcAddress, ExpressionType length) -> PartialResult
     1332{
     1333    ASSERT(dstAddress.tmp());
     1334    ASSERT(dstAddress.type() == Type::I32);
     1335
     1336    ASSERT(srcAddress.tmp());
     1337    ASSERT(srcAddress.type() == Type::I32);
     1338
     1339    ASSERT(length.tmp());
     1340    ASSERT(length.type() == Type::I32);
     1341
     1342    auto result = tmpForType(Type::I32);
     1343    emitCCall(
     1344        &operationWasmMemoryInit, result, instanceValue(),
     1345        addConstant(Type::I32, dataSegmentIndex),
     1346        dstAddress, srcAddress, length);
     1347
     1348    emitCheck([&] {
     1349        return Inst(BranchTest32, nullptr, Arg::resCond(MacroAssembler::Zero), result, result);
     1350    }, [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
     1351        this->emitThrowException(jit, ExceptionType::OutOfBoundsTableAccess);
     1352    });
     1353
     1354    return { };
     1355}
     1356
     1357auto AirIRGenerator::addDataDrop(unsigned dataSegmentIndex) -> PartialResult
     1358{
     1359    emitCCall(&operationWasmDataDrop, TypedTmp(), instanceValue(), addConstant(Type::I32, dataSegmentIndex));
    13001360    return { };
    13011361}
  • trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp

    r270855 r270948  
    237237    PartialResult WARN_UNUSED_RETURN addCurrentMemory(ExpressionType& result);
    238238    PartialResult WARN_UNUSED_RETURN addMemoryFill(ExpressionType dstAddress, ExpressionType targetValue, ExpressionType count);
     239    PartialResult WARN_UNUSED_RETURN addMemoryCopy(ExpressionType dstAddress, ExpressionType srcAddress, ExpressionType count);
     240    PartialResult WARN_UNUSED_RETURN addMemoryInit(unsigned, ExpressionType dstAddress, ExpressionType srcAddress, ExpressionType length);
     241    PartialResult WARN_UNUSED_RETURN addDataDrop(unsigned);
    239242
    240243    // Atomics
     
    901904        });
    902905    }
     906
     907    return { };
     908}
     909
     910auto B3IRGenerator::addMemoryInit(unsigned dataSegmentIndex, ExpressionType dstAddress, ExpressionType srcAddress, ExpressionType length) -> PartialResult
     911{
     912    auto result = m_currentBlock->appendNew<CCallValue>(
     913        m_proc, toB3Type(I32), origin(),
     914        m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunction<OperationPtrTag>(operationWasmMemoryInit)),
     915        instanceValue(),
     916        m_currentBlock->appendNew<Const32Value>(m_proc, origin(), dataSegmentIndex),
     917        dstAddress, srcAddress, length);
     918
     919    {
     920        CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, origin(),
     921            m_currentBlock->appendNew<Value>(m_proc, Equal, origin(), result, m_currentBlock->appendNew<Const32Value>(m_proc, origin(), 0)));
     922
     923        check->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
     924            this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsTableAccess);
     925        });
     926    }
     927
     928    return { };
     929}
     930
     931auto B3IRGenerator::addMemoryCopy(ExpressionType dstAddress, ExpressionType srcAddress, ExpressionType count) -> PartialResult
     932{
     933    auto result = m_currentBlock->appendNew<CCallValue>(
     934        m_proc, toB3Type(I32), origin(),
     935        m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunction<OperationPtrTag>(operationWasmMemoryCopy)),
     936        instanceValue(),
     937        dstAddress, srcAddress, count);
     938
     939    {
     940        CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, origin(),
     941            m_currentBlock->appendNew<Value>(m_proc, Equal, origin(), result, m_currentBlock->appendNew<Const32Value>(m_proc, origin(), 0)));
     942
     943        check->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
     944            this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsTableAccess);
     945        });
     946    }
     947
     948    return { };
     949}
     950
     951auto B3IRGenerator::addDataDrop(unsigned dataSegmentIndex) -> PartialResult
     952{
     953    m_currentBlock->appendNew<CCallValue>(
     954        m_proc, B3::Void, origin(),
     955        m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunction<OperationPtrTag>(operationWasmDataDrop)),
     956        instanceValue(),
     957        m_currentBlock->appendNew<Const32Value>(m_proc, origin(), dataSegmentIndex));
    903958
    904959    return { };
  • trunk/Source/JavaScriptCore/wasm/WasmFormat.cpp

    r261755 r270948  
    3535namespace JSC { namespace Wasm {
    3636
    37 Segment* Segment::create(I32InitExpr offset, uint32_t sizeInBytes)
     37Segment::Ptr Segment::create(Optional<I32InitExpr> offset, uint32_t sizeInBytes, Kind kind)
    3838{
    3939    Checked<uint32_t, RecordOverflow> totalBytesChecked = sizeInBytes;
     
    4141    uint32_t totalBytes;
    4242    if (totalBytesChecked.safeGet(totalBytes) == CheckedState::DidOverflow)
    43         return nullptr;
     43        return Ptr(nullptr, &Segment::destroy);
    4444    auto allocated = tryFastCalloc(totalBytes, 1);
    4545    Segment* segment;
    4646    if (!allocated.getValue(segment))
    47         return nullptr;
    48     segment->offset = offset;
     47        return Ptr(nullptr, &Segment::destroy);
     48    ASSERT(kind == Kind::Passive || !!offset);
     49    segment->kind = kind;
     50    segment->offsetIfActive = WTFMove(offset);
    4951    segment->sizeInBytes = sizeInBytes;
    50     return segment;
     52    return Ptr(segment, &Segment::destroy);
    5153}
    5254
     
    5456{
    5557    fastFree(segment);
    56 }
    57 
    58 Segment::Ptr Segment::adoptPtr(Segment* segment)
    59 {
    60     return Ptr(segment, &Segment::destroy);
    6158}
    6259
  • trunk/Source/JavaScriptCore/wasm/WasmFormat.h

    r270689 r270948  
    212212struct Segment {
    213213    WTF_MAKE_STRUCT_FAST_ALLOCATED;
     214
     215    enum class Kind : uint8_t {
     216        Active,
     217        Passive,
     218    };
     219
     220    Kind kind;
    214221    uint32_t sizeInBytes;
    215     I32InitExpr offset;
     222    Optional<I32InitExpr> offsetIfActive;
    216223    // Bytes are allocated at the end.
    217224    uint8_t& byte(uint32_t pos)
     
    220227        return *reinterpret_cast<uint8_t*>(reinterpret_cast<char*>(this) + sizeof(Segment) + pos);
    221228    }
    222     static Segment* create(I32InitExpr, uint32_t);
     229
    223230    static void destroy(Segment*);
    224231    typedef std::unique_ptr<Segment, decltype(&Segment::destroy)> Ptr;
    225     static Ptr adoptPtr(Segment*);
     232    static Segment::Ptr create(Optional<I32InitExpr>, uint32_t, Kind);
     233
     234    bool isActive() const { return kind == Kind::Active; }
     235    bool isPassive() const { return kind == Kind::Passive; }
    226236};
    227237
  • trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h

    r270855 r270948  
    138138    PartialResult WARN_UNUSED_RETURN parseTableIndex(unsigned&);
    139139    PartialResult WARN_UNUSED_RETURN parseElementIndex(unsigned&);
     140    PartialResult WARN_UNUSED_RETURN parseDataSegmentIndex(unsigned&);
    140141
    141142    struct TableInitImmediates {
     
    158159
    159160    PartialResult WARN_UNUSED_RETURN parseMemoryFillImmediate();
     161    PartialResult WARN_UNUSED_RETURN parseMemoryCopyImmediates();
     162
     163    struct MemoryInitImmediates {
     164        unsigned dataSegmentIndex;
     165        unsigned unused;
     166    };
     167    PartialResult WARN_UNUSED_RETURN parseMemoryInitImmediates(MemoryInitImmediates&);
    160168
    161169#define WASM_TRY_ADD_TO_CONTEXT(add_expression) WASM_FAIL_IF_HELPER_FAILS(m_context.add_expression)
     
    524532
    525533template<typename Context>
     534auto FunctionParser<Context>::parseDataSegmentIndex(unsigned& result) -> PartialResult
     535{
     536    unsigned dataSegmentIndex;
     537    WASM_PARSER_FAIL_IF(!parseVarUInt32(dataSegmentIndex), "can't parse data segment index");
     538    WASM_VALIDATOR_FAIL_IF(dataSegmentIndex >= m_info.dataSegmentsCount(), "data segment index ", dataSegmentIndex, " is invalid, limit is ", m_info.dataSegmentsCount());
     539    result = dataSegmentIndex;
     540    return { };
     541}
     542
     543template<typename Context>
    526544auto FunctionParser<Context>::parseTableInitImmediates(TableInitImmediates& result) -> PartialResult
    527545{
     
    576594    WASM_PARSER_FAIL_IF(!parseUInt8(auxiliaryByte), "can't parse auxiliary byte");
    577595    WASM_PARSER_FAIL_IF(!!auxiliaryByte, "auxiliary byte for memory.fill should be zero, but got ", auxiliaryByte);
     596    return { };
     597}
     598
     599template<typename Context>
     600auto FunctionParser<Context>::parseMemoryCopyImmediates() -> PartialResult
     601{
     602    uint8_t firstAuxiliaryByte;
     603    WASM_PARSER_FAIL_IF(!parseUInt8(firstAuxiliaryByte), "can't parse auxiliary byte");
     604    WASM_PARSER_FAIL_IF(!!firstAuxiliaryByte, "auxiliary byte for memory.copy should be zero, but got ", firstAuxiliaryByte);
     605
     606    uint8_t secondAuxiliaryByte;
     607    WASM_PARSER_FAIL_IF(!parseUInt8(secondAuxiliaryByte), "can't parse auxiliary byte");
     608    WASM_PARSER_FAIL_IF(!!secondAuxiliaryByte, "auxiliary byte for memory.copy should be zero, but got ", secondAuxiliaryByte);
     609    return { };
     610}
     611
     612template<typename Context>
     613auto FunctionParser<Context>::parseMemoryInitImmediates(MemoryInitImmediates& result) -> PartialResult
     614{
     615    unsigned dataSegmentIndex;
     616    WASM_FAIL_IF_HELPER_FAILS(parseDataSegmentIndex(dataSegmentIndex));
     617
     618    unsigned unused;
     619    WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't parse unused");
     620    WASM_PARSER_FAIL_IF(!!unused, "memory.init invalid unsued byte");
     621
     622    result.unused = unused;
     623    result.dataSegmentIndex = dataSegmentIndex;
    578624    return { };
    579625}
     
    846892
    847893            WASM_TRY_ADD_TO_CONTEXT(addMemoryFill(dstAddress, targetValue, count));
     894            break;
     895        }
     896        case ExtTableOpType::MemoryCopy: {
     897            WASM_FAIL_IF_HELPER_FAILS(parseMemoryCopyImmediates());
     898
     899            WASM_VALIDATOR_FAIL_IF(!m_info.memoryCount(), "memory must be present");
     900
     901            TypedExpression dstAddress;
     902            TypedExpression srcAddress;
     903            TypedExpression count;
     904
     905            WASM_TRY_POP_EXPRESSION_STACK_INTO(count, "memory.copy");
     906            WASM_TRY_POP_EXPRESSION_STACK_INTO(srcAddress, "memory.copy");
     907            WASM_TRY_POP_EXPRESSION_STACK_INTO(dstAddress, "memory.copy");
     908
     909            WASM_VALIDATOR_FAIL_IF(I32 != dstAddress.type(), "memory.copy dstAddress to type ", dstAddress.type(), " expected ", I32);
     910            WASM_VALIDATOR_FAIL_IF(I32 != srcAddress.type(), "memory.copy targetValue to type ", srcAddress.type(), " expected ", I32);
     911            WASM_VALIDATOR_FAIL_IF(I32 != count.type(), "memory.copy size to type ", count.type(), " expected ", I32);
     912
     913            WASM_TRY_ADD_TO_CONTEXT(addMemoryCopy(dstAddress, srcAddress, count));
     914            break;
     915        }
     916        case ExtTableOpType::MemoryInit: {
     917            MemoryInitImmediates immediates;
     918            WASM_FAIL_IF_HELPER_FAILS(parseMemoryInitImmediates(immediates));
     919
     920            TypedExpression dstAddress;
     921            TypedExpression srcAddress;
     922            TypedExpression length;
     923            WASM_TRY_POP_EXPRESSION_STACK_INTO(length, "memory.init");
     924            WASM_TRY_POP_EXPRESSION_STACK_INTO(srcAddress, "memory.init");
     925            WASM_TRY_POP_EXPRESSION_STACK_INTO(dstAddress, "memory.init");
     926
     927            WASM_VALIDATOR_FAIL_IF(I32 != dstAddress.type(), "memory.init dst address to type ", dstAddress.type(), " expected ", I32);
     928            WASM_VALIDATOR_FAIL_IF(I32 != srcAddress.type(), "memory.init src address to type ", srcAddress.type(), " expected ", I32);
     929            WASM_VALIDATOR_FAIL_IF(I32 != length.type(), "memory.init length to type ", length.type(), " expected ", I32);
     930
     931            WASM_TRY_ADD_TO_CONTEXT(addMemoryInit(immediates.dataSegmentIndex, dstAddress, srcAddress, length));
     932            break;
     933        }
     934        case ExtTableOpType::DataDrop: {
     935            unsigned dataSegmentIndex;
     936            WASM_FAIL_IF_HELPER_FAILS(parseDataSegmentIndex(dataSegmentIndex));
     937
     938            WASM_TRY_ADD_TO_CONTEXT(addDataDrop(dataSegmentIndex));
    848939            break;
    849940        }
     
    14201511            return { };
    14211512        }
     1513        case ExtTableOpType::MemoryCopy: {
     1514            WASM_FAIL_IF_HELPER_FAILS(parseMemoryCopyImmediates());
     1515            return { };
     1516        }
     1517        case ExtTableOpType::MemoryInit: {
     1518            MemoryInitImmediates immediates;
     1519            WASM_FAIL_IF_HELPER_FAILS(parseMemoryInitImmediates(immediates));
     1520            return { };
     1521        }
     1522        case ExtTableOpType::DataDrop: {
     1523            unsigned dataSegmentIndex;
     1524            WASM_FAIL_IF_HELPER_FAILS(parseDataSegmentIndex(dataSegmentIndex));
     1525            return { };
     1526        }
    14221527        default:
    14231528            WASM_PARSER_FAIL_IF(true, "invalid extended table op ", extOp);
  • trunk/Source/JavaScriptCore/wasm/WasmInstance.cpp

    r270689 r270948  
    5656    , m_numImportFunctions(m_module->moduleInformation().importFunctionCount())
    5757    , m_passiveElements(m_module->moduleInformation().elementCount())
     58    , m_passiveDataSegments(m_module->moduleInformation().dataSegmentsCount())
    5859{
    5960    for (unsigned i = 0; i < m_numImportFunctions; ++i)
     
    7677            m_passiveElements.quickSet(elementIndex);
    7778    }
     79
     80    for (unsigned dataSegmentIndex = 0; dataSegmentIndex < m_module->moduleInformation().dataSegmentsCount(); ++dataSegmentIndex) {
     81        const auto& dataSegment = m_module->moduleInformation().data[dataSegmentIndex];
     82        if (dataSegment->isPassive())
     83            m_passiveDataSegments.quickSet(dataSegmentIndex);
     84    }
    7885}
    7986
     
    164171{
    165172    m_passiveElements.quickClear(elementIndex);
     173}
     174
     175bool Instance::memoryInit(uint32_t dstAddress, uint32_t srcAddress, uint32_t length, uint32_t dataSegmentIndex)
     176{
     177    RELEASE_ASSERT(dataSegmentIndex < module().moduleInformation().dataSegmentsCount());
     178
     179    if (sumOverflows<uint32_t>(srcAddress, length))
     180        return false;
     181
     182    const Segment::Ptr& segment = module().moduleInformation().data[dataSegmentIndex];
     183    const uint32_t segmentSizeInBytes = m_passiveDataSegments.quickGet(dataSegmentIndex) ? segment->sizeInBytes : 0U;
     184    if (srcAddress + length > segmentSizeInBytes)
     185        return false;
     186
     187    const uint8_t* segmentData = !length ? nullptr : &segment->byte(srcAddress);
     188
     189    ASSERT(memory());
     190    return memory()->init(dstAddress, segmentData, length);
     191}
     192
     193void Instance::dataDrop(uint32_t dataSegmentIndex)
     194{
     195    m_passiveDataSegments.quickClear(dataSegmentIndex);
    166196}
    167197
  • trunk/Source/JavaScriptCore/wasm/WasmInstance.h

    r270689 r270948  
    9292    void elemDrop(uint32_t elementIndex);
    9393
     94    bool memoryInit(uint32_t dstAddress, uint32_t srcAddress, uint32_t length, uint32_t dataSegmentIndex);
     95
     96    void dataDrop(uint32_t dataSegmentIndex);
     97
    9498    void* cachedMemory() const { return m_cachedMemory.getMayBeNull(cachedBoundsCheckingSize()); }
    9599    size_t cachedBoundsCheckingSize() const { return m_cachedBoundsCheckingSize; }
     
    232236    HashMap<uint32_t, Ref<Global>, IntHash<uint32_t>, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>> m_linkedGlobals;
    233237    BitVector m_passiveElements;
     238    BitVector m_passiveDataSegments;
    234239};
    235240
  • trunk/Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp

    r270855 r270948  
    213213    PartialResult WARN_UNUSED_RETURN addCurrentMemory(ExpressionType& result);
    214214    PartialResult WARN_UNUSED_RETURN addMemoryFill(ExpressionType dstAddress, ExpressionType targetValue, ExpressionType count);
     215    PartialResult WARN_UNUSED_RETURN addMemoryCopy(ExpressionType dstAddress, ExpressionType srcAddress, ExpressionType count);
     216    PartialResult WARN_UNUSED_RETURN addMemoryInit(unsigned, ExpressionType dstAddress, ExpressionType srcAddress, ExpressionType length);
     217    PartialResult WARN_UNUSED_RETURN addDataDrop(unsigned);
    215218
    216219    // Atomics
     
    11811184}
    11821185
     1186auto LLIntGenerator::addMemoryInit(unsigned dataSegmentIndex, ExpressionType dstAddress, ExpressionType srcAddress, ExpressionType length) -> PartialResult
     1187{
     1188    WasmMemoryInit::emit(this, dstAddress, srcAddress, length, dataSegmentIndex);
     1189
     1190    return { };
     1191}
     1192
     1193auto LLIntGenerator::addDataDrop(unsigned dataSegmentIndex) -> PartialResult
     1194{
     1195    WasmDataDrop::emit(this, dataSegmentIndex);
     1196
     1197    return { };
     1198}
     1199
    11831200auto LLIntGenerator::addGrowMemory(ExpressionType delta, ExpressionType& result) -> PartialResult
    11841201{
     
    11921209{
    11931210    WasmMemoryFill::emit(this, dstAddress, targetValue, count);
     1211    return { };
     1212}
     1213
     1214auto LLIntGenerator::addMemoryCopy(ExpressionType dstAddress, ExpressionType srcAddress, ExpressionType count) -> PartialResult
     1215{
     1216    WasmMemoryCopy::emit(this, dstAddress, srcAddress, count);
    11941217    return { };
    11951218}
  • trunk/Source/JavaScriptCore/wasm/WasmMemory.cpp

    r270855 r270948  
    631631}
    632632
     633bool Memory::copy(uint32_t dstAddress, uint32_t srcAddress, uint32_t count)
     634{
     635    if (sumOverflows<uint32_t>(dstAddress, count) || sumOverflows<uint32_t>(srcAddress, count))
     636        return false;
     637
     638    const uint32_t lastDstAddress = dstAddress + count;
     639    const uint32_t lastSrcAddress = srcAddress + count;
     640
     641    if (lastDstAddress > size() || lastSrcAddress > size())
     642        return false;
     643
     644    if (!count)
     645        return true;
     646
     647    uint8_t* base = reinterpret_cast<uint8_t*>(memory());
     648    memcpy(base + dstAddress, base + srcAddress, count);
     649    return true;
     650}
     651
     652bool Memory::init(uint32_t offset, const uint8_t* data, uint32_t length)
     653{
     654    if (sumOverflows<uint32_t>(offset, length))
     655        return false;
     656
     657    if (offset + length > m_handle->size())
     658        return false;
     659
     660    if (!length)
     661        return true;
     662
     663    memcpy(reinterpret_cast<uint8_t*>(memory()) + offset, data, length);
     664    return true;
     665}
     666
    633667void Memory::registerInstance(Instance* instance)
    634668{
  • trunk/Source/JavaScriptCore/wasm/WasmMemory.h

    r270855 r270948  
    134134    Expected<PageCount, GrowFailReason> grow(PageCount);
    135135    bool fill(uint32_t, uint8_t, uint32_t);
     136    bool copy(uint32_t, uint32_t, uint32_t);
     137    bool init(uint32_t, const uint8_t*, uint32_t);
     138
    136139    void registerInstance(Instance*);
    137140
  • trunk/Source/JavaScriptCore/wasm/WasmModuleInformation.h

    r270689 r270948  
    6868    uint32_t tableCount() const { return tables.size(); }
    6969    uint32_t elementCount() const { return elements.size(); }
     70    uint32_t dataSegmentsCount() const { return numberOfDataSegments; }
    7071
    7172    const TableInformation& table(unsigned index) const { return tables[index]; }
     
    9394    Vector<CustomSection> customSections;
    9495    Ref<NameSection> nameSection;
     96    uint32_t numberOfDataSegments { 0 };
    9597   
    9698    mutable BitVector m_referencedFunctions;
  • trunk/Source/JavaScriptCore/wasm/WasmOperations.cpp

    r270855 r270948  
    644644}
    645645
     646JSC_DEFINE_JIT_OPERATION(operationWasmMemoryCopy, bool, (Instance* instance, uint32_t dstAddress, uint32_t srcAddress, uint32_t count))
     647{
     648    return instance->memory()->copy(dstAddress, srcAddress, count);
     649}
     650
    646651JSC_DEFINE_JIT_OPERATION(operationGetWasmTableElement, EncodedJSValue, (Instance* instance, unsigned tableIndex, int32_t signedIndex))
    647652{
     
    896901}
    897902
     903JSC_DEFINE_JIT_OPERATION(operationWasmMemoryInit, bool, (Instance* instance, unsigned dataSegmentIndex, uint32_t dstAddress, uint32_t srcAddress, uint32_t length))
     904{
     905    ASSERT(dataSegmentIndex < instance->module().moduleInformation().dataSegmentsCount());
     906    return instance->memoryInit(dstAddress, srcAddress, length, dataSegmentIndex);
     907}
     908
     909JSC_DEFINE_JIT_OPERATION(operationWasmDataDrop, void, (Instance* instance, unsigned dataSegmentIndex))
     910{
     911    ASSERT(dataSegmentIndex < instance->module().moduleInformation().dataSegmentsCount());
     912    instance->dataDrop(dataSegmentIndex);
     913}
     914
    898915JSC_DEFINE_JIT_OPERATION(operationWasmToJSException, void*, (CallFrame* callFrame, Wasm::ExceptionType type, Instance* wasmInstance))
    899916{
  • trunk/Source/JavaScriptCore/wasm/WasmOperations.h

    r270855 r270948  
    6363JSC_DECLARE_JIT_OPERATION(operationGrowMemory, int32_t, (void*, Instance*, int32_t));
    6464JSC_DECLARE_JIT_OPERATION(operationWasmMemoryFill, bool, (Instance*, uint32_t dstAddress, uint32_t targetValue, uint32_t count));
     65JSC_DECLARE_JIT_OPERATION(operationWasmMemoryCopy, bool, (Instance*, uint32_t dstAddress, uint32_t srcAddress, uint32_t count));
    6566
    6667JSC_DECLARE_JIT_OPERATION(operationGetWasmTableElement, EncodedJSValue, (Instance*, unsigned, int32_t));
     
    7778JSC_DECLARE_JIT_OPERATION(operationMemoryAtomicWait64, int32_t, (Instance* instance, unsigned base, unsigned offset, uint64_t value, int64_t timeout));
    7879JSC_DECLARE_JIT_OPERATION(operationMemoryAtomicNotify, int32_t, (Instance*, unsigned, unsigned, int32_t));
     80JSC_DECLARE_JIT_OPERATION(operationWasmMemoryInit, bool, (Instance*, unsigned dataSegmentIndex, uint32_t dstAddress, uint32_t srcAddress, uint32_t length));
     81JSC_DECLARE_JIT_OPERATION(operationWasmDataDrop, void, (Instance*, unsigned dataSegmentIndex));
    7982
    8083JSC_DECLARE_JIT_OPERATION(operationWasmToJSException, void*, (CallFrame*, Wasm::ExceptionType, Instance*));
  • trunk/Source/JavaScriptCore/wasm/WasmSectionParser.cpp

    r270689 r270948  
    394394
    395395            Optional<I32InitExpr> initExpr;
    396             WASM_FAIL_IF_HELPER_FAILS(parseI32InitExpr(initExpr));
     396            WASM_FAIL_IF_HELPER_FAILS(parseI32InitExprForElementSection(initExpr));
    397397
    398398            uint32_t indexCount;
     
    428428
    429429            Optional<I32InitExpr> initExpr;
    430             WASM_FAIL_IF_HELPER_FAILS(parseI32InitExpr(initExpr));
     430            WASM_FAIL_IF_HELPER_FAILS(parseI32InitExprForElementSection(initExpr));
    431431
    432432            uint8_t elementKind;
     
    465465
    466466            Optional<I32InitExpr> initExpr;
    467             WASM_FAIL_IF_HELPER_FAILS(parseI32InitExpr(initExpr));
     467            WASM_FAIL_IF_HELPER_FAILS(parseI32InitExprForElementSection(initExpr));
    468468
    469469            uint32_t indexCount;
     
    502502
    503503            Optional<I32InitExpr> initExpr;
    504             WASM_FAIL_IF_HELPER_FAILS(parseI32InitExpr(initExpr));
     504            WASM_FAIL_IF_HELPER_FAILS(parseI32InitExprForElementSection(initExpr));
    505505
    506506            Type refType;
     
    638638}
    639639
    640 auto SectionParser::parseI32InitExpr(Optional<I32InitExpr>& initExpr) -> PartialResult
     640auto SectionParser::parseI32InitExpr(Optional<I32InitExpr>& initExpr, ASCIILiteral failMessage) -> PartialResult
    641641{
    642642    uint8_t initOpcode;
     
    644644    Type initExprType;
    645645    WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, initExprBits, initExprType));
    646     WASM_PARSER_FAIL_IF(initExprType != I32, "Element init_expr must produce an i32");
     646    WASM_PARSER_FAIL_IF(initExprType != I32, failMessage);
    647647    initExpr = makeI32InitExpr(initOpcode, initExprBits);
    648648
    649649    return { };
     650}
     651
     652auto SectionParser::parseI32InitExprForElementSection(Optional<I32InitExpr>& initExpr) -> PartialResult
     653{
     654    return parseI32InitExpr(initExpr, "Element init_expr must produce an i32"_s);
    650655}
    651656
     
    710715}
    711716
     717auto SectionParser::parseI32InitExprForDataSection(Optional<I32InitExpr>& initExpr) -> PartialResult
     718{
     719    return parseI32InitExpr(initExpr, "Data init_expr must produce an i32"_s);
     720}
     721
    712722auto SectionParser::parseGlobalType(GlobalInformation& global) -> PartialResult
    713723{
     
    728738
    729739    for (uint32_t segmentNumber = 0; segmentNumber < segmentCount; ++segmentNumber) {
    730         uint32_t memoryIndex;
    731         uint64_t initExprBits;
    732         uint8_t initOpcode;
    733         uint32_t dataByteLength;
    734 
    735         WASM_PARSER_FAIL_IF(!parseVarUInt32(memoryIndex), "can't get ", segmentNumber, "th Data segment's index");
    736         WASM_PARSER_FAIL_IF(memoryIndex >= m_info->memoryCount(), segmentNumber, "th Data segment has index ", memoryIndex, " which exceeds the number of Memories ", m_info->memoryCount());
    737         Type initExprType;
    738         WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, initExprBits, initExprType));
    739         WASM_PARSER_FAIL_IF(initExprType != I32, segmentNumber, "th Data segment's init_expr must produce an i32");
    740         WASM_PARSER_FAIL_IF(!parseVarUInt32(dataByteLength), "can't get ", segmentNumber, "th Data segment's data byte length");
    741         WASM_PARSER_FAIL_IF(dataByteLength > maxModuleSize, segmentNumber, "th Data segment's data byte length is too big ", dataByteLength, " maximum ", maxModuleSize);
    742 
    743         Segment* segment = Segment::create(makeI32InitExpr(initOpcode, initExprBits), dataByteLength);
    744         WASM_PARSER_FAIL_IF(!segment, "can't allocate enough memory for ", segmentNumber, "th Data segment of size ", dataByteLength);
    745         m_info->data.uncheckedAppend(Segment::adoptPtr(segment));
    746         for (uint32_t dataByte = 0; dataByte < dataByteLength; ++dataByte) {
    747             uint8_t byte;
    748             WASM_PARSER_FAIL_IF(!parseUInt8(byte), "can't get ", dataByte, "th data byte from ", segmentNumber, "th Data segment");
    749             segment->byte(dataByte) = byte;
    750         }
    751     }
     740        uint32_t memoryIndex = UINT32_MAX;
     741        uint8_t dataFlag = UINT8_MAX;
     742
     743        if (Options::useWebAssemblyReferences()) {
     744            WASM_PARSER_FAIL_IF(!parseUInt8(dataFlag), "can't get ", segmentNumber, "th Data segment's flag");
     745            memoryIndex = 0U;
     746        } else
     747            WASM_PARSER_FAIL_IF(!parseVarUInt32(memoryIndex), "can't get ", segmentNumber, "th Data segment's index");
     748
     749        if (!Options::useWebAssemblyReferences() || !dataFlag) {
     750            WASM_PARSER_FAIL_IF(memoryIndex >= m_info->memoryCount(), segmentNumber, "th Data segment has index ", memoryIndex, " which exceeds the number of Memories ", m_info->memoryCount());
     751
     752            Optional<I32InitExpr> initExpr;
     753            WASM_FAIL_IF_HELPER_FAILS(parseI32InitExprForDataSection(initExpr));
     754
     755            uint32_t dataByteLength;
     756            WASM_PARSER_FAIL_IF(!parseVarUInt32(dataByteLength), "can't get ", segmentNumber, "th Data segment's data byte length");
     757            WASM_PARSER_FAIL_IF(dataByteLength > maxModuleSize, segmentNumber, "th Data segment's data byte length is too big ", dataByteLength, " maximum ", maxModuleSize);
     758
     759            auto segment = Segment::create(*initExpr, dataByteLength, Segment::Kind::Active);
     760            WASM_PARSER_FAIL_IF(!segment, "can't allocate enough memory for ", segmentNumber, "th Data segment of size ", dataByteLength);
     761            for (uint32_t dataByte = 0; dataByte < dataByteLength; ++dataByte) {
     762                uint8_t byte;
     763                WASM_PARSER_FAIL_IF(!parseUInt8(byte), "can't get ", dataByte, "th data byte from ", segmentNumber, "th Data segment");
     764                segment->byte(dataByte) = byte;
     765            }
     766            m_info->data.uncheckedAppend(WTFMove(segment));
     767            continue;
     768        }
     769
     770        ASSERT(Options::useWebAssemblyReferences());
     771
     772        if (dataFlag == 0x01) {
     773            uint32_t dataByteLength;
     774            WASM_PARSER_FAIL_IF(!parseVarUInt32(dataByteLength), "can't get ", segmentNumber, "th Data segment's data byte length");
     775            WASM_PARSER_FAIL_IF(dataByteLength > maxModuleSize, segmentNumber, "th Data segment's data byte length is too big ", dataByteLength, " maximum ", maxModuleSize);
     776
     777            auto segment = Segment::create(WTF::nullopt, dataByteLength, Segment::Kind::Passive);
     778            WASM_PARSER_FAIL_IF(!segment, "can't allocate enough memory for ", segmentNumber, "th Data segment of size ", dataByteLength);
     779            for (uint32_t dataByte = 0; dataByte < dataByteLength; ++dataByte) {
     780                uint8_t byte;
     781                WASM_PARSER_FAIL_IF(!parseUInt8(byte), "can't get ", dataByte, "th data byte from ", segmentNumber, "th Data segment");
     782                segment->byte(dataByte) = byte;
     783            }
     784            m_info->data.uncheckedAppend(WTFMove(segment));
     785            continue;
     786
     787        }
     788
     789        if (dataFlag == 0x02) {
     790            uint32_t memoryIndex;
     791            WASM_PARSER_FAIL_IF(!parseVarUInt32(memoryIndex), "can't get ", segmentNumber, "th Data segment's index");
     792            WASM_PARSER_FAIL_IF(memoryIndex >= m_info->memoryCount(), segmentNumber, "th Data segment has index ", memoryIndex, " which exceeds the number of Memories ", m_info->memoryCount());
     793
     794            Optional<I32InitExpr> initExpr;
     795            WASM_FAIL_IF_HELPER_FAILS(parseI32InitExprForDataSection(initExpr));
     796
     797            uint32_t dataByteLength;
     798            WASM_PARSER_FAIL_IF(!parseVarUInt32(dataByteLength), "can't get ", segmentNumber, "th Data segment's data byte length");
     799            WASM_PARSER_FAIL_IF(dataByteLength > maxModuleSize, segmentNumber, "th Data segment's data byte length is too big ", dataByteLength, " maximum ", maxModuleSize);
     800
     801            auto segment = Segment::create(*initExpr, dataByteLength, Segment::Kind::Active);
     802            WASM_PARSER_FAIL_IF(!segment, "can't allocate enough memory for ", segmentNumber, "th Data segment of size ", dataByteLength);
     803            for (uint32_t dataByte = 0; dataByte < dataByteLength; ++dataByte) {
     804                uint8_t byte;
     805                WASM_PARSER_FAIL_IF(!parseUInt8(byte), "can't get ", dataByte, "th data byte from ", segmentNumber, "th Data segment");
     806                segment->byte(dataByte) = byte;
     807            }
     808            m_info->data.uncheckedAppend(WTFMove(segment));
     809            continue;
     810        }
     811
     812        WASM_PARSER_FAIL_IF(true, "unknown ", segmentNumber, "th Data segment's flag");
     813    }
     814
     815    return { };
     816}
     817
     818auto SectionParser::parseDataCount() -> PartialResult
     819{
     820    WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
     821    uint32_t numberOfDataSegments;
     822    WASM_PARSER_FAIL_IF(!parseVarUInt32(numberOfDataSegments), "can't get Data Count section's count");
     823
     824    m_info->numberOfDataSegments = numberOfDataSegments;
    752825    return { };
    753826}
  • trunk/Source/JavaScriptCore/wasm/WasmSectionParser.h

    r270689 r270948  
    3232#include "WasmOps.h"
    3333#include "WasmParser.h"
     34#include <wtf/text/ASCIILiteral.h>
    3435
    3536namespace JSC { namespace Wasm {
     
    6768    PartialResult WARN_UNUSED_RETURN parseResizableLimits(uint32_t& initial, Optional<uint32_t>& maximum, bool& isShared, LimitsType);
    6869    PartialResult WARN_UNUSED_RETURN parseInitExpr(uint8_t&, uint64_t&, Type& initExprType);
     70    PartialResult WARN_UNUSED_RETURN parseI32InitExpr(Optional<I32InitExpr>&, ASCIILiteral failMessage);
    6971
    7072    PartialResult WARN_UNUSED_RETURN validateElementTableIdx(uint32_t);
    71     PartialResult WARN_UNUSED_RETURN parseI32InitExpr(Optional<I32InitExpr>&);
     73    PartialResult WARN_UNUSED_RETURN parseI32InitExprForElementSection(Optional<I32InitExpr>&);
    7274    PartialResult WARN_UNUSED_RETURN parseElementKind(uint8_t& elementKind);
    7375    PartialResult WARN_UNUSED_RETURN parseIndexCountForElementSection(uint32_t&, const unsigned);
    7476    PartialResult WARN_UNUSED_RETURN parseElementSegmentVectorOfExpressions(Vector<uint32_t>&, const unsigned, const unsigned);
    7577    PartialResult WARN_UNUSED_RETURN parseElementSegmentVectorOfIndexes(Vector<uint32_t>&, const unsigned, const unsigned);
     78
     79    PartialResult WARN_UNUSED_RETURN parseI32InitExprForDataSection(Optional<I32InitExpr>&);
    7680
    7781    size_t m_offsetInSource;
  • trunk/Source/JavaScriptCore/wasm/WasmSections.h

    r254087 r270948  
    3535
    3636#define FOR_EACH_KNOWN_WASM_SECTION(macro) \
    37     macro(Type,     1, "Function signature declarations") \
    38     macro(Import,   2, "Import declarations") \
    39     macro(Function, 3, "Function declarations") \
    40     macro(Table,    4, "Indirect function table and other tables") \
    41     macro(Memory,   5, "Memory attributes") \
    42     macro(Global,   6, "Global declarations") \
    43     macro(Export,   7, "Exports") \
    44     macro(Start,    8, "Start function declaration") \
    45     macro(Element,  9, "Elements section") \
    46     macro(Code,    10, "Function bodies (code)") \
    47     macro(Data,    11, "Data segments")
     37    macro(Type,       1, "Function signature declarations") \
     38    macro(Import,     2, "Import declarations") \
     39    macro(Function,   3, "Function declarations") \
     40    macro(Table,      4, "Indirect function table and other tables") \
     41    macro(Memory,     5, "Memory attributes") \
     42    macro(Global,     6, "Global declarations") \
     43    macro(Export,     7, "Exports") \
     44    macro(Start,      8, "Start function declaration") \
     45    macro(Element,    9, "Elements section") \
     46    macro(Code,      10, "Function bodies (code)") \
     47    macro(Data,      11, "Data segments") \
     48    macro(DataCount, 12, "Data count")
    4849
    4950enum class Section : uint8_t {
     
    8889{
    8990    ASSERT(isKnownSection(previousKnown) || previousKnown == Section::Begin);
     91    if (previousKnown == Section::DataCount && next == Section::Code)
     92        return true;
    9093    return static_cast<uint8_t>(previousKnown) < static_cast<uint8_t>(next);
    9194}
  • trunk/Source/JavaScriptCore/wasm/WasmSlowPaths.cpp

    r270855 r270948  
    391391}
    392392
     393WASM_SLOW_PATH_DECL(memory_copy)
     394{
     395    auto instruction = pc->as<WasmMemoryCopy, WasmOpcodeTraits>();
     396    uint32_t dstAddress = READ(instruction.m_dstAddress).unboxedUInt32();
     397    uint32_t srcAddress = READ(instruction.m_srcAddress).unboxedUInt32();
     398    uint32_t count = READ(instruction.m_count).unboxedUInt32();
     399    if (!Wasm::operationWasmMemoryCopy(instance, dstAddress, srcAddress, count))
     400        WASM_THROW(Wasm::ExceptionType::OutOfBoundsMemoryAccess);
     401    WASM_END();
     402}
     403
     404WASM_SLOW_PATH_DECL(memory_init)
     405{
     406    auto instruction = pc->as<WasmMemoryInit, WasmOpcodeTraits>();
     407    uint32_t dstAddress = READ(instruction.m_dstAddress).unboxedUInt32();
     408    uint32_t srcAddress = READ(instruction.m_srcAddress).unboxedUInt32();
     409    uint32_t length = READ(instruction.m_length).unboxedUInt32();
     410    if (!Wasm::operationWasmMemoryInit(instance, instruction.m_dataSegmentIndex, dstAddress, srcAddress, length))
     411        WASM_THROW(Wasm::ExceptionType::OutOfBoundsMemoryAccess);
     412    WASM_END();
     413}
     414
     415WASM_SLOW_PATH_DECL(data_drop)
     416{
     417    UNUSED_PARAM(callFrame);
     418
     419    auto instruction = pc->as<WasmDataDrop, WasmOpcodeTraits>();
     420    Wasm::operationWasmDataDrop(instance, instruction.m_dataSegmentIndex);
     421    WASM_END();
     422}
     423
    393424inline SlowPathReturnType doWasmCall(Wasm::Instance* instance, unsigned functionIndex)
    394425{
  • trunk/Source/JavaScriptCore/wasm/WasmSlowPaths.h

    r270855 r270948  
    6868WASM_SLOW_PATH_HIDDEN_DECL(grow_memory);
    6969WASM_SLOW_PATH_HIDDEN_DECL(memory_fill);
     70WASM_SLOW_PATH_HIDDEN_DECL(memory_copy);
     71WASM_SLOW_PATH_HIDDEN_DECL(memory_init);
     72WASM_SLOW_PATH_HIDDEN_DECL(data_drop);
    7073WASM_SLOW_PATH_HIDDEN_DECL(call);
    7174WASM_SLOW_PATH_HIDDEN_DECL(call_no_tls);
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp

    r270689 r270948  
    568568    };
    569569
    570     auto forEachSegment = [&] (auto fn) {
     570    auto forEachActiveDataSegment = [&] (auto fn) {
    571571        auto wasmMemory = m_instance->instance().memory();
    572572        uint8_t* memory = reinterpret_cast<uint8_t*>(wasmMemory->memory());
     
    574574
    575575        for (const Wasm::Segment::Ptr& segment : data) {
    576             uint32_t offset = segment->offset.isGlobalImport()
    577                 ? static_cast<uint32_t>(m_instance->instance().loadI32Global(segment->offset.globalImportIndex()))
    578                 : segment->offset.constValue();
     576            if (!segment->isActive())
     577                continue;
     578            uint32_t offset = segment->offsetIfActive->isGlobalImport()
     579                ? static_cast<uint32_t>(m_instance->instance().loadI32Global(segment->offsetIfActive->globalImportIndex()))
     580                : segment->offsetIfActive->constValue();
    579581
    580582            fn(memory, sizeInBytes, segment, offset);
     
    596598
    597599    // Validation of all segment ranges comes before all Table and Memory initialization.
    598     forEachSegment([&] (uint8_t*, uint64_t sizeInBytes, const Wasm::Segment::Ptr& segment, uint32_t offset) {
     600    forEachActiveDataSegment([&] (uint8_t*, uint64_t sizeInBytes, const Wasm::Segment::Ptr& segment, uint32_t offset) {
    599601        if (UNLIKELY(sizeInBytes < segment->sizeInBytes))
    600602            exception = dataSegmentFail(globalObject, vm, scope, sizeInBytes, segment->sizeInBytes, offset, ", segment is too big"_s);
     
    653655    ASSERT(!exception);
    654656
    655     forEachSegment([&] (uint8_t* memory, uint64_t, const Wasm::Segment::Ptr& segment, uint32_t offset) {
     657    forEachActiveDataSegment([&] (uint8_t* memory, uint64_t, const Wasm::Segment::Ptr& segment, uint32_t offset) {
    656658        // Empty segments are valid, but only if memory isn't present, which would be undefined behavior in memcpy.
    657659        if (segment->sizeInBytes) {
  • trunk/Source/JavaScriptCore/wasm/wasm.json

    r270855 r270948  
    8080        "table.copy":          { "category": "exttable",   "value":  252, "return": [],                              "parameter": ["i32", "i32", "i32"],          "immediate": [{"name": "dst_index",      "type": "varuint32"}, {"name": "src_index",  "type": "varuint32"}],"description": "copy table elements from dst_table[dstOffset, dstOffset + length] to src_table[srcOffset, srcOffset + length]", "extendedOp": 14 },
    8181        "memory.fill":         { "category": "exttable",   "value":  252, "return": [],                              "parameter": ["i32", "i32", "i32"],          "immediate": [{"name": "unused",         "type": "uint8"}],                                                 "description": "sets all values in a region to a given byte", "extendedOp": 11 },
     82        "memory.copy":         { "category": "exttable",   "value":  252, "return": [],                              "parameter": ["i32", "i32", "i32"],          "immediate": [{"name": "unused",         "type": "uint8"}, {"name": "unused",         "type": "uint8"}],    "description": "copies data from a source memory region to destination region", "extendedOp": 10 },
     83        "memory.init":         { "category": "exttable",   "value":  252, "return": [],                              "parameter": ["i32", "i32", "i32"],          "immediate": [{"name": "segment_index",  "type": "varuint32"}, {"name": "unsued",  "type": "varuint32"}],   "description": "copies data from a passive data segment into a memory", "extendedOp": 8 },
     84        "data.drop":           { "category": "exttable",   "value":  252, "return": [],                              "parameter": [],                             "immediate": [{"name": "segment_index",  "type": "varuint32"}],                                             "description": "shrinks the size of the segment to zero", "extendedOp": 9 },
    8285        "call":                { "category": "call",       "value":  16, "return": ["call"],                         "parameter": ["call"],                       "immediate": [{"name": "function_index", "type": "varuint32"}],                                             "description": "call a function by its index" },
    8386        "call_indirect":       { "category": "call",       "value":  17, "return": ["call"],                         "parameter": ["call"],                       "immediate": [{"name": "type_index",     "type": "varuint32"}, {"name": "table_index","type": "varuint32"}],"description": "call a function indirect with an expected signature" },
Note: See TracChangeset for help on using the changeset viewer.