[JSC] Implement WebAssembly.Memory with shared
https://bugs.webkit.org/show_bug.cgi?id=218693
Reviewed by Saam Barati.
JSTests:
- wasm/function-tests/trap-load-shared.js: Added.
(wasmFrameCountFromError):
- wasm/function-tests/trap-store-shared.js: Added.
- wasm/js-api/test_memory.js:
(binaryShouldNotParse):
- wasm/stress/shared-memory-errors.js: Added.
(assert.throws):
- wasm/stress/shared-wasm-memory-buffer.js: Added.
LayoutTests/imported/w3c:
- web-platform-tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/requires-success.any.worker-expected.txt:
- web-platform-tests/wasm/jsapi/memory/constructor-shared.tentative.any-expected.txt:
- web-platform-tests/wasm/jsapi/memory/constructor-shared.tentative.any.worker-expected.txt:
- web-platform-tests/wasm/jsapi/memory/constructor.any-expected.txt:
- web-platform-tests/wasm/jsapi/memory/constructor.any.worker-expected.txt:
- web-platform-tests/wasm/jsapi/memory/grow.any-expected.txt:
- web-platform-tests/wasm/jsapi/memory/grow.any.worker-expected.txt:
- web-platform-tests/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel-expected.txt:
Source/JavaScriptCore:
This patch implements shared WebAssembly.Memory. This can be shared between workers like SharedArrayBuffer.
The most interesting thing of shared WebAssembly.Memory is that it is growable. The memory can be grown in
one thread, and immediately, it should be accessible in the other threads.
To achieve that, shared WebAssembly.Memory leverages signaling even if bounds-checking is mainly used.
If the fast memory is enabled, we just use it so that mprotect can make memory grown easily. But if fast memory
is disabled, we allocates requested VA region and perform bounds-checking with this VA. Since WebAssembly.Memory
always requires "maximum" size of memory, we can first allocate VA and map active part of memory first. And
when growing, we perform mprotect to the rest of the memory. Since this VA is not 4GB, we still need to perform
bounds-checking, but we perform bounds-checking with VA size instead of active memory size. As a result, even if
shared WebAssembly.Memory is grown, we do not need to update (1) pointer and (2) bounds-checking size.
The shared bounds-checking WebAssembly.Memory is something like below.
<================================================ maximum ============================><------------ other memory, protected by bounds-checking --...
<======= active ==========><===================== not active yet =====================>
[ if we access this, fault handler will detect it]
pointer bounds checking size
These "growable bound-checking memory" is now managed by wasm memory-manager. And fault handler is used even if fast memory is disabled.
And fault handler also accepts signals from Wasm LLInt code since both bounds-checkings + signalings are required to confine memory access even in
Wasm LLInt. This patch also renamed memory-size and size-register to bounds-checking-size and bounds-checking-size-register since this is no longer
a size of memory.
- CMakeLists.txt:
- JavaScriptCore.xcodeproj/project.pbxproj:
- llint/LLIntPCRanges.h:
(JSC::LLInt::isWasmLLIntPC):
- llint/LowLevelInterpreter.asm:
- llint/WebAssembly.asm:
- runtime/JSArrayBuffer.h:
(JSC::JSArrayBuffer::toWrappedAllowShared):
- runtime/JSArrayBufferView.h:
- runtime/JSArrayBufferViewInlines.h:
(JSC::JSArrayBufferView::toWrappedAllowShared):
- runtime/JSGenericTypedArrayView.h:
(JSC::JSGenericTypedArrayView<Adaptor>::toWrappedAllowShared):
(JSC::overrideDefaults):
(JSC::Options::initialize):
- wasm/WasmAirIRGenerator.cpp:
(JSC::Wasm::AirIRGenerator::AirIRGenerator):
(JSC::Wasm::AirIRGenerator::restoreWebAssemblyGlobalState):
(JSC::Wasm::AirIRGenerator::addCurrentMemory):
(JSC::Wasm::AirIRGenerator::emitCheckAndPreparePointer):
(JSC::Wasm::AirIRGenerator::addCall):
(JSC::Wasm::AirIRGenerator::addCallIndirect):
- wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::B3IRGenerator):
(JSC::Wasm::B3IRGenerator::restoreWebAssemblyGlobalState):
(JSC::Wasm::B3IRGenerator::addCurrentMemory):
(JSC::Wasm::B3IRGenerator::emitCheckAndPreparePointer):
(JSC::Wasm::B3IRGenerator::addCall):
(JSC::Wasm::B3IRGenerator::addCallIndirect):
(JSC::Wasm::wasmToWasm):
- wasm/WasmFaultSignalHandler.cpp:
(JSC::Wasm::trapHandler):
(JSC::Wasm::enableFastMemory):
(JSC::Wasm::prepareFastMemory):
(JSC::Wasm::Instance::cachedMemory const):
(JSC::Wasm::Instance::cachedBoundsCheckingSize const):
(JSC::Wasm::Instance::updateCachedMemory):
(JSC::Wasm::Instance::offsetOfCachedBoundsCheckingSize):
(JSC::Wasm::Instance::cachedMemorySize const): Deleted.
(JSC::Wasm::Instance::offsetOfCachedMemorySize): Deleted.
(JSC::Wasm::MemoryHandle::MemoryHandle):
(JSC::Wasm::MemoryHandle::~MemoryHandle):
(JSC::Wasm::Memory::Memory):
(JSC::Wasm::Memory::create):
(JSC::Wasm::Memory::tryCreate):
(JSC::Wasm::Memory::addressIsInGrowableOrFastMemory):
(JSC::Wasm::Memory::growShared):
(JSC::Wasm::Memory::grow):
(JSC::Wasm::Memory::dump const):
(JSC::Wasm::Memory::~Memory): Deleted.
(JSC::Wasm::Memory::addressIsInActiveFastMemory): Deleted.
(JSC::Wasm::Memory::addressIsInGrowableOrFastMemory):
(JSC::Wasm::Memory::operator bool const): Deleted.
(JSC::Wasm::Memory::memory const): Deleted.
(JSC::Wasm::Memory::size const): Deleted.
(JSC::Wasm::Memory::sizeInPages const): Deleted.
(JSC::Wasm::Memory::initial const): Deleted.
(JSC::Wasm::Memory::maximum const): Deleted.
(JSC::Wasm::Memory::mode const): Deleted.
(JSC::Wasm::Memory::check): Deleted.
(JSC::Wasm::Memory::offsetOfMemory): Deleted.
(JSC::Wasm::Memory::offsetOfSize): Deleted.
(JSC::Wasm::Memory::addressIsInActiveFastMemory): Deleted.
- wasm/WasmMemoryInformation.cpp:
(JSC::Wasm::PinnedRegisterInfo::get):
(JSC::Wasm::PinnedRegisterInfo::PinnedRegisterInfo):
- wasm/WasmMemoryInformation.h:
(JSC::Wasm::PinnedRegisterInfo::toSave const):
(JSC::Wasm::makeString):
- wasm/WasmMemoryMode.h:
- wasm/js/JSToWasm.cpp:
(JSC::Wasm::createJSToWasmWrapper):
- wasm/js/JSWebAssemblyInstance.cpp:
(JSC::JSWebAssemblyInstance::tryCreate):
- wasm/js/JSWebAssemblyMemory.cpp:
(JSC::JSWebAssemblyMemory::buffer):
(JSC::JSWebAssemblyMemory::growSuccessCallback):
- wasm/js/JSWebAssemblyMemory.h:
- wasm/js/WebAssemblyFunction.cpp:
(JSC::WebAssemblyFunction::jsCallEntrypointSlow):
- wasm/js/WebAssemblyMemoryConstructor.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):
- wasm/js/WebAssemblyMemoryPrototype.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):
- wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::evaluate):
Source/WebCore:
In WebCore, we need three things.
- Shared WebAssembly.Memory serialization/deserialization
This patch adds structure-cloning for WebAssembly.Memory to pass it to the other workers. Cloning is available
only when the WebAssembly.Memory is shared mode. And it is only available when we are using it in postMessage.
So we cannot store WebAssembly.Memory in IndexedDB.
- WebCoreTypedArrayController::isAtomicsWaitAllowedOnCurrentThread
Atomics.wait is usable only in Workers, and *not* usable in Service Workers. When creating VM, we pass WorkerThreadType
and make WebCoreTypedArrayController::isAtomicsWaitAllowedOnCurrentThread return appropriate value.
- [AllowShared] support for WPT
WPT tests for this are broken, and tests are saying "PASS" while the feature is not implemented at all.
Now, the feature is actually implemented, and WPT tests start showing that [AllowShared] annotation in IDL
is not implemented. [AllowShared] is that, usually, DOM does not accept TypedArray originated from SharedArrayBuffer.
e.g. encodeInto(..., Uint8Array) DOM IDL throws an error if Uint8Array is backed by SharedArrayBuffer.
But in the limited places, we are explicitly allowing this. This is [AllowShared] annotation.
This patch implements that so that we keep passing TextEncoder / TextDecoder tests.
- Headers.cmake:
- Modules/indexeddb/server/IDBSerializationContext.cpp:
(WebCore::IDBServer::IDBSerializationContext::initializeVM):
- WebCore.xcodeproj/project.pbxproj:
- bindings/IDLTypes.h:
- bindings/js/CommonVM.cpp:
(WebCore::commonVMSlow):
- bindings/js/JSDOMConvertBufferSource.h:
(WebCore::Detail::BufferSourceConverter::convert):
(WebCore::Converter<IDLArrayBuffer>::convert):
(WebCore::Converter<IDLDataView>::convert):
(WebCore::Converter<IDLInt8Array>::convert):
(WebCore::Converter<IDLInt16Array>::convert):
(WebCore::Converter<IDLInt32Array>::convert):
(WebCore::Converter<IDLUint8Array>::convert):
(WebCore::Converter<IDLUint16Array>::convert):
(WebCore::Converter<IDLUint32Array>::convert):
(WebCore::Converter<IDLUint8ClampedArray>::convert):
(WebCore::Converter<IDLFloat32Array>::convert):
(WebCore::Converter<IDLFloat64Array>::convert):
(WebCore::Converter<IDLArrayBufferView>::convert):
(WebCore::Converter<IDLAllowSharedAdaptor<T>>::convert):
- bindings/js/JSDOMConvertUnion.h:
- bindings/js/SerializedScriptValue.cpp:
(WebCore::CloneSerializer::serialize):
(WebCore::CloneSerializer::CloneSerializer):
(WebCore::CloneSerializer::dumpIfTerminal):
(WebCore::CloneDeserializer::deserialize):
(WebCore::CloneDeserializer::CloneDeserializer):
(WebCore::CloneDeserializer::readTerminal):
(WebCore::SerializedScriptValue::SerializedScriptValue):
(WebCore::SerializedScriptValue::computeMemoryCost const):
(WebCore::SerializedScriptValue::create):
(WebCore::SerializedScriptValue::deserialize):
- bindings/js/SerializedScriptValue.h:
- bindings/js/WebCoreJSClientData.cpp:
(WebCore::JSVMClientData::initNormalWorld):
- bindings/js/WebCoreJSClientData.h:
- bindings/js/WebCoreTypedArrayController.cpp:
(WebCore::WebCoreTypedArrayController::WebCoreTypedArrayController):
(WebCore::WebCoreTypedArrayController::isAtomicsWaitAllowedOnCurrentThread):
- bindings/js/WebCoreTypedArrayController.h:
- bindings/scripts/CodeGeneratorJS.pm:
(IsAnnotatedType):
(GetAnnotatedIDLType):
- bindings/scripts/IDLAttributes.json:
- bindings/scripts/test/JS/JSTestObj.cpp:
(WebCore::JSTestObjDOMConstructor::construct):
(WebCore::jsTestObjPrototypeFunction_encodeIntoBody):
(WebCore::JSC_DEFINE_HOST_FUNCTION):
- bindings/scripts/test/TestObj.idl:
- dom/TextDecoder.idl:
- dom/TextDecoderStreamDecoder.idl:
- dom/TextEncoder.idl:
- workers/DedicatedWorkerGlobalScope.cpp:
(WebCore::DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope):
- workers/WorkerGlobalScope.cpp:
(WebCore::WorkerGlobalScope::WorkerGlobalScope):
- workers/WorkerGlobalScope.h:
- workers/WorkerOrWorkletGlobalScope.cpp:
(WebCore::WorkerOrWorkletGlobalScope::WorkerOrWorkletGlobalScope):
- workers/WorkerOrWorkletGlobalScope.h:
- workers/WorkerOrWorkletScriptController.cpp:
(WebCore::WorkerOrWorkletScriptController::WorkerOrWorkletScriptController):
- workers/WorkerOrWorkletScriptController.h:
- workers/WorkerThreadType.h: Added.
- workers/service/ServiceWorkerGlobalScope.cpp:
(WebCore::ServiceWorkerGlobalScope::ServiceWorkerGlobalScope):
- worklets/WorkletGlobalScope.cpp:
(WebCore::WorkletGlobalScope::WorkletGlobalScope):
LayoutTests:
- js/dom/resources/webassembly-memory-normal-fail-worker.js: Added.
- js/dom/resources/webassembly-memory-shared-worker.js: Added.
(onmessage):
- js/dom/webassembly-memory-normal-fail-expected.txt: Added.
- js/dom/webassembly-memory-normal-fail.html: Added.
- js/dom/webassembly-memory-shared-basic-expected.txt: Added.
- js/dom/webassembly-memory-shared-basic.html: Added.
- js/dom/webassembly-memory-shared-fail-expected.txt: Added.
- js/dom/webassembly-memory-shared-fail.html: Added.
- platform/win/TestExpectations:
- storage/indexeddb/resources/shared-memory-structured-clone.js: Added.
(prepareDatabase):
(async startTests):
(testSharedWebAssemblyMemory):
- storage/indexeddb/shared-memory-structured-clone-expected.txt: Added.
- storage/indexeddb/shared-memory-structured-clone.html: Added.