haikuwebkit/LayoutTests/workers/sab/worker-resources.js

87 lines
2.5 KiB
JavaScript
Raw Permalink Normal View History

JSC should support SharedArrayBuffer https://bugs.webkit.org/show_bug.cgi?id=163986 Reviewed by Keith Miller. JSTests: This adds our own test for the various corner cases of SharedArrayBuffer. This test is meant to check all of the things that don't require concurrency. * stress/SharedArrayBuffer.js: Added. (checkAtomics): (shouldFail): (Symbol): (runAtomic): Source/JavaScriptCore: This implements https://tc39.github.io/ecmascript_sharedmem/shmem.html. There is now a new SharedArrayBuffer type. In the JS runtime, which includes typed array types, the SharedArrayBuffer is a drop-in replacement for ArrayBuffer, even though they are distinct types (new SharedArrayBuffer() instanceof ArrayBuffer == false and vice versa). The DOM will not recognize SharedArrayBuffer, or any typed array that wraps it, to ensure safety. This matches what other browsers intend to do, see https://github.com/tc39/ecmascript_sharedmem/issues/38. API is provided for the DOM to opt into SharedArrayBuffer. One notable place is postMessage, which will share the SharedArrayBuffer's underlying data storage with other workers. This creates a pool of shared memory that the workers can use to talk to each other. There is also an Atomics object in global scope, which exposes sequentially consistent atomic operations: add, and, compareExchange, exchange, load, or, store, sub, and xor. Additionally it exposes a Atomics.isLockFree utility, which takes a byte amount and returns true or false. Also there is Atomics.wake/wait, which neatly map to ParkingLot. Accesses to typed arrays that wrap SharedArrayBuffer are optimized by JSC the same way as always. I believe that DFG and B3 already obey the following memory model, which I believe is a bit weaker than Cambridge and a bit stronger than what is being proposed for SharedArrayBuffer. To predict a program's behavior under the B3 memory model, imagine the space of all possible programs that would result from running an optimizer that adversarially follows B3's transformation rules. B3 transformations are correct if the newly created program is equivalent to the old one, assuming that any opaque effect in IR (like the reads and writes of a patchpoint/call/fence) could perform any load/store that satisfies the B3::Effects summary. Opaque effects are a way of describing an infinite set of programs: any program that only does the effects summarized in B3::Effects belongs to the set. For example, this prevents motion of operations across fences since fences are summarized as opaque effects that could read or write memory. This rule alone is not enough, because it leaves the door open for turning an atomic operation (like a load) into a non-atomic one (like a load followed by a store of the same value back to the same location or multiple loads). This is not an optimization that either our compiler or the CPU would want to do. One way to think of what exactly is forbidden is that B3 transformations that mess with memory accesses can only reorder them or remove them. This means that for any execution of the untransformed program, the corresponding execution of the transformed program (i.e. with the same input arguments and the same programs filled in for the opaque effects) must have the same loads and stores, with some removed and some reordered. This is a fairly simple mental model that B3 and DFG already follow and it's based on existing abstractions for the infinite set of programs inside an opaque effect (DFG's AbstractHeaps and B3's Effects). This patch makes all atomics operations intrinsic, but the DFG doesn't know about any of them yet. That's covered by bug 164108. This ought to be perf-neutral, but I am still running tests to confirm this. I'm also still writing new tests to cover all of the Atomics functionality and the behavior of SAB objects. * API/JSTypedArray.cpp: (JSObjectGetTypedArrayBytesPtr): (JSObjectGetTypedArrayBuffer): (JSObjectMakeArrayBufferWithBytesNoCopy): * API/tests/CompareAndSwapTest.cpp: (Bitmap::concurrentTestAndSet): * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * dfg/DFGDesiredWatchpoints.cpp: (JSC::DFG::ArrayBufferViewWatchpointAdaptor::add): * heap/Heap.cpp: (JSC::Heap::reportExtraMemoryVisited): (JSC::Heap::reportExternalMemoryVisited): * jsc.cpp: (functionTransferArrayBuffer): * runtime/ArrayBuffer.cpp: (JSC::SharedArrayBufferContents::SharedArrayBufferContents): (JSC::SharedArrayBufferContents::~SharedArrayBufferContents): (JSC::ArrayBufferContents::ArrayBufferContents): (JSC::ArrayBufferContents::operator=): (JSC::ArrayBufferContents::~ArrayBufferContents): (JSC::ArrayBufferContents::clear): (JSC::ArrayBufferContents::destroy): (JSC::ArrayBufferContents::reset): (JSC::ArrayBufferContents::tryAllocate): (JSC::ArrayBufferContents::makeShared): (JSC::ArrayBufferContents::transferTo): (JSC::ArrayBufferContents::copyTo): (JSC::ArrayBufferContents::shareWith): (JSC::ArrayBuffer::create): (JSC::ArrayBuffer::createAdopted): (JSC::ArrayBuffer::createFromBytes): (JSC::ArrayBuffer::tryCreate): (JSC::ArrayBuffer::createUninitialized): (JSC::ArrayBuffer::tryCreateUninitialized): (JSC::ArrayBuffer::createInternal): (JSC::ArrayBuffer::ArrayBuffer): (JSC::ArrayBuffer::slice): (JSC::ArrayBuffer::sliceImpl): (JSC::ArrayBuffer::makeShared): (JSC::ArrayBuffer::setSharingMode): (JSC::ArrayBuffer::transferTo): (JSC::ArrayBuffer::transfer): Deleted. * runtime/ArrayBuffer.h: (JSC::arrayBufferSharingModeName): (JSC::SharedArrayBufferContents::data): (JSC::ArrayBufferContents::data): (JSC::ArrayBufferContents::sizeInBytes): (JSC::ArrayBufferContents::isShared): (JSC::ArrayBuffer::sharingMode): (JSC::ArrayBuffer::isShared): (JSC::ArrayBuffer::gcSizeEstimateInBytes): (JSC::arrayBufferDestructorNull): Deleted. (JSC::arrayBufferDestructorDefault): Deleted. (JSC::ArrayBufferContents::ArrayBufferContents): Deleted. (JSC::ArrayBufferContents::transfer): Deleted. (JSC::ArrayBufferContents::copyTo): Deleted. (JSC::ArrayBuffer::create): Deleted. (JSC::ArrayBuffer::createAdopted): Deleted. (JSC::ArrayBuffer::createFromBytes): Deleted. (JSC::ArrayBuffer::tryCreate): Deleted. (JSC::ArrayBuffer::createUninitialized): Deleted. (JSC::ArrayBuffer::tryCreateUninitialized): Deleted. (JSC::ArrayBuffer::createInternal): Deleted. (JSC::ArrayBuffer::ArrayBuffer): Deleted. (JSC::ArrayBuffer::slice): Deleted. (JSC::ArrayBuffer::sliceImpl): Deleted. (JSC::ArrayBufferContents::tryAllocate): Deleted. (JSC::ArrayBufferContents::~ArrayBufferContents): Deleted. * runtime/ArrayBufferSharingMode.h: Added. * runtime/ArrayBufferView.h: (JSC::ArrayBufferView::possiblySharedBuffer): (JSC::ArrayBufferView::unsharedBuffer): (JSC::ArrayBufferView::isShared): (JSC::ArrayBufferView::buffer): Deleted. * runtime/AtomicsObject.cpp: Added. (JSC::AtomicsObject::AtomicsObject): (JSC::AtomicsObject::create): (JSC::AtomicsObject::createStructure): (JSC::AtomicsObject::finishCreation): (JSC::atomicsFuncAdd): (JSC::atomicsFuncAnd): (JSC::atomicsFuncCompareExchange): (JSC::atomicsFuncExchange): (JSC::atomicsFuncIsLockFree): (JSC::atomicsFuncLoad): (JSC::atomicsFuncOr): (JSC::atomicsFuncStore): (JSC::atomicsFuncSub): (JSC::atomicsFuncWait): (JSC::atomicsFuncWake): (JSC::atomicsFuncXor): * runtime/AtomicsObject.h: Added. * runtime/CommonIdentifiers.h: * runtime/DataView.cpp: (JSC::DataView::wrap): * runtime/GenericTypedArrayViewInlines.h: (JSC::GenericTypedArrayView<Adaptor>::subarray): * runtime/Intrinsic.h: * runtime/JSArrayBuffer.cpp: (JSC::JSArrayBuffer::finishCreation): (JSC::JSArrayBuffer::isShared): (JSC::JSArrayBuffer::sharingMode): * runtime/JSArrayBuffer.h: (JSC::toPossiblySharedArrayBuffer): (JSC::toUnsharedArrayBuffer): (JSC::JSArrayBuffer::toWrapped): (JSC::toArrayBuffer): Deleted. * runtime/JSArrayBufferConstructor.cpp: (JSC::JSArrayBufferConstructor::JSArrayBufferConstructor): (JSC::JSArrayBufferConstructor::finishCreation): (JSC::JSArrayBufferConstructor::create): (JSC::constructArrayBuffer): * runtime/JSArrayBufferConstructor.h: (JSC::JSArrayBufferConstructor::sharingMode): * runtime/JSArrayBufferPrototype.cpp: (JSC::arrayBufferProtoFuncSlice): (JSC::JSArrayBufferPrototype::JSArrayBufferPrototype): (JSC::JSArrayBufferPrototype::finishCreation): (JSC::JSArrayBufferPrototype::create): * runtime/JSArrayBufferPrototype.h: * runtime/JSArrayBufferView.cpp: (JSC::JSArrayBufferView::finishCreation): (JSC::JSArrayBufferView::visitChildren): (JSC::JSArrayBufferView::unsharedBuffer): (JSC::JSArrayBufferView::unsharedJSBuffer): (JSC::JSArrayBufferView::possiblySharedJSBuffer): (JSC::JSArrayBufferView::neuter): (JSC::JSArrayBufferView::toWrapped): Deleted. * runtime/JSArrayBufferView.h: (JSC::JSArrayBufferView::jsBuffer): Deleted. * runtime/JSArrayBufferViewInlines.h: (JSC::JSArrayBufferView::isShared): (JSC::JSArrayBufferView::possiblySharedBuffer): (JSC::JSArrayBufferView::possiblySharedImpl): (JSC::JSArrayBufferView::unsharedImpl): (JSC::JSArrayBufferView::byteOffset): (JSC::JSArrayBufferView::toWrapped): (JSC::JSArrayBufferView::buffer): Deleted. (JSC::JSArrayBufferView::impl): Deleted. (JSC::JSArrayBufferView::neuter): Deleted. * runtime/JSDataView.cpp: (JSC::JSDataView::possiblySharedTypedImpl): (JSC::JSDataView::unsharedTypedImpl): (JSC::JSDataView::getTypedArrayImpl): (JSC::JSDataView::typedImpl): Deleted. * runtime/JSDataView.h: (JSC::JSDataView::possiblySharedBuffer): (JSC::JSDataView::unsharedBuffer): (JSC::JSDataView::buffer): Deleted. * runtime/JSDataViewPrototype.cpp: (JSC::dataViewProtoGetterBuffer): * runtime/JSGenericTypedArrayView.h: (JSC::toPossiblySharedNativeTypedView): (JSC::toUnsharedNativeTypedView): (JSC::JSGenericTypedArrayView<Adaptor>::toWrapped): (JSC::JSGenericTypedArrayView::typedImpl): Deleted. (JSC::toNativeTypedView): Deleted. * runtime/JSGenericTypedArrayViewInlines.h: (JSC::JSGenericTypedArrayView<Adaptor>::create): (JSC::JSGenericTypedArrayView<Adaptor>::possiblySharedTypedImpl): (JSC::JSGenericTypedArrayView<Adaptor>::unsharedTypedImpl): (JSC::JSGenericTypedArrayView<Adaptor>::getTypedArrayImpl): * runtime/JSGenericTypedArrayViewPrototypeFunctions.h: (JSC::genericTypedArrayViewProtoGetterFuncBuffer): (JSC::genericTypedArrayViewPrivateFuncSubarrayCreate): * runtime/JSGlobalObject.cpp: (JSC::createAtomicsProperty): (JSC::JSGlobalObject::init): (JSC::JSGlobalObject::visitChildren): * runtime/JSGlobalObject.h: (JSC::JSGlobalObject::arrayBufferPrototype): (JSC::JSGlobalObject::arrayBufferStructure): * runtime/MathObject.cpp: * runtime/RuntimeFlags.h: * runtime/SimpleTypedArrayController.cpp: (JSC::SimpleTypedArrayController::toJS): * runtime/TypedArrayType.h: (JSC::typedArrayTypeForType): Source/WebCore: New tests added in the LayoutTests/workers/sab directory. This teaches WebCore that a typed array could be shared or not. By default, WebCore will reject shared typed arrays as if they were not typed arrays. This ensures that we don't get race conditions in code that can't handle it. If you postMessage a SharedArrayBuffer or something that wraps it, you will send the shared memory to the other worker. * Modules/encryptedmedia/CDMSessionClearKey.cpp: (WebCore::CDMSessionClearKey::cachedKeyForKeyID): * Modules/fetch/FetchBody.cpp: (WebCore::FetchBody::extract): * Modules/mediastream/RTCDataChannel.cpp: (WebCore::RTCDataChannel::send): * Modules/webaudio/AudioBuffer.cpp: (WebCore::AudioBuffer::getChannelData): * Modules/websockets/WebSocket.cpp: (WebCore::WebSocket::send): * bindings/js/JSBlobCustom.cpp: (WebCore::constructJSBlob): * bindings/js/JSCryptoAlgorithmDictionary.cpp: (WebCore::createRsaKeyGenParams): * bindings/js/JSCryptoCustom.cpp: (WebCore::JSCrypto::getRandomValues): * bindings/js/JSCryptoOperationData.cpp: (WebCore::cryptoOperationDataFromJSValue): * bindings/js/JSDOMBinding.h: (WebCore::toJS): (WebCore::toPossiblySharedArrayBufferView): (WebCore::toUnsharedArrayBufferView): (WebCore::toPossiblySharedInt8Array): (WebCore::toPossiblySharedInt16Array): (WebCore::toPossiblySharedInt32Array): (WebCore::toPossiblySharedUint8Array): (WebCore::toPossiblySharedUint8ClampedArray): (WebCore::toPossiblySharedUint16Array): (WebCore::toPossiblySharedUint32Array): (WebCore::toPossiblySharedFloat32Array): (WebCore::toPossiblySharedFloat64Array): (WebCore::toUnsharedInt8Array): (WebCore::toUnsharedInt16Array): (WebCore::toUnsharedInt32Array): (WebCore::toUnsharedUint8Array): (WebCore::toUnsharedUint8ClampedArray): (WebCore::toUnsharedUint16Array): (WebCore::toUnsharedUint32Array): (WebCore::toUnsharedFloat32Array): (WebCore::toUnsharedFloat64Array): (WebCore::toArrayBufferView): Deleted. (WebCore::toInt8Array): Deleted. (WebCore::toInt16Array): Deleted. (WebCore::toInt32Array): Deleted. (WebCore::toUint8Array): Deleted. (WebCore::toUint8ClampedArray): Deleted. (WebCore::toUint16Array): Deleted. (WebCore::toUint32Array): Deleted. (WebCore::toFloat32Array): Deleted. (WebCore::toFloat64Array): Deleted. * bindings/js/JSDataCueCustom.cpp: (WebCore::constructJSDataCue): * bindings/js/JSDictionary.cpp: (WebCore::JSDictionary::convertValue): * bindings/js/JSFileCustom.cpp: (WebCore::constructJSFile): * bindings/js/JSMessagePortCustom.cpp: (WebCore::extractTransferables): * bindings/js/JSWebGLRenderingContextBaseCustom.cpp: (WebCore::dataFunctionf): (WebCore::dataFunctioni): (WebCore::dataFunctionMatrix): * bindings/js/JSXMLHttpRequestCustom.cpp: (WebCore::JSXMLHttpRequest::send): * bindings/js/SerializedScriptValue.cpp: (WebCore::CloneSerializer::dumpArrayBufferView): (WebCore::CloneSerializer::dumpIfTerminal): (WebCore::CloneDeserializer::readArrayBufferView): (WebCore::CloneDeserializer::readTerminal): (WebCore::SerializedScriptValue::transferArrayBuffers): * bindings/js/StructuredClone.cpp: (WebCore::structuredCloneArrayBuffer): (WebCore::structuredCloneArrayBufferView): * bindings/scripts/CodeGeneratorJS.pm: (JSValueToNative): * css/FontFace.cpp: (WebCore::FontFace::create): * html/canvas/WebGL2RenderingContext.cpp: (WebCore::WebGL2RenderingContext::bufferData): (WebCore::WebGL2RenderingContext::bufferSubData): * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp: (WebCore::MediaPlayerPrivateAVFoundation::extractKeyURIKeyIDAndCertificateFromInitData): Source/WebKit/mac: Support the RuntimeFlag. * WebView/WebPreferencesPrivate.h: Source/WebKit/win: Support the RuntimeFlag. * Interfaces/IWebPreferencesPrivate.idl: Source/WebKit2: Adds some small things we need for SharedArrayBuffer. * UIProcess/API/C/WKPreferencesRefPrivate.h: * UIProcess/API/Cocoa/WKPreferencesPrivate.h: * WebProcess/InjectedBundle/InjectedBundle.cpp: (WebKit::InjectedBundle::createWebDataFromUint8Array): Source/WTF: Adds some small things we need for SharedArrayBuffer. * wtf/Atomics.h: (WTF::Atomic::compareExchangeWeakRelaxed): (WTF::Atomic::exchangeAdd): (WTF::Atomic::exchangeAnd): (WTF::Atomic::exchangeOr): (WTF::Atomic::exchangeSub): (WTF::Atomic::exchangeXor): (WTF::atomicLoad): (WTF::atomicStore): (WTF::atomicCompareExchangeWeak): (WTF::atomicCompareExchangeWeakRelaxed): (WTF::atomicCompareExchangeStrong): (WTF::atomicExchangeAdd): (WTF::atomicExchangeAnd): (WTF::atomicExchangeOr): (WTF::atomicExchangeSub): (WTF::atomicExchangeXor): (WTF::atomicExchange): (WTF::Atomic::exchangeAndAdd): Deleted. (WTF::weakCompareAndSwap): Deleted. We need to be able to do atomics operations on naked pointers. We also need to be able to do all of the things that std::atomic does. This adds those things and renames weakCompareAndSwap to atomicCompareExchangeWeakRelaxed so that we're using consistent terminology. * wtf/Bitmap.h: (WTF::WordType>::concurrentTestAndSet): Renamed weakCompareAndSwap. (WTF::WordType>::concurrentTestAndClear): Renamed weakCompareAndSwap. * wtf/FastBitVector.h: (WTF::FastBitVector::atomicSetAndCheck): Renamed weakCompareAndSwap. * wtf/ParkingLot.cpp: (WTF::ParkingLot::unparkOne): (WTF::ParkingLot::unparkCount): * wtf/ParkingLot.h: Added unparkCount(), which lets you unpark some bounded number of threads and returns the number of threads unparked. This is just a modest extension of unparkAll(). unparkAll() now just calls unparkCount(ptr, UINT_MAX). Tools: Use the right kind of typed array API. * DumpRenderTree/TestRunner.cpp: (setAudioResultCallback): LayoutTests: Adding tests. This is a work in progress. * workers/sab: Added. * workers/sab/simple-worker-1.js: Added. (onmessage): * workers/sab/simple-worker-2.js: Added. (onmessage): * workers/sab/simple.html: Added. Canonical link: https://commits.webkit.org/181984@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208209 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-01 03:10:00 +00:00
function wait(memory, index, waitCondition, wakeCondition)
{
while (memory[index] == waitCondition) {
var result = Atomics.wait(memory, index, waitCondition);
switch (result) {
case "not-equal":
case "ok":
break;
default:
postMessage("Error: bad result from wait: " + result);
postMessage("error");
break;
}
var value = memory[index];
if (value != wakeCondition) {
postMessage("Error: wait returned not-equal but the memory has a bad value: " + value);
postMessage("error");
}
}
var value = memory[index];
if (value != wakeCondition) {
postMessage("Error: done waiting but the memory has a bad value: " + value);
postMessage("error");
}
}
function wake(memory, index)
{
var result = Atomics.wake(memory, index, 1);
if (result != 0 && result != 1) {
postMessage("Error: bad result from wake: " + result);
postMessage("error");
}
}
SharedArrayBuffer does not need to be in the transfer list https://bugs.webkit.org/show_bug.cgi?id=168079 Reviewed by Geoffrey Garen and Keith Miller. Source/JavaScriptCore: Exposes a simple shareWith() API for when you know you want to share the contents of a shared buffer. Also a useful explicit operator bool. * runtime/ArrayBuffer.cpp: (JSC::ArrayBuffer::shareWith): * runtime/ArrayBuffer.h: (JSC::ArrayBufferContents::operator bool): Source/WebCore: Tests: workers/sab/multi-memory-multi-buffer.html workers/sab/multi-memory.html workers/sab/no-transfer.html workers/sab/postMessage-clones.html workers/sab/sent-from-worker-no-transfer.html workers/sab/sent-from-worker-transfer.html The SAB API that we originally implemented required that SABs get put in transfer lists when they are sent to workers. The new SAB API that everyone is converging towards requires that you do not put the SAB in the transfer list. That's supposed to be an error. Instead, anytime that a SAB is part of any message to or from a dedicated worker then it is automatically shared. The new API provides a lot more clarity about what is supposed to happen in contexts that support transfering but don't support sharing. Right now this patch allows both styles to work, but I hope we can disable the transfer list capability soon. * bindings/js/IDBBindingUtilities.cpp: (WebCore::deserializeIDBValueToJSValue): * bindings/js/JSMessageEventCustom.cpp: (WebCore::JSMessageEvent::data): * 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::create): (WebCore::SerializedScriptValue::deserialize): * bindings/js/SerializedScriptValue.h: (): Deleted. * dom/CustomEvent.cpp: (WebCore::CustomEvent::trySerializeDetail): * dom/ErrorEvent.cpp: (WebCore::ErrorEvent::trySerializeError): * dom/MessageEvent.cpp: (WebCore::MessageEvent::trySerializeData): * dom/PopStateEvent.cpp: (WebCore::PopStateEvent::trySerializeState): * workers/DedicatedWorkerGlobalScope.cpp: (WebCore::DedicatedWorkerGlobalScope::postMessage): * workers/Worker.cpp: (WebCore::Worker::postMessage): LayoutTests: This adds tests that ensure that SABs behave correctly (are either cloned or shared) depending on context, and that we currently share SABs whether they are in the transfer list or not. This also adds tests for SABs being passed around via more complicated data structures. * workers/sab/multi-memory-expected.txt: Added. * workers/sab/multi-memory-multi-buffer-expected.txt: Added. * workers/sab/multi-memory-multi-buffer.html: Added. * workers/sab/multi-memory-worker-1.js: Added. (onmessage): * workers/sab/multi-memory-worker-2.js: Added. (onmessage): * workers/sab/multi-memory.html: Added. * workers/sab/no-transfer-expected.txt: Added. * workers/sab/no-transfer.html: Added. * workers/sab/postMessage-clones-expected.txt: Added. * workers/sab/postMessage-clones.html: Added. * workers/sab/sab-creator-no-transfer.js: Added. * workers/sab/sab-creator-transfer.js: Added. * workers/sab/sent-from-worker-no-transfer-expected.txt: Added. * workers/sab/sent-from-worker-no-transfer.html: Added. * workers/sab/sent-from-worker-transfer-expected.txt: Added. * workers/sab/sent-from-worker-transfer.html: Added. * workers/sab/worker-resources.js: Canonical link: https://commits.webkit.org/185140@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@212035 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-02-10 02:42:20 +00:00
function checkBufferSharing(shouldShareBuffer)
{
var set = new Set();
for (var i = 1; i < arguments.length; ++i)
set.add(arguments[i].buffer);
if (shouldShareBuffer) {
if (set.size != 1) {
postMessage("Error: buffers should be shared but are not shared (set.size == " + set.size + ")");
postMessage("error");
}
} else {
if (set.size != arguments.length - 1) {
postMessage("Error: buffers should not be shared but are shared");
postMessage("error");
}
}
}
Optimize SharedArrayBuffer in the DFG+FTL https://bugs.webkit.org/show_bug.cgi?id=164108 Reviewed by Saam Barati. JSTests: Added a fairly comprehensive test of the intrinsics. This creates a function for each possible combination of type and operation, and then first uses it nicely and then tries a bunch of erroneous conditions like OOB. * stress/SharedArrayBuffer-opt.js: Added. (string_appeared_here.switch): (string_appeared_here.str): (runAtomic): (shouldFail): (Symbol): (string_appeared_here.a.of.arrays.m.of.atomics): * stress/SharedArrayBuffer.js: Source/JavaScriptCore: This adds atomics intrinsics to the DFG and wires them through to the DFG and FTL backends. This was super easy in the FTL since B3 already has comprehensive atomic intrinsics, which are more powerful than what we need right now. In the DFG backend, I went with an easy-to-write implementation that just reduces everything to a weak CAS loop. It's very inefficient with registers (it needs ~8) but it's the DFG backend, so it's not obvious how much we care. To make the rare cases easy to handle, I refactored AtomicsObject.cpp so that the operations for the slow paths can share code with the native functions. This also fixes register handling in the X86 implementations of CAS, in the case that expectedAndResult is not %rax. This also fixes the ARM64 implementation of branchWeakCAS. I adapted the CascadeLock from WTF/benchmarks/ToyLocks.h as a microbenchmark of lock performance. This benchmark performs 2.5x faster, in both the contended and uncontended case, thanks to this change. It's still about 3x slower than native. I investigated this only a bit. I suspect that the story will be different in asm.js code, which will get constant-folding of the typed array backing store by virtue of how it uses lexically scoped variables as pointers to the heap arrays. It's worth noting that the native lock I was comparing against, the very nicely-tuned CascadeLock, is at the very high end of lock throughput under virtually all conditions (uncontended, microcontended, held for a long time). I also compared to WTF::Lock and others, and the only ones that performed better in this microbenchmark were spinlocks. I don't recommend using those. So, when I say this is 3x slower than native, I really mean that it's 3x slower than the fastest native lock that I have in my arsenal. Also worth noting is that I experimented with exposing Atomics.yield(), which uses sched_yield, as a way of testing if adding a yield loop to the JS cascadeLock would help. It does not help. I did not investigate why. * assembler/AbstractMacroAssembler.h: (JSC::AbstractMacroAssembler::JumpList::append): * assembler/CPU.h: (JSC::is64Bit): (JSC::is32Bit): * b3/B3Common.h: (JSC::B3::is64Bit): Deleted. (JSC::B3::is32Bit): Deleted. * b3/B3LowerToAir.cpp: (JSC::B3::Air::LowerToAir::appendTrapping): (JSC::B3::Air::LowerToAir::appendCAS): (JSC::B3::Air::LowerToAir::appendGeneralAtomic): * dfg/DFGAbstractInterpreterInlines.h: (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::handleIntrinsicCall): * dfg/DFGClobberize.h: (JSC::DFG::clobberize): * dfg/DFGDoesGC.cpp: (JSC::DFG::doesGC): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGNode.h: (JSC::DFG::Node::hasHeapPrediction): (JSC::DFG::Node::hasArrayMode): * dfg/DFGNodeType.h: (JSC::DFG::isAtomicsIntrinsic): (JSC::DFG::numExtraAtomicsArgs): * dfg/DFGPredictionPropagationPhase.cpp: * dfg/DFGSSALoweringPhase.cpp: (JSC::DFG::SSALoweringPhase::handleNode): * dfg/DFGSafeToExecute.h: (JSC::DFG::safeToExecute): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::loadFromIntTypedArray): (JSC::DFG::SpeculativeJIT::setIntTypedArrayLoadResult): (JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray): (JSC::DFG::SpeculativeJIT::getIntTypedArrayStoreOperand): (JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray): * dfg/DFGSpeculativeJIT.h: (JSC::DFG::SpeculativeJIT::callOperation): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * ftl/FTLAbstractHeapRepository.cpp: (JSC::FTL::AbstractHeapRepository::decorateFencedAccess): (JSC::FTL::AbstractHeapRepository::computeRangesAndDecorateInstructions): * ftl/FTLAbstractHeapRepository.h: * ftl/FTLCapabilities.cpp: (JSC::FTL::canCompile): * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileNode): (JSC::FTL::DFG::LowerDFGToB3::compileAtomicsReadModifyWrite): (JSC::FTL::DFG::LowerDFGToB3::compileAtomicsIsLockFree): (JSC::FTL::DFG::LowerDFGToB3::compileGetByVal): (JSC::FTL::DFG::LowerDFGToB3::compilePutByVal): (JSC::FTL::DFG::LowerDFGToB3::pointerIntoTypedArray): (JSC::FTL::DFG::LowerDFGToB3::loadFromIntTypedArray): (JSC::FTL::DFG::LowerDFGToB3::storeType): (JSC::FTL::DFG::LowerDFGToB3::setIntTypedArrayLoadResult): (JSC::FTL::DFG::LowerDFGToB3::getIntTypedArrayStoreOperand): (JSC::FTL::DFG::LowerDFGToB3::vmCall): * ftl/FTLOutput.cpp: (JSC::FTL::Output::store): (JSC::FTL::Output::store32As8): (JSC::FTL::Output::store32As16): (JSC::FTL::Output::atomicXchgAdd): (JSC::FTL::Output::atomicXchgAnd): (JSC::FTL::Output::atomicXchgOr): (JSC::FTL::Output::atomicXchgSub): (JSC::FTL::Output::atomicXchgXor): (JSC::FTL::Output::atomicXchg): (JSC::FTL::Output::atomicStrongCAS): * ftl/FTLOutput.h: (JSC::FTL::Output::store32): (JSC::FTL::Output::store64): (JSC::FTL::Output::storePtr): (JSC::FTL::Output::storeFloat): (JSC::FTL::Output::storeDouble): * jit/JITOperations.h: * runtime/AtomicsObject.cpp: (JSC::atomicsFuncAdd): (JSC::atomicsFuncAnd): (JSC::atomicsFuncCompareExchange): (JSC::atomicsFuncExchange): (JSC::atomicsFuncIsLockFree): (JSC::atomicsFuncLoad): (JSC::atomicsFuncOr): (JSC::atomicsFuncStore): (JSC::atomicsFuncSub): (JSC::atomicsFuncWait): (JSC::atomicsFuncWake): (JSC::atomicsFuncXor): (JSC::operationAtomicsAdd): (JSC::operationAtomicsAnd): (JSC::operationAtomicsCompareExchange): (JSC::operationAtomicsExchange): (JSC::operationAtomicsIsLockFree): (JSC::operationAtomicsLoad): (JSC::operationAtomicsOr): (JSC::operationAtomicsStore): (JSC::operationAtomicsSub): (JSC::operationAtomicsXor): * runtime/AtomicsObject.h: Source/WTF: Made small changes as part of benchmarking the JS versions of these locks. * benchmarks/LockSpeedTest.cpp: * benchmarks/ToyLocks.h: * wtf/Range.h: (WTF::Range::dump): LayoutTests: Add a test of futex performance. * workers/sab/cascade_lock-worker.js: Added. (onmessage): * workers/sab/cascade_lock.html: Added. * workers/sab/worker-resources.js: (cascadeLockSlow): (cascadeLock): (cascadeUnlock): Canonical link: https://commits.webkit.org/187970@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@215565 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-04-20 17:55:44 +00:00
var cascadeLockUnlocked = 0;
var cascadeLockLocked = 1;
var cascadeLockLockedAndParked = 2;
function cascadeLockSlow(memory, index)
{
var desiredState = cascadeLockLocked;
for (;;) {
if (Atomics.compareExchange(memory, index, cascadeLockUnlocked, desiredState) == cascadeLockUnlocked)
return;
desiredState = cascadeLockLockedAndParked;
Atomics.compareExchange(memory, index, cascadeLockLocked, cascadeLockLockedAndParked);
Atomics.wait(memory, index, cascadeLockLockedAndParked);
}
}
function cascadeLock(memory, index)
{
if (Atomics.compareExchange(memory, index, cascadeLockUnlocked, cascadeLockLocked) == cascadeLockUnlocked)
return;
cascadeLockSlow(memory, index);
}
function cascadeUnlock(memory, index)
{
if (Atomics.exchange(memory, index, cascadeLockUnlocked) == cascadeLockLocked)
return;
Atomics.wake(memory, index, 1);
}