Changeset 270948 in webkit
- Timestamp:
- Dec 17, 2020 2:25:20 PM (19 months ago)
- Location:
- trunk
- Files:
-
- 4 added
- 26 edited
- 1 moved
-
JSTests/ChangeLog (modified) (1 diff)
-
JSTests/wasm.yaml (modified) (1 diff)
-
JSTests/wasm/references-spec-tests/memory_copy.wast.js (added)
-
JSTests/wasm/references-spec-tests/memory_init.wast.js (added)
-
JSTests/wasm/references/memory_copy.js (added)
-
JSTests/wasm/references/memory_copy_shared.js (added)
-
JSTests/wasm/references/parse_unreachable.js (moved) (moved from trunk/JSTests/wasm/references/table_instructions_parse_unreachable.js) (2 diffs)
-
JSTests/wasm/wasm.json (modified) (1 diff)
-
Source/JavaScriptCore/ChangeLog (modified) (1 diff)
-
Source/JavaScriptCore/bytecode/BytecodeList.rb (modified) (1 diff)
-
Source/JavaScriptCore/llint/WebAssembly.asm (modified) (1 diff)
-
Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp (modified) (2 diffs)
-
Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp (modified) (2 diffs)
-
Source/JavaScriptCore/wasm/WasmFormat.cpp (modified) (3 diffs)
-
Source/JavaScriptCore/wasm/WasmFormat.h (modified) (2 diffs)
-
Source/JavaScriptCore/wasm/WasmFunctionParser.h (modified) (6 diffs)
-
Source/JavaScriptCore/wasm/WasmInstance.cpp (modified) (3 diffs)
-
Source/JavaScriptCore/wasm/WasmInstance.h (modified) (2 diffs)
-
Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp (modified) (3 diffs)
-
Source/JavaScriptCore/wasm/WasmMemory.cpp (modified) (1 diff)
-
Source/JavaScriptCore/wasm/WasmMemory.h (modified) (1 diff)
-
Source/JavaScriptCore/wasm/WasmModuleInformation.h (modified) (2 diffs)
-
Source/JavaScriptCore/wasm/WasmOperations.cpp (modified) (2 diffs)
-
Source/JavaScriptCore/wasm/WasmOperations.h (modified) (2 diffs)
-
Source/JavaScriptCore/wasm/WasmSectionParser.cpp (modified) (8 diffs)
-
Source/JavaScriptCore/wasm/WasmSectionParser.h (modified) (2 diffs)
-
Source/JavaScriptCore/wasm/WasmSections.h (modified) (2 diffs)
-
Source/JavaScriptCore/wasm/WasmSlowPaths.cpp (modified) (1 diff)
-
Source/JavaScriptCore/wasm/WasmSlowPaths.h (modified) (1 diff)
-
Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp (modified) (4 diffs)
-
Source/JavaScriptCore/wasm/wasm.json (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r270923 r270948 1 2020-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 1 26 2020-12-15 Yusuke Suzuki <ysuzuki@apple.com> 2 27 -
trunk/JSTests/wasm.yaml
r270855 r270948 59 59 - path: wasm/references-spec-tests/memory_fill.wast.js 60 60 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 61 65 62 66 - path: wasm/multi-value-spec-tests/block.wast.js -
trunk/JSTests/wasm/references/parse_unreachable.js
r270947 r270948 283 283 } 284 284 285 function 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 299 function 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 327 function 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 342 function 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 358 function 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 373 function 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 285 389 validTableInitUnreachable(); 286 390 invalidTableInitUnreachable(); … … 306 410 validMemoryFillUnreachable(); 307 411 invalidMemoryFillUnreachable(); 412 413 validMemoryCopyUnreachable(); 414 invalidMemoryCopyUnreachable(); 415 416 validMemoryInitUnreachable(); 417 invalidMemoryInitUnreachable(); 418 419 validDataDropUnreachable(); 420 invalidDataDropUnreachable(); -
trunk/JSTests/wasm/wasm.json
r270855 r270948 80 80 "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 }, 81 81 "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 }, 82 85 "call": { "category": "call", "value": 16, "return": ["call"], "parameter": ["call"], "immediate": [{"name": "function_index", "type": "varuint32"}], "description": "call a function by its index" }, 83 86 "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 1 2020-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 1 90 2020-12-16 Yusuke Suzuki <ysuzuki@apple.com> 2 91 -
trunk/Source/JavaScriptCore/bytecode/BytecodeList.rb
r270874 r270948 1683 1683 } 1684 1684 1685 op :memory_copy, 1686 args: { 1687 dstAddress: VirtualRegister, 1688 srcAddress: VirtualRegister, 1689 count: VirtualRegister, 1690 } 1691 1692 op :memory_init, 1693 args: { 1694 dstAddress: VirtualRegister, 1695 srcAddress: VirtualRegister, 1696 length: VirtualRegister, 1697 dataSegmentIndex: unsigned, 1698 } 1699 1700 op :data_drop, 1701 args: { 1702 dataSegmentIndex: unsigned, 1703 } 1704 1685 1705 op :select, 1686 1706 args: { -
trunk/Source/JavaScriptCore/llint/WebAssembly.asm
r270855 r270948 569 569 slowWasmOp(table_grow) 570 570 slowWasmOp(memory_fill) 571 slowWasmOp(memory_copy) 572 slowWasmOp(memory_init) 573 slowWasmOp(data_drop) 571 574 slowWasmOp(set_global_ref) 572 575 slowWasmOp(set_global_ref_portable_binding) -
trunk/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp
r270855 r270948 282 282 PartialResult WARN_UNUSED_RETURN addCurrentMemory(ExpressionType& result); 283 283 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); 284 287 285 288 // Atomics … … 1298 1301 }); 1299 1302 1303 return { }; 1304 } 1305 1306 auto 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 1331 auto 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 1357 auto AirIRGenerator::addDataDrop(unsigned dataSegmentIndex) -> PartialResult 1358 { 1359 emitCCall(&operationWasmDataDrop, TypedTmp(), instanceValue(), addConstant(Type::I32, dataSegmentIndex)); 1300 1360 return { }; 1301 1361 } -
trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
r270855 r270948 237 237 PartialResult WARN_UNUSED_RETURN addCurrentMemory(ExpressionType& result); 238 238 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); 239 242 240 243 // Atomics … … 901 904 }); 902 905 } 906 907 return { }; 908 } 909 910 auto 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 931 auto 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 951 auto 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)); 903 958 904 959 return { }; -
trunk/Source/JavaScriptCore/wasm/WasmFormat.cpp
r261755 r270948 35 35 namespace JSC { namespace Wasm { 36 36 37 Segment * Segment::create(I32InitExpr offset, uint32_t sizeInBytes)37 Segment::Ptr Segment::create(Optional<I32InitExpr> offset, uint32_t sizeInBytes, Kind kind) 38 38 { 39 39 Checked<uint32_t, RecordOverflow> totalBytesChecked = sizeInBytes; … … 41 41 uint32_t totalBytes; 42 42 if (totalBytesChecked.safeGet(totalBytes) == CheckedState::DidOverflow) 43 return nullptr;43 return Ptr(nullptr, &Segment::destroy); 44 44 auto allocated = tryFastCalloc(totalBytes, 1); 45 45 Segment* segment; 46 46 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); 49 51 segment->sizeInBytes = sizeInBytes; 50 return segment;52 return Ptr(segment, &Segment::destroy); 51 53 } 52 54 … … 54 56 { 55 57 fastFree(segment); 56 }57 58 Segment::Ptr Segment::adoptPtr(Segment* segment)59 {60 return Ptr(segment, &Segment::destroy);61 58 } 62 59 -
trunk/Source/JavaScriptCore/wasm/WasmFormat.h
r270689 r270948 212 212 struct Segment { 213 213 WTF_MAKE_STRUCT_FAST_ALLOCATED; 214 215 enum class Kind : uint8_t { 216 Active, 217 Passive, 218 }; 219 220 Kind kind; 214 221 uint32_t sizeInBytes; 215 I32InitExpr offset;222 Optional<I32InitExpr> offsetIfActive; 216 223 // Bytes are allocated at the end. 217 224 uint8_t& byte(uint32_t pos) … … 220 227 return *reinterpret_cast<uint8_t*>(reinterpret_cast<char*>(this) + sizeof(Segment) + pos); 221 228 } 222 static Segment* create(I32InitExpr, uint32_t); 229 223 230 static void destroy(Segment*); 224 231 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; } 226 236 }; 227 237 -
trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h
r270855 r270948 138 138 PartialResult WARN_UNUSED_RETURN parseTableIndex(unsigned&); 139 139 PartialResult WARN_UNUSED_RETURN parseElementIndex(unsigned&); 140 PartialResult WARN_UNUSED_RETURN parseDataSegmentIndex(unsigned&); 140 141 141 142 struct TableInitImmediates { … … 158 159 159 160 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&); 160 168 161 169 #define WASM_TRY_ADD_TO_CONTEXT(add_expression) WASM_FAIL_IF_HELPER_FAILS(m_context.add_expression) … … 524 532 525 533 template<typename Context> 534 auto 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 543 template<typename Context> 526 544 auto FunctionParser<Context>::parseTableInitImmediates(TableInitImmediates& result) -> PartialResult 527 545 { … … 576 594 WASM_PARSER_FAIL_IF(!parseUInt8(auxiliaryByte), "can't parse auxiliary byte"); 577 595 WASM_PARSER_FAIL_IF(!!auxiliaryByte, "auxiliary byte for memory.fill should be zero, but got ", auxiliaryByte); 596 return { }; 597 } 598 599 template<typename Context> 600 auto 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 612 template<typename Context> 613 auto 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; 578 624 return { }; 579 625 } … … 846 892 847 893 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)); 848 939 break; 849 940 } … … 1420 1511 return { }; 1421 1512 } 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 } 1422 1527 default: 1423 1528 WASM_PARSER_FAIL_IF(true, "invalid extended table op ", extOp); -
trunk/Source/JavaScriptCore/wasm/WasmInstance.cpp
r270689 r270948 56 56 , m_numImportFunctions(m_module->moduleInformation().importFunctionCount()) 57 57 , m_passiveElements(m_module->moduleInformation().elementCount()) 58 , m_passiveDataSegments(m_module->moduleInformation().dataSegmentsCount()) 58 59 { 59 60 for (unsigned i = 0; i < m_numImportFunctions; ++i) … … 76 77 m_passiveElements.quickSet(elementIndex); 77 78 } 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 } 78 85 } 79 86 … … 164 171 { 165 172 m_passiveElements.quickClear(elementIndex); 173 } 174 175 bool 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 193 void Instance::dataDrop(uint32_t dataSegmentIndex) 194 { 195 m_passiveDataSegments.quickClear(dataSegmentIndex); 166 196 } 167 197 -
trunk/Source/JavaScriptCore/wasm/WasmInstance.h
r270689 r270948 92 92 void elemDrop(uint32_t elementIndex); 93 93 94 bool memoryInit(uint32_t dstAddress, uint32_t srcAddress, uint32_t length, uint32_t dataSegmentIndex); 95 96 void dataDrop(uint32_t dataSegmentIndex); 97 94 98 void* cachedMemory() const { return m_cachedMemory.getMayBeNull(cachedBoundsCheckingSize()); } 95 99 size_t cachedBoundsCheckingSize() const { return m_cachedBoundsCheckingSize; } … … 232 236 HashMap<uint32_t, Ref<Global>, IntHash<uint32_t>, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>> m_linkedGlobals; 233 237 BitVector m_passiveElements; 238 BitVector m_passiveDataSegments; 234 239 }; 235 240 -
trunk/Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp
r270855 r270948 213 213 PartialResult WARN_UNUSED_RETURN addCurrentMemory(ExpressionType& result); 214 214 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); 215 218 216 219 // Atomics … … 1181 1184 } 1182 1185 1186 auto 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 1193 auto LLIntGenerator::addDataDrop(unsigned dataSegmentIndex) -> PartialResult 1194 { 1195 WasmDataDrop::emit(this, dataSegmentIndex); 1196 1197 return { }; 1198 } 1199 1183 1200 auto LLIntGenerator::addGrowMemory(ExpressionType delta, ExpressionType& result) -> PartialResult 1184 1201 { … … 1192 1209 { 1193 1210 WasmMemoryFill::emit(this, dstAddress, targetValue, count); 1211 return { }; 1212 } 1213 1214 auto LLIntGenerator::addMemoryCopy(ExpressionType dstAddress, ExpressionType srcAddress, ExpressionType count) -> PartialResult 1215 { 1216 WasmMemoryCopy::emit(this, dstAddress, srcAddress, count); 1194 1217 return { }; 1195 1218 } -
trunk/Source/JavaScriptCore/wasm/WasmMemory.cpp
r270855 r270948 631 631 } 632 632 633 bool 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 652 bool 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 633 667 void Memory::registerInstance(Instance* instance) 634 668 { -
trunk/Source/JavaScriptCore/wasm/WasmMemory.h
r270855 r270948 134 134 Expected<PageCount, GrowFailReason> grow(PageCount); 135 135 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 136 139 void registerInstance(Instance*); 137 140 -
trunk/Source/JavaScriptCore/wasm/WasmModuleInformation.h
r270689 r270948 68 68 uint32_t tableCount() const { return tables.size(); } 69 69 uint32_t elementCount() const { return elements.size(); } 70 uint32_t dataSegmentsCount() const { return numberOfDataSegments; } 70 71 71 72 const TableInformation& table(unsigned index) const { return tables[index]; } … … 93 94 Vector<CustomSection> customSections; 94 95 Ref<NameSection> nameSection; 96 uint32_t numberOfDataSegments { 0 }; 95 97 96 98 mutable BitVector m_referencedFunctions; -
trunk/Source/JavaScriptCore/wasm/WasmOperations.cpp
r270855 r270948 644 644 } 645 645 646 JSC_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 646 651 JSC_DEFINE_JIT_OPERATION(operationGetWasmTableElement, EncodedJSValue, (Instance* instance, unsigned tableIndex, int32_t signedIndex)) 647 652 { … … 896 901 } 897 902 903 JSC_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 909 JSC_DEFINE_JIT_OPERATION(operationWasmDataDrop, void, (Instance* instance, unsigned dataSegmentIndex)) 910 { 911 ASSERT(dataSegmentIndex < instance->module().moduleInformation().dataSegmentsCount()); 912 instance->dataDrop(dataSegmentIndex); 913 } 914 898 915 JSC_DEFINE_JIT_OPERATION(operationWasmToJSException, void*, (CallFrame* callFrame, Wasm::ExceptionType type, Instance* wasmInstance)) 899 916 { -
trunk/Source/JavaScriptCore/wasm/WasmOperations.h
r270855 r270948 63 63 JSC_DECLARE_JIT_OPERATION(operationGrowMemory, int32_t, (void*, Instance*, int32_t)); 64 64 JSC_DECLARE_JIT_OPERATION(operationWasmMemoryFill, bool, (Instance*, uint32_t dstAddress, uint32_t targetValue, uint32_t count)); 65 JSC_DECLARE_JIT_OPERATION(operationWasmMemoryCopy, bool, (Instance*, uint32_t dstAddress, uint32_t srcAddress, uint32_t count)); 65 66 66 67 JSC_DECLARE_JIT_OPERATION(operationGetWasmTableElement, EncodedJSValue, (Instance*, unsigned, int32_t)); … … 77 78 JSC_DECLARE_JIT_OPERATION(operationMemoryAtomicWait64, int32_t, (Instance* instance, unsigned base, unsigned offset, uint64_t value, int64_t timeout)); 78 79 JSC_DECLARE_JIT_OPERATION(operationMemoryAtomicNotify, int32_t, (Instance*, unsigned, unsigned, int32_t)); 80 JSC_DECLARE_JIT_OPERATION(operationWasmMemoryInit, bool, (Instance*, unsigned dataSegmentIndex, uint32_t dstAddress, uint32_t srcAddress, uint32_t length)); 81 JSC_DECLARE_JIT_OPERATION(operationWasmDataDrop, void, (Instance*, unsigned dataSegmentIndex)); 79 82 80 83 JSC_DECLARE_JIT_OPERATION(operationWasmToJSException, void*, (CallFrame*, Wasm::ExceptionType, Instance*)); -
trunk/Source/JavaScriptCore/wasm/WasmSectionParser.cpp
r270689 r270948 394 394 395 395 Optional<I32InitExpr> initExpr; 396 WASM_FAIL_IF_HELPER_FAILS(parseI32InitExpr (initExpr));396 WASM_FAIL_IF_HELPER_FAILS(parseI32InitExprForElementSection(initExpr)); 397 397 398 398 uint32_t indexCount; … … 428 428 429 429 Optional<I32InitExpr> initExpr; 430 WASM_FAIL_IF_HELPER_FAILS(parseI32InitExpr (initExpr));430 WASM_FAIL_IF_HELPER_FAILS(parseI32InitExprForElementSection(initExpr)); 431 431 432 432 uint8_t elementKind; … … 465 465 466 466 Optional<I32InitExpr> initExpr; 467 WASM_FAIL_IF_HELPER_FAILS(parseI32InitExpr (initExpr));467 WASM_FAIL_IF_HELPER_FAILS(parseI32InitExprForElementSection(initExpr)); 468 468 469 469 uint32_t indexCount; … … 502 502 503 503 Optional<I32InitExpr> initExpr; 504 WASM_FAIL_IF_HELPER_FAILS(parseI32InitExpr (initExpr));504 WASM_FAIL_IF_HELPER_FAILS(parseI32InitExprForElementSection(initExpr)); 505 505 506 506 Type refType; … … 638 638 } 639 639 640 auto SectionParser::parseI32InitExpr(Optional<I32InitExpr>& initExpr ) -> PartialResult640 auto SectionParser::parseI32InitExpr(Optional<I32InitExpr>& initExpr, ASCIILiteral failMessage) -> PartialResult 641 641 { 642 642 uint8_t initOpcode; … … 644 644 Type initExprType; 645 645 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); 647 647 initExpr = makeI32InitExpr(initOpcode, initExprBits); 648 648 649 649 return { }; 650 } 651 652 auto SectionParser::parseI32InitExprForElementSection(Optional<I32InitExpr>& initExpr) -> PartialResult 653 { 654 return parseI32InitExpr(initExpr, "Element init_expr must produce an i32"_s); 650 655 } 651 656 … … 710 715 } 711 716 717 auto SectionParser::parseI32InitExprForDataSection(Optional<I32InitExpr>& initExpr) -> PartialResult 718 { 719 return parseI32InitExpr(initExpr, "Data init_expr must produce an i32"_s); 720 } 721 712 722 auto SectionParser::parseGlobalType(GlobalInformation& global) -> PartialResult 713 723 { … … 728 738 729 739 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 818 auto 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; 752 825 return { }; 753 826 } -
trunk/Source/JavaScriptCore/wasm/WasmSectionParser.h
r270689 r270948 32 32 #include "WasmOps.h" 33 33 #include "WasmParser.h" 34 #include <wtf/text/ASCIILiteral.h> 34 35 35 36 namespace JSC { namespace Wasm { … … 67 68 PartialResult WARN_UNUSED_RETURN parseResizableLimits(uint32_t& initial, Optional<uint32_t>& maximum, bool& isShared, LimitsType); 68 69 PartialResult WARN_UNUSED_RETURN parseInitExpr(uint8_t&, uint64_t&, Type& initExprType); 70 PartialResult WARN_UNUSED_RETURN parseI32InitExpr(Optional<I32InitExpr>&, ASCIILiteral failMessage); 69 71 70 72 PartialResult WARN_UNUSED_RETURN validateElementTableIdx(uint32_t); 71 PartialResult WARN_UNUSED_RETURN parseI32InitExpr (Optional<I32InitExpr>&);73 PartialResult WARN_UNUSED_RETURN parseI32InitExprForElementSection(Optional<I32InitExpr>&); 72 74 PartialResult WARN_UNUSED_RETURN parseElementKind(uint8_t& elementKind); 73 75 PartialResult WARN_UNUSED_RETURN parseIndexCountForElementSection(uint32_t&, const unsigned); 74 76 PartialResult WARN_UNUSED_RETURN parseElementSegmentVectorOfExpressions(Vector<uint32_t>&, const unsigned, const unsigned); 75 77 PartialResult WARN_UNUSED_RETURN parseElementSegmentVectorOfIndexes(Vector<uint32_t>&, const unsigned, const unsigned); 78 79 PartialResult WARN_UNUSED_RETURN parseI32InitExprForDataSection(Optional<I32InitExpr>&); 76 80 77 81 size_t m_offsetInSource; -
trunk/Source/JavaScriptCore/wasm/WasmSections.h
r254087 r270948 35 35 36 36 #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") 48 49 49 50 enum class Section : uint8_t { … … 88 89 { 89 90 ASSERT(isKnownSection(previousKnown) || previousKnown == Section::Begin); 91 if (previousKnown == Section::DataCount && next == Section::Code) 92 return true; 90 93 return static_cast<uint8_t>(previousKnown) < static_cast<uint8_t>(next); 91 94 } -
trunk/Source/JavaScriptCore/wasm/WasmSlowPaths.cpp
r270855 r270948 391 391 } 392 392 393 WASM_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 404 WASM_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 415 WASM_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 393 424 inline SlowPathReturnType doWasmCall(Wasm::Instance* instance, unsigned functionIndex) 394 425 { -
trunk/Source/JavaScriptCore/wasm/WasmSlowPaths.h
r270855 r270948 68 68 WASM_SLOW_PATH_HIDDEN_DECL(grow_memory); 69 69 WASM_SLOW_PATH_HIDDEN_DECL(memory_fill); 70 WASM_SLOW_PATH_HIDDEN_DECL(memory_copy); 71 WASM_SLOW_PATH_HIDDEN_DECL(memory_init); 72 WASM_SLOW_PATH_HIDDEN_DECL(data_drop); 70 73 WASM_SLOW_PATH_HIDDEN_DECL(call); 71 74 WASM_SLOW_PATH_HIDDEN_DECL(call_no_tls); -
trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp
r270689 r270948 568 568 }; 569 569 570 auto forEach Segment = [&] (auto fn) {570 auto forEachActiveDataSegment = [&] (auto fn) { 571 571 auto wasmMemory = m_instance->instance().memory(); 572 572 uint8_t* memory = reinterpret_cast<uint8_t*>(wasmMemory->memory()); … … 574 574 575 575 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(); 579 581 580 582 fn(memory, sizeInBytes, segment, offset); … … 596 598 597 599 // Validation of all segment ranges comes before all Table and Memory initialization. 598 forEach Segment([&] (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) { 599 601 if (UNLIKELY(sizeInBytes < segment->sizeInBytes)) 600 602 exception = dataSegmentFail(globalObject, vm, scope, sizeInBytes, segment->sizeInBytes, offset, ", segment is too big"_s); … … 653 655 ASSERT(!exception); 654 656 655 forEach Segment([&] (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) { 656 658 // Empty segments are valid, but only if memory isn't present, which would be undefined behavior in memcpy. 657 659 if (segment->sizeInBytes) { -
trunk/Source/JavaScriptCore/wasm/wasm.json
r270855 r270948 80 80 "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 }, 81 81 "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 }, 82 85 "call": { "category": "call", "value": 16, "return": ["call"], "parameter": ["call"], "immediate": [{"name": "function_index", "type": "varuint32"}], "description": "call a function by its index" }, 83 86 "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.